Compare commits
5 Commits
main
...
cocos-room
Author | SHA1 | Date | |
---|---|---|---|
|
f70fff7851 | ||
|
e197b2842a | ||
|
238ebb9857 | ||
|
3fd0679492 | ||
|
d2f770d3ad |
@ -15,4 +15,5 @@ Start local frontend server:
|
|||||||
```
|
```
|
||||||
cd <example-dir>/frontend
|
cd <example-dir>/frontend
|
||||||
npm install
|
npm install
|
||||||
|
npm run dev
|
||||||
```
|
```
|
@ -15,10 +15,10 @@
|
|||||||
"@types/node": "^15.14.9",
|
"@types/node": "^15.14.9",
|
||||||
"onchange": "^7.1.0",
|
"onchange": "^7.1.0",
|
||||||
"ts-node": "^9.1.1",
|
"ts-node": "^9.1.1",
|
||||||
"tsrpc-cli": "^2.4.0",
|
"tsrpc-cli": "^2.0.8",
|
||||||
"typescript": "^4.5.5"
|
"typescript": "^4.4.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsrpc": "^3.2.0"
|
"tsrpc": "^3.0.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,15 +7,15 @@
|
|||||||
"build": "webpack --mode=production"
|
"build": "webpack --mode=production"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"copy-webpack-plugin": "^9.1.0",
|
"copy-webpack-plugin": "^9.0.1",
|
||||||
"html-webpack-plugin": "^5.5.0",
|
"html-webpack-plugin": "^5.3.2",
|
||||||
"ts-loader": "^9.2.6",
|
"ts-loader": "^9.2.6",
|
||||||
"typescript": "^4.5.5",
|
"typescript": "^4.4.3",
|
||||||
"webpack": "^5.69.1",
|
"webpack": "^5.57.1",
|
||||||
"webpack-cli": "^4.9.2",
|
"webpack-cli": "^4.9.0",
|
||||||
"webpack-dev-server": "^3.11.3"
|
"webpack-dev-server": "^3.11.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsrpc-browser": "^3.2.0"
|
"tsrpc-browser": "^3.0.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,11 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^15.14.9",
|
"@types/node": "^15.14.9",
|
||||||
"onchange": "^7.1.0",
|
"onchange": "^7.1.0",
|
||||||
"ts-node": "^10.5.0",
|
"ts-node": "^10.2.1",
|
||||||
"tsrpc-cli": "^2.4.0",
|
"tsrpc-cli": "^2.0.8",
|
||||||
"typescript": "^4.5.5"
|
"typescript": "^4.4.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsrpc": "^3.2.0"
|
"tsrpc": "^3.0.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,16 +7,16 @@
|
|||||||
"build": "webpack --mode=production"
|
"build": "webpack --mode=production"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"copy-webpack-plugin": "^9.1.0",
|
"copy-webpack-plugin": "^9.0.1",
|
||||||
"html-webpack-plugin": "^5.5.0",
|
"html-webpack-plugin": "^5.3.2",
|
||||||
"ts-loader": "^9.2.6",
|
"ts-loader": "^9.2.6",
|
||||||
"typescript": "^4.5.5",
|
"typescript": "^4.4.3",
|
||||||
"webpack": "^5.69.1",
|
"webpack": "^5.57.1",
|
||||||
"webpack-cli": "^4.9.2",
|
"webpack-cli": "^4.9.0",
|
||||||
"webpack-dev-server": "^3.11.3"
|
"webpack-dev-server": "^3.11.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsrpc-browser": "^3.2.0"
|
"tsrpc-browser": "^3.0.7"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"defaults"
|
"defaults"
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
"@types/node": "^15.14.9",
|
"@types/node": "^15.14.9",
|
||||||
"onchange": "^7.1.0",
|
"onchange": "^7.1.0",
|
||||||
"ts-node": "^9.1.1",
|
"ts-node": "^9.1.1",
|
||||||
"tsrpc-cli": "^2.4.0",
|
"tsrpc-cli": "^2.2.0",
|
||||||
"typescript": "^4.5.5"
|
"typescript": "^4.5.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsrpc": "^3.2.0"
|
"tsrpc": "^3.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,7 +9,7 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsrpc-browser": "^3.2.0",
|
"tsrpc-browser": "^3.1.2",
|
||||||
"tsrpc-miniapp": "^3.2.0"
|
"tsrpc-miniapp": "^3.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
"@types/node": "^15.14.9",
|
"@types/node": "^15.14.9",
|
||||||
"onchange": "^7.1.0",
|
"onchange": "^7.1.0",
|
||||||
"ts-node": "^9.1.1",
|
"ts-node": "^9.1.1",
|
||||||
"tsrpc-cli": "^2.4.0",
|
"tsrpc-cli": "^2.2.0",
|
||||||
"typescript": "^4.5.5"
|
"typescript": "^4.5.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsrpc": "^3.2.0"
|
"tsrpc": "^3.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,7 @@
|
|||||||
"uuid": "cd1e2fff-2ab5-4407-b917-e60b25207723",
|
"uuid": "cd1e2fff-2ab5-4407-b917-e60b25207723",
|
||||||
"version": "3.3.2",
|
"version": "3.3.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsrpc-browser": "^3.2.0",
|
"tsrpc-browser": "^3.1.2",
|
||||||
"tsrpc-miniapp": "^3.2.0"
|
"tsrpc-miniapp": "^3.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
6
examples/cocos-room-cluster/README.md
Normal file
6
examples/cocos-room-cluster/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
TSRPC 分布式游戏房间服务 Demo
|
||||||
|
===
|
||||||
|
|
||||||
|
## 特性
|
||||||
|
1. 可开房间、随机匹配,房间逻辑可以自定义
|
||||||
|
2. 支持分布式部署和水平扩展
|
3
examples/cocos-room-cluster/backend/.gitignore
vendored
Normal file
3
examples/cocos-room-cluster/backend/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.DS_STORE
|
11
examples/cocos-room-cluster/backend/.mocharc.js
Normal file
11
examples/cocos-room-cluster/backend/.mocharc.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module.exports = {
|
||||||
|
require: [
|
||||||
|
'ts-node/register',
|
||||||
|
],
|
||||||
|
timeout: 999999,
|
||||||
|
exit: true,
|
||||||
|
spec: [
|
||||||
|
'./test/**/*.test.ts'
|
||||||
|
],
|
||||||
|
'preserve-symlinks': true
|
||||||
|
}
|
30
examples/cocos-room-cluster/backend/.vscode/launch.json
vendored
Normal file
30
examples/cocos-room-cluster/backend/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "mocha current file",
|
||||||
|
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
|
||||||
|
"args": [
|
||||||
|
"${file}"
|
||||||
|
],
|
||||||
|
"internalConsoleOptions": "openOnSessionStart",
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "ts-node current file",
|
||||||
|
"protocol": "inspector",
|
||||||
|
"args": [
|
||||||
|
"${relativeFile}"
|
||||||
|
],
|
||||||
|
"cwd": "${workspaceRoot}",
|
||||||
|
"runtimeArgs": [
|
||||||
|
"-r",
|
||||||
|
"ts-node/register"
|
||||||
|
],
|
||||||
|
"internalConsoleOptions": "openOnSessionStart"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
3
examples/cocos-room-cluster/backend/.vscode/settings.json
vendored
Normal file
3
examples/cocos-room-cluster/backend/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"typescript.tsdk": "node_modules\\typescript\\lib"
|
||||||
|
}
|
30
examples/cocos-room-cluster/backend/Dockerfile
Normal file
30
examples/cocos-room-cluster/backend/Dockerfile
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
FROM node
|
||||||
|
|
||||||
|
# 使用淘宝 NPM 镜像(国内机器构建推荐启用)
|
||||||
|
# RUN npm config set registry https://registry.npm.taobao.org/
|
||||||
|
|
||||||
|
# npm install
|
||||||
|
ADD package*.json /src/
|
||||||
|
WORKDIR /src
|
||||||
|
RUN npm i
|
||||||
|
|
||||||
|
# build
|
||||||
|
ADD . /src
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# clean
|
||||||
|
RUN npm prune --production
|
||||||
|
|
||||||
|
# move
|
||||||
|
RUN rm -rf /app \
|
||||||
|
&& mv dist /app \
|
||||||
|
&& mv node_modules /app/ \
|
||||||
|
&& rm -rf /src
|
||||||
|
|
||||||
|
# ENV
|
||||||
|
ENV NODE_ENV production
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
CMD node index.js
|
31
examples/cocos-room-cluster/backend/README.md
Normal file
31
examples/cocos-room-cluster/backend/README.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# TSRPC Server
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
### Local dev server
|
||||||
|
|
||||||
|
Dev server would restart automatically when code changed.
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate API document
|
||||||
|
|
||||||
|
Generate API document in swagger/openapi and markdown format.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
npm run doc
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run unit Test
|
||||||
|
Execute `npm run dev` first, then execute:
|
||||||
|
```
|
||||||
|
npm run test
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
30
examples/cocos-room-cluster/backend/package.json
Normal file
30
examples/cocos-room-cluster/backend/package.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "backend",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev:hall": "tsrpc-cli dev --entry src/hallServer.ts",
|
||||||
|
"dev:room": "tsrpc-cli dev --entry src/roomServer.ts",
|
||||||
|
"build": "tsrpc-cli build",
|
||||||
|
"doc": "tsrpc-cli doc",
|
||||||
|
"test": "mocha test/**/*.test.ts",
|
||||||
|
"proto": "tsrpc-cli proto",
|
||||||
|
"sync": "tsrpc-cli sync",
|
||||||
|
"api": "tsrpc-cli api"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/mocha": "^8.2.3",
|
||||||
|
"@types/node": "^15.14.9",
|
||||||
|
"@types/uuid": "^8.3.4",
|
||||||
|
"mocha": "^9.2.2",
|
||||||
|
"onchange": "^7.1.0",
|
||||||
|
"ts-node": "^10.7.0",
|
||||||
|
"tsrpc-cli": "^2.4.3-dev.1",
|
||||||
|
"typescript": "^4.6.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tsrpc": "^3.3.0",
|
||||||
|
"uuid": "^8.3.2"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
import path from "path";
|
||||||
|
import { HttpServer, WsClient } from "tsrpc";
|
||||||
|
import { UserUtil } from "../models/UserUtil";
|
||||||
|
import { MsgUpdateRoomState } from "../shared/protocols/roomServer/admin/MsgUpdateRoomState";
|
||||||
|
import { serviceProto } from "../shared/protocols/serviceProto_hallServer";
|
||||||
|
import { ServiceType as ServiceType_Room } from "../shared/protocols/serviceProto_roomServer";
|
||||||
|
import { UserInfo } from "../shared/types/UserInfo";
|
||||||
|
|
||||||
|
export class HallServer {
|
||||||
|
readonly server = new HttpServer(serviceProto, {
|
||||||
|
port: 3000,
|
||||||
|
// Remove this to use binary mode (remove from the client too)
|
||||||
|
json: true
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 已注册的 RoomServer */
|
||||||
|
readonly roomServers: {
|
||||||
|
url: string,
|
||||||
|
conn: WsClient<ServiceType_Room>,
|
||||||
|
state?: MsgUpdateRoomState
|
||||||
|
}[] = [];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// Flows
|
||||||
|
// 前置鉴别登录态
|
||||||
|
this.server.flows.preApiCallFlow.push(async call => {
|
||||||
|
call.currentUser = call.req.sso ? await UserUtil.parseSso(call.req.sso) : undefined;
|
||||||
|
|
||||||
|
// 需要登录的接口:前置登录态判定
|
||||||
|
if (!call.service.conf?.allowGuest) {
|
||||||
|
if (!call.currentUser) {
|
||||||
|
call.error('你还未登录', { code: 'NEED_LOGIN' });
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (call.currentUser) {
|
||||||
|
call.logger.prefixs.push(`[uid=${call.currentUser.id}]`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return call;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
await this.server.autoImplementApi(path.resolve(__dirname, './api'));
|
||||||
|
}
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
await this.server.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'tsrpc' {
|
||||||
|
export interface ApiCall {
|
||||||
|
/** 只要协议配置的 `allowGuest` 不为 `true`,则必定有值 */
|
||||||
|
currentUser?: UserInfo;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
import { ApiCall, TsrpcError } from "tsrpc";
|
||||||
|
import { hallServer } from "../../hallServer";
|
||||||
|
import { BackConfig } from "../../models/BackConfig";
|
||||||
|
import { ReqCreateRoom, ResCreateRoom } from "../../shared/protocols/hallServer/PtlCreateRoom";
|
||||||
|
|
||||||
|
export async function ApiCreateRoom(call: ApiCall<ReqCreateRoom, ResCreateRoom>) {
|
||||||
|
// 挑选一个人数最少的 RoomServer
|
||||||
|
let server = hallServer.roomServers.filter(v => v.state).orderBy(v => v.state!.userNum)[0];
|
||||||
|
if (!server) {
|
||||||
|
return call.error('没有可用的 RoomServer', { type: TsrpcError.Type.ServerError });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!call.req.roomName) {
|
||||||
|
return call.error('请输入房间名称');
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPC
|
||||||
|
let op = await server.conn.callApi('admin/CreateRoom', {
|
||||||
|
adminToken: BackConfig.adminToken,
|
||||||
|
creator: {
|
||||||
|
uid: call.currentUser!.id,
|
||||||
|
nickname: call.currentUser!.nickname
|
||||||
|
},
|
||||||
|
roomName: call.req.roomName
|
||||||
|
})
|
||||||
|
if (!op.isSucc) {
|
||||||
|
return call.error(op.err);
|
||||||
|
}
|
||||||
|
|
||||||
|
call.succ({
|
||||||
|
serverUrl: server.url,
|
||||||
|
roomId: op.res.roomId
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
import { ApiCall } from "tsrpc";
|
||||||
|
import { hallServer } from "../../hallServer";
|
||||||
|
import { ReqListRooms, ResListRooms } from "../../shared/protocols/hallServer/PtlListRooms";
|
||||||
|
|
||||||
|
export async function ApiListRooms(call: ApiCall<ReqListRooms, ResListRooms>) {
|
||||||
|
let rooms = hallServer.roomServers.reduce((prev, next) => {
|
||||||
|
if (next.state) {
|
||||||
|
prev = prev.concat(next.state.rooms.map(v => ({
|
||||||
|
name: v.name,
|
||||||
|
userNum: v.userNum,
|
||||||
|
serverUrl: next.url,
|
||||||
|
roomId: v.id,
|
||||||
|
updateTime: v.updateTime
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}, [] as (ResListRooms['rooms'][0] & { updateTime: number })[])
|
||||||
|
|
||||||
|
call.succ({
|
||||||
|
rooms: rooms.orderByDesc(v => v.updateTime).slice(0, 100)
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import { ApiCall } from "tsrpc";
|
||||||
|
import uuid from "uuid";
|
||||||
|
import { UserUtil } from "../../models/UserUtil";
|
||||||
|
import { ReqLogin, ResLogin } from "../../shared/protocols/hallServer/PtlLogin";
|
||||||
|
import { UserInfo } from "../../shared/types/UserInfo";
|
||||||
|
|
||||||
|
export async function ApiLogin(call: ApiCall<ReqLogin, ResLogin>) {
|
||||||
|
let uid = uuid.v4();
|
||||||
|
let user: UserInfo = {
|
||||||
|
id: uid,
|
||||||
|
nickname: call.req.nickname
|
||||||
|
};
|
||||||
|
let sso = await UserUtil.createSso(user)
|
||||||
|
|
||||||
|
call.succ({ sso, user })
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import { ApiCall } from "tsrpc";
|
||||||
|
import { ReqStartMatch, ResStartMatch } from "../../shared/protocols/hallServer/PtlStartMatch";
|
||||||
|
|
||||||
|
export async function ApiStartMatch(call: ApiCall<ReqStartMatch, ResStartMatch>) {
|
||||||
|
// TODO
|
||||||
|
call.error('API Not Implemented');
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
import { ApiCall, TerminalColorLogger, WsClient } from "tsrpc";
|
||||||
|
import { hallServer } from "../../../hallServer";
|
||||||
|
import { BackConfig } from "../../../models/BackConfig";
|
||||||
|
import { ReqRegisterRoomServer, ResRegisterRoomServer } from "../../../shared/protocols/hallServer/admin/PtlRegisterRoomServer";
|
||||||
|
import { serviceProto } from "../../../shared/protocols/serviceProto_roomServer";
|
||||||
|
import { HallServer } from "../../HallServer";
|
||||||
|
|
||||||
|
let nextRoomIndex = 1;
|
||||||
|
|
||||||
|
export async function ApiRegisterRoomServer(call: ApiCall<ReqRegisterRoomServer, ResRegisterRoomServer>) {
|
||||||
|
// 鉴权
|
||||||
|
if (call.req.adminToken !== BackConfig.adminToken) {
|
||||||
|
return call.error('非法操作');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create
|
||||||
|
let client = new WsClient(serviceProto, {
|
||||||
|
server: call.req.serverUrl,
|
||||||
|
logger: new TerminalColorLogger({
|
||||||
|
pid: `RoomServer${nextRoomIndex++}`
|
||||||
|
}),
|
||||||
|
heartbeat: {
|
||||||
|
interval: 5000,
|
||||||
|
timeout: 5000
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Flows
|
||||||
|
client.flows.postDisconnectFlow.push(v => {
|
||||||
|
hallServer.roomServers.remove(v1 => v1.conn === client);
|
||||||
|
return v;
|
||||||
|
});
|
||||||
|
client.listenMsg('admin/UpdateRoomState', msg => {
|
||||||
|
roomServer.state = msg;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Connect
|
||||||
|
let op = await client.connect();
|
||||||
|
if (!op.isSucc) {
|
||||||
|
return call.error(op.errMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auth
|
||||||
|
let op2 = await client.callApi('admin/Auth', { adminToken: call.req.adminToken });
|
||||||
|
if (!op2.isSucc) {
|
||||||
|
return call.error(op2.err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Succ
|
||||||
|
let roomServer: HallServer['roomServers'][number] = {
|
||||||
|
url: call.req.serverUrl,
|
||||||
|
conn: client
|
||||||
|
}
|
||||||
|
hallServer.roomServers.push(roomServer);
|
||||||
|
call.succ({});
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
import path from "path";
|
||||||
|
import { WsServer } from "tsrpc";
|
||||||
|
import { Room } from "../models/Room";
|
||||||
|
import { serviceProto } from "../shared/protocols/serviceProto_roomServer";
|
||||||
|
import { UserInfo } from "../shared/types/UserInfo";
|
||||||
|
|
||||||
|
export class RoomServer {
|
||||||
|
readonly server = new WsServer(serviceProto, {
|
||||||
|
port: parseInt(process.env['PORT'] || '3001'),
|
||||||
|
// Remove this to use binary mode (remove from the client too)
|
||||||
|
json: true
|
||||||
|
});
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// Flows
|
||||||
|
// 前置鉴别登录态
|
||||||
|
this.server.flows.preApiCallFlow.push(async call => {
|
||||||
|
// 需要登录的接口:前置登录态判定
|
||||||
|
if (!call.service.conf?.allowGuest) {
|
||||||
|
if (!call.conn.currentUser) {
|
||||||
|
call.error('你还未登录', { code: 'NEED_LOGIN' });
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return call;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
await this.server.autoImplementApi(path.resolve(__dirname, './api'));
|
||||||
|
}
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
await this.server.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'tsrpc' {
|
||||||
|
export interface BaseConnection {
|
||||||
|
currentUser?: UserInfo;
|
||||||
|
currentRoom?: Room;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import { ApiCall } from "tsrpc";
|
||||||
|
import { ReqExitRoom, ResExitRoom } from "../../shared/protocols/roomServer/PtlExitRoom";
|
||||||
|
|
||||||
|
export async function ApiExitRoom(call: ApiCall<ReqExitRoom, ResExitRoom>) {
|
||||||
|
// TODO
|
||||||
|
call.error('API Not Implemented');
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import { ApiCall } from "tsrpc";
|
||||||
|
import { ReqJoinRoom, ResJoinRoom } from "../../shared/protocols/roomServer/PtlJoinRoom";
|
||||||
|
|
||||||
|
export async function ApiJoinRoom(call: ApiCall<ReqJoinRoom, ResJoinRoom>) {
|
||||||
|
// TODO
|
||||||
|
call.error('API Not Implemented');
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import { ApiCall } from "tsrpc";
|
||||||
|
import { ReqUpdateRoom, ResUpdateRoom } from "../../shared/protocols/roomServer/PtlUpdateRoom";
|
||||||
|
|
||||||
|
export async function ApiUpdateRoom(call: ApiCall<ReqUpdateRoom, ResUpdateRoom>) {
|
||||||
|
// TODO
|
||||||
|
call.error('API Not Implemented');
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import { ApiCall } from "tsrpc";
|
||||||
|
import { ReqAuth, ResAuth } from "../../../shared/protocols/roomServer/admin/PtlAuth";
|
||||||
|
|
||||||
|
export async function ApiAuth(call: ApiCall<ReqAuth, ResAuth>) {
|
||||||
|
// TODO
|
||||||
|
call.error('API Not Implemented');
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import { ApiCall } from "tsrpc";
|
||||||
|
import { ReqCreateRoom, ResCreateRoom } from "../../../shared/protocols/roomServer/admin/PtlCreateRoom";
|
||||||
|
|
||||||
|
export async function ApiCreateRoom(call: ApiCall<ReqCreateRoom, ResCreateRoom>) {
|
||||||
|
// TODO
|
||||||
|
call.error('API Not Implemented');
|
||||||
|
}
|
11
examples/cocos-room-cluster/backend/src/hallServer.ts
Normal file
11
examples/cocos-room-cluster/backend/src/hallServer.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { HallServer } from "./HallServer/HallServer";
|
||||||
|
|
||||||
|
export const hallServer = new HallServer();
|
||||||
|
|
||||||
|
// Entry function
|
||||||
|
async function main() {
|
||||||
|
await hallServer.init();
|
||||||
|
await hallServer.start();
|
||||||
|
}
|
||||||
|
main();
|
||||||
|
|
@ -0,0 +1,5 @@
|
|||||||
|
export const BackConfig = {
|
||||||
|
|
||||||
|
adminToken: 'AAABBBCCC'
|
||||||
|
|
||||||
|
}
|
3
examples/cocos-room-cluster/backend/src/models/Room.ts
Normal file
3
examples/cocos-room-cluster/backend/src/models/Room.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export class Room {
|
||||||
|
|
||||||
|
}
|
21
examples/cocos-room-cluster/backend/src/models/UserUtil.ts
Normal file
21
examples/cocos-room-cluster/backend/src/models/UserUtil.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { UserInfo } from "../shared/types/UserInfo";
|
||||||
|
|
||||||
|
// 登录态 SSO 的编解码
|
||||||
|
// 这里简单起见,使用未加密的 JSON 字符串
|
||||||
|
// 你可以根据自己的需要,改为加密字符串,或者服务端 Session Key 等
|
||||||
|
export class UserUtil {
|
||||||
|
|
||||||
|
static async createSso(user: UserInfo): Promise<string> {
|
||||||
|
return JSON.stringify(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async parseSso(sso: string): Promise<UserInfo | undefined> {
|
||||||
|
try {
|
||||||
|
return JSON.parse(sso);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
examples/cocos-room-cluster/backend/src/roomServer.ts
Normal file
10
examples/cocos-room-cluster/backend/src/roomServer.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { RoomServer } from "./RoomServer/RoomServer";
|
||||||
|
|
||||||
|
export const roomServer = new RoomServer();
|
||||||
|
|
||||||
|
// Entry function
|
||||||
|
async function main() {
|
||||||
|
await roomServer.init();
|
||||||
|
await roomServer.start();
|
||||||
|
}
|
||||||
|
main();
|
@ -0,0 +1,20 @@
|
|||||||
|
export interface BaseRequest {
|
||||||
|
/** 登录态 */
|
||||||
|
sso?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BaseResponse {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BaseConf {
|
||||||
|
/**
|
||||||
|
* 此接口是否允许为登录用户调用
|
||||||
|
* @defaultValue false
|
||||||
|
*/
|
||||||
|
allowGuest?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BaseMessage {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
import { BaseConf, BaseRequest, BaseResponse } from "./../base";
|
||||||
|
|
||||||
|
export interface ReqCreateRoom extends BaseRequest {
|
||||||
|
roomName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResCreateRoom extends BaseResponse {
|
||||||
|
serverUrl: string,
|
||||||
|
roomId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const conf: BaseConf = {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
import { uint } from "tsrpc";
|
||||||
|
import { BaseConf, BaseRequest, BaseResponse } from "./../base";
|
||||||
|
|
||||||
|
export interface ReqListRooms extends BaseRequest {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResListRooms extends BaseResponse {
|
||||||
|
rooms: {
|
||||||
|
name: string,
|
||||||
|
userNum: uint,
|
||||||
|
serverUrl: string,
|
||||||
|
roomId: string
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const conf: BaseConf = {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
import { UserInfo } from "../../types/UserInfo";
|
||||||
|
import { BaseConf } from "../base";
|
||||||
|
|
||||||
|
export interface ReqLogin {
|
||||||
|
nickname: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResLogin {
|
||||||
|
sso: string,
|
||||||
|
user: UserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
export const conf: BaseConf = {
|
||||||
|
allowGuest: true
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
import { uint } from "tsrpc-proto";
|
||||||
|
import { BaseConf, BaseRequest, BaseResponse } from "./../base";
|
||||||
|
|
||||||
|
export interface ReqStartMatch extends BaseRequest {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResStartMatch extends BaseResponse {
|
||||||
|
serverUrl: string,
|
||||||
|
roomId: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
export const conf: BaseConf = {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import { BaseConf } from "../../base";
|
||||||
|
|
||||||
|
export interface ReqRegisterRoomServer {
|
||||||
|
/** RoomServer 的连接地址 */
|
||||||
|
serverUrl: string,
|
||||||
|
/** Token 用于鉴权 */
|
||||||
|
adminToken: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResRegisterRoomServer {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import { BaseConf, BaseRequest, BaseResponse } from "./../base";
|
||||||
|
|
||||||
|
export interface ReqExitRoom extends BaseRequest {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResExitRoom extends BaseResponse {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const conf: BaseConf = {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import { BaseRequest, BaseResponse, BaseConf } from "./../base";
|
||||||
|
|
||||||
|
export interface ReqJoinRoom extends BaseRequest {
|
||||||
|
roomId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResJoinRoom extends BaseResponse {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const conf: BaseConf = {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
import { BaseConf, BaseRequest, BaseResponse } from "../base";
|
||||||
|
|
||||||
|
export interface ReqUpdateRoom extends BaseRequest {
|
||||||
|
roomId: string,
|
||||||
|
roomName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResUpdateRoom extends BaseResponse {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const conf: BaseConf = {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import { uint } from "tsrpc-proto";
|
||||||
|
|
||||||
|
export interface MsgUpdateRoomState {
|
||||||
|
userNum: uint,
|
||||||
|
rooms: {
|
||||||
|
id: string,
|
||||||
|
name: string,
|
||||||
|
userNum: uint,
|
||||||
|
/** 为 undefined 代表不在匹配中 */
|
||||||
|
startMatchTime?: uint,
|
||||||
|
// 房间信息的最后更新时间
|
||||||
|
updateTime: uint
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// export const conf = {}
|
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
export interface ReqAuth {
|
||||||
|
adminToken: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResAuth {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
export interface ReqCreateRoom {
|
||||||
|
adminToken: string,
|
||||||
|
creator: {
|
||||||
|
uid: string,
|
||||||
|
nickname: string
|
||||||
|
}
|
||||||
|
roomName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResCreateRoom {
|
||||||
|
roomId: string
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
export interface MsgChat {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// export const conf = {}
|
@ -0,0 +1,5 @@
|
|||||||
|
export interface MsgUpdateRoomInfo {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// export const conf = {}
|
@ -0,0 +1,319 @@
|
|||||||
|
import { ServiceProto } from 'tsrpc-proto';
|
||||||
|
import { ReqRegisterRoomServer, ResRegisterRoomServer } from './hallServer/admin/PtlRegisterRoomServer';
|
||||||
|
import { ReqCreateRoom, ResCreateRoom } from './hallServer/PtlCreateRoom';
|
||||||
|
import { ReqListRooms, ResListRooms } from './hallServer/PtlListRooms';
|
||||||
|
import { ReqLogin, ResLogin } from './hallServer/PtlLogin';
|
||||||
|
import { ReqStartMatch, ResStartMatch } from './hallServer/PtlStartMatch';
|
||||||
|
|
||||||
|
export interface ServiceType {
|
||||||
|
api: {
|
||||||
|
"admin/RegisterRoomServer": {
|
||||||
|
req: ReqRegisterRoomServer,
|
||||||
|
res: ResRegisterRoomServer
|
||||||
|
},
|
||||||
|
"CreateRoom": {
|
||||||
|
req: ReqCreateRoom,
|
||||||
|
res: ResCreateRoom
|
||||||
|
},
|
||||||
|
"ListRooms": {
|
||||||
|
req: ReqListRooms,
|
||||||
|
res: ResListRooms
|
||||||
|
},
|
||||||
|
"Login": {
|
||||||
|
req: ReqLogin,
|
||||||
|
res: ResLogin
|
||||||
|
},
|
||||||
|
"StartMatch": {
|
||||||
|
req: ReqStartMatch,
|
||||||
|
res: ResStartMatch
|
||||||
|
}
|
||||||
|
},
|
||||||
|
msg: {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const serviceProto: ServiceProto<ServiceType> = {
|
||||||
|
"version": 2,
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "admin/RegisterRoomServer",
|
||||||
|
"type": "api"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "CreateRoom",
|
||||||
|
"type": "api",
|
||||||
|
"conf": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "ListRooms",
|
||||||
|
"type": "api",
|
||||||
|
"conf": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "Login",
|
||||||
|
"type": "api",
|
||||||
|
"conf": {
|
||||||
|
"allowGuest": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "StartMatch",
|
||||||
|
"type": "api",
|
||||||
|
"conf": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"types": {
|
||||||
|
"admin/PtlRegisterRoomServer/ReqRegisterRoomServer": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "serverUrl",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "adminToken",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"admin/PtlRegisterRoomServer/ResRegisterRoomServer": {
|
||||||
|
"type": "Interface"
|
||||||
|
},
|
||||||
|
"PtlCreateRoom/ReqCreateRoom": {
|
||||||
|
"type": "Interface",
|
||||||
|
"extends": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../base/BaseRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "roomName",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"../base/BaseRequest": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "sso",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
},
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PtlCreateRoom/ResCreateRoom": {
|
||||||
|
"type": "Interface",
|
||||||
|
"extends": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../base/BaseResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "serverUrl",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "roomId",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"../base/BaseResponse": {
|
||||||
|
"type": "Interface"
|
||||||
|
},
|
||||||
|
"PtlListRooms/ReqListRooms": {
|
||||||
|
"type": "Interface",
|
||||||
|
"extends": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../base/BaseRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PtlListRooms/ResListRooms": {
|
||||||
|
"type": "Interface",
|
||||||
|
"extends": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../base/BaseResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "rooms",
|
||||||
|
"type": {
|
||||||
|
"type": "Array",
|
||||||
|
"elementType": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "name",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "userNum",
|
||||||
|
"type": {
|
||||||
|
"type": "Number",
|
||||||
|
"scalarType": "uint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "serverUrl",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "roomId",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PtlLogin/ReqLogin": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "nickname",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PtlLogin/ResLogin": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "sso",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "user",
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../../types/UserInfo/UserInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"../../types/UserInfo/UserInfo": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "id",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "nickname",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PtlStartMatch/ReqStartMatch": {
|
||||||
|
"type": "Interface",
|
||||||
|
"extends": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../base/BaseRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PtlStartMatch/ResStartMatch": {
|
||||||
|
"type": "Interface",
|
||||||
|
"extends": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../base/BaseResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "serverUrl",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "roomId",
|
||||||
|
"type": {
|
||||||
|
"type": "Number",
|
||||||
|
"scalarType": "uint"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,342 @@
|
|||||||
|
import { ServiceProto } from 'tsrpc-proto';
|
||||||
|
import { MsgUpdateRoomState } from './roomServer/admin/MsgUpdateRoomState';
|
||||||
|
import { ReqAuth, ResAuth } from './roomServer/admin/PtlAuth';
|
||||||
|
import { ReqCreateRoom, ResCreateRoom } from './roomServer/admin/PtlCreateRoom';
|
||||||
|
import { ReqExitRoom, ResExitRoom } from './roomServer/PtlExitRoom';
|
||||||
|
import { ReqJoinRoom, ResJoinRoom } from './roomServer/PtlJoinRoom';
|
||||||
|
import { ReqUpdateRoom, ResUpdateRoom } from './roomServer/PtlUpdateRoom';
|
||||||
|
import { MsgChat } from './roomServer/roomMsg/MsgChat';
|
||||||
|
import { MsgUpdateRoomInfo } from './roomServer/roomMsg/MsgUpdateRoomInfo';
|
||||||
|
|
||||||
|
export interface ServiceType {
|
||||||
|
api: {
|
||||||
|
"admin/Auth": {
|
||||||
|
req: ReqAuth,
|
||||||
|
res: ResAuth
|
||||||
|
},
|
||||||
|
"admin/CreateRoom": {
|
||||||
|
req: ReqCreateRoom,
|
||||||
|
res: ResCreateRoom
|
||||||
|
},
|
||||||
|
"ExitRoom": {
|
||||||
|
req: ReqExitRoom,
|
||||||
|
res: ResExitRoom
|
||||||
|
},
|
||||||
|
"JoinRoom": {
|
||||||
|
req: ReqJoinRoom,
|
||||||
|
res: ResJoinRoom
|
||||||
|
},
|
||||||
|
"UpdateRoom": {
|
||||||
|
req: ReqUpdateRoom,
|
||||||
|
res: ResUpdateRoom
|
||||||
|
}
|
||||||
|
},
|
||||||
|
msg: {
|
||||||
|
"admin/UpdateRoomState": MsgUpdateRoomState,
|
||||||
|
"roomMsg/Chat": MsgChat,
|
||||||
|
"roomMsg/UpdateRoomInfo": MsgUpdateRoomInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const serviceProto: ServiceProto<ServiceType> = {
|
||||||
|
"version": 2,
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "admin/UpdateRoomState",
|
||||||
|
"type": "msg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "admin/Auth",
|
||||||
|
"type": "api"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "admin/CreateRoom",
|
||||||
|
"type": "api"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "ExitRoom",
|
||||||
|
"type": "api",
|
||||||
|
"conf": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "JoinRoom",
|
||||||
|
"type": "api",
|
||||||
|
"conf": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"name": "UpdateRoom",
|
||||||
|
"type": "api",
|
||||||
|
"conf": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"name": "roomMsg/Chat",
|
||||||
|
"type": "msg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"name": "roomMsg/UpdateRoomInfo",
|
||||||
|
"type": "msg"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"types": {
|
||||||
|
"admin/MsgUpdateRoomState/MsgUpdateRoomState": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "userNum",
|
||||||
|
"type": {
|
||||||
|
"type": "Number",
|
||||||
|
"scalarType": "uint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "rooms",
|
||||||
|
"type": {
|
||||||
|
"type": "Array",
|
||||||
|
"elementType": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "id",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "name",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "userNum",
|
||||||
|
"type": {
|
||||||
|
"type": "Number",
|
||||||
|
"scalarType": "uint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "startMatchTime",
|
||||||
|
"type": {
|
||||||
|
"type": "Number",
|
||||||
|
"scalarType": "uint"
|
||||||
|
},
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "updateTime",
|
||||||
|
"type": {
|
||||||
|
"type": "Number",
|
||||||
|
"scalarType": "uint"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"admin/PtlAuth/ReqAuth": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "adminToken",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"admin/PtlAuth/ResAuth": {
|
||||||
|
"type": "Interface"
|
||||||
|
},
|
||||||
|
"admin/PtlCreateRoom/ReqCreateRoom": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "adminToken",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "creator",
|
||||||
|
"type": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "uid",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "nickname",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "roomName",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"admin/PtlCreateRoom/ResCreateRoom": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "roomId",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PtlExitRoom/ReqExitRoom": {
|
||||||
|
"type": "Interface",
|
||||||
|
"extends": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../base/BaseRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"../base/BaseRequest": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "sso",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
},
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PtlExitRoom/ResExitRoom": {
|
||||||
|
"type": "Interface",
|
||||||
|
"extends": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../base/BaseResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"../base/BaseResponse": {
|
||||||
|
"type": "Interface"
|
||||||
|
},
|
||||||
|
"PtlJoinRoom/ReqJoinRoom": {
|
||||||
|
"type": "Interface",
|
||||||
|
"extends": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../base/BaseRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "roomId",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PtlJoinRoom/ResJoinRoom": {
|
||||||
|
"type": "Interface",
|
||||||
|
"extends": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../base/BaseResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PtlUpdateRoom/ReqUpdateRoom": {
|
||||||
|
"type": "Interface",
|
||||||
|
"extends": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../base/BaseRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "roomId",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "roomName",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PtlUpdateRoom/ResUpdateRoom": {
|
||||||
|
"type": "Interface",
|
||||||
|
"extends": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": {
|
||||||
|
"type": "Reference",
|
||||||
|
"target": "../base/BaseResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"roomMsg/MsgChat/MsgChat": {
|
||||||
|
"type": "Interface"
|
||||||
|
},
|
||||||
|
"roomMsg/MsgUpdateRoomInfo/MsgUpdateRoomInfo": {
|
||||||
|
"type": "Interface"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,4 @@
|
|||||||
|
export interface UserInfo {
|
||||||
|
id: string,
|
||||||
|
nickname: string
|
||||||
|
}
|
40
examples/cocos-room-cluster/backend/test/api/ApiSend.test.ts
Normal file
40
examples/cocos-room-cluster/backend/test/api/ApiSend.test.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import assert from 'assert';
|
||||||
|
import { TsrpcError, WsClient } from 'tsrpc';
|
||||||
|
import { serviceProto } from '../../src/shared/protocols/serviceProto';
|
||||||
|
|
||||||
|
// 1. EXECUTE `npm run dev` TO START A LOCAL DEV SERVER
|
||||||
|
// 2. EXECUTE `npm test` TO START UNIT TEST
|
||||||
|
|
||||||
|
describe('ApiSend', function () {
|
||||||
|
let client = new WsClient(serviceProto, {
|
||||||
|
server: 'ws://127.0.0.1:3000',
|
||||||
|
json: true,
|
||||||
|
logger: console
|
||||||
|
});
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
let res = await client.connect();
|
||||||
|
assert.strictEqual(res.isSucc, true, 'Failed to connect to server, have you executed `npm run dev` already?');
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Success', async function () {
|
||||||
|
let ret = await client.callApi('Send', {
|
||||||
|
content: 'Test'
|
||||||
|
});
|
||||||
|
assert.ok(ret.isSucc)
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Check content is empty', async function () {
|
||||||
|
let ret = await client.callApi('Send', {
|
||||||
|
content: ''
|
||||||
|
});
|
||||||
|
assert.deepStrictEqual(ret, {
|
||||||
|
isSucc: false,
|
||||||
|
err: new TsrpcError('Content is empty')
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
await client.disconnect();
|
||||||
|
})
|
||||||
|
})
|
15
examples/cocos-room-cluster/backend/test/tsconfig.json
Normal file
15
examples/cocos-room-cluster/backend/test/tsconfig.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"lib": [
|
||||||
|
"es2018"
|
||||||
|
],
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es2018",
|
||||||
|
"outDir": "dist",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"moduleResolution": "node"
|
||||||
|
}
|
||||||
|
}
|
18
examples/cocos-room-cluster/backend/tsconfig.json
Normal file
18
examples/cocos-room-cluster/backend/tsconfig.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"lib": [
|
||||||
|
"es2018"
|
||||||
|
],
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es2018",
|
||||||
|
"outDir": "dist",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"moduleResolution": "node"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
|
}
|
47
examples/cocos-room-cluster/backend/tsrpc.config.ts
Normal file
47
examples/cocos-room-cluster/backend/tsrpc.config.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { CodeTemplate, TsrpcConfig } from 'tsrpc-cli';
|
||||||
|
|
||||||
|
const tsrpcConf: TsrpcConfig = {
|
||||||
|
// Generate ServiceProto
|
||||||
|
proto: [
|
||||||
|
{
|
||||||
|
ptlDir: 'src/shared/protocols/hallServer', // Protocol dir
|
||||||
|
output: 'src/shared/protocols/serviceProto_hallServer.ts', // Path for generated ServiceProto
|
||||||
|
apiDir: 'src/HallServer/api', // API dir
|
||||||
|
docDir: 'docs/hallServer', // API documents dir
|
||||||
|
ptlTemplate: CodeTemplate.getExtendedPtl(),
|
||||||
|
// msgTemplate: CodeTemplate.getExtendedMsg(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ptlDir: 'src/shared/protocols/roomServer', // Protocol dir
|
||||||
|
output: 'src/shared/protocols/serviceProto_roomServer.ts', // Path for generated ServiceProto
|
||||||
|
apiDir: 'src/RoomServer/api', // API dir
|
||||||
|
docDir: 'docs/roomServer', // API documents dir
|
||||||
|
ptlTemplate: CodeTemplate.getExtendedPtl(),
|
||||||
|
// msgTemplate: CodeTemplate.getExtendedMsg(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// Sync shared code
|
||||||
|
sync: [
|
||||||
|
// {
|
||||||
|
// from: 'src/shared',
|
||||||
|
// to: '../frontend/src/shared',
|
||||||
|
// type: 'symlink' // Change this to 'copy' if your environment not support symlink
|
||||||
|
// }
|
||||||
|
],
|
||||||
|
// Dev server
|
||||||
|
dev: {
|
||||||
|
autoProto: true, // Auto regenerate proto
|
||||||
|
autoSync: true, // Auto sync when file changed
|
||||||
|
autoApi: true, // Auto create API when ServiceProto updated
|
||||||
|
watch: 'src', // Restart dev server when these files changed
|
||||||
|
entry: 'src/index.ts', // Dev server command: node -r ts-node/register {entry}
|
||||||
|
},
|
||||||
|
// Build config
|
||||||
|
build: {
|
||||||
|
autoProto: true, // Auto generate proto before build
|
||||||
|
autoSync: true, // Auto sync before build
|
||||||
|
autoApi: true, // Auto generate API before build
|
||||||
|
outDir: 'dist', // Clean this dir before build
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default tsrpcConf;
|
@ -15,10 +15,10 @@
|
|||||||
"@types/node": "^15.14.9",
|
"@types/node": "^15.14.9",
|
||||||
"onchange": "^7.1.0",
|
"onchange": "^7.1.0",
|
||||||
"ts-node": "^9.1.1",
|
"ts-node": "^9.1.1",
|
||||||
"tsrpc-cli": "^2.4.0",
|
"tsrpc-cli": "^2.0.8",
|
||||||
"typescript": "^4.5.5"
|
"typescript": "^4.4.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsrpc": "^3.2.0"
|
"tsrpc": "^3.0.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,8 +6,7 @@ import { serviceProto } from "./shared/protocols/serviceProto";
|
|||||||
// Create the Server
|
// Create the Server
|
||||||
const server = new HttpServer(serviceProto, {
|
const server = new HttpServer(serviceProto, {
|
||||||
port: 3000,
|
port: 3000,
|
||||||
cors: '*',
|
cors: '*'
|
||||||
json: true
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Flow: Serve static files
|
// Flow: Serve static files
|
||||||
|
@ -7,15 +7,15 @@
|
|||||||
"build": "webpack --mode=production"
|
"build": "webpack --mode=production"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"copy-webpack-plugin": "^9.1.0",
|
"copy-webpack-plugin": "^9.0.1",
|
||||||
"html-webpack-plugin": "^5.5.0",
|
"html-webpack-plugin": "^5.3.2",
|
||||||
"ts-loader": "^9.2.6",
|
"ts-loader": "^9.2.6",
|
||||||
"typescript": "^4.5.5",
|
"typescript": "^4.4.3",
|
||||||
"webpack": "^5.69.1",
|
"webpack": "^5.57.1",
|
||||||
"webpack-cli": "^4.9.2",
|
"webpack-cli": "^4.9.0",
|
||||||
"webpack-dev-server": "^3.11.3"
|
"webpack-dev-server": "^3.11.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsrpc-browser": "^3.2.0"
|
"tsrpc-browser": "^3.0.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,6 @@
|
|||||||
"typescript": "^4.4.3"
|
"typescript": "^4.4.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsrpc": "^3.1.8"
|
"tsrpc": "^3.0.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,8 +4,5 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
timeout: 999999,
|
timeout: 999999,
|
||||||
exit: true,
|
exit: true,
|
||||||
'preserve-symlinks': true,
|
'preserve-symlinks': true
|
||||||
spec: [
|
|
||||||
'./test/**/*.test.ts'
|
|
||||||
]
|
|
||||||
}
|
}
|
@ -9,21 +9,20 @@
|
|||||||
"api": "tsrpc api",
|
"api": "tsrpc api",
|
||||||
"doc": "tsrpc doc",
|
"doc": "tsrpc doc",
|
||||||
"dev": "tsrpc dev",
|
"dev": "tsrpc dev",
|
||||||
"build": "tsrpc build",
|
"build": "tsrpc build"
|
||||||
"test": "mocha"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mocha": "^8.2.3",
|
"@types/mocha": "^8.2.3",
|
||||||
"@types/mongodb": "^3.6.20",
|
"@types/mongodb": "^3.6.20",
|
||||||
"@types/node": "^15.14.9",
|
"@types/node": "^15.14.9",
|
||||||
"mocha": "^9.2.1",
|
"mocha": "^9.1.2",
|
||||||
"onchange": "^7.1.0",
|
"onchange": "^7.1.0",
|
||||||
"ts-node": "^10.5.0",
|
"ts-node": "^10.2.1",
|
||||||
"tsrpc-cli": "^2.4.0",
|
"tsrpc-cli": "^2.0.8",
|
||||||
"typescript": "^4.5.5"
|
"typescript": "^4.4.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mongodb": "^4.4.0",
|
"mongodb": "^3.7.2",
|
||||||
"tsrpc": "^3.2.0"
|
"tsrpc": "^3.0.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,3 @@
|
|||||||
import { Document, ObjectId } from "mongodb";
|
|
||||||
import { ApiCall } from "tsrpc";
|
import { ApiCall } from "tsrpc";
|
||||||
import { Global } from "../models/Global";
|
import { Global } from "../models/Global";
|
||||||
import { ReqAddPost, ResAddPost } from "../shared/protocols/PtlAddPost";
|
import { ReqAddPost, ResAddPost } from "../shared/protocols/PtlAddPost";
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { ObjectId } from 'mongodb';
|
import { ObjectID } from 'mongodb';
|
||||||
import { ApiCall } from "tsrpc";
|
import { ApiCall } from "tsrpc";
|
||||||
import { Global } from "../models/Global";
|
import { Global } from "../models/Global";
|
||||||
import { ReqDelPost, ResDelPost } from "../shared/protocols/PtlDelPost";
|
import { ReqDelPost, ResDelPost } from "../shared/protocols/PtlDelPost";
|
||||||
|
|
||||||
export async function ApiDelPost(call: ApiCall<ReqDelPost, ResDelPost>) {
|
export async function ApiDelPost(call: ApiCall<ReqDelPost, ResDelPost>) {
|
||||||
let op = await Global.collection('Post').deleteOne({
|
let op = await Global.collection('Post').deleteOne({
|
||||||
_id: call.req._id
|
_id: new ObjectID(call.req._id)
|
||||||
})
|
})
|
||||||
|
|
||||||
call.succ({});
|
call.succ({});
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { ObjectId } from 'mongodb';
|
import { ObjectID } from 'mongodb';
|
||||||
import { ApiCall } from "tsrpc";
|
import { ApiCall } from "tsrpc";
|
||||||
import { Global } from "../models/Global";
|
import { Global } from "../models/Global";
|
||||||
import { ReqGetPost, ResGetPost } from "../shared/protocols/PtlGetPost";
|
import { ReqGetPost, ResGetPost } from "../shared/protocols/PtlGetPost";
|
||||||
|
|
||||||
export async function ApiGetPost(call: ApiCall<ReqGetPost, ResGetPost>) {
|
export async function ApiGetPost(call: ApiCall<ReqGetPost, ResGetPost>) {
|
||||||
let op = await Global.collection('Post').findOne({
|
let op = await Global.collection('Post').findOne({
|
||||||
_id: call.req._id
|
_id: new ObjectID(call.req._id)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!op) {
|
if (!op) {
|
||||||
@ -16,7 +16,7 @@ export async function ApiGetPost(call: ApiCall<ReqGetPost, ResGetPost>) {
|
|||||||
call.succ({
|
call.succ({
|
||||||
post: {
|
post: {
|
||||||
...op,
|
...op,
|
||||||
_id: op._id
|
_id: op._id.toHexString()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
@ -1,16 +1,16 @@
|
|||||||
import { ObjectId } from 'mongodb';
|
import { ObjectID } from 'mongodb';
|
||||||
import { ApiCall } from "tsrpc";
|
import { ApiCall } from "tsrpc";
|
||||||
import { Global } from "../models/Global";
|
import { Global } from "../models/Global";
|
||||||
import { ReqUpdatePost, ResUpdatePost } from "../shared/protocols/PtlUpdatePost";
|
import { ReqUpdatePost, ResUpdatePost } from "../shared/protocols/PtlUpdatePost";
|
||||||
|
|
||||||
export async function ApiUpdatePost(call: ApiCall<ReqUpdatePost, ResUpdatePost>) {
|
export async function ApiUpdatePost(call: ApiCall<ReqUpdatePost, ResUpdatePost>) {
|
||||||
let { _id, ...rest } = call.req.update;
|
let { _id, ...update } = call.req.update;
|
||||||
|
|
||||||
let op = await Global.collection('Post').updateOne({
|
let op = await Global.collection('Post').updateOne({
|
||||||
_id: _id
|
_id: new ObjectID(_id)
|
||||||
}, {
|
}, {
|
||||||
$set: {
|
$set: {
|
||||||
...rest,
|
...update,
|
||||||
update: {
|
update: {
|
||||||
uid: 'xxx',
|
uid: 'xxx',
|
||||||
time: new Date()
|
time: new Date()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export const BackConfig = {
|
export const BackConfig = {
|
||||||
// Please replace by your db
|
// Please replace by your db
|
||||||
mongoDb: 'mongodb+srv://test:test@tsrpc-example.0gzai.mongodb.net/tsrpc-example?retryWrites=true&w=majority',
|
mongoDb: 'mongodb://username:password@xxx.com:27017/test?authSource=admin',
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { Collection, Db, MongoClient, OptionalId } from "mongodb";
|
import { Collection, Db, MongoClient } from "mongodb";
|
||||||
import { Logger } from "tsrpc";
|
import { Logger } from "tsrpc";
|
||||||
import { DbPost } from "../shared/db/DbPost";
|
|
||||||
import { BackConfig } from "./BackConfig";
|
import { BackConfig } from "./BackConfig";
|
||||||
|
import { DbPost } from "./dbItems/DbPost";
|
||||||
|
|
||||||
export class Global {
|
export class Global {
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ export class Global {
|
|||||||
this.db = client.db();
|
this.db = client.db();
|
||||||
}
|
}
|
||||||
|
|
||||||
static collection<T extends keyof DbCollectionType>(col: T): Collection<OptionalId<DbCollectionType[T]>> {
|
static collection<T extends keyof DbCollectionType>(col: T): Collection<DbCollectionType[T]> {
|
||||||
return this.db.collection(col);
|
return this.db.collection(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
import { ObjectID } from "mongodb";
|
||||||
|
import { Overwrite } from "tsrpc";
|
||||||
|
import { Post } from "../../shared/protocols/models/Post";
|
||||||
|
|
||||||
|
export type DbPost = Overwrite<Post, {
|
||||||
|
_id: ObjectID
|
||||||
|
}>
|
@ -1,7 +1,7 @@
|
|||||||
import { DbPost } from "../db/DbPost";
|
import { Post } from "./models/Post";
|
||||||
|
|
||||||
export interface ReqAddPost {
|
export interface ReqAddPost {
|
||||||
newPost: Omit<DbPost, '_id' | 'create' | 'update' | 'visitedNum'>;
|
newPost: Omit<Post, '_id' | 'create' | 'update' | 'visitedNum'>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResAddPost {
|
export interface ResAddPost {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import { ObjectId } from "bson";
|
|
||||||
|
|
||||||
export interface ReqDelPost {
|
export interface ReqDelPost {
|
||||||
_id: ObjectId;
|
_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResDelPost {
|
export interface ResDelPost {
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { ObjectId } from "bson";
|
import { Post } from "./models/Post";
|
||||||
import { DbPost } from "../db/DbPost";
|
|
||||||
|
|
||||||
export interface ReqGetPost {
|
export interface ReqGetPost {
|
||||||
_id: ObjectId;
|
_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResGetPost {
|
export interface ResGetPost {
|
||||||
post: DbPost;
|
post: Post;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { DbPost } from "../db/DbPost";
|
import { Post } from "./models/Post";
|
||||||
|
|
||||||
export interface ReqUpdatePost {
|
export interface ReqUpdatePost {
|
||||||
update: Pick<DbPost, '_id'> & Partial<Pick<DbPost, 'title' | 'content'>>;
|
update: { _id: string } & Partial<Pick<Post, 'title' | 'content'>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResUpdatePost {
|
export interface ResUpdatePost {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import { ObjectId } from "mongodb";
|
export interface Post {
|
||||||
|
_id: string;
|
||||||
export interface DbPost {
|
|
||||||
_id: ObjectId;
|
|
||||||
author: string;
|
author: string;
|
||||||
title: string;
|
title: string;
|
||||||
content: string;
|
content: string;
|
@ -29,7 +29,7 @@ export interface ServiceType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const serviceProto: ServiceProto<ServiceType> = {
|
export const serviceProto: ServiceProto<ServiceType> = {
|
||||||
"version": 17,
|
"version": 16,
|
||||||
"services": [
|
"services": [
|
||||||
{
|
{
|
||||||
"id": 0,
|
"id": 0,
|
||||||
@ -62,7 +62,7 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
"type": {
|
"type": {
|
||||||
"target": {
|
"target": {
|
||||||
"type": "Reference",
|
"type": "Reference",
|
||||||
"target": "../db/DbPost/DbPost"
|
"target": "models/Post/Post"
|
||||||
},
|
},
|
||||||
"keys": [
|
"keys": [
|
||||||
"_id",
|
"_id",
|
||||||
@ -75,15 +75,14 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"../db/DbPost/DbPost": {
|
"models/Post/Post": {
|
||||||
"type": "Interface",
|
"type": "Interface",
|
||||||
"properties": [
|
"properties": [
|
||||||
{
|
{
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "_id",
|
"name": "_id",
|
||||||
"type": {
|
"type": {
|
||||||
"type": "Reference",
|
"type": "String"
|
||||||
"target": "?mongodb/ObjectId"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -182,8 +181,7 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "_id",
|
"name": "_id",
|
||||||
"type": {
|
"type": {
|
||||||
"type": "Reference",
|
"type": "String"
|
||||||
"target": "?bson/ObjectId"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -198,8 +196,7 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "_id",
|
"name": "_id",
|
||||||
"type": {
|
"type": {
|
||||||
"type": "Reference",
|
"type": "String"
|
||||||
"target": "?bson/ObjectId"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -212,7 +209,7 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
"name": "post",
|
"name": "post",
|
||||||
"type": {
|
"type": {
|
||||||
"type": "Reference",
|
"type": "Reference",
|
||||||
"target": "../db/DbPost/DbPost"
|
"target": "models/Post/Post"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -227,26 +224,28 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
"type": "Intersection",
|
"type": "Intersection",
|
||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 1,
|
||||||
"type": {
|
"type": {
|
||||||
"target": {
|
"type": "Interface",
|
||||||
"type": "Reference",
|
"properties": [
|
||||||
"target": "../db/DbPost/DbPost"
|
{
|
||||||
},
|
"id": 0,
|
||||||
"keys": [
|
"name": "_id",
|
||||||
"_id"
|
"type": {
|
||||||
],
|
"type": "String"
|
||||||
"type": "Pick"
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 5,
|
"id": 3,
|
||||||
"type": {
|
"type": {
|
||||||
"type": "Partial",
|
"type": "Partial",
|
||||||
"target": {
|
"target": {
|
||||||
"target": {
|
"target": {
|
||||||
"type": "Reference",
|
"type": "Reference",
|
||||||
"target": "../db/DbPost/DbPost"
|
"target": "models/Post/Post"
|
||||||
},
|
},
|
||||||
"keys": [
|
"keys": [
|
||||||
"title",
|
"title",
|
||||||
|
@ -7,16 +7,16 @@
|
|||||||
"build": "webpack --mode=production"
|
"build": "webpack --mode=production"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"copy-webpack-plugin": "^9.1.0",
|
"copy-webpack-plugin": "^9.0.1",
|
||||||
"html-webpack-plugin": "^5.5.0",
|
"html-webpack-plugin": "^5.3.2",
|
||||||
"ts-loader": "^9.2.6",
|
"ts-loader": "^9.2.6",
|
||||||
"typescript": "^4.5.5",
|
"typescript": "^4.4.3",
|
||||||
"webpack": "^5.69.1",
|
"webpack": "^5.57.1",
|
||||||
"webpack-cli": "^4.9.2",
|
"webpack-cli": "^4.9.0",
|
||||||
"webpack-dev-server": "^3.11.3"
|
"webpack-dev-server": "^3.11.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsrpc-browser": "^3.2.0"
|
"tsrpc-browser": "^3.0.7"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"defaults"
|
"defaults"
|
||||||
|
9
examples/mongodb-crud/frontend/src/env.d.ts
vendored
9
examples/mongodb-crud/frontend/src/env.d.ts
vendored
@ -1,9 +0,0 @@
|
|||||||
// TSRPC would decode ObjectId as string in frontend.
|
|
||||||
declare module 'mongodb' {
|
|
||||||
export type ObjectId = string;
|
|
||||||
export type ObjectID = string;
|
|
||||||
}
|
|
||||||
declare module 'bson' {
|
|
||||||
export type ObjectId = string;
|
|
||||||
export type ObjectID = string;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user