mirror of
https://github.com/laochan-eacnet/backend.git
synced 2026-10-07 14:07:57 +03:00
eacnet framework
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import _ from 'lodash';
|
||||
import { to_bin } from '@kamyu/kbinxml';
|
||||
import { LZ77 } from '../utils/lz77.js';
|
||||
|
||||
function serializeValue(value: any, type: string): string {
|
||||
if (
|
||||
@@ -115,7 +116,7 @@ function serializeObject(obj: Object, name: string, linePrefix: string = '') {
|
||||
return output + `</${name}>\n`;
|
||||
}
|
||||
|
||||
export function kxml(topName: string = 'response', encoding: 'UTF-8' | 'SHIFT_JIS' = 'UTF-8'): MethodDecorator {
|
||||
export function eacnet(topName: string, encoding: 'UTF-8' | 'SHIFT_JIS' = 'UTF-8'): MethodDecorator {
|
||||
return function (_target, _propertyKey, descriptor) {
|
||||
const orig = descriptor.value as Function;
|
||||
descriptor.value = async function (...args: any[]) {
|
||||
@@ -123,27 +124,17 @@ export function kxml(topName: string = 'response', encoding: 'UTF-8' | 'SHIFT_JI
|
||||
const xml =
|
||||
`<?xml version="1.0" encoding="${encoding}"?>` + serializeObject(obj, topName);
|
||||
const kxml = to_bin(xml);
|
||||
const compressed = LZ77.compress(kxml.data);
|
||||
const result = Buffer.allocUnsafe(compressed.length + 0x2E);
|
||||
|
||||
return Buffer.from(kxml.data);
|
||||
result.write('P2D:2015091800', 0, 'ascii');
|
||||
result.set(compressed, 0x2E);
|
||||
|
||||
return result;
|
||||
} as unknown as any;
|
||||
}
|
||||
}
|
||||
|
||||
export function serviceKxml(service: string, topName: string = 'response', encoding: 'UTF-8' | 'SHIFT_JIS' = 'UTF-8'): (method: string) => MethodDecorator {
|
||||
return function (method: string) {
|
||||
const toKxml = kxml(topName, encoding);
|
||||
return function (_target, _propertyKey, descriptor) {
|
||||
const orig = descriptor.value as Function;
|
||||
descriptor.value = async function (...args: any[]) {
|
||||
const obj = await orig.apply(this, args);
|
||||
return { [service]: { method, ...obj } };
|
||||
} as unknown as any;
|
||||
|
||||
toKxml(_target, _propertyKey, descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// console.log(serializeObject({
|
||||
// $attr: 'attr1',
|
||||
// sb: {
|
||||
@@ -1,21 +0,0 @@
|
||||
import pug from 'pug';
|
||||
import { to_bin } from '@kamyu/kbinxml';
|
||||
|
||||
export function kxmlTemplate(
|
||||
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 kxml = to_bin(xml);
|
||||
|
||||
return Buffer.from(kxml.data);
|
||||
} as unknown as any;
|
||||
};
|
||||
}
|
||||
+37
-45
@@ -1,15 +1,13 @@
|
||||
import 'reflect-metadata';
|
||||
|
||||
import Koa, { DefaultState } from 'koa';
|
||||
import bodyParser from 'koa-bodyparser';
|
||||
import { InjectionToken, Provider, container } from 'tsyringe';
|
||||
|
||||
import { ILaochanContext } from './types.js';
|
||||
import { DefaultService } from './services/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 { eacnet } from './middlewares/eacnet.js';
|
||||
import config from './utils/config.js';
|
||||
import { MongoClient, Db } from 'mongodb';
|
||||
|
||||
@@ -30,7 +28,7 @@ function register<T>(
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const logger = new Logger('laochan-net');
|
||||
const logger = new Logger('laochan-eacnet');
|
||||
|
||||
logger.info('initialization...');
|
||||
|
||||
@@ -59,38 +57,22 @@ async function main(): Promise<void> {
|
||||
ctx.body = `${e.stack ?? 'Internal Error'}`;
|
||||
}
|
||||
})
|
||||
.use(binaryBody)
|
||||
.use(crypto)
|
||||
.use(decompress)
|
||||
.use(parseKxml)
|
||||
.use(bodyParser({
|
||||
formLimit: '1mb',
|
||||
}))
|
||||
.use(eacnet)
|
||||
.use(async (ctx, next) => {
|
||||
if (typeof ctx.query.f !== 'string') {
|
||||
if (!ctx.service) {
|
||||
throw new Error('invaild service');
|
||||
}
|
||||
|
||||
if (typeof ctx.query.model !== 'string') {
|
||||
throw new Error('invaild model');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [serviceName, method] = ctx.query.f.split('.');
|
||||
|
||||
ctx.model = ctx.query.model;
|
||||
ctx.service = {
|
||||
name: serviceName,
|
||||
method,
|
||||
};
|
||||
|
||||
ctx.body = ctx.body[ctx.service.name];
|
||||
ctx.logger = ctx.service
|
||||
? register(`logger:${ctx.service.name}`, {
|
||||
useValue: new Logger(ctx.service.name),
|
||||
? register(`logger:${ctx.service.name}:${ctx.service.method}`, {
|
||||
useValue: new Logger(`${ctx.service.name}:${ctx.service.method}`),
|
||||
})
|
||||
: logger;
|
||||
|
||||
let service: object | undefined = ctx.service
|
||||
? tryResolve(ctx.service.name)
|
||||
: container.resolve(DefaultService);
|
||||
let service: object | undefined = tryResolve(ctx.service.name);
|
||||
|
||||
if (service === undefined) {
|
||||
try {
|
||||
@@ -100,43 +82,53 @@ async function main(): Promise<void> {
|
||||
module = await import(
|
||||
`./services/${ctx.service.name}/index.js`
|
||||
);
|
||||
} catch {
|
||||
module = await import(
|
||||
`./services/${ctx.service.name}.js`
|
||||
);
|
||||
} catch (e) {
|
||||
if (e.code != 'ERR_MODULE_NOT_FOUND') {
|
||||
logger.error(
|
||||
`load service error %s`,
|
||||
JSON.stringify(e, Object.getOwnPropertyNames(e), 2),
|
||||
);
|
||||
} else {
|
||||
module = await import(
|
||||
`./services/${ctx.service.name}.js`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
service = register(ctx.service.name, {
|
||||
useClass: module.default,
|
||||
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
`load service error %s`,
|
||||
JSON.stringify(e, Object.getOwnPropertyNames(e), 2),
|
||||
);
|
||||
if (e.code != 'ERR_MODULE_NOT_FOUND') {
|
||||
logger.error(
|
||||
`load service error %s`,
|
||||
JSON.stringify(e, Object.getOwnPropertyNames(e), 2),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(
|
||||
'%s.$s [%s]: request = %s',
|
||||
'%s.%s [%s]: request = %s',
|
||||
ctx.service.name,
|
||||
ctx.service.method,
|
||||
ctx.pcbid,
|
||||
JSON.stringify(ctx.request.body),
|
||||
ctx.token,
|
||||
JSON.stringify(ctx.body),
|
||||
);
|
||||
|
||||
if (service === undefined || !(method in service)) {
|
||||
logger.warn(`unimplemented method ${ctx.service.method} in ${ctx.service.name}`);
|
||||
let method = ctx.service.method;
|
||||
|
||||
if (!service || !(service[method])?.bind) {
|
||||
logger.warn(`unimplemented method ${method} in ${ctx.service.name}`);
|
||||
|
||||
service = container.resolve(DefaultService);
|
||||
method = 'default';
|
||||
}
|
||||
|
||||
ctx.body = await service[method](ctx);
|
||||
ctx.body = await (service[method] as Function).bind(service)(ctx);
|
||||
ctx.status = 200;
|
||||
|
||||
logger.info('%s [server]: status = %d', ctx.service, ctx.status);
|
||||
logger.info('%s.%s [server]: status = %d', ctx.service.name, ctx.service.method, ctx.status);
|
||||
return await next();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { Next } from 'koa';
|
||||
import { Context } from '../types.js';
|
||||
|
||||
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']);
|
||||
if (length === 0) {
|
||||
return next();
|
||||
}
|
||||
|
||||
ctx.request.body = await new Promise((resolve, reject) => {
|
||||
const buffer = Buffer.allocUnsafe(length);
|
||||
let len = 0;
|
||||
|
||||
ctx.req.on('data', (chunk: Buffer) => {
|
||||
chunk.copy(buffer, len);
|
||||
len += chunk.length;
|
||||
|
||||
if (len == length) {
|
||||
resolve(buffer);
|
||||
}
|
||||
});
|
||||
|
||||
ctx.req.on('close', () => {
|
||||
if (len < length) {
|
||||
reject(new Error('socket hanged up unexceptly.'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return next();
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { Next } from 'koa';
|
||||
import { Context } from '../types.js';
|
||||
import { rc4Transfrom } from '../utils/rc4.js';
|
||||
|
||||
export async function crypto(ctx: Context, next: Next): Promise<any> {
|
||||
if (typeof ctx.req.headers['x-eamuse-info'] !== 'string') {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!(ctx.request.body instanceof Buffer)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
{
|
||||
const eamuseInfo: string[] = ctx.req.headers['x-eamuse-info'].split('-');
|
||||
const version = eamuseInfo[0];
|
||||
const time = eamuseInfo[1];
|
||||
const salt = eamuseInfo[2];
|
||||
|
||||
if (version !== '1') {
|
||||
throw new Error(`unsupported crypto version ${version}`);
|
||||
}
|
||||
|
||||
const decrypted = rc4Transfrom(time + salt, ctx.request.body);
|
||||
ctx.request.body = decrypted;
|
||||
}
|
||||
|
||||
await next();
|
||||
|
||||
if (!(ctx.body instanceof Buffer)) {
|
||||
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 encrypted = rc4Transfrom(time + salt, ctx.body);
|
||||
ctx.body = encrypted;
|
||||
|
||||
ctx.set('X-Eamuse-Info', `1-${time}-${salt}`);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { Next } from 'koa';
|
||||
import { Context } from '../types.js';
|
||||
import { lz77Decode } from '../utils/lz77.js';
|
||||
|
||||
export async function decompress(ctx: Context, next: Next): Promise<any> {
|
||||
if (!(ctx.request.body instanceof Buffer)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (typeof ctx.request.headers['x-compress'] !== 'string') {
|
||||
return next();
|
||||
}
|
||||
|
||||
// no compression for response
|
||||
ctx.set('X-Compress', 'none');
|
||||
|
||||
if (ctx.request.headers['x-compress'] == 'none') {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (ctx.request.headers['x-compress'] != 'lz77') {
|
||||
throw new Error('unsupported compression mehotd');
|
||||
}
|
||||
|
||||
ctx.request.body = lz77Decode(ctx.request.body);
|
||||
return next();
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Next } from 'koa';
|
||||
import { Context } from '../types.js';
|
||||
import { LZ77 } from '../utils/lz77.js';
|
||||
import { to_xml } from '@kamyu/kbinxml';
|
||||
import { XMLParser } from 'fast-xml-parser';
|
||||
|
||||
@@ -83,26 +84,43 @@ function kxmlToObject(node: Record<string, unknown>): any {
|
||||
return obj;
|
||||
}
|
||||
|
||||
export async function parseKxml(ctx: Context, next: Next): Promise<object> {
|
||||
if (!(ctx.request.body instanceof Buffer)) {
|
||||
export async function eacnet(ctx: Context, next: Next): Promise<any> {
|
||||
const body = ctx.request.body as {
|
||||
request: string;
|
||||
p2d_token: string;
|
||||
} | undefined;
|
||||
|
||||
if (!body || !body.request) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if ('x-dev' in ctx.request.headers) {
|
||||
ctx.request.body = JSON.parse(ctx.request.body.toString('utf-8'));
|
||||
const { request, p2d_token: token } = body;
|
||||
const buffer = Buffer.from(request
|
||||
.replaceAll(' ', '+')
|
||||
.replaceAll('-', '+')
|
||||
.replaceAll('_', '/') + '===',
|
||||
'base64'
|
||||
);
|
||||
const decoded = LZ77.decompress(buffer);
|
||||
const xmlResult = kxmlToObject(parser.parse(to_xml(decoded).data));
|
||||
|
||||
const game = Object.keys(xmlResult)[0];
|
||||
|
||||
if (!(game in xmlResult)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if(xmlResult[game].params) {
|
||||
ctx.body = xmlResult.p2d.params;
|
||||
} else {
|
||||
const xmlResult = to_xml(ctx.request.body);
|
||||
ctx.request.body = kxmlToObject(parser.parse(xmlResult.data));
|
||||
ctx.body = {};
|
||||
}
|
||||
|
||||
const body = ctx.request.body as any;
|
||||
|
||||
if ('call' in body) {
|
||||
ctx.pcbid = body.call.srcid;
|
||||
ctx.tag = body.call.tag;
|
||||
|
||||
ctx.body = body.call;
|
||||
ctx.service = {
|
||||
name: game,
|
||||
method: xmlResult[game].method,
|
||||
}
|
||||
|
||||
ctx.token = token;
|
||||
return next();
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import { serviceKxml } from "../../decorators/to-kxml.js";
|
||||
// import { v } from "../../utils/kxml-value.js";
|
||||
|
||||
const resp = serviceKxml('IIDX31music');
|
||||
|
||||
export default class {
|
||||
@resp('crate')
|
||||
async crate() {
|
||||
return {
|
||||
$expire: 1800,
|
||||
c: [
|
||||
// v.s32('114514', { mid: 11451 }),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@resp('reg')
|
||||
async reg() {
|
||||
return {
|
||||
$clid: 0,
|
||||
$crate: 0,
|
||||
$frate: 0,
|
||||
$mid: 0,
|
||||
$rankside: 0,
|
||||
$status: 0,
|
||||
shopdata: {
|
||||
$rank: 252,
|
||||
},
|
||||
ranklist: {
|
||||
$total_user_num: 1,
|
||||
data: [{
|
||||
$clflg: 4,
|
||||
$dgrade: -1,
|
||||
$sgrade: -1,
|
||||
$iidx_id: '114514',
|
||||
$myFlg: '0',
|
||||
$name: 'MK_',
|
||||
$opname: '雷窝',
|
||||
$pid: 0,
|
||||
$rnum: 0,
|
||||
$score: 0,
|
||||
$update: 0,
|
||||
$body: 0,
|
||||
$face: 0,
|
||||
$hair: 0,
|
||||
$hand: 0,
|
||||
$head: 0,
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
import { serviceKxml } from "../../decorators/to-kxml.js";
|
||||
import { Context } from "../../types.js";
|
||||
import { v } from "../../utils/kxml-value.js";
|
||||
|
||||
interface GetPCDataCall {
|
||||
ccode: string,
|
||||
cid: string,
|
||||
ctype: string,
|
||||
did: string,
|
||||
lid: string,
|
||||
pid: string,
|
||||
rid: string,
|
||||
}
|
||||
|
||||
const resp = serviceKxml('IIDX31pc');
|
||||
|
||||
export default class {
|
||||
@resp('common')
|
||||
async common() {
|
||||
return {
|
||||
system_voice_phase: {
|
||||
$phase: 0,
|
||||
},
|
||||
ir: {
|
||||
$beat: 0,
|
||||
},
|
||||
vip_pass_black: {},
|
||||
common_evnet: {
|
||||
$flg: -1,
|
||||
},
|
||||
play_video: {},
|
||||
music_retry: {},
|
||||
display_asio_logo: {},
|
||||
lane_gacha: {},
|
||||
tourism_booster: {},
|
||||
cm_movie_info: {
|
||||
$type: 3,
|
||||
},
|
||||
monthly_mranking: v.u16([]),
|
||||
total_mranking: v.u16([]),
|
||||
hitchart: [{
|
||||
$kind: 0,
|
||||
$period: 0,
|
||||
ranking: [{
|
||||
$music_id: 31021,
|
||||
$rank: 1
|
||||
}]
|
||||
}],
|
||||
$expire: 180,
|
||||
};
|
||||
}
|
||||
|
||||
@resp('get')
|
||||
get(ctx: Context) {
|
||||
const { cid } = ctx.body as GetPCDataCall;
|
||||
return {
|
||||
pcdata: this.getPlayerPcData(cid),
|
||||
bind_eaappli: {},
|
||||
secret: {
|
||||
flg1: v.s64([-1, -1, 1048575]),
|
||||
flg2: v.s64([-1, -1, 0]),
|
||||
flg3: v.s64([-1, -1, 0]),
|
||||
flg4: v.s64([-1, -1, 0]),
|
||||
},
|
||||
favorite: {
|
||||
sp_mlist: v.bin(Buffer.alloc(1, 0)),
|
||||
sp_clist: v.bin(Buffer.alloc(1, 0)),
|
||||
dp_mlist: v.bin(Buffer.alloc(1, 0)),
|
||||
dp_clist: v.bin(Buffer.alloc(1, 0)),
|
||||
},
|
||||
extra_favorite: [{
|
||||
$folder_id: 0,
|
||||
sp_mlist: v.bin(Buffer.alloc(1, 0)),
|
||||
sp_clist: v.bin(Buffer.alloc(1, 0)),
|
||||
dp_mlist: v.bin(Buffer.alloc(1, 0)),
|
||||
dp_clist: v.bin(Buffer.alloc(1, 0)),
|
||||
}, {
|
||||
$folder_id: 0,
|
||||
sp_mlist: v.bin(Buffer.alloc(1, 0)),
|
||||
sp_clist: v.bin(Buffer.alloc(1, 0)),
|
||||
dp_mlist: v.bin(Buffer.alloc(1, 0)),
|
||||
dp_clist: v.bin(Buffer.alloc(1, 0)),
|
||||
}],
|
||||
grade: {
|
||||
$dgid: -1,
|
||||
$sgid: -1,
|
||||
g: v.u8([0, 13, 3, 58]),
|
||||
},
|
||||
skin: v.s16(new Array(20).fill(0)),
|
||||
tdjskin: v.s16([0, 0, 0, 0]),
|
||||
qprodata: v.s16([0, 0, 0, 0, 0]),
|
||||
spdp_rival: {
|
||||
$flg: 1,
|
||||
},
|
||||
rlist: {},
|
||||
ex: {},
|
||||
secret_course_data: {},
|
||||
weekly: {
|
||||
$mid: 31048,
|
||||
$wid: 2041,
|
||||
},
|
||||
weekly_score: [],
|
||||
visitor: {
|
||||
$anum: 1,
|
||||
$pnum: 1,
|
||||
$snum: 1,
|
||||
$vs_flg: 0,
|
||||
},
|
||||
step: {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private getPlayerPcData(id: string) {
|
||||
const data = {
|
||||
d_auto_adjust: 0,
|
||||
d_auto_scrach: 0,
|
||||
d_camera_layout: 0,
|
||||
d_classic_hispeed: 0,
|
||||
d_disp_judge: 0,
|
||||
d_gauge_disp: 0,
|
||||
d_ghost_score: 0,
|
||||
d_gno: 0,
|
||||
d_graph_score: 0,
|
||||
d_gtype: 0,
|
||||
d_hispeed: 0.000000,
|
||||
d_judge: 0,
|
||||
d_judgeAdj: 0,
|
||||
d_lane_brignt: 0,
|
||||
d_liflen: 0,
|
||||
d_notes: 0.000000,
|
||||
d_opstyle: 0,
|
||||
d_pace: 0,
|
||||
d_sdlen: 0,
|
||||
d_sdtype: 0,
|
||||
d_sorttype: 0,
|
||||
d_sub_gno: 0,
|
||||
d_timing: 0,
|
||||
d_timing_split: 0,
|
||||
d_tsujigiri_disp: 0,
|
||||
d_visualization: 0,
|
||||
dach: 0,
|
||||
dp_opt: 1048577,
|
||||
dp_opt2: 1048577,
|
||||
dpnum: 0,
|
||||
gpos: 0,
|
||||
id: 0,
|
||||
idstr: '00000000',
|
||||
mode: 3,
|
||||
name: 'MK_',
|
||||
ngrade: 0,
|
||||
pid: 48,
|
||||
player_kind: 0,
|
||||
pmode: 0,
|
||||
rtype: 0,
|
||||
s_auto_adjust: 1,
|
||||
s_auto_scrach: 0,
|
||||
s_camera_layout: 0,
|
||||
s_classic_hispeed: 0,
|
||||
s_disp_judge: 1,
|
||||
s_gauge_disp: 0,
|
||||
s_ghost_score: 0,
|
||||
s_gno: 0,
|
||||
s_graph_score: 0,
|
||||
s_gtype: 1,
|
||||
s_hispeed: 7.888014,
|
||||
s_judge: 0,
|
||||
s_judgeAdj: -22,
|
||||
s_lane_brignt: 0,
|
||||
s_liflen: 90,
|
||||
s_notes: 28.497925,
|
||||
s_opstyle: 2,
|
||||
s_pace: 0,
|
||||
s_sdlen: 258,
|
||||
s_sdtype: 1,
|
||||
s_sorttype: 0,
|
||||
s_sub_gno: 0,
|
||||
s_timing: 1,
|
||||
s_timing_split: 1,
|
||||
s_tsujigiri_disp: 0,
|
||||
s_visualization: 0,
|
||||
sach: 49,
|
||||
sp_opt: 17180950528,
|
||||
spnum: 2,
|
||||
cardid: id,
|
||||
};
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(data).map(v => ['$' + v[0], v[1]])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { serviceKxml } from "../../decorators/to-kxml.js";
|
||||
|
||||
const resp = serviceKxml('IIDX31shop');
|
||||
|
||||
export default class {
|
||||
@resp('getname')
|
||||
async getname() {
|
||||
return {
|
||||
$cls_opt: 14400,
|
||||
$expire: 0,
|
||||
$opname: '原神, 启动',
|
||||
$pid: 30,
|
||||
};
|
||||
}
|
||||
|
||||
@resp('sentinfo')
|
||||
async sentinfo() {
|
||||
return {
|
||||
$status: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import { serviceKxml } from "../../decorators/to-kxml.js";
|
||||
|
||||
const resp = serviceKxml('IIDX31streaming');
|
||||
|
||||
export default class {
|
||||
@resp('common')
|
||||
common() {
|
||||
return {
|
||||
$expire: Math.floor(new Date().valueOf() / 1000) + 259200,
|
||||
cm_info: {},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
import { serviceKxml } from "../../decorators/to-kxml.js";
|
||||
import { Context } from "../../types.js";
|
||||
|
||||
interface CardInquire {
|
||||
cardid: string,
|
||||
cardtype: string,
|
||||
}
|
||||
|
||||
interface CardAuth {
|
||||
pass: string,
|
||||
refid: string,
|
||||
}
|
||||
|
||||
interface GetRefId {
|
||||
cardid: string,
|
||||
passwd: string;
|
||||
}
|
||||
|
||||
const resp = serviceKxml('cardmng');
|
||||
|
||||
export default class {
|
||||
@resp('authpass')
|
||||
authpass(ctx: Context) {
|
||||
const { refid, pass } = ctx.body as CardAuth;
|
||||
ctx.logger.info('auth %s with pass %s', refid, pass);
|
||||
|
||||
return {
|
||||
$status: 0,
|
||||
};
|
||||
}
|
||||
|
||||
@resp('getrefid')
|
||||
getrefid(ctx: Context) {
|
||||
const { cardid, passwd } = ctx.body as GetRefId;
|
||||
ctx.logger.info('registering %s with passwd %s.', cardid, passwd);
|
||||
|
||||
return {
|
||||
$dataid: cardid,
|
||||
$refid: cardid,
|
||||
}
|
||||
}
|
||||
|
||||
@resp('inquire')
|
||||
inquire(ctx: Context) {
|
||||
const { cardid, cardtype } = ctx.body as CardInquire;
|
||||
ctx.logger.info('card %s (type %d) inquire', cardid, cardtype);
|
||||
|
||||
return {
|
||||
$binded: 1,
|
||||
$newflag: 0,
|
||||
$ecflag: 1,
|
||||
$expired: 0,
|
||||
$dataid: cardid,
|
||||
$refid: cardid,
|
||||
$status: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
+14
-8
@@ -1,14 +1,20 @@
|
||||
import { Context } from '../types.js';
|
||||
import { kxml } from '../decorators/to-kxml.js';
|
||||
import { eacnet } from '../decorators/eacnet.js';
|
||||
import { v } from '../utils/kxml-value.js';
|
||||
|
||||
export class DefaultService {
|
||||
@kxml()
|
||||
async default(ctx: Context) {
|
||||
return {
|
||||
[ctx.service.name]: {
|
||||
$method: ctx.service.method,
|
||||
status: '0',
|
||||
}
|
||||
}
|
||||
const descriptor = {
|
||||
value: () => ({
|
||||
status: v.s32(0),
|
||||
error: v.s32(0),
|
||||
result: {
|
||||
dummy: v.u8(0),
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
eacnet(ctx.service.name)(undefined, undefined, descriptor);
|
||||
return descriptor.value();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { serviceKxml } from "../../decorators/to-kxml.js";
|
||||
import { v } from "../../utils/kxml-value.js";
|
||||
|
||||
const resp = serviceKxml('eacoin');
|
||||
|
||||
export default class {
|
||||
@resp('checkin')
|
||||
checkin() {
|
||||
return {
|
||||
$status: 0,
|
||||
balance: v.s32(114514),
|
||||
sessid: v.str('0000000000000000'),
|
||||
acstatus: v.u8(0),
|
||||
sequence: v.s16(1),
|
||||
acid: v.str('0000000000000000'),
|
||||
acname: v.str('0000000000000000'),
|
||||
}
|
||||
}
|
||||
|
||||
@resp('consume')
|
||||
consume() {
|
||||
return {
|
||||
$status: 0,
|
||||
autocharge: v.u8(0),
|
||||
acstatus: v.u8(0),
|
||||
balance: v.u8(114514),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import { kxmlTemplate } from '../../decorators/render-kxml.js';
|
||||
import { singleton } from 'tsyringe';
|
||||
|
||||
@singleton()
|
||||
export default class {
|
||||
@kxmlTemplate('facility/get')
|
||||
async get(): Promise<object> {
|
||||
return {
|
||||
status: 0,
|
||||
location: {
|
||||
id: 'EA000000',
|
||||
type: 0,
|
||||
country: 'JP',
|
||||
region: 'JP-0',
|
||||
name: 'LaoChan Test',
|
||||
countryName: 'LaoChan',
|
||||
countryJName: '老禅',
|
||||
regionName: 'BianYu',
|
||||
regionJName: '變魚',
|
||||
customerCode: 'LaoChan',
|
||||
companyCode: 'LaoChan',
|
||||
latitude: 0,
|
||||
longitude: 0,
|
||||
accuracy: 0,
|
||||
},
|
||||
line: {
|
||||
id: '0',
|
||||
class: 8,
|
||||
upClass: 8,
|
||||
rtt: 22,
|
||||
},
|
||||
portfw: {
|
||||
globalIp: '127.0.0.1',
|
||||
globalPort: 5700,
|
||||
privatePort: 5700,
|
||||
},
|
||||
public: {
|
||||
flag: 0,
|
||||
name: 'LaoChan Test',
|
||||
latitude: '0',
|
||||
longitude: '0',
|
||||
},
|
||||
share: {
|
||||
url: '老禅 LaoChan LaoChan 老禅',
|
||||
eapass: 365,
|
||||
eacoin: {
|
||||
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,
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import { serviceKxml } from '../../decorators/to-kxml.js';
|
||||
|
||||
const resp = serviceKxml('message');
|
||||
|
||||
export default class {
|
||||
@resp('get')
|
||||
async get(): Promise<object> {
|
||||
return {
|
||||
$status: 0,
|
||||
$expire: 60,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Service } from "./service.js";
|
||||
|
||||
function Combine(...modules: ({ new(): any })[]) {
|
||||
class Modules {
|
||||
constructor() {
|
||||
modules.forEach(v => Object.assign(this, new v()));
|
||||
}
|
||||
}
|
||||
|
||||
modules.forEach(v => {
|
||||
Object.getOwnPropertyNames(v.prototype)
|
||||
.filter(p => p != 'constructor')
|
||||
.forEach(p => Modules.prototype[p] = v.prototype[p])
|
||||
});
|
||||
|
||||
return Modules;
|
||||
}
|
||||
|
||||
export default class extends Combine(Service) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
import { eacnet } from '../../decorators/eacnet.js';
|
||||
import { Context } from '../../types.js';
|
||||
import config from '../../utils/config.js';
|
||||
import { v } from '../../utils/kxml-value.js';
|
||||
|
||||
export class Service {
|
||||
@eacnet('p2d')
|
||||
async getServerState() {
|
||||
return {
|
||||
status: v.s32(0),
|
||||
error: v.s32(0),
|
||||
result: {
|
||||
server_state: v.s32(1),
|
||||
mainte_start_clock: v.u64(0),
|
||||
mainte_end_clock: v.u64(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@eacnet('p2d')
|
||||
async getServerClock() {
|
||||
return {
|
||||
status: v.s32(0),
|
||||
error: v.s32(0),
|
||||
result: {
|
||||
server_clock: v.u64(new Date().valueOf()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@eacnet('p2d')
|
||||
async getServerValues() {
|
||||
return {
|
||||
status: v.s32(0),
|
||||
error: v.s32(0),
|
||||
result: {
|
||||
bit_boost_magnification: v.str('2'),
|
||||
debug_user_force_subscription: v.str('TRUE'),
|
||||
devline_ignore_maintenance: v.str('TRUE'),
|
||||
enable_file_upload: v.str('TRUE'),
|
||||
frame_bit_magnification: v.str('TRUE'),
|
||||
open_bemani_linkage_hinabita2023: v.str('TRUE'),
|
||||
open_bemani_linkage_knst2024sp: v.str('TRUE'),
|
||||
open_bemani_linkage_mixup: v.str('TRUE'),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@eacnet('p2d')
|
||||
async checkGameVersion() {
|
||||
return {
|
||||
status: v.s32(0),
|
||||
error: v.s32(0),
|
||||
result: {
|
||||
permission: v.s32(1),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@eacnet('p2d')
|
||||
async heartbeat(ctx: Context) {
|
||||
return {
|
||||
status: v.s32(0),
|
||||
error: v.s32(0),
|
||||
result: {
|
||||
state: v.s32(1),
|
||||
next_clock: v.u64(new Date().valueOf() + 36e5),
|
||||
token: ctx.token,
|
||||
time_remain: v.s32(0x7fffffff),
|
||||
subscription_status: v.s32(1),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@eacnet('p2d')
|
||||
async checkSendLogAvailable() {
|
||||
return {
|
||||
status: v.s32(0),
|
||||
error: v.s32(0),
|
||||
result: {
|
||||
status: v.s32(1),
|
||||
daily_count: v.s32(999),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@eacnet('p2d')
|
||||
async getServices() {
|
||||
return {
|
||||
status: v.s32(0),
|
||||
error: v.s32(0),
|
||||
result: {
|
||||
service_num: v.s32(63),
|
||||
service: [
|
||||
{
|
||||
service_name: v.str(`addPoint`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/AddPoint`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`addPointDirect`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/AddPointDirect`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`cancelReserveChangePoint`),
|
||||
url: v.str(
|
||||
`${config.selfUrl}/needAuth/CancelReserveChangePoint`,
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`cancelReserveConsumeItem`),
|
||||
url: v.str(
|
||||
`${config.selfUrl}/needAuth/CancelReserveConsumeItem`,
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`checkChampionshipInfo`),
|
||||
url: v.str(
|
||||
`${config.selfUrl}/needlessAuth/CheckChampionshipInfo`,
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`checkGameStart`),
|
||||
url: v.str(`${config.selfUrl}/preProcess/CheckGameStart`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`checkGameVersion`),
|
||||
url: v.str(`${config.selfUrl}/needlessAuth/CheckGameVersion`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`checkPlayData`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/CheckPlayData`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`checkPlayableMusicList`),
|
||||
url: v.str(
|
||||
`${config.selfUrl}/needAuth/CheckPlayableMusicList`,
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`checkSendLogAvailable`),
|
||||
url: v.str(
|
||||
`${config.selfUrl}/needlessAuth/CheckSendLogAvailable`,
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`checkTakeover`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/CheckTakeover`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`checkUpdate`),
|
||||
url: v.str(`${config.selfUrl}/needlessAuth/CheckUpdate`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`checkVersion`),
|
||||
url: v.str(
|
||||
`${config.selfUrl}/needlessAuth/CheckLauncherVersion`,
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`consumeItem`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/ConsumeItem`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`gameEnd`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GameEnd`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getAdvertise`),
|
||||
url: v.str(`${config.selfUrl}/needlessAuth/GetAdvertise`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getChampionshipInfo`),
|
||||
url: v.str(
|
||||
`${config.selfUrl}/needlessAuth/GetChampionshipInfo`,
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getChampionshipRank`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetChampionshipRank`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getChampionshipRecord`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetChampionshipRecord`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getClearRate`),
|
||||
url: v.str(`${config.selfUrl}/needlessAuth/GetClearRate`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getCompeScoreData`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetCompeScoreData`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getCustomizeSetting`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetCustomizeSetting`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getDownloadResource`),
|
||||
url: v.str(
|
||||
'https://d1rc4pwxnc0pe0.cloudfront.net/v2/resource/distribution/ondemand',
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getGoodsList`),
|
||||
url: v.str(`${config.selfUrl}/needlessAuth/GetGoodsList`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getHash`),
|
||||
url: v.str(`${config.selfUrl}/needlessAuth/GetHash`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getInformation`),
|
||||
url: v.str(`${config.selfUrl}/needlessAuth/GetInformation`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getItemList`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetItemList`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getItemNum`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetItemNum`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getMusicData`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetMusicData`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getMusicGhost`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetMusicGhost`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getMusicList`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetMusicList`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getPackageList`),
|
||||
url: v.str(`${config.selfUrl}/needlessAuth/GetPackageList`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getPlayData`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetPlayData`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getPlayableMusicList`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetPlayableMusicList`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getPointList`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetPointList`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getPrivilegeClient`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetPrivilegeClient`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getPrivilegeServer`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetPrivilegeServer`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getResourceInfo`),
|
||||
url: v.str(`${config.selfUrl}/needlessAuth/GetFile`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getRival`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetRival`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getRivalChallenge`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetRivalChallenge`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getRivalInfo`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/GetRivalInfo`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getServerClock`),
|
||||
url: v.str(`${config.selfUrl}/preProcess/GetServerClock`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getServerState`),
|
||||
url: v.str(`${config.selfUrl}/preProcess/GetServerState`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getServerValues`),
|
||||
url: v.str(`${config.selfUrl}/needlessAuth/GetServerValues`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getServices`),
|
||||
url: v.str(`${config.selfUrl}/preProcess/GetServices`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`getTemporaryFiles`),
|
||||
url: v.str(`${config.selfUrl}/needlessAuth/GetTemporaryFiles`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`heartbeat`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/Heartbeat`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`loginEX`),
|
||||
url: v.str(
|
||||
'https://p.eagate.573.jp/game/eac2dx/infinitas/API/page/loginEX.html',
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`registPlayer`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/RegistPlayer`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`reportMusicResult`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/ReportMusicResult`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`reserveChangePoint`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/ReserveChangePoint`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`reserveConsumeItem`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/ReserveConsumeItem`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`saveChampionshipRecord`),
|
||||
url: v.str(
|
||||
`${config.selfUrl}/needAuth/SaveChampionshipRecord`,
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`savePlayData`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/SavePlayData`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`sendGradeCertificationLog`),
|
||||
url: v.str(
|
||||
`${config.selfUrl}/needAuth/SendGradeCertificationLog`,
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`sendLog`),
|
||||
url: v.str(`${config.selfUrl}/needlessAuth/SendLog`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`unlockMusic`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/UnlockMusic`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`uploadFile`),
|
||||
url: v.str(
|
||||
`${config.selfUrl}/needlessAuth/UploadFileMultipart`,
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`urlAgreement`),
|
||||
url: v.str(
|
||||
'https://p.eagate.573.jp/game/infinitas/2/jump/agreement.html',
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`urlEaShop`),
|
||||
url: v.str('https://p.eagate.573.jp/game/eac2dx/jump/eashop.html'),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`urlKAC5th`),
|
||||
url: v.str(
|
||||
'http://p.eagate.573.jp/game/kac5th/detail.html?id=infinitas&group=outline&lang=ja',
|
||||
),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`usePoint`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/UsePoint`),
|
||||
},
|
||||
{
|
||||
service_name: v.str(`usePointDirect`),
|
||||
url: v.str(`${config.selfUrl}/needAuth/UsePointDirect`),
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { DefaultService } from '../default.js';
|
||||
|
||||
export default class extends DefaultService {
|
||||
list = this.default;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { DefaultService } from '../default.js';
|
||||
|
||||
export default class extends DefaultService {
|
||||
put = this.default;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { serviceKxml } from '../../decorators/to-kxml.js';
|
||||
|
||||
const resp = serviceKxml('pcbtracker');
|
||||
|
||||
export default class {
|
||||
@resp('alive')
|
||||
async alive(): Promise<object> {
|
||||
return {
|
||||
$ecenable: 1,
|
||||
$expire: 3600,
|
||||
$status: 0,
|
||||
$time: Math.floor(new Date().valueOf() / 1000),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import { singleton } from 'tsyringe';
|
||||
import config from '../../utils/config.js';
|
||||
import { serviceKxml } from '../../decorators/to-kxml.js';
|
||||
|
||||
const resp = serviceKxml('services');
|
||||
|
||||
@singleton()
|
||||
export default class {
|
||||
@resp('get')
|
||||
async get() {
|
||||
const selfServices = [
|
||||
'services', 'dlstatus', 'cardmng',
|
||||
'eacoin', 'userdata', 'userid', 'pcbtracker', 'pcbevent',
|
||||
'message', 'facility', 'apsmanager', 'sidmgr', 'package',
|
||||
'uploaders', 'local', 'local2', 'lobby',
|
||||
]
|
||||
|
||||
return {
|
||||
$expire: 43200,
|
||||
$mode: 'operation',
|
||||
$product_domain: 1,
|
||||
$statuc: 0,
|
||||
item: [
|
||||
{
|
||||
$name: 'keepalive',
|
||||
$url: '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',
|
||||
},
|
||||
{
|
||||
$name: 'ntp',
|
||||
$url: config.ntpUrl,
|
||||
},
|
||||
...selfServices.map(v => ({
|
||||
$name: v,
|
||||
$url: config.selfUrl,
|
||||
}))
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-7
@@ -2,9 +2,7 @@ import { Logger } from '@cordisjs/logger';
|
||||
import { DefaultState, ParameterizedContext } from 'koa';
|
||||
|
||||
export interface ILaochanContext {
|
||||
model?: string;
|
||||
tag?: string;
|
||||
pcbid?: string;
|
||||
token?: string;
|
||||
|
||||
service: {
|
||||
name: string,
|
||||
@@ -12,10 +10,7 @@ export interface ILaochanContext {
|
||||
};
|
||||
|
||||
logger: Logger;
|
||||
|
||||
request: {
|
||||
body: Buffer | object | undefined;
|
||||
};
|
||||
body?: unknown;
|
||||
}
|
||||
|
||||
export type Context = ParameterizedContext<DefaultState, ILaochanContext, any>;
|
||||
|
||||
+4
-4
@@ -3,11 +3,11 @@ dotenv.config();
|
||||
|
||||
class Config {
|
||||
get port() {
|
||||
return process.env.PORT ? parseInt(process.env.PORT) : 10573;
|
||||
return process.env.PORT ? parseInt(process.env.PORT) : 25730;
|
||||
}
|
||||
|
||||
get selfUrl() {
|
||||
return process.env.SELF_URL ?? 'http://127.0.0.1:10573';
|
||||
return process.env.SELF_URL ?? 'http://localhost:25730';
|
||||
}
|
||||
|
||||
get ntpUrl() {
|
||||
@@ -15,11 +15,11 @@ class Config {
|
||||
}
|
||||
|
||||
get mongoUrl() {
|
||||
return process.env.MONGO_URL ?? 'mongodb://127.0.0.1:27017';
|
||||
return process.env.MONGO_URL ?? 'mongodb://localhost:27017';
|
||||
}
|
||||
|
||||
get dbName() {
|
||||
return process.env.DB_NAME ?? 'laochan-net';
|
||||
return process.env.DB_NAME ?? 'laochan-eacnet';
|
||||
}
|
||||
|
||||
get isDev() {
|
||||
|
||||
@@ -27,7 +27,7 @@ function vg(type: ValueTypes) {
|
||||
}
|
||||
}
|
||||
|
||||
return attrs;
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+58
-31
@@ -1,37 +1,64 @@
|
||||
export function lz77Decode(data: Buffer): Buffer {
|
||||
let offset = 0;
|
||||
const output: number[] = [];
|
||||
|
||||
while (offset < data.length) {
|
||||
const flag = data[offset];
|
||||
offset += 1;
|
||||
|
||||
for (let bit = 0; bit < 8; bit++) {
|
||||
if (flag & (1 << bit)) {
|
||||
output.push(data[offset]);
|
||||
offset += 1;
|
||||
} else {
|
||||
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;
|
||||
|
||||
for (let i = 0; i < lookbackLength; i++) {
|
||||
const loffset = output.length - lookbackOffset;
|
||||
|
||||
if (loffset <= 0 || loffset >= output.length) {
|
||||
output.push(0);
|
||||
} else {
|
||||
output.push(output[loffset]);
|
||||
}
|
||||
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 Buffer.from(output);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user