增加一些基本的代码

This commit is contained in:
zhl 2021-01-07 12:53:24 +08:00
parent 51947d4b73
commit 8f9c5e3f64
10 changed files with 232 additions and 43 deletions

View File

@ -1,6 +1,8 @@
# 卡牌游戏接口说明 # 卡牌游戏接口说明
## 一. 说明 ## 一. 说明
所有接口均需上传sessionid
通用返回JSON结构, 接口Response的数据结构说明只包含data部分 通用返回JSON结构, 接口Response的数据结构说明只包含data部分
``` JSON ``` JSON
{ {
@ -14,7 +16,7 @@
## 二. 客户端接口列表 ## 二. 客户端接口列表
### 1. 玩家资料 ### 1. 玩家资料
1. Method: GET 1. Method: POST
2. URI: /api/:accountid/uinfo 2. URI: /api/:accountid/uinfo
| 字段 | 说明 | | 字段 | 说明 |
@ -28,7 +30,7 @@
``` ```
### 2. 可用卡牌信息 ### 2. 可用卡牌信息
1. Method: GET 1. Method: POST
2. URI: /api/:accountid/cards 2. URI: /api/:accountid/cards
| 字段 | 说明 | | 字段 | 说明 |
@ -52,7 +54,7 @@
``` ```
### 3. 可用英雄列表 ### 3. 可用英雄列表
1. Method: GET 1. Method: POST
2. URI: /api/:accountid 2. URI: /api/:accountid
| 字段 | 说明 | | 字段 | 说明 |
@ -80,7 +82,7 @@
``` ```
### 4. 自定义卡组列表 ### 4. 自定义卡组列表
1. Method: GET 1. Method: POST
2. URI: /api/:accountid/card_group/:heroid 2. URI: /api/:accountid/card_group/:heroid
| 字段 | 说明 | | 字段 | 说明 |
@ -128,7 +130,7 @@
根据errcode判断成功or失败 根据errcode判断成功or失败
### 6. 删除卡组 ### 6. 删除卡组
1. Method: GET 1. Method: POST
2. URI: /api/:accountid/card_group/delete/:gid 2. URI: /api/:accountid/card_group/delete/:gid
@ -165,7 +167,7 @@
根据errcode判断成功or失败 根据errcode判断成功or失败
### 8. 抽卡 ### 8. 抽卡
1. Method: GET 1. Method: POST
2. URI: /api/:accountid/card/draw/:count 2. URI: /api/:accountid/card/draw/:count
| 字段 | 说明 | | 字段 | 说明 |
@ -186,7 +188,7 @@
``` ```
### 9. 对战记录列表 ### 9. 对战记录列表
1. Method: GET 1. Method: POST
2. URI: /api/:accountid/records 2. URI: /api/:accountid/records
| 字段 | 说明 | | 字段 | 说明 |
@ -221,7 +223,7 @@
```json ```json
{ {
exp: 1022, // 当前经验值 exp: 1022, // 当前经验值
exp_get: 100, // 本次获得的经验 exp_POST: 100, // 本次获得的经验
level: 1 // 当前等级 level: 1 // 当前等级
} }
``` ```

43
package-lock.json generated
View File

@ -29,6 +29,7 @@
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz",
"integrity": "sha512-mVRvYnTOZJz3ccpxhr3wgxVmSeiYinW+zlzQz3SXWaJmD1DuL05Jeq7nKw3SnbKmbleW5qrLG5vdyWe/A9sXhw==", "integrity": "sha512-mVRvYnTOZJz3ccpxhr3wgxVmSeiYinW+zlzQz3SXWaJmD1DuL05Jeq7nKw3SnbKmbleW5qrLG5vdyWe/A9sXhw==",
"dev": true,
"requires": { "requires": {
"@types/node": "*" "@types/node": "*"
} }
@ -51,6 +52,7 @@
"version": "3.6.3", "version": "3.6.3",
"resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.3.tgz", "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.3.tgz",
"integrity": "sha512-6YNqGP1hk5bjUFaim+QoFFuI61WjHiHE1BNeB41TA00Xd2K7zG4lcWyLLq/XtIp36uMavvS5hoAUJ+1u/GcX2Q==", "integrity": "sha512-6YNqGP1hk5bjUFaim+QoFFuI61WjHiHE1BNeB41TA00Xd2K7zG4lcWyLLq/XtIp36uMavvS5hoAUJ+1u/GcX2Q==",
"dev": true,
"requires": { "requires": {
"@types/bson": "*", "@types/bson": "*",
"@types/node": "*" "@types/node": "*"
@ -590,9 +592,9 @@
} }
}, },
"kareem": { "kareem": {
"version": "2.3.2", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz",
"integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ==" "integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw=="
}, },
"light-my-request": { "light-my-request": {
"version": "4.4.1", "version": "4.4.1",
@ -700,11 +702,11 @@
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
}, },
"mongodb": { "mongodb": {
"version": "3.6.3", "version": "3.6.1",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.3.tgz", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.1.tgz",
"integrity": "sha512-rOZuR0QkodZiM+UbQE5kDsJykBqWi0CL4Ec2i1nrGrUI3KO11r6Fbxskqmq3JK2NH7aW4dcccBuUujAP0ERl5w==", "integrity": "sha512-uH76Zzr5wPptnjEKJRQnwTsomtFOU/kQEU8a9hKHr2M7y9qVk7Q4Pkv0EQVp88742z9+RwvsdTw6dRjDZCNu1g==",
"requires": { "requires": {
"bl": "^2.2.1", "bl": "^2.2.0",
"bson": "^1.1.4", "bson": "^1.1.4",
"denque": "^1.4.1", "denque": "^1.4.1",
"require_optional": "^1.0.1", "require_optional": "^1.0.1",
@ -720,17 +722,16 @@
} }
}, },
"mongoose": { "mongoose": {
"version": "5.11.10", "version": "5.10.3",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.11.10.tgz", "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.10.3.tgz",
"integrity": "sha512-daE2L6VW7WNywv7tL2KUkBViWvODbzr50Of1kJpIbzW3w3N5/TYcgSmhCsEDWfYGQXbun2rdd7+sOdsEC8zQSQ==", "integrity": "sha512-FLemltuzcsCHlFpEZ3bYOiNhJfHful+GoS+3uRgdEWGlY0HKfOjm9xsISM/tql8vRvhjr7qveuRfoBBGO3xNtw==",
"requires": { "requires": {
"@types/mongodb": "^3.5.27",
"bson": "^1.1.4", "bson": "^1.1.4",
"kareem": "2.3.2", "kareem": "2.3.1",
"mongodb": "3.6.3", "mongodb": "3.6.1",
"mongoose-legacy-pluralize": "1.0.2", "mongoose-legacy-pluralize": "1.0.2",
"mpath": "0.8.3", "mpath": "0.7.0",
"mquery": "3.2.3", "mquery": "3.2.2",
"ms": "2.1.2", "ms": "2.1.2",
"regexp-clone": "1.0.0", "regexp-clone": "1.0.0",
"safe-buffer": "5.2.1", "safe-buffer": "5.2.1",
@ -756,14 +757,14 @@
"integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ=="
}, },
"mpath": { "mpath": {
"version": "0.8.3", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.3.tgz", "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.7.0.tgz",
"integrity": "sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA==" "integrity": "sha512-Aiq04hILxhz1L+f7sjGyn7IxYzWm1zLNNXcfhDtx04kZ2Gk7uvFdgZ8ts1cWa/6d0TQmag2yR8zSGZUmp0tFNg=="
}, },
"mquery": { "mquery": {
"version": "3.2.3", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.3.tgz", "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.2.tgz",
"integrity": "sha512-cIfbP4TyMYX+SkaQ2MntD+F2XbqaBHUYWk3j+kqdDztPWok3tgyssOZxMHMtzbV1w9DaSlvEea0Iocuro41A4g==", "integrity": "sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q==",
"requires": { "requires": {
"bluebird": "3.5.1", "bluebird": "3.5.1",
"debug": "3.1.0", "debug": "3.1.0",

View File

@ -4,7 +4,7 @@
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "dev:api": "DEBUG=colyseus:*,jc:* node --require ts-node/register --inspect src/api.ts"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
@ -22,14 +22,14 @@
"fastify-jwt": "^2.2.0", "fastify-jwt": "^2.2.0",
"fastify-plugin": "^3.0.0", "fastify-plugin": "^3.0.0",
"mime-types": "^2.1.28", "mime-types": "^2.1.28",
"mongoose": "^5.11.10", "mongoose": "5.10.3",
"mongoose-findorcreate": "^3.0.0", "mongoose-findorcreate": "^3.0.0",
"tracer": "^1.1.4", "tracer": "^1.1.4",
"urlencode": "^1.1.0" "urlencode": "^1.1.0"
}, },
"devDependencies": { "devDependencies": {
"@types/debug": "^4.1.5", "@types/debug": "4.1.5",
"@types/mongoose": "^5.10.3", "@types/mongoose": "5.10.3",
"@types/node": "^14.14.20", "@types/node": "^14.14.20",
"ts-node": "^9.1.1", "ts-node": "^9.1.1",
"typescript": "^4.1.3" "typescript": "^4.1.3"

View File

@ -1,4 +1,9 @@
import fastify, {FastifyError, FastifyInstance} from 'fastify' import fastify, {
FastifyError,
FastifyInstance,
FastifyReply,
FastifyRequest
} from 'fastify'
import helmet from 'fastify-helmet' import helmet from 'fastify-helmet'
import { Server, IncomingMessage, ServerResponse } from 'http' import { Server, IncomingMessage, ServerResponse } from 'http'
import {RouterMap} from './decorators/router'; import {RouterMap} from './decorators/router';
@ -7,7 +12,6 @@ import logger from './logger/logger';
import {Config} from "./cfg/Config"; import {Config} from "./cfg/Config";
const zReqParserPlugin = require('./plugins/zReqParser'); const zReqParserPlugin = require('./plugins/zReqParser');
const apiAuthPlugin = require('./plugins/apiauth'); const apiAuthPlugin = require('./plugins/apiauth');
const fs = require('fs'); const fs = require('fs');
@ -25,10 +29,10 @@ export class ApiServer {
private registerPlugins() { private registerPlugins() {
this.server.register(require('fastify-formbody')); this.server.register(require('fastify-formbody'));
this.server.register(zReqParserPlugin); this.server.register(zReqParserPlugin);
// @ts-ignore this.server.register(apiAuthPlugin);
this.server.register( this.server.register(
helmet, helmet,
{ hidePoweredBy: { setTo: 'PHP 4.2.0' } } { hidePoweredBy: false }
) )
this.server.register(require('fastify-cors'), {}); this.server.register(require('fastify-cors'), {});
@ -57,7 +61,7 @@ export class ApiServer {
*/ */
initControllers() { initControllers() {
logger.info('Bootstrap controllers...'); logger.info('Bootstrap controllers...');
const controllers = join(__dirname, 'api/controllers'); const controllers = join(__dirname, 'controllers');
fs.readdirSync(controllers) fs.readdirSync(controllers)
.filter((file: string) => ~file.search(/^[^.].*\.(ts|js)$/)) .filter((file: string) => ~file.search(/^[^.].*\.(ts|js)$/))
.forEach((file: any) => { .forEach((file: any) => {
@ -81,10 +85,10 @@ export class ApiServer {
} }
} }
private setErrHandler() { private setErrHandler() {
this.server.setNotFoundHandler(function(request: any, reply: { send: (arg0: { code: number; msg: string; }) => void; }){ this.server.setNotFoundHandler(function(request: any, reply: { send: (arg0: { errcode: number; errmsg: string; }) => void; }){
reply.send({code: 404, msg: 'page not found'}) reply.send({errcode: 404, errmsg: 'page not found'})
}); });
this.server.setErrorHandler(function (error: FastifyError, request: any, reply: { send: (arg0: { code: any; msg: any; }) => void; }) { this.server.setErrorHandler(function (error: FastifyError, request: any, reply: { send: (arg0: { errcode: any; errmsg: any; }) => void; }) {
let statusCode = error && error.statusCode || 100; let statusCode = error && error.statusCode || 100;
if (statusCode >= 500) { if (statusCode >= 500) {
logger.error(error) logger.error(error)
@ -93,7 +97,19 @@ export class ApiServer {
} else { } else {
logger.error(error) logger.error(error)
} }
reply.send({code: statusCode, msg: error ? error.message : 'unknown error'}) reply.send({errcode: statusCode, errmsg: error ? error.message : 'unknown error'})
})
}
private setFormatSend() {
this.server.addHook('preSerialization', async (request: FastifyRequest, reply: FastifyReply, payload) => {
// @ts-ignore
if (!payload.errcode) {
payload = {
errcode: 0,
data: payload
}
}
return payload
}) })
} }
public async start() { public async start() {
@ -103,6 +119,7 @@ export class ApiServer {
self.initControllers(); self.initControllers();
self.registerRouter(); self.registerRouter();
self.setErrHandler(); self.setErrHandler();
self.setFormatSend();
this.server.listen({port: config.port}, (err: any, address: any) => { this.server.listen({port: config.port}, (err: any, address: any) => {
if (err) { if (err) {
logger.log(err) logger.log(err)

14
src/common/ZError.ts Normal file
View File

@ -0,0 +1,14 @@
import {FastifyError} from "fastify";
export class ZError implements FastifyError {
code: string;
statusCode?: number;
message: string;
name: string;
constructor(statusCode: number, message: string) {
this.statusCode = statusCode;
this.message = message;
}
}

View File

@ -0,0 +1,18 @@
import BaseController from "../common/base.controller";
import {role, router} from "../decorators/router";
import {Account} from "../models/Account";
import {ZError} from "../common/ZError";
export default class AccountController extends BaseController {
@role('anon')
@router('post /api/:accountid/uinfo')
async info(req: any, res: any) {
let {accountid} = req.params;
if (true) {
throw new ZError(101, 'no acc');
}
let account = (await Account.findOrCreate({accountid})).doc;
return account.toJson();
}
}

35
src/models/Account.ts Normal file
View File

@ -0,0 +1,35 @@
import {prop, getModelForClass, modelOptions, index, plugin} from '@typegoose/typegoose';
import {dbconn} from '../decorators/dbconn';
// @ts-ignore
import findOrCreate from 'mongoose-findorcreate';
import {Base, FindOrCreate, TimeStamps} from "@typegoose/typegoose/lib/defaultClasses";
interface AccountClass extends Base, TimeStamps {}
@dbconn()
@index({ accountid: 1}, { unique: true })
@plugin(findOrCreate)
@modelOptions({schemaOptions: {collection: "account", timestamps: true}})
class AccountClass extends FindOrCreate{
@prop()
public accountid: string;
@prop()
public city?: string;
@prop({default: false})
public locked: boolean;
@prop()
public lockedTime?: Date;
@prop()
public comment?: string;
@prop()
public lastLogin?: Date;
public toJson() {
return {
accountid: this.accountid,
}
}
}
// @ts-ignore
export const Account = getModelForClass(AccountClass, {existingConnection: AccountClass['db']});

60
src/plugins/apiauth.ts Normal file
View File

@ -0,0 +1,60 @@
import {
FastifyInstance,
FastifyPluginAsync, FastifyReply,
FastifyRequest,
} from 'fastify';
import fastifyPlugin from 'fastify-plugin';
import {Account} from '../models/Account';
declare module 'fastify' {
interface FastifyInstance {
apiAuth: (request: FastifyRequest, reply: FastifyReply) => {};
}
interface FastifyRequest {
session?: {[key: string]: any};
roles?: any,
user?: any
}
}
const apiAuthPlugin: FastifyPluginAsync = async function(
fastify: FastifyInstance,
options?: any
) {
// 只有路由配置的role为anon才不需要过滤
fastify.decorate("apiAuth", async function(request: FastifyRequest, reply: FastifyReply) {
if (!request.roles || request.roles.indexOf('anon') == -1) {
try {
// @ts-ignore
let { accountid, sessionid } = request.params;
//TODO: 增加sessionid的校验
// if (!accountid || !sessionid) {
// return reply.send({code: 11, msg: 'need accountid and sessionid'});
// }
if (!accountid) {
return reply.send({code: 11, msg: 'need accountid and sessionid'});
}
// const data = this.jwt.verify(request.token);
// if (!data || !data.id) {
// return reply.send({code: 10, msg: 'need login'});
// }
// let account = await Account.findById(data.id);
// if (!account) {
// return reply.send({code: 10, msg: 'need login'});
// }
// request.user = account;
} catch (err) {
return reply.send({code: 401, msg: 'need auth'})
}
}
})
};
export = fastifyPlugin(apiAuthPlugin, {
fastify: '>=3.0.0',
name: 'apiauth',
});

41
src/plugins/zReqParser.ts Normal file
View File

@ -0,0 +1,41 @@
import {
FastifyInstance,
FastifyPluginAsync,
FastifyReply,
FastifyRequest
} from "fastify";
import fastifyPlugin from "fastify-plugin";
/**
* post get req.params
*/
declare module 'fastify' {
interface FastifyInstance {
zReqParser: (request: FastifyRequest, reply: FastifyReply) => {};
}
interface FastifyRequest {
session?: {[key: string]: any};
}
}
const zReqParserPlugin: FastifyPluginAsync = async function(
fastify: FastifyInstance,
options?: any,
) {
fastify.addHook('preValidation', async (request: FastifyRequest, reply: FastifyReply) => {
let params = request.params || {};
if (request.query) {
Object.assign(params, request.query);
}
if (request.body) {
Object.assign(params, request.body);
}
request.params = params;
})
return;
}
export = fastifyPlugin(zReqParserPlugin, {
fastify: '>=3.0.0',
name: 'zReqParser',
});

View File

@ -15,6 +15,7 @@
"strictNullChecks": false, "strictNullChecks": false,
"esModuleInterop": true, "esModuleInterop": true,
"moduleResolution": "node", "moduleResolution": "node",
"experimentalDecorators": true "experimentalDecorators": true,
"emitDecoratorMetadata": true,
} }
} }