mirror of
https://github.com/laochan-eacnet/backend.git
synced 2026-09-28 09:47:58 +03:00
157 lines
4.0 KiB
TypeScript
157 lines
4.0 KiB
TypeScript
import 'reflect-metadata';
|
|
|
|
import cors from '@koa/cors';
|
|
import Koa, { DefaultState } from 'koa';
|
|
import bodyParser from 'koa-bodyparser';
|
|
import { InjectionToken, Provider, container } from 'tsyringe';
|
|
|
|
import { ILaochanContext } from './types.js';
|
|
import { DefaultService } from './controllers/default.js';
|
|
import { Logger } from '@cordisjs/logger';
|
|
import { eacnet } from './middlewares/eacnet.js';
|
|
import config from './utils/config.js';
|
|
import { MongoClient, Db } from 'mongodb';
|
|
import { apiRoutes } from './apis/index.js';
|
|
|
|
function tryResolve<T>(token: InjectionToken<T>): T | 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);
|
|
|
|
// @ts-expect-error: noob tsc
|
|
return container.register(token, provider).resolve(token);
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
const logger = new Logger('laochan-eacnet');
|
|
|
|
logger.info('initialization...');
|
|
|
|
{
|
|
logger.info('connecting to mongodb...');
|
|
const client = await MongoClient.connect(config.mongoUrl);
|
|
|
|
container.register(Db, {
|
|
useValue: client.db(config.dbName),
|
|
});
|
|
}
|
|
|
|
logger.info('creating koa app...');
|
|
|
|
const app = new Koa<DefaultState, ILaochanContext>()
|
|
.use(async (ctx, next) => {
|
|
try {
|
|
await next();
|
|
} catch (e) {
|
|
logger.error(
|
|
'unexcepted error: %s',
|
|
JSON.stringify(e, Object.getOwnPropertyNames(e), 2),
|
|
);
|
|
|
|
ctx.status = e.status ?? 500;
|
|
ctx.body = `${e.stack ?? 'Internal Error'}`;
|
|
}
|
|
})
|
|
.use(cors())
|
|
.use(bodyParser({
|
|
formLimit: '1mb',
|
|
}))
|
|
.use(eacnet)
|
|
.use(async (ctx, next) => {
|
|
ctx.logger = ctx.service
|
|
? register(`logger:${ctx.service.name}:${ctx.service.method}`, {
|
|
useValue: new Logger(`${ctx.service.name}:${ctx.service.method}`),
|
|
})
|
|
: logger;
|
|
|
|
if (!ctx.service) {
|
|
return await next();
|
|
}
|
|
|
|
let service: object | undefined = tryResolve(ctx.service.name);
|
|
|
|
if (service === undefined) {
|
|
try {
|
|
let module: any = null;
|
|
|
|
try {
|
|
module = await import(
|
|
`./controllers/${ctx.service.name}/index.js`
|
|
);
|
|
} catch (e) {
|
|
if (e.code != 'ERR_MODULE_NOT_FOUND') {
|
|
ctx.logger.error(
|
|
`load service error %s`,
|
|
JSON.stringify(e, Object.getOwnPropertyNames(e), 2),
|
|
);
|
|
} else {
|
|
module = await import(
|
|
`./controllers/${ctx.service.name}.js`
|
|
);
|
|
}
|
|
}
|
|
|
|
service = register(ctx.service.name, {
|
|
useClass: module.default,
|
|
});
|
|
} catch (e) {
|
|
if (e.code != 'ERR_MODULE_NOT_FOUND') {
|
|
ctx.logger.error(
|
|
`load controller error %s`,
|
|
JSON.stringify(e, Object.getOwnPropertyNames(e), 2),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
ctx.logger.info(
|
|
'%s [%s]: request = %s',
|
|
ctx.url,
|
|
ctx.token,
|
|
JSON.stringify(ctx.body, (key, value) => {
|
|
if (key === 'pdata') {
|
|
return '<PDATA>';
|
|
}
|
|
|
|
return value;
|
|
}),
|
|
);
|
|
|
|
let method = ctx.service.method;
|
|
|
|
if (!service || !(service[method])?.bind) {
|
|
ctx.logger.warn(`unimplemented method.`);
|
|
|
|
service = container.resolve(DefaultService);
|
|
method = 'default';
|
|
}
|
|
|
|
ctx.body = await (service[method] as Function).bind(service)(ctx);
|
|
ctx.status = 200;
|
|
|
|
ctx.logger.info('[server]: status = %d', ctx.status);
|
|
})
|
|
.use(apiRoutes)
|
|
.use(async (ctx, next) => {
|
|
if (!ctx.body) {
|
|
ctx.body = 'Laochan-Eacnet is running.';
|
|
}
|
|
|
|
return next();
|
|
});
|
|
|
|
app.context.resolve = container.resolve.bind(container);
|
|
|
|
logger.info('listening on %d', config.port);
|
|
app.listen(config.port);
|
|
}
|
|
|
|
main();
|