155 lines
4.4 KiB
TypeScript
155 lines
4.4 KiB
TypeScript
import { fastify, FastifyError, FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
|
|
import { IncomingMessage, Server, ServerResponse } from 'http'
|
|
import { RouterMap } from 'decorators/router'
|
|
import helmet from '@fastify/helmet'
|
|
import logger from 'logger/logger'
|
|
import * as dotenv from 'dotenv'
|
|
const NODE_ENV = process.env.NODE_ENV || 'development'
|
|
|
|
const zReqParserPlugin = require('plugins/zReqParser')
|
|
const zTokenParserPlugin = require('plugins/zTokenParser')
|
|
const apiAuthPlugin = require('plugins/apiauth')
|
|
|
|
const fs = require('fs')
|
|
const join = require('path').join
|
|
const env = process.env
|
|
;(() => {
|
|
let path
|
|
switch (process.env.NODE_ENV) {
|
|
case 'test':
|
|
path = `${__dirname}/../.env.development`
|
|
break
|
|
case 'production':
|
|
path = `${__dirname}/../.env.production`
|
|
break
|
|
default:
|
|
path = `${__dirname}/../.env.development`
|
|
}
|
|
dotenv.config({ path: path, debug: NODE_ENV === 'development' })
|
|
})()
|
|
export class ApiServer {
|
|
server: FastifyInstance<Server, IncomingMessage, ServerResponse>
|
|
|
|
public constructor() {
|
|
this.server = fastify({ logger: true, trustProxy: 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: process.env.API_TOKEN_SECRET,
|
|
expiresIn: process.env.API_TOKEN_EXPIRESIN,
|
|
})
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
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(
|
|
'add router',
|
|
data.method || 'all',
|
|
data.path,
|
|
`${data.target.constructor.name}.${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))
|
|
})
|
|
}
|
|
|
|
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.errcode) {
|
|
payload = {
|
|
errcode: 0,
|
|
data: payload,
|
|
}
|
|
}
|
|
return payload
|
|
})
|
|
}
|
|
|
|
public async start() {
|
|
let self = this
|
|
return new Promise(async (resolve, reject) => {
|
|
self.initControllers()
|
|
self.registerRouter()
|
|
self.setErrHandler()
|
|
self.setFormatSend()
|
|
this.server.listen({ port: +env.API_PORT, host: env.API_HOST }, (err: any, address: any) => {
|
|
if (err) {
|
|
logger.log(err)
|
|
process.exit(0)
|
|
}
|
|
resolve && resolve(address)
|
|
})
|
|
})
|
|
}
|
|
}
|