添加骨架代码

This commit is contained in:
zhl 2021-01-06 20:54:41 +08:00
parent 6f7553fc18
commit 51947d4b73
11 changed files with 1424 additions and 3 deletions

5
config/config.json Normal file
View File

@ -0,0 +1,5 @@
{
"redis": "redis://127.0.0.1:6379/15",
"db_main": "mongodb://127.0.0.1/card-development",
"port": 2987
}

View File

@ -53,12 +53,11 @@
### 3. 可用英雄列表
1. Method: GET
2. URI: /api/:accountid/heros
2. URI: /api/:accountid
| 字段 | 说明 |
| -------- | -------------------------------------- |
| accountid | 帐号id |
| heroid | 帐号id |
3. Response: JSON

1136
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,5 +7,31 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
"license": "ISC",
"dependencies": {
"@typegoose/auto-increment": "^0.6.0",
"@typegoose/typegoose": "^7.4.6",
"bson": "^4.2.2",
"debug": "^4.3.1",
"fast-rbac": "^1.3.0",
"fastify": "^3.9.2",
"fastify-cors": "^5.1.0",
"fastify-file-upload": "^3.0.0",
"fastify-formbody": "^5.0.0",
"fastify-helmet": "^5.0.3",
"fastify-jwt": "^2.2.0",
"fastify-plugin": "^3.0.0",
"mime-types": "^2.1.28",
"mongoose": "^5.11.10",
"mongoose-findorcreate": "^3.0.0",
"tracer": "^1.1.4",
"urlencode": "^1.1.0"
},
"devDependencies": {
"@types/debug": "^4.1.5",
"@types/mongoose": "^5.10.3",
"@types/node": "^14.14.20",
"ts-node": "^9.1.1",
"typescript": "^4.1.3"
}
}

117
src/api.server.ts Normal file
View File

@ -0,0 +1,117 @@
import fastify, {FastifyError, FastifyInstance} 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";
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');
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);
// @ts-ignore
this.server.register(
helmet,
{ hidePoweredBy: { setTo: 'PHP 4.2.0' } }
)
this.server.register(require('fastify-cors'), {});
}
private registerRouter() {
logger.log('register api routers');
let self = this;
for (let [controller, config] of RouterMap.decoratedRouters) {
let controllers = Array.isArray(controller) ? controller : [controller]
controllers.forEach((controller) => {
logger.info('find api router', config.method || 'all', config.path, controller.name);
// @ts-ignore
self.server[config.method || 'all'](config.path, {
preValidation: async function (request: { roles: string[]; }, reply: any, done: any) {
request.roles = config.roles;
await this.apiAuth(request, reply, done);
}
}, controller);
})
}
// this.server.register(new AccountRouter().applyAll, {prefix: 'user', logLevel: 'debug'});
}
/**
* 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: { code: number; msg: string; }) => void; }){
reply.send({code: 404, msg: 'page not found'})
});
this.server.setErrorHandler(function (error: FastifyError, request: any, reply: { send: (arg0: { code: any; msg: any; }) => void; }) {
let statusCode = error && error.statusCode || 100;
if (statusCode >= 500) {
logger.error(error)
} else if (statusCode >= 400) {
logger.info(error)
} else {
logger.error(error)
}
reply.send({code: statusCode, msg: error ? error.message : 'unknown error'})
})
}
public async start() {
let self = this;
return new Promise(async (resolve, reject) => {
await self.connectDB();
self.initControllers();
self.registerRouter();
self.setErrHandler();
this.server.listen({port: config.port}, (err: any, address: any) => {
if (err) {
logger.log(err)
process.exit(0)
}
resolve && resolve(address);
})
});
}
}

13
src/api.ts Normal file
View File

@ -0,0 +1,13 @@
import {ApiServer} from './api.server';
import logger from "./logger/logger";
class Server extends ApiServer {
constructor() {
super();
}
}
let server = new Server();
server.start().then((address) => {
logger.log(`Api Server listening at ${address}`)
})

5
src/cfg/Config.ts Normal file
View File

@ -0,0 +1,5 @@
export interface Config {
redis: string;
db_main: string;
port: number;
}

View File

@ -0,0 +1,9 @@
import fastify = require('fastify');
class BaseController {
aotoRoute(req: fastify.FastifyRequest, res: any) {
}
}
export default BaseController

19
src/decorators/dbconn.ts Normal file
View File

@ -0,0 +1,19 @@
import {mongoose} from "@typegoose/typegoose";
import {Config} from "../cfg/Config";
/**
* model指定数据库连接
* @param {string} name config中必须要有对应的配置 main db_main
* */
let config: Config = require('../../config/config.json');
export function dbconn(name?: string) {
return (target: any) => {
name = name || 'main';
// @ts-ignore
const url = config['db_'+name];
target['db'] = mongoose.createConnection(url, {
useNewUrlParser: true,
useCreateIndex:true,
useFindAndModify: false,
useUnifiedTopology: true});
};
}

90
src/decorators/router.ts Normal file
View File

@ -0,0 +1,90 @@
import BaseController from '../common/base.controller';
export class RouterMap {
static decoratedRouters: Map<Function | Function[], {
target?: any,
method?: string,
path?: string,
roles?: string[],
permissions?: string[]
}> = new Map()
}
export function router(route?: string) {
return (target: BaseController, name: string, value: PropertyDescriptor) => {
if (!route) {
const controller = target.constructor.name
const controllerName = controller.toLowerCase().replace('.controller', '')
route = 'all ' + ['', controllerName, name].join('/')
}
const split = route.split(' ');
if (split.length > 2) {
throw new Error('路由中只允许一个空格')
}
const [method, path] = split
// @ts-ignore
const key = target[name];
let routerObj = {
target: target,
path: path,
method: method
};
if (RouterMap.decoratedRouters.has(key)) {
let objCurrent = RouterMap.decoratedRouters.get(key);
Object.assign(objCurrent, routerObj);
// @ts-ignore
RouterMap.decoratedRouters.set(target[name], objCurrent);
} else {
// @ts-ignore
RouterMap.decoratedRouters.set(target[name], routerObj);
}
}
}
export function role(roles?: string | string[]) {
return (target: BaseController, name: string, value: PropertyDescriptor) => {
let roleList: string[] = [];
if (roles) {
if (Array.isArray(roles)) {
roleList = roles;
} else {
roleList = [roles];
}
}
// @ts-ignore
const key = target[name];
let roleObj = {roles: roleList};
if (RouterMap.decoratedRouters.has(key)) {
let objCurrent = RouterMap.decoratedRouters.get(key);
Object.assign(objCurrent, roleObj);
// @ts-ignore
RouterMap.decoratedRouters.set(target[name], objCurrent);
} else {
// @ts-ignore
RouterMap.decoratedRouters.set(target[name], roleObj);
}
}
}
export function permission(permissions?: string | string[]) {
return (target: BaseController, name: string, value: PropertyDescriptor) => {
let permissionList: string[] = [];
if (permissions) {
if (Array.isArray(permissions)) {
permissionList = permissions;
} else {
permissionList = [permissions];
}
}
// @ts-ignore
const key = target[name];
let permissionObj = {permissions: permissionList};
if (RouterMap.decoratedRouters.has(key)) {
let objCurrent = RouterMap.decoratedRouters.get(key);
Object.assign(objCurrent, permissionObj);
// @ts-ignore
RouterMap.decoratedRouters.set(target[name], objCurrent);
} else {
// @ts-ignore
RouterMap.decoratedRouters.set(target[name], permissionObj);
}
}
}

2
src/logger/logger.ts Normal file
View File

@ -0,0 +1,2 @@
const logger = require('tracer').colorConsole({dateformat: 'yyyy-mm-dd HH:MM:ss.L'});
export default logger