158 lines
5.1 KiB
TypeScript
158 lines
5.1 KiB
TypeScript
import fastify, {
|
|
FastifyError,
|
|
FastifyInstance,
|
|
FastifyReply,
|
|
FastifyRequest
|
|
} from 'fastify'
|
|
import helmet from 'fastify-helmet'
|
|
import {IncomingMessage, Server, ServerResponse} from 'http'
|
|
import {RouterMap} from 'decorators/router';
|
|
import {mongoose} from "@typegoose/typegoose";
|
|
import logger from 'logger/logger';
|
|
import config from 'config/config';
|
|
import { initCfgData } from './common/GConfig'
|
|
import { Schedule } from './clock/Schedule'
|
|
import { QCategoryCache } from './services/QCategoryCache'
|
|
|
|
const zReqParserPlugin = require('plugins/zReqParser');
|
|
|
|
const zTokenParserPlugin = require("plugins/zTokenParser");
|
|
|
|
const apiAuthPlugin = require('plugins/apiauth');
|
|
|
|
const fs = require('fs');
|
|
const join = require('path').join;
|
|
|
|
require('./common/Extend');
|
|
|
|
export class ApiServer {
|
|
server: FastifyInstance<Server, IncomingMessage, ServerResponse>;
|
|
|
|
public constructor() {
|
|
this.server = fastify({logger: true});
|
|
this.registerPlugins();
|
|
}
|
|
private registerPlugins() {
|
|
this.server.register(require('fastify-formbody'));
|
|
this.server.register(zReqParserPlugin);
|
|
this.server.register(
|
|
helmet,
|
|
{ hidePoweredBy: false }
|
|
)
|
|
this.server.register(zTokenParserPlugin);
|
|
|
|
this.server.register(apiAuthPlugin, {
|
|
secret: config.api.token_secret,
|
|
expiresIn: config.api.token_expiresIn
|
|
})
|
|
|
|
this.server.register(require('fastify-cors'), {});
|
|
}
|
|
|
|
private registerRouter() {
|
|
logger.log('register api routers');
|
|
let self = this;
|
|
for (let [controller, config] of RouterMap.decoratedRouters) {
|
|
for(let data of config.data) {
|
|
logger.info('find api router', data.method || 'all',
|
|
data.path, controller.name);
|
|
// @ts-ignore
|
|
self.server[data.method || 'all'](data.path, {
|
|
preValidation: async function (request: FastifyRequest, reply: FastifyReply) {
|
|
request.roles = config.roles;
|
|
await this.apiAuth(request, reply);
|
|
}
|
|
}, controller);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* 加载所有的controller
|
|
*/
|
|
initControllers() {
|
|
logger.info('Bootstrap controllers...');
|
|
const controllers = join(__dirname, 'api/controllers');
|
|
fs.readdirSync(controllers)
|
|
.filter((file: string) => ~file.search(/^[^.].*\.(ts|js)$/))
|
|
.forEach((file: any) => {
|
|
// logger.log(file);
|
|
return require(join(controllers, file))});
|
|
}
|
|
async connectDB() {
|
|
const options = {useNewUrlParser: true,
|
|
poolSize: 5,
|
|
keepAlive: true,
|
|
keepAliveInitialDelay: 300000,
|
|
useUnifiedTopology: true};
|
|
const uri = config.db_main;
|
|
logger.info(`connect to ${uri} ...`);
|
|
try {
|
|
// await mongoose.createConnection(uri, options)
|
|
await mongoose.connect(uri, options)
|
|
logger.log('DB Connected');
|
|
} catch (err) {
|
|
logger.log(`DB Connection Error: ${err.message}`);
|
|
}
|
|
}
|
|
private setErrHandler() {
|
|
this.server.setNotFoundHandler(function(request: any, reply: { send: (arg0: { errcode: number; errmsg: string; }) => void; }){
|
|
reply.send({errcode: 404, errmsg: 'page not found'})
|
|
});
|
|
this.server.setErrorHandler(function (error: FastifyError, request: FastifyRequest, reply: FastifyReply) {
|
|
let statusCode = error && error.statusCode || 100;
|
|
if (statusCode >= 500) {
|
|
logger.error(error)
|
|
} else if (statusCode >= 400) {
|
|
logger.info(error)
|
|
} else {
|
|
logger.error(error)
|
|
}
|
|
reply.code(200).send({errcode: statusCode, errmsg: error ? error.message : 'unknown error'})
|
|
})
|
|
}
|
|
/**
|
|
* 格式化接口返回数据, 统一封装成如下格式
|
|
* {
|
|
* code: 0,
|
|
* msg?: '',
|
|
* data: any
|
|
* }
|
|
* @private
|
|
*/
|
|
private setFormatSend() {
|
|
this.server.addHook('preSerialization', async (request: FastifyRequest, reply: FastifyReply, payload) => {
|
|
reply.header('X-Powered-By', 'PHP/5.4.16')
|
|
// @ts-ignore
|
|
if (!payload.code) {
|
|
payload = {
|
|
errcode: 0,
|
|
data: payload
|
|
}
|
|
}
|
|
return payload
|
|
})
|
|
}
|
|
public async start() {
|
|
let self = this;
|
|
return new Promise(async (resolve, reject) => {
|
|
await self.connectDB();
|
|
self.initControllers();
|
|
self.registerRouter();
|
|
self.setErrHandler();
|
|
self.setFormatSend();
|
|
initCfgData();
|
|
await new QCategoryCache().init();
|
|
new Schedule().start()
|
|
this.server.listen({port: config.api.port}, (err: any, address: any) => {
|
|
if (err) {
|
|
logger.log(err)
|
|
process.exit(0)
|
|
}
|
|
resolve && resolve(address);
|
|
})
|
|
});
|
|
|
|
}
|
|
|
|
}
|