mirror of
https://github.com/laochan-eacnet/backend.git
synced 2026-10-10 07:18:10 +03:00
pass sdvx requests to maomani
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { AcRelayInfo } from '../types.js';
|
||||
import { fromKBinXml, toKBinXml, toObject } from './kbinxml.js';
|
||||
import { Serializable } from './kxml-value.js';
|
||||
import { LZ77 } from './lz77.js';
|
||||
import { tokenToCardNumber } from './laochan-id.js';
|
||||
import config from './config.js';
|
||||
|
||||
const PCB_ID = '1A0C1A0C1A0C1A0C1A0C';
|
||||
|
||||
export async function requestEa3(info: AcRelayInfo, model: string, token: string, ea3Url: string = 'http://maomani.cn:573/'): Promise<{
|
||||
status: number,
|
||||
response: Serializable,
|
||||
}> {
|
||||
if (config.isDev) {
|
||||
console.log('ea3 call:');
|
||||
}
|
||||
|
||||
const request = toKBinXml('call', {
|
||||
[info.module]: {
|
||||
$method: info.method,
|
||||
$model: model,
|
||||
$cardid: tokenToCardNumber(token),
|
||||
$srcid: PCB_ID,
|
||||
...info.request,
|
||||
},
|
||||
}, 'UTF-8', config.isDev);
|
||||
|
||||
const compressed = LZ77.compress(request.data);
|
||||
const body = new Blob([compressed]);
|
||||
|
||||
const result = await fetch(`${ea3Url}/?model=${model}&f=${info.module}.${info.method}`, {
|
||||
method: 'post',
|
||||
body,
|
||||
headers: {
|
||||
'X-Compress': 'lz77',
|
||||
},
|
||||
}).then(async r => {
|
||||
const raw = new Uint8Array(await r.arrayBuffer());
|
||||
if (r.headers.get('x-compress') === 'lz77') {
|
||||
return new Uint8Array(LZ77.decompress(raw));
|
||||
}
|
||||
|
||||
return raw;
|
||||
});
|
||||
|
||||
if (config.isDev) {
|
||||
console.log('ea3 response:');
|
||||
}
|
||||
|
||||
const response = fromKBinXml(result, config.isDev);
|
||||
|
||||
return {
|
||||
status: parseInt(response['response'][info.module]?.$status ?? '0'),
|
||||
response: response['response'],
|
||||
};
|
||||
}
|
||||
|
||||
export async function requestEa3Typed<T>(info: AcRelayInfo, model: string, token: string, ea3Url?: string): Promise<T> {
|
||||
const { response } = await requestEa3(info, model, token, ea3Url);
|
||||
return toObject<T>(response);
|
||||
}
|
||||
+29
-20
@@ -1,4 +1,4 @@
|
||||
import { to_bin, to_xml } from "@kamyu/kbinxml";
|
||||
import { to_bin, to_xml } from "@geekidos/kbinxml";
|
||||
import { XMLParser } from "fast-xml-parser";
|
||||
import _ from "lodash";
|
||||
import { Serializable } from "./kxml-value.js";
|
||||
@@ -8,6 +8,7 @@ export const parser = new XMLParser({
|
||||
parseAttributeValue: false,
|
||||
attributeNamePrefix: '$',
|
||||
removeNSPrefix: true,
|
||||
textNodeName: '__value',
|
||||
numberParseOptions: {
|
||||
hex: false,
|
||||
leadingZeros: false,
|
||||
@@ -32,49 +33,49 @@ function parseValue(node: { $__type: string; $__count?: unknown }): any {
|
||||
].includes(node.$__type)
|
||||
) {
|
||||
if (isArray) {
|
||||
return node['#text'].split(' ').map((v) => parseInt(v));
|
||||
return node['__value'].split(' ').map((v) => parseInt(v));
|
||||
}
|
||||
|
||||
return parseInt(node['#text']);
|
||||
return parseInt(node['__value']);
|
||||
}
|
||||
|
||||
if (['float', 'double'].includes(node.$__type)) {
|
||||
if (isArray) {
|
||||
return node['#text'].split(' ').map((v) => parseFloat(v));
|
||||
return node['__value'].split(' ').map((v) => parseFloat(v));
|
||||
}
|
||||
|
||||
return parseFloat(node['#text']);
|
||||
return parseFloat(node['__value']);
|
||||
}
|
||||
|
||||
if (['b', 'bool'].includes(node.$__type)) {
|
||||
return !!parseInt(node['#text']);
|
||||
return !!parseInt(node['__value']);
|
||||
}
|
||||
|
||||
if (['bin', 'binary'].includes(node.$__type)) {
|
||||
return Buffer.from(node['#text'], 'hex');
|
||||
return Buffer.from(node['__value'], 'hex');
|
||||
}
|
||||
|
||||
if (['ip4', 'str', 'string'].includes(node.$__type)) {
|
||||
return node['#text'];
|
||||
return node['__value'];
|
||||
}
|
||||
|
||||
if (node.$__type == 'time') {
|
||||
return new Date(parseInt(node['#text']) * 1000);
|
||||
return new Date(parseInt(node['__value']) * 1000);
|
||||
}
|
||||
|
||||
return {
|
||||
type: node.$__type,
|
||||
value: node['#text'],
|
||||
value: node['__value'],
|
||||
};
|
||||
}
|
||||
|
||||
export function toObject(node: Record<string, unknown> | unknown[] | string): any {
|
||||
export function toObject<T = any>(node: Record<string, unknown> | unknown[] | string): T {
|
||||
if (node instanceof Array) {
|
||||
return node.map((v) => toObject(v as Record<string, unknown>));
|
||||
return node.map((v) => toObject(v as Record<string, unknown>)) as T;
|
||||
}
|
||||
|
||||
if (typeof node === 'string') {
|
||||
return {};
|
||||
return {} as T;
|
||||
}
|
||||
|
||||
if ('$__type' in node) {
|
||||
@@ -95,13 +96,17 @@ export function toObject(node: Record<string, unknown> | unknown[] | string): an
|
||||
obj[key] = toObject(node[key] as Record<string, unknown>);
|
||||
}
|
||||
|
||||
return obj;
|
||||
return obj as T;
|
||||
}
|
||||
|
||||
export function fromKBinXml(kbinxml: Uint8Array) {
|
||||
const xml = to_xml(kbinxml).data;
|
||||
const parsedXml = parser.parse(xml);
|
||||
return toObject(parsedXml);
|
||||
export function fromKBinXml(kbinxml: Uint8Array, dumpXml: boolean = false) {
|
||||
const xml = to_xml(kbinxml, true).data;
|
||||
|
||||
if (dumpXml) {
|
||||
console.log(xml);
|
||||
}
|
||||
|
||||
return parser.parse(xml);
|
||||
}
|
||||
|
||||
function serializeValue(value: any, type: string): string {
|
||||
@@ -239,8 +244,12 @@ function serializeObject(obj: Serializable, name: string, linePrefix: string = '
|
||||
return output + `</${name}>\n`;
|
||||
}
|
||||
|
||||
export function toKBinXml(topName: string, obj: Serializable, encoding: 'UTF-8' | 'SHIFT_JIS' = 'UTF-8') {
|
||||
export function toKBinXml(topName: string, obj: Serializable, encoding: 'UTF-8' | 'SHIFT_JIS' = 'UTF-8', dumpXml: boolean = false) {
|
||||
const xml = `<?xml version="1.0" encoding="${encoding}"?>` + serializeObject(obj, topName);
|
||||
console.log(xml);
|
||||
|
||||
if (dumpXml) {
|
||||
console.log(xml);
|
||||
}
|
||||
|
||||
return to_bin(xml);
|
||||
}
|
||||
|
||||
+5
-58
@@ -1,64 +1,11 @@
|
||||
import {compress, decompress} from '@kamyu/lz77';
|
||||
|
||||
export class LZ77 {
|
||||
static compress(input: ArrayLike<number>) {
|
||||
const a = Uint8Array.from(input);
|
||||
const res = new Uint8Array(a.length + a.length / 8 + 3);
|
||||
let p = 0;
|
||||
for (let i = 0; i < a.length; ++i) {
|
||||
if (i % 8 === 0) {
|
||||
if (a.length - i < 8) {
|
||||
res[p] = (Math.pow(2, a.length - i) - 1);
|
||||
} else {
|
||||
res[p] = 255;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
res[p] = a[i];
|
||||
p++;
|
||||
}
|
||||
res[p] = 0;
|
||||
res[p + 1] = 0;
|
||||
|
||||
return Buffer.from(res);
|
||||
return compress(Uint8Array.from(input));
|
||||
}
|
||||
|
||||
static decompress(a: ArrayLike<number>) {
|
||||
const res = new Uint8Array(0x190000);
|
||||
let p = 0;
|
||||
let r = 0;
|
||||
let t = 0;
|
||||
let b = 8;
|
||||
let mask = 0;
|
||||
|
||||
while (true) {
|
||||
if (b === 8) {
|
||||
mask = a[p];
|
||||
p++;
|
||||
b = 0;
|
||||
}
|
||||
if ((mask & 1) === 1) {
|
||||
res[r] = a[p];
|
||||
r++;
|
||||
p++;
|
||||
} else {
|
||||
let distance = a[p];
|
||||
let count = a[p + 1];
|
||||
if (distance === 0 && count === 0) break;
|
||||
p += 2;
|
||||
distance <<= 4;
|
||||
distance |= count >> 4;
|
||||
count = (count & 0x0F) + 3;
|
||||
t = r - distance;
|
||||
for (let i = 0; i < count; ++i) {
|
||||
res[r] = t < 0 ? 0x00 : res[t];
|
||||
r++;
|
||||
t++;
|
||||
}
|
||||
}
|
||||
mask >>= 1;
|
||||
b += 1;
|
||||
}
|
||||
|
||||
const o = res.slice(0, r);
|
||||
return Buffer.from(o);
|
||||
static decompress(input: ArrayLike<number>) {
|
||||
return decompress(Uint8Array.from(input));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user