mirror of
https://github.com/laochan-eacnet/backend.git
synced 2026-09-26 16:18:16 +03:00
add js object to kxml decorator
add config warpper around environment variables
This commit is contained in:
Generated
+28
-14
@@ -1,20 +1,22 @@
|
||||
{
|
||||
"name": "node-typescript-boilerplate",
|
||||
"name": "@laochan/ea3",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "node-typescript-boilerplate",
|
||||
"name": "@laochan/ea3",
|
||||
"version": "0.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@cordisjs/logger": "^0.1.3",
|
||||
"@kamyu/kbinxml": "^2.0.2",
|
||||
"arc4": "^3.4.0",
|
||||
"arc4": "^2.1.4",
|
||||
"dedent-js": "^1.0.1",
|
||||
"dotenv": "^16.4.5",
|
||||
"fast-xml-parser": "^4.3.2",
|
||||
"koa": "^2.15.0",
|
||||
"lodash": "^4.17.21",
|
||||
"pug": "^3.0.2",
|
||||
"reflect-metadata": "^0.2.1",
|
||||
"tslib": "~2.6",
|
||||
@@ -23,6 +25,7 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "~29.5",
|
||||
"@types/koa": "^2.13.12",
|
||||
"@types/lodash": "^4.14.202",
|
||||
"@types/node": "~20",
|
||||
"@types/pug": "^2.0.10",
|
||||
"@typescript-eslint/eslint-plugin": "~6.15",
|
||||
@@ -2042,6 +2045,12 @@
|
||||
"@types/koa": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.202",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
|
||||
"integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/mime": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmmirror.com/@types/mime/-/mime-1.3.5.tgz",
|
||||
@@ -2443,14 +2452,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/arc4": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/arc4/-/arc4-3.4.0.tgz",
|
||||
"integrity": "sha512-zFQmSbTwSTrICYV8kldrD3YreCtlLIKEZk+lmlNSlpUKU/cF9o746WFEy9eNqLrqSyUgAAjB3gnD9UXdK23beA==",
|
||||
"dependencies": {
|
||||
"lodash": "4.17.4"
|
||||
},
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/arc4/-/arc4-2.1.4.tgz",
|
||||
"integrity": "sha512-yYR7Ragh8qYiPMRipZmtoP6BVtENdOmFo7+sdBX7VD/F+hzblmsZjr56ir7G3485AEh3EWBscLv0h4iE+bWzwQ==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/arg": {
|
||||
@@ -3118,6 +3124,14 @@
|
||||
"resolved": "https://registry.npmmirror.com/doctypes/-/doctypes-1.1.0.tgz",
|
||||
"integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ=="
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.4.5",
|
||||
"resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.4.5.tgz",
|
||||
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/eastasianwidth": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||
@@ -5110,9 +5124,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.4",
|
||||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.4.tgz",
|
||||
"integrity": "sha512-6X37Sq9KCpLSXEh8uM12AKYlviHPNNk4RxiGBn4cmKGJinbXBneWIV7iE/nXkM928O7ytHcHb6+X6Svl0f4hXg=="
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash.memoize": {
|
||||
"version": "4.1.2",
|
||||
|
||||
+4
-1
@@ -9,6 +9,7 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "~29.5",
|
||||
"@types/koa": "^2.13.12",
|
||||
"@types/lodash": "^4.14.202",
|
||||
"@types/node": "~20",
|
||||
"@types/pug": "^2.0.10",
|
||||
"@typescript-eslint/eslint-plugin": "~6.15",
|
||||
@@ -43,10 +44,12 @@
|
||||
"dependencies": {
|
||||
"@cordisjs/logger": "^0.1.3",
|
||||
"@kamyu/kbinxml": "^2.0.2",
|
||||
"arc4": "^3.4.0",
|
||||
"arc4": "^2.1.4",
|
||||
"dedent-js": "^1.0.1",
|
||||
"dotenv": "^16.4.5",
|
||||
"fast-xml-parser": "^4.3.2",
|
||||
"koa": "^2.15.0",
|
||||
"lodash": "^4.17.21",
|
||||
"pug": "^3.0.2",
|
||||
"reflect-metadata": "^0.2.1",
|
||||
"tslib": "~2.6",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import pug from 'pug';
|
||||
import { to_bin } from '@kamyu/kbinxml';
|
||||
|
||||
export function kxml(
|
||||
export function kxmlTemplate(
|
||||
templatePath: string,
|
||||
encoding: 'UTF-8' | 'SHIFT_JIS' = 'UTF-8',
|
||||
): MethodDecorator {
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
import _ from 'lodash';
|
||||
import { to_bin } from '@kamyu/kbinxml';
|
||||
|
||||
function serializeValue(value: any, type: string): string {
|
||||
if (
|
||||
[
|
||||
's8',
|
||||
'u8',
|
||||
's16',
|
||||
'u16',
|
||||
's32',
|
||||
'u32',
|
||||
's64',
|
||||
'u64',
|
||||
'float',
|
||||
'double',
|
||||
].includes(type)
|
||||
) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
if (['b', 'bool'].includes('type')) {
|
||||
return value ? '1' : '0';
|
||||
}
|
||||
|
||||
if (['bin', 'binary'].includes(type)) {
|
||||
if (!(value instanceof Buffer)) {
|
||||
throw new Error('binary with non-buffer value');
|
||||
}
|
||||
|
||||
return value.toString('hex');
|
||||
}
|
||||
|
||||
if (['ip4', 'str', 'string'].includes(type)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (type == 'time') {
|
||||
if (value instanceof Date) {
|
||||
return Math.floor(value.valueOf() / 1000).toString();
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
throw new Error('time with not date or number');
|
||||
}
|
||||
|
||||
throw new Error(`unsupported type ${type}`);
|
||||
}
|
||||
|
||||
function serializeObject(obj: Object, name: string, linePrefix: string = '') {
|
||||
let output = `${linePrefix}<${name}`;
|
||||
|
||||
const entries = Object.entries(obj);
|
||||
const attrs = entries
|
||||
.filter(v => v[0].startsWith('$'))
|
||||
.map(v => [v[0].substring(1), v[1]]);
|
||||
|
||||
for (const attr of attrs) {
|
||||
output += ` ${attr[0]}="${_.escape(attr[1])}"`;
|
||||
}
|
||||
|
||||
// handle kxml value shit
|
||||
const value = entries.find(v => v[0] == '__value');
|
||||
|
||||
if (value && value[1] instanceof Array) {
|
||||
output += ` __count="${value[1].length}"`;
|
||||
}
|
||||
|
||||
output += '>';
|
||||
|
||||
if (value) {
|
||||
const type = attrs.find(v => v[0] == '__type');
|
||||
|
||||
if (!type) {
|
||||
// or normal xml innerXml?
|
||||
throw new Error(`value with no type in ${name}`);
|
||||
}
|
||||
|
||||
output += (value[1] instanceof Array ? value[1] : [value[1]])
|
||||
.map(v => serializeValue(v, type[1]))
|
||||
.join(' ');
|
||||
} else {
|
||||
const elements = entries
|
||||
.filter(v => !v[0].startsWith('$'));
|
||||
|
||||
if (elements.length) {
|
||||
output += '\n';
|
||||
|
||||
for (const element of elements) {
|
||||
if (element[1] instanceof Array) {
|
||||
for (const item of element[1])
|
||||
output += serializeObject(item, element[0], linePrefix + ' ');
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
output += serializeObject(element[1], element[0], linePrefix + ' ');
|
||||
}
|
||||
|
||||
output += linePrefix;
|
||||
}
|
||||
}
|
||||
|
||||
return output + `</${name}>\n`;
|
||||
}
|
||||
|
||||
export function kxml(topName: string = 'response', 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[]) {
|
||||
const obj = await orig.apply(this, args);
|
||||
const xml =
|
||||
`<?xml version="1.0" encoding="${encoding}"?>` + serializeObject(obj, topName);
|
||||
const kxml = to_bin(xml);
|
||||
|
||||
return Buffer.from(kxml.data);
|
||||
} as unknown as any;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
console.log(serializeObject({
|
||||
$attr: 'attr1',
|
||||
sb: {
|
||||
$attr: 'attr2',
|
||||
$__type: 'str',
|
||||
__value: 'sba',
|
||||
},
|
||||
sb1: {
|
||||
$attr: 'attr3',
|
||||
nested: {
|
||||
$attr: 'attr4',
|
||||
$__type: 's32',
|
||||
__value: [1, 1, 4, 5, 1, 4],
|
||||
}
|
||||
},
|
||||
array: [{
|
||||
$attr: 'test'
|
||||
}, {
|
||||
$attr: 'test2'
|
||||
}, {
|
||||
$attr: 'test3'
|
||||
}, {
|
||||
$attr: 'test4'
|
||||
}, {
|
||||
$attr: 'test5'
|
||||
}]
|
||||
}, 'test'))
|
||||
|
||||
+10
-14
@@ -1,22 +1,18 @@
|
||||
import { singleton } from 'tsyringe';
|
||||
import { Context, ILaochanService } from '../types.js';
|
||||
import dedent from 'dedent-js';
|
||||
import { to_bin } from '@kamyu/kbinxml';
|
||||
import { kxml } from '../decorators/to-kxml.js';
|
||||
|
||||
@singleton()
|
||||
export class DefaultService implements ILaochanService {
|
||||
async process(ctx: Context): Promise<Buffer> {
|
||||
const tmp = ctx.service.split('.');
|
||||
const module = tmp[0];
|
||||
const method = tmp[1];
|
||||
@kxml()
|
||||
async process(ctx: Context) {
|
||||
const [module, method] = ctx.service.split('.');
|
||||
|
||||
const xml = dedent`
|
||||
<?xml version="1.0" encoding="SHIFT_JIS"?>
|
||||
<response>
|
||||
<${module} method="${method}" status="0"/>
|
||||
</response>
|
||||
`;
|
||||
|
||||
return Buffer.from(to_bin(xml).data);
|
||||
return {
|
||||
[module]: {
|
||||
$method: method,
|
||||
status: '0',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { kxml } from '../../decorators/render-kxml.js';
|
||||
import { kxmlTemplate } from '../../decorators/render-kxml.js';
|
||||
import { ILaochanService } from '../../types.js';
|
||||
import { singleton } from 'tsyringe';
|
||||
|
||||
@singleton()
|
||||
export default class implements ILaochanService {
|
||||
@kxml('facility/get')
|
||||
@kxmlTemplate('facility/get')
|
||||
async process(): Promise<object> {
|
||||
return {
|
||||
status: 0,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { kxml } from '../../decorators/render-kxml.js';
|
||||
import { kxmlTemplate } from '../../decorators/render-kxml.js';
|
||||
import { ILaochanService } from '../../types.js';
|
||||
import { singleton } from 'tsyringe';
|
||||
|
||||
@singleton()
|
||||
export default class implements ILaochanService {
|
||||
@kxml('message/get')
|
||||
@kxmlTemplate('message/get')
|
||||
async process(): Promise<object> {
|
||||
return {
|
||||
status: 0,
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import { kxml } from '../../decorators/render-kxml.js';
|
||||
import { kxml } from '../../decorators/to-kxml.js';
|
||||
import { ILaochanService } from '../../types.js';
|
||||
import { singleton } from 'tsyringe';
|
||||
|
||||
@singleton()
|
||||
export default class implements ILaochanService {
|
||||
@kxml('pcbtracker/alive')
|
||||
@kxml()
|
||||
async process(): Promise<object> {
|
||||
return {
|
||||
status: 0,
|
||||
expire: 3600,
|
||||
time: Math.floor(new Date().valueOf() / 1000),
|
||||
ecEnable: 1,
|
||||
pcbtracker: {
|
||||
$ecenable: 1,
|
||||
$expire: 3600,
|
||||
$method: 'alive',
|
||||
$status: 0,
|
||||
$time: Math.floor(new Date().valueOf() / 1000),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,41 @@
|
||||
import { kxml } from '../../decorators/render-kxml.js';
|
||||
import { ILaochanService } from '../../types.js';
|
||||
import { singleton } from 'tsyringe';
|
||||
import config from '../../utils/config.js';
|
||||
import { kxml } from '../../decorators/to-kxml.js';
|
||||
|
||||
@singleton()
|
||||
export default class implements ILaochanService {
|
||||
@kxml('services/get')
|
||||
async process(): Promise<object> {
|
||||
@kxml()
|
||||
async process() {
|
||||
const selfServices = [
|
||||
'services', 'dlstatus', 'cardmng',
|
||||
'eacoin', 'userdata', 'userid', 'pcbtracker', 'pcbevent',
|
||||
'message', 'facility', 'apsmanager', 'sidmgr', 'package',
|
||||
'uploaders', 'local', 'local2', 'lobby',
|
||||
]
|
||||
|
||||
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',
|
||||
ntpUrl: 'ntp://pool.ntp.org',
|
||||
selfUrl: 'http://localhost:10573',
|
||||
};
|
||||
services: {
|
||||
$expire: 43200,
|
||||
$method: 'get',
|
||||
$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,
|
||||
}))
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
|
||||
class Config {
|
||||
get port() {
|
||||
return process.env.PORT ? parseInt(process.env.PORT) : 10573;
|
||||
}
|
||||
|
||||
get selfUrl() {
|
||||
return process.env.SELF_URL ?? 'http://127.0.0.1:10573';
|
||||
}
|
||||
|
||||
get ntpUrl() {
|
||||
return process.env.NTP_URL ?? 'ntp://pool.ntp.org';
|
||||
}
|
||||
|
||||
get mongoUrl() {
|
||||
return process.env.MONGO_URL ?? 'mongodb://127.0.0.1:27017';
|
||||
}
|
||||
|
||||
get isDev() {
|
||||
return process.env.NODE_ENV !== 'production';
|
||||
}
|
||||
}
|
||||
|
||||
export const config = new Config();
|
||||
export default config;
|
||||
Reference in New Issue
Block a user