card_info_svr/src/api.server.ts
2021-02-01 10:15:03 +08:00

180 lines
5.7 KiB
TypeScript

import fastify, {
FastifyError,
FastifyInstance,
FastifyReply,
FastifyRequest
} from 'fastify'
import helmet from 'fastify-helmet'
import { Server, IncomingMessage, ServerResponse } from 'http'
import {RouterMap} from './decorators/router'
import {mongoose} from "@typegoose/typegoose"
import logger from './logger/logger'
import {Config} from "./cfg/Config"
import {initData} from "./common/GConfig"
import { RedisClient } from './redis/RedisClient'
import { initRobotCache } from './service/jcfw'
import { error } from './common/Debug'
import {
registerGracefulShutdown,
registService,
unRegistService
} from './utils/system.util'
const zReqParserPlugin = require('./plugins/zReqParser')
const apiAuthPlugin = require('./plugins/apiauth')
const fs = require('fs')
const join = require('path').join
let config: Config = require('../config/config.json')
require('./common/Extend')
export class ApiServer {
server: FastifyInstance<Server, IncomingMessage, ServerResponse>
port: number
public constructor() {
this.server = fastify({logger: true})
this.registerPlugins()
this.port = Number(process.env.PORT || config.port);
}
private registerPlugins() {
this.server.register(require('fastify-formbody'))
this.server.register(zReqParserPlugin)
this.server.register(apiAuthPlugin)
this.server.register(
helmet,
{ hidePoweredBy: false }
)
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, '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}`)
}
let opts = {url: config.redis}
new RedisClient(opts)
}
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'})
})
}
/**
* 格式化接口返回数据, 统一封装成如下格式
* {
* errcode: 0,
* errmsg?: '',
* 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.errcode) {
payload = {
errcode: 0,
data: payload
}
}
return payload
})
}
private async initCache() {
try {
await initRobotCache(100)
} catch (err) {
error('error init robot info', err)
}
}
/**
* 处理process意外退出
* @param {boolean} exit
* @param {Error} err
* @return {Promise<void>}
*/
public async gracefullyShutdown(exit: boolean = true, err?: Error) {
await unRegistService(this.port)
}
public async start() {
let self = this
return new Promise(async (resolve, reject) => {
await registerGracefulShutdown((err) => self.gracefullyShutdown(true, err));
await self.connectDB()
await self.initCache()
await registService(self.port)
self.initControllers()
self.registerRouter()
self.setErrHandler()
self.setFormatSend()
initData()
this.server.listen({port: self.port}, (err: any, address: any) => {
if (err) {
logger.log(err)
process.exit(0)
}
resolve && resolve(address)
})
})
}
}