mirror of
https://github.com/laochan-eacnet/backend.git
synced 2026-10-02 19:47:59 +03:00
fix lint error
This commit is contained in:
+3
-1
@@ -22,6 +22,8 @@
|
||||
// examples, and because it is not a recommended rule, you should either
|
||||
// disable it, or understand what it enforces.
|
||||
// https://typescript-eslint.io/rules/explicit-function-return-type/
|
||||
"@typescript-eslint/explicit-function-return-type": "warn"
|
||||
"@typescript-eslint/explicit-function-return-type": "warn",
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"build:watch": "tsc -w -p tsconfig.json",
|
||||
"build:release": "npm run clean && tsc -p tsconfig.release.json",
|
||||
"lint": "eslint . --ext .ts --ext .mts",
|
||||
"lint:fix": "eslint . --ext .ts --ext .mts --fix",
|
||||
"test": "jest --coverage",
|
||||
"prettier": "prettier --config .prettierrc --write .",
|
||||
"test:watch": "jest --watch"
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
import pug from 'pug';
|
||||
import { to_bin } from "@kamyu/kbinxml";
|
||||
import { to_bin } from '@kamyu/kbinxml';
|
||||
|
||||
export function kxml(templatePath: string, encoding: 'UTF-8' | 'SHIFT_JIS' = 'UTF-8'): MethodDecorator {
|
||||
export function kxml(
|
||||
templatePath: string,
|
||||
encoding: 'UTF-8' | 'SHIFT_JIS' = 'UTF-8',
|
||||
): MethodDecorator {
|
||||
const template = pug.compileFile('templates/' + templatePath + '.pug');
|
||||
|
||||
return function (_target, _propertyKey, descriptor) {
|
||||
const orig = descriptor.value as Function;
|
||||
descriptor.value = async function (...args: any[]) {
|
||||
const obj = await orig.apply(this, args);
|
||||
const xml = `<?xml version="1.0" encoding="${encoding}"?>` + template(obj);
|
||||
const xml =
|
||||
`<?xml version="1.0" encoding="${encoding}"?>` + template(obj);
|
||||
const kxml = to_bin(xml);
|
||||
|
||||
return Buffer.from(kxml.data);
|
||||
} as unknown as any;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { singleton } from "tsyringe";
|
||||
import { Context, ILaochanService } from "../types.js";
|
||||
import dedent from 'dedent-js'
|
||||
import { to_bin } from "@kamyu/kbinxml";
|
||||
import { singleton } from 'tsyringe';
|
||||
import { Context, ILaochanService } from '../types.js';
|
||||
import dedent from 'dedent-js';
|
||||
import { to_bin } from '@kamyu/kbinxml';
|
||||
|
||||
@singleton()
|
||||
export class DefaultService implements ILaochanService {
|
||||
async process(ctx: Context) {
|
||||
async process(ctx: Context): Promise<Buffer> {
|
||||
const tmp = ctx.service.split('.');
|
||||
const module = tmp[0];
|
||||
const method = tmp[1];
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { kxml } from "../../decorators/render-kxml.js";
|
||||
import { ILaochanService } from "../../types.js";
|
||||
import { singleton } from "tsyringe";
|
||||
import { kxml } from '../../decorators/render-kxml.js';
|
||||
import { ILaochanService } from '../../types.js';
|
||||
import { singleton } from 'tsyringe';
|
||||
|
||||
@singleton()
|
||||
export default class implements ILaochanService {
|
||||
@kxml('facility/get')
|
||||
async process() {
|
||||
async process(): Promise<object> {
|
||||
return {
|
||||
status: 0,
|
||||
location: {
|
||||
@@ -48,12 +48,16 @@ export default class implements ILaochanService {
|
||||
notchAmount: 0,
|
||||
notchCount: 0,
|
||||
supplyLimit: 100000,
|
||||
}
|
||||
},
|
||||
},
|
||||
calendar: {
|
||||
year: 2024,
|
||||
holiday: [0, 1, 8, 41, 53, 79, 118, 122, 123, 124, 197, 222, 260, 265, 281, 306, 326, 365, 372, 406, 407, 418, 444, 484, 488, 489, 490, 491, 561, 588, 589, 624, 630, 631, 652, 672, 673, 692],
|
||||
}
|
||||
holiday: [
|
||||
0, 1, 8, 41, 53, 79, 118, 122, 123, 124, 197, 222, 260, 265, 281, 306,
|
||||
326, 365, 372, 406, 407, 418, 444, 484, 488, 489, 490, 491, 561, 588,
|
||||
589, 624, 630, 631, 652, 672, 673, 692,
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { kxml } from "../../decorators/render-kxml.js";
|
||||
import { ILaochanService } from "../../types.js";
|
||||
import { singleton } from "tsyringe";
|
||||
import { kxml } from '../../decorators/render-kxml.js';
|
||||
import { ILaochanService } from '../../types.js';
|
||||
import { singleton } from 'tsyringe';
|
||||
|
||||
@singleton()
|
||||
export default class implements ILaochanService {
|
||||
@kxml('message/get')
|
||||
async process() {
|
||||
async process(): Promise<object> {
|
||||
return {
|
||||
status: 0,
|
||||
expire: 60,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { singleton } from "tsyringe";
|
||||
import { DefaultService } from "../default.js";
|
||||
import { singleton } from 'tsyringe';
|
||||
import { DefaultService } from '../default.js';
|
||||
|
||||
@singleton()
|
||||
export default class extends DefaultService {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { singleton } from "tsyringe";
|
||||
import { DefaultService } from "../default.js";
|
||||
import { singleton } from 'tsyringe';
|
||||
import { DefaultService } from '../default.js';
|
||||
|
||||
@singleton()
|
||||
export default class extends DefaultService {}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { kxml } from "../../decorators/render-kxml.js";
|
||||
import { ILaochanService } from "../../types.js";
|
||||
import { singleton } from "tsyringe";
|
||||
import { kxml } from '../../decorators/render-kxml.js';
|
||||
import { ILaochanService } from '../../types.js';
|
||||
import { singleton } from 'tsyringe';
|
||||
|
||||
@singleton()
|
||||
export default class implements ILaochanService {
|
||||
@kxml('pcbtracker/alive')
|
||||
async process() {
|
||||
async process(): Promise<object> {
|
||||
return {
|
||||
status: 0,
|
||||
expire: 3600,
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { kxml } from "../../decorators/render-kxml.js";
|
||||
import { ILaochanService } from "../../types.js";
|
||||
import { singleton } from "tsyringe";
|
||||
import { kxml } from '../../decorators/render-kxml.js';
|
||||
import { ILaochanService } from '../../types.js';
|
||||
import { singleton } from 'tsyringe';
|
||||
|
||||
@singleton()
|
||||
export default class implements ILaochanService {
|
||||
@kxml('services/get')
|
||||
async process() {
|
||||
async process(): Promise<object> {
|
||||
return {
|
||||
keepaliveUrl: 'ping://127.0.0.1/?pa=127.0.0.1&ia=127.0.0.1&ga=127.0.0.1ma=127.0.0.1&t1=2&t2=15&rt=2',
|
||||
keepaliveUrl:
|
||||
'ping://127.0.0.1/?pa=127.0.0.1&ia=127.0.0.1&ga=127.0.0.1ma=127.0.0.1&t1=2&t2=15&rt=2',
|
||||
ntpUrl: 'ntp://pool.ntp.org',
|
||||
selfUrl: 'http://localhost:10573',
|
||||
};
|
||||
|
||||
+44
-27
@@ -1,34 +1,33 @@
|
||||
import "reflect-metadata";
|
||||
import 'reflect-metadata';
|
||||
|
||||
import Koa, { DefaultState } from 'koa';
|
||||
import { InjectionToken, Provider, container } from "tsyringe";
|
||||
import { InjectionToken, Provider, container } from 'tsyringe';
|
||||
|
||||
import { ILaochanContext, ILaochanService } from './types.js';
|
||||
import { DefaultService } from "./functions/default.js";
|
||||
import { Logger } from "@cordisjs/logger";
|
||||
import { crypto } from "./middlewares/crypto.js";
|
||||
import { binaryBody } from "./middlewares/binarybody.js";
|
||||
import { parseKxml } from "./middlewares/parseKxml.js";
|
||||
import { decompress } from "./middlewares/decompress.js";
|
||||
import { DefaultService } from './functions/default.js';
|
||||
import { Logger } from '@cordisjs/logger';
|
||||
import { crypto } from './middlewares/crypto.js';
|
||||
import { binaryBody } from './middlewares/binarybody.js';
|
||||
import { parseKxml } from './middlewares/parseKxml.js';
|
||||
import { decompress } from './middlewares/decompress.js';
|
||||
|
||||
function tryResolve<T>(token: InjectionToken<T>): T | undefined {
|
||||
if (!container.isRegistered(token))
|
||||
return undefined;
|
||||
if (!container.isRegistered(token)) return undefined;
|
||||
|
||||
return container.resolve(token);
|
||||
}
|
||||
|
||||
function register<T>(token: InjectionToken<T>, provider: Provider<T> | { new(...args: any[]): T }): T {
|
||||
if (container.isRegistered(token))
|
||||
return container.resolve(token);
|
||||
function register<T>(
|
||||
token: InjectionToken<T>,
|
||||
provider: Provider<T> | { new (...args: any[]): T },
|
||||
): T {
|
||||
if (container.isRegistered(token)) return container.resolve(token);
|
||||
|
||||
// @ts-ignore
|
||||
return container.register(token, provider)
|
||||
.resolve(token);
|
||||
// @ts-expect-error: noob tsc
|
||||
return container.register(token, provider).resolve(token);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const logger = new Logger('main');
|
||||
|
||||
const app = new Koa<DefaultState, ILaochanContext>()
|
||||
@@ -47,20 +46,30 @@ async function main() {
|
||||
|
||||
ctx.model = ctx.query.model;
|
||||
ctx.service = ctx.query.f;
|
||||
ctx.logger = ctx.service ? register(`logger:${ctx.service}`, {
|
||||
useValue: new Logger(ctx.service),
|
||||
}) : logger;
|
||||
ctx.logger = ctx.service
|
||||
? register(`logger:${ctx.service}`, {
|
||||
useValue: new Logger(ctx.service),
|
||||
})
|
||||
: logger;
|
||||
|
||||
let service: ILaochanService | undefined = ctx.service ?
|
||||
tryResolve(ctx.service) : container.resolve(DefaultService);
|
||||
let service: ILaochanService | undefined = ctx.service
|
||||
? tryResolve(ctx.service)
|
||||
: container.resolve(DefaultService);
|
||||
|
||||
if (service === undefined) {
|
||||
try {
|
||||
const module = await import(`./functions/${ctx.service.replace('.', '/')}.js`);
|
||||
const module = await import(
|
||||
`./functions/${ctx.service.replace('.', '/')}.js`
|
||||
);
|
||||
service = register(ctx.service, {
|
||||
useClass: module.default,
|
||||
});
|
||||
} catch { }
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
`load service error %s`,
|
||||
JSON.stringify(e, Object.getOwnPropertyNames(e), 2),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (service === undefined) {
|
||||
@@ -68,13 +77,21 @@ async function main() {
|
||||
service = container.resolve(DefaultService);
|
||||
}
|
||||
|
||||
logger.info('%s [%s]: request = %s', ctx.service, ctx.pcbid, JSON.stringify(ctx.request.body));
|
||||
logger.info(
|
||||
'%s [%s]: request = %s',
|
||||
ctx.service,
|
||||
ctx.pcbid,
|
||||
JSON.stringify(ctx.request.body),
|
||||
);
|
||||
|
||||
try {
|
||||
ctx.body = await service.process(ctx);
|
||||
ctx.status = 200;
|
||||
} catch (e) {
|
||||
logger.error('unexcepted error: %s', JSON.stringify(e, Object.getOwnPropertyNames(e), 2));
|
||||
logger.error(
|
||||
'unexcepted error: %s',
|
||||
JSON.stringify(e, Object.getOwnPropertyNames(e), 2),
|
||||
);
|
||||
|
||||
ctx.status = e.status ?? 500;
|
||||
ctx.body = `${e.stack ?? 'Internal Error'}`;
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { Next } from "koa";
|
||||
import { Context } from "../types.js";
|
||||
import { Next } from 'koa';
|
||||
import { Context } from '../types.js';
|
||||
|
||||
export async function binaryBody(ctx: Context, next: Next) {
|
||||
if (typeof ctx.headers["content-length"] !== 'string') {
|
||||
export async function binaryBody(ctx: Context, next: Next): Promise<any> {
|
||||
if (typeof ctx.headers['content-length'] !== 'string') {
|
||||
return next();
|
||||
}
|
||||
|
||||
const length = parseInt(ctx.headers["content-length"]);
|
||||
const length = parseInt(ctx.headers['content-length']);
|
||||
if (length === 0) {
|
||||
return next();
|
||||
}
|
||||
|
||||
ctx.request.body = await new Promise((resolve, reject) => {
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
let len = 0
|
||||
let len = 0;
|
||||
|
||||
ctx.req.on('data', (chunk: Buffer) => {
|
||||
chunk.copy(buffer, len);
|
||||
@@ -28,7 +28,7 @@ export async function binaryBody(ctx: Context, next: Next) {
|
||||
if (len < length) {
|
||||
reject(new Error('socket hanged up unexceptly.'));
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
return next();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Next } from "koa";
|
||||
import { Context } from "../types.js";
|
||||
import { rc4Transfrom } from "../utils/rc4.js";
|
||||
import { Next } from 'koa';
|
||||
import { Context } from '../types.js';
|
||||
import { rc4Transfrom } from '../utils/rc4.js';
|
||||
|
||||
export async function crypto(ctx: Context, next: Next) {
|
||||
export async function crypto(ctx: Context, next: Next): Promise<any> {
|
||||
if (typeof ctx.req.headers['x-eamuse-info'] !== 'string') {
|
||||
return next();
|
||||
}
|
||||
@@ -31,8 +31,12 @@ export async function crypto(ctx: Context, next: Next) {
|
||||
return;
|
||||
}
|
||||
|
||||
const time = Math.floor(new Date().valueOf() / 1000).toString(16).padStart(8, '0');
|
||||
const salt = Math.floor(Math.random() * 0xFFFF).toString(16).padStart(4, '0');
|
||||
const time = Math.floor(new Date().valueOf() / 1000)
|
||||
.toString(16)
|
||||
.padStart(8, '0');
|
||||
const salt = Math.floor(Math.random() * 0xffff)
|
||||
.toString(16)
|
||||
.padStart(4, '0');
|
||||
|
||||
const encrypted = rc4Transfrom(time + salt, ctx.body);
|
||||
ctx.body = encrypted;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Next } from "koa";
|
||||
import { Context } from "../types.js";
|
||||
import { lz77Decode } from "../utils/lz77.js";
|
||||
import { Next } from 'koa';
|
||||
import { Context } from '../types.js';
|
||||
import { lz77Decode } from '../utils/lz77.js';
|
||||
|
||||
export async function decompress(ctx: Context, next: Next) {
|
||||
export async function decompress(ctx: Context, next: Next): Promise<any> {
|
||||
if (!(ctx.request.body instanceof Buffer)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Next } from "koa";
|
||||
import { Context } from "../types.js";
|
||||
import { to_xml } from "@kamyu/kbinxml";
|
||||
import { Next } from 'koa';
|
||||
import { Context } from '../types.js';
|
||||
import { to_xml } from '@kamyu/kbinxml';
|
||||
import { XMLParser } from 'fast-xml-parser';
|
||||
|
||||
const parser = new XMLParser({
|
||||
@@ -11,46 +11,59 @@ const parser = new XMLParser({
|
||||
allowBooleanAttributes: true,
|
||||
});
|
||||
|
||||
function parseValue(node: any) {
|
||||
function parseValue(node: { $__type: string; $__count?: unknown }): any {
|
||||
const isArray = '$__count' in node;
|
||||
|
||||
if (['s8', 'u8', 's16', 'u16', 's32', 'u32', 's64', 'u64', 'float', 'double'].includes(node.$__type)) {
|
||||
if (isArray) {
|
||||
return node['#text'].split(' ').map(v => new Number(v));
|
||||
}
|
||||
if (
|
||||
[
|
||||
's8',
|
||||
'u8',
|
||||
's16',
|
||||
'u16',
|
||||
's32',
|
||||
'u32',
|
||||
's64',
|
||||
'u64',
|
||||
'float',
|
||||
'double',
|
||||
].includes(node.$__type)
|
||||
) {
|
||||
if (isArray) {
|
||||
return node['#text'].split(' ').map((v) => new Number(v));
|
||||
}
|
||||
|
||||
return new Number(node['#text']);
|
||||
return new Number(node['#text']);
|
||||
}
|
||||
|
||||
if(['b', 'bool'].includes(node.$__type)) {
|
||||
if (['b', 'bool'].includes(node.$__type)) {
|
||||
return !!parseInt(node['#text']);
|
||||
}
|
||||
|
||||
if (['bin', 'binary'].includes(node.$__type)) {
|
||||
return Buffer.from(node['#text'], 'hex')
|
||||
return Buffer.from(node['#text'], 'hex');
|
||||
}
|
||||
|
||||
if(['ip4', 'str', 'string'].includes(node.$__type)) {
|
||||
if (['ip4', 'str', 'string'].includes(node.$__type)) {
|
||||
return node['#text'];
|
||||
}
|
||||
|
||||
if(node.$__type == 'time') {
|
||||
if (node.$__type == 'time') {
|
||||
return new Date(parseInt(node['#text']) * 1000);
|
||||
}
|
||||
|
||||
return {
|
||||
type: node.$__type,
|
||||
value: node['#text'],
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function kxmlToObject(node: any) {
|
||||
function kxmlToObject(node: Record<string, unknown>): any {
|
||||
if (node instanceof Array) {
|
||||
return node.map(v => kxmlToObject(v));
|
||||
return node.map((v) => kxmlToObject(v));
|
||||
}
|
||||
|
||||
if ('$__type' in node) {
|
||||
return parseValue(node);
|
||||
return parseValue(node as { $__type: string; $__count?: unknown });
|
||||
}
|
||||
|
||||
const obj: object = {};
|
||||
@@ -64,13 +77,13 @@ function kxmlToObject(node: any) {
|
||||
continue;
|
||||
}
|
||||
|
||||
obj[key] = kxmlToObject(node[key]);
|
||||
obj[key] = kxmlToObject(node[key] as Record<string, unknown>);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
export async function parseKxml(ctx: Context, next: Next) {
|
||||
export async function parseKxml(ctx: Context, next: Next): Promise<object> {
|
||||
if (!(ctx.request.body instanceof Buffer)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
import { Logger } from "@cordisjs/logger";
|
||||
import { DefaultState, ParameterizedContext } from "koa";
|
||||
import { Logger } from '@cordisjs/logger';
|
||||
import { DefaultState, ParameterizedContext } from 'koa';
|
||||
|
||||
export interface ILaochanContext {
|
||||
model?: string;
|
||||
@@ -9,7 +9,7 @@ export interface ILaochanContext {
|
||||
|
||||
request: {
|
||||
body: Buffer | object | undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export type Context = ParameterizedContext<DefaultState, ILaochanContext, any>;
|
||||
|
||||
+3
-6
@@ -10,21 +10,18 @@ export function lz77Decode(data: Buffer): Buffer {
|
||||
if (flag & (1 << bit)) {
|
||||
output.push(data[offset]);
|
||||
offset += 1;
|
||||
|
||||
} else {
|
||||
if (offset >= data.length)
|
||||
break;
|
||||
if (offset >= data.length) break;
|
||||
|
||||
const lookbackFlag = data.readUInt16BE(offset);
|
||||
const lookbackLength = (lookbackFlag & 0x000f) + 3;
|
||||
const lookbackOffset = lookbackFlag >> 4;
|
||||
|
||||
offset += 2;
|
||||
if (lookbackFlag == 0)
|
||||
break;
|
||||
if (lookbackFlag == 0) break;
|
||||
|
||||
for (let i = 0; i < lookbackLength; i++) {
|
||||
let loffset = output.length - lookbackOffset;
|
||||
const loffset = output.length - lookbackOffset;
|
||||
|
||||
if (loffset <= 0 || loffset >= output.length) {
|
||||
output.push(0);
|
||||
|
||||
+5
-6
@@ -1,13 +1,12 @@
|
||||
import { createHash } from "crypto";
|
||||
import { createHash } from 'crypto';
|
||||
import rc4 from 'arc4';
|
||||
|
||||
const EAMUSE_RC4_KEY = '69D74627D985EE2187161570D08D93B12455035B6DF0D8205DF5';
|
||||
|
||||
export function rc4Transfrom(keyHex: string, data: Buffer) {
|
||||
export function rc4Transfrom(keyHex: string, data: Buffer): Buffer {
|
||||
const key = createHash('md5')
|
||||
.update(keyHex + EAMUSE_RC4_KEY, 'hex')
|
||||
.digest();
|
||||
.update(keyHex + EAMUSE_RC4_KEY, 'hex')
|
||||
.digest();
|
||||
|
||||
return rc4('arc4', key)
|
||||
.encodeBuffer(data)
|
||||
return rc4('arc4', key).encodeBuffer(data);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user