@fastcar/template-microservices 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +124 -0
- package/package.json +35 -0
- package/template/.prettierrc +9 -0
- package/template/.vscode/launch.json +183 -0
- package/template/README.md +1 -0
- package/template/package.json +47 -0
- package/template/resource/application-dev.yml +56 -0
- package/template/resource/application.yml +2 -0
- package/template/src/annotation/AuthServiceRole.ts +76 -0
- package/template/src/annotation/EnableHotConfig.ts +13 -0
- package/template/src/app-node.ts +94 -0
- package/template/src/app-pm2.ts +191 -0
- package/template/src/common/Code.ts +26 -0
- package/template/src/common/Constant.ts +28 -0
- package/template/src/common/Result.ts +40 -0
- package/template/src/common/TaskAsync.ts +17 -0
- package/template/src/hotconfig/ExampleConfigService.ts +29 -0
- package/template/src/hotconfig/HotConfigInterface.ts +43 -0
- package/template/src/middleware/checkForm.ts +20 -0
- package/template/src/middleware/checkLogin.ts +25 -0
- package/template/src/middleware/parseSession.ts +44 -0
- package/template/src/servers/base/BaseServer.ts +120 -0
- package/template/src/servers/base/common/BackSessionEntryController.ts +33 -0
- package/template/src/servers/base/common/RemoteController.ts +70 -0
- package/template/src/servers/base/service/BackSessionService.ts +97 -0
- package/template/src/servers/base/service/CenterClient.ts +457 -0
- package/template/src/servers/base/service/DataService.ts +85 -0
- package/template/src/servers/base/service/RouterService.ts +185 -0
- package/template/src/servers/center/app.ts +14 -0
- package/template/src/servers/center/controller/EntryController.ts +89 -0
- package/template/src/servers/center/controller/ServerController.ts +62 -0
- package/template/src/servers/center/service/ServerManager.ts +336 -0
- package/template/src/servers/chat/RoomHandler.ts +65 -0
- package/template/src/servers/chat/RoomService.ts +24 -0
- package/template/src/servers/chat/app.ts +11 -0
- package/template/src/servers/connector/app.ts +13 -0
- package/template/src/servers/connector/controller/AccountHandler.ts +80 -0
- package/template/src/servers/connector/controller/ChannelRemote.ts +63 -0
- package/template/src/servers/connector/middleware/forwardMsg.ts +54 -0
- package/template/src/servers/web/HelloController.ts +51 -0
- package/template/src/servers/web/SyncConfigService.ts +13 -0
- package/template/src/servers/web/app.ts +15 -0
- package/template/src/types/ClientSimpleSession.ts +3 -0
- package/template/src/types/ForwardRpcContext.ts +3 -0
- package/template/src/types/ReqSession.ts +8 -0
- package/template/src/types/ResultType.ts +5 -0
- package/template/src/types/ServerMeta.ts +48 -0
- package/template/src/types/SessionAttribute.ts +13 -0
- package/template/src/utils/ConnectorUtils.ts +25 -0
- package/template/src/utils/MicroservicesUtils.ts +101 -0
- package/template/src/utils/NetWork.ts +31 -0
- package/template/src/utils/SessionUtil.ts +46 -0
- package/template/test/connector-test.ts +64 -0
- package/template/test/hello.ts +71 -0
- package/template/tsconfig.json +39 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
//使用pm2启动微服务
|
|
2
|
+
import NetWork from "@/utils/NetWork";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import { FileUtil } from "@fastcar/core/utils";
|
|
5
|
+
import * as os from "os";
|
|
6
|
+
import MicroservicesUtils from "./utils/MicroservicesUtils";
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as yaml from "yaml";
|
|
9
|
+
import { exec, execSync } from "child_process";
|
|
10
|
+
|
|
11
|
+
class APPPm2 {
|
|
12
|
+
exec() {
|
|
13
|
+
let cmdArgs = MicroservicesUtils.parseArgs(process.argv);
|
|
14
|
+
let { cmd } = cmdArgs;
|
|
15
|
+
|
|
16
|
+
cmd = "start"; // 测试
|
|
17
|
+
|
|
18
|
+
switch (cmd) {
|
|
19
|
+
case "start": {
|
|
20
|
+
this.start();
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
case "stop": {
|
|
24
|
+
this.stop();
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
default: {
|
|
28
|
+
console.log(`未匹配到cmd---->${cmd}`);
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async start() {
|
|
35
|
+
const serverPath = path.join(__dirname, "servers");
|
|
36
|
+
let microservices = MicroservicesUtils.format(MicroservicesUtils.getMicroservicesConfig());
|
|
37
|
+
let pargs = MicroservicesUtils.parseArgs(process.argv);
|
|
38
|
+
let argServerType = Reflect.get(pargs, "serverType");
|
|
39
|
+
let argServiceId = Reflect.get(pargs, "serviceId");
|
|
40
|
+
let apps = [];
|
|
41
|
+
|
|
42
|
+
for (let serverType in microservices) {
|
|
43
|
+
if (argServerType && argServerType != serverType) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//判断是否为
|
|
48
|
+
let item = microservices[serverType];
|
|
49
|
+
let servers = item.servers;
|
|
50
|
+
for (let s of servers) {
|
|
51
|
+
if (argServiceId && argServiceId != s.serviceId) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (NetWork.isLocalIP(s.host)) {
|
|
56
|
+
let args: string[] = [];
|
|
57
|
+
|
|
58
|
+
args.push(serverType);
|
|
59
|
+
args.push(s.serviceId);
|
|
60
|
+
|
|
61
|
+
console.log(s.serviceId);
|
|
62
|
+
|
|
63
|
+
let scriptPath = require.resolve(path.join(serverPath, serverType, "app"));
|
|
64
|
+
let execArgs: { [key: string]: any } = {
|
|
65
|
+
name: `${s.serviceId}-usa`,
|
|
66
|
+
script: scriptPath,
|
|
67
|
+
args, //动态参数
|
|
68
|
+
// max_memory_restart: 1024 * 1024 * 1024, //最大重启内存
|
|
69
|
+
// max_restarts: 1, //最大重启一次
|
|
70
|
+
// autorestart: true,
|
|
71
|
+
cwd: __dirname,
|
|
72
|
+
env: {
|
|
73
|
+
TZ: "UTC", //替换成统一的时区
|
|
74
|
+
},
|
|
75
|
+
wait_ready: true,
|
|
76
|
+
kill_timeout: 5000,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
if (FileUtil.getSuffix(scriptPath) == "ts") {
|
|
80
|
+
execArgs.interpreter = path.join(__dirname, "../", "node_modules", ".bin", "ts-node");
|
|
81
|
+
|
|
82
|
+
if (os.type().startsWith("Windows")) {
|
|
83
|
+
execArgs.exec_mode = "cluster"; //不改为集群模式会有问题
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (execArgs?.env) {
|
|
87
|
+
execArgs.env["TS_NODE_PROJECT"] = path.join(__dirname, "../tsconfig.json");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (s.debugPort && execArgs.exec_mode != "cluster") {
|
|
92
|
+
let nodeArgs: string = execArgs.node_args as string;
|
|
93
|
+
if (!nodeArgs) {
|
|
94
|
+
execArgs.node_args = "";
|
|
95
|
+
}
|
|
96
|
+
execArgs.node_args += ` --inspect=${s.host}:${s.debugPort}`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
apps.push(execArgs);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let execPath = path.join(__dirname, "../", "resource", "ecosystem.config.yml");
|
|
105
|
+
//写入配置文件
|
|
106
|
+
fs.writeFileSync(
|
|
107
|
+
execPath,
|
|
108
|
+
yaml.stringify({
|
|
109
|
+
apps,
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
//先杀掉进程在执行启动
|
|
114
|
+
execSync(`pm2 stop ${execPath}`);
|
|
115
|
+
console.log("pm2 stop server complete");
|
|
116
|
+
|
|
117
|
+
let execRes = exec(`pm2 start ${execPath}`);
|
|
118
|
+
execRes.on("exit", () => {
|
|
119
|
+
console.info("start complete");
|
|
120
|
+
let startRes = execSync(`pm2 list`);
|
|
121
|
+
console.log(startRes.toString());
|
|
122
|
+
process.exit(0);
|
|
123
|
+
});
|
|
124
|
+
// setTimeout(() => {
|
|
125
|
+
// execRes.kill();
|
|
126
|
+
// }, 1000);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async stop() {
|
|
130
|
+
let microservices = MicroservicesUtils.format(MicroservicesUtils.getMicroservicesConfig());
|
|
131
|
+
let pargs = MicroservicesUtils.parseArgs(process.argv);
|
|
132
|
+
let argServerType: string = Reflect.get(pargs, "serverType");
|
|
133
|
+
let argServiceId: string = Reflect.get(pargs, "serviceId");
|
|
134
|
+
|
|
135
|
+
let all = false;
|
|
136
|
+
if (!argServerType && !argServiceId) {
|
|
137
|
+
all = true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
let names: string[] = [];
|
|
141
|
+
if (all) {
|
|
142
|
+
Object.values(microservices).forEach((t) => {
|
|
143
|
+
t.servers.forEach((item) => {
|
|
144
|
+
if (NetWork.isLocalIP(item.host)) {
|
|
145
|
+
names.push(item.serviceId);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
} else {
|
|
150
|
+
if (!!argServerType) {
|
|
151
|
+
let t = microservices[argServerType];
|
|
152
|
+
t.servers.forEach((item) => {
|
|
153
|
+
if (!argServiceId || item.serviceId == argServiceId) {
|
|
154
|
+
if (NetWork.isLocalIP(item.host)) {
|
|
155
|
+
names.push(item.serviceId);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
} else if (!!argServiceId) {
|
|
160
|
+
Object.keys(microservices).forEach((k) => {
|
|
161
|
+
let v = microservices[k];
|
|
162
|
+
v.servers.forEach((item) => {
|
|
163
|
+
if (item.serviceId == argServiceId) {
|
|
164
|
+
if (NetWork.isLocalIP(item.host)) {
|
|
165
|
+
names.push(item.serviceId);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (names.length > 0) {
|
|
174
|
+
names = names.map((n) => {
|
|
175
|
+
return `${n}-usa`;
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
let cmdStr = `pm2 stop ${names.join(" ")}`;
|
|
179
|
+
let execRes = exec(cmdStr);
|
|
180
|
+
execRes.on("exit", () => {
|
|
181
|
+
console.log("pm2 stop server list:");
|
|
182
|
+
names.forEach((item) => {
|
|
183
|
+
console.log(item);
|
|
184
|
+
});
|
|
185
|
+
process.exit(0);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export default new APPPm2().exec();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
SYS: {
|
|
3
|
+
OK: 200,
|
|
4
|
+
NOACCESS: 403, //禁止访问
|
|
5
|
+
NOT_FOUND: 404, //找不到服务
|
|
6
|
+
FAIL: 500, //内部错误
|
|
7
|
+
DISCONNECT: 501, //断线
|
|
8
|
+
RETRYTIMES: 502,
|
|
9
|
+
UNAVAILABLE: 503, //不可用
|
|
10
|
+
TIMEOUT: 504, //超时
|
|
11
|
+
BUSY: 505,
|
|
12
|
+
},
|
|
13
|
+
COMMON: {
|
|
14
|
+
PARAMETER_ERROR: 10001, //参数错误
|
|
15
|
+
PERMISSIONS_MISSING: 10002, //缺少权限
|
|
16
|
+
SERVER_CONNECT_FORBID: 10003, //连接禁止
|
|
17
|
+
},
|
|
18
|
+
CENTER: {
|
|
19
|
+
SERVER_NOT_FOUND: 20001, //服务不存在
|
|
20
|
+
SERVER_TOKEN_ERROR: 20002, //密码错误
|
|
21
|
+
SERVER_NOT_LOGIN: 20003, //服务未登录
|
|
22
|
+
},
|
|
23
|
+
ACCOUNT: {
|
|
24
|
+
NOT_LOGIN: 30001, //未登录
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const ServerTypeSymbol = Symbol("ServerType"); //特指每一组的类型
|
|
2
|
+
|
|
3
|
+
export const ServerMicroservices = "microservices";
|
|
4
|
+
|
|
5
|
+
//频道
|
|
6
|
+
export enum ChannelKind {
|
|
7
|
+
"FRONT" = "__front__", //前端服务
|
|
8
|
+
"REMOTE" = "__remote__", //后端调用服务
|
|
9
|
+
"CENTER" = "__center__", //中心服务
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//进行服务分类
|
|
13
|
+
export enum ServerKind {
|
|
14
|
+
"front" = "front", //前端程序服务
|
|
15
|
+
"remote" = "remote", //内部通讯服务
|
|
16
|
+
"center" = "center", //中心服务
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export enum ServerCommonUrl {
|
|
20
|
+
Connect = "connect_receipt",
|
|
21
|
+
ServiceStatusNotify = "/center/client/serviceStatusNotify", //客户端服务更新
|
|
22
|
+
ServiceStatusAllNotify = "/center/client/serviceStatusAllNotify", //全部路由更新
|
|
23
|
+
ServiceBalance = "/center/rebalance", //重新负载均衡
|
|
24
|
+
ServiceSyncConfig = "/center/syncConfig", //同步配置
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//热更新配置集合
|
|
28
|
+
export const HotConfigKeys = Symbol("hotConfigKeys");
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ValidationUtil } from "@fastcar/core/utils";
|
|
2
|
+
import CODE from "./Code";
|
|
3
|
+
|
|
4
|
+
/***
|
|
5
|
+
* @version 1.0 封装返回类
|
|
6
|
+
*/
|
|
7
|
+
export default class Result {
|
|
8
|
+
static ok(data?: Object) {
|
|
9
|
+
return {
|
|
10
|
+
code: CODE.SYS.OK,
|
|
11
|
+
msg: "success",
|
|
12
|
+
data: ValidationUtil.isNotNull(data) ? data : {},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static errorMsg(msg: string) {
|
|
17
|
+
return {
|
|
18
|
+
code: CODE.SYS.FAIL,
|
|
19
|
+
msg: msg,
|
|
20
|
+
data: {},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static errorCode(code: number, msg?: string) {
|
|
25
|
+
let res: { code: number; data: any; msg?: any } = {
|
|
26
|
+
code: code ? code : CODE.SYS.FAIL,
|
|
27
|
+
data: {},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
if (msg) {
|
|
31
|
+
res.msg = msg;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return res;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static isOK(code: number) {
|
|
38
|
+
return code == CODE.SYS.OK;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AsyncResource } from "async_hooks";
|
|
2
|
+
|
|
3
|
+
class TaskAsync extends AsyncResource {
|
|
4
|
+
protected callback: any;
|
|
5
|
+
|
|
6
|
+
constructor(callback: any) {
|
|
7
|
+
super("TaskAsync");
|
|
8
|
+
this.callback = callback;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
done(result?: any) {
|
|
12
|
+
this.runInAsyncScope(this.callback, null, result);
|
|
13
|
+
this.emitDestroy();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default TaskAsync;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BootPriority, Logger } from "@fastcar/core";
|
|
2
|
+
import { ApplicationStart, BeanName, Log } from "@fastcar/core/annotation";
|
|
3
|
+
import { getHotKey, HotConfigInterface } from "./HotConfigInterface";
|
|
4
|
+
|
|
5
|
+
@BeanName("ExampleConfigService")
|
|
6
|
+
@ApplicationStart(BootPriority.Common)
|
|
7
|
+
export default class ExampleConfigService implements HotConfigInterface {
|
|
8
|
+
@Log()
|
|
9
|
+
private logger!: Logger;
|
|
10
|
+
|
|
11
|
+
async run() {
|
|
12
|
+
this.logger.debug(`初始化配置`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//加载游戏配置
|
|
16
|
+
load(list: string[], serverType: string) {
|
|
17
|
+
//通知模板来
|
|
18
|
+
let keys = getHotKey(__filename);
|
|
19
|
+
if (keys && !keys.includes(serverType)) {
|
|
20
|
+
return this.logger.warn(`无需加载配置`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!!serverType) {
|
|
24
|
+
this.logger.debug(`加载单个配置${serverType}`);
|
|
25
|
+
} else {
|
|
26
|
+
this.logger.debug(`加载全部配置`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { HotConfigKeys } from "@/common/Constant";
|
|
2
|
+
import { DataMap } from "@fastcar/core";
|
|
3
|
+
|
|
4
|
+
export interface HotConfigInterface {
|
|
5
|
+
load(...args: any[]): void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
//设置热更新的模块和key值
|
|
9
|
+
export function setHotKey(filename: string, keys: Array<string>) {
|
|
10
|
+
if (keys && keys.length > 0) {
|
|
11
|
+
let m: DataMap<string, string[]> = Reflect.get(global, HotConfigKeys);
|
|
12
|
+
if (!m) {
|
|
13
|
+
m = new DataMap<string, string[]>();
|
|
14
|
+
Reflect.set(global, HotConfigKeys, m);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (keys.length == 0) {
|
|
18
|
+
m.set(filename, keys);
|
|
19
|
+
} else {
|
|
20
|
+
//全局存在的则忽略
|
|
21
|
+
let currKeys = m.get(filename);
|
|
22
|
+
if (!!currKeys && currKeys.length == 0) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!currKeys) {
|
|
27
|
+
currKeys = [];
|
|
28
|
+
m.set(filename, currKeys);
|
|
29
|
+
}
|
|
30
|
+
keys.forEach((key) => {
|
|
31
|
+
if (!currKeys.includes(key)) {
|
|
32
|
+
currKeys.push(key);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getHotKey(filename: string): string[] | undefined {
|
|
40
|
+
let m: DataMap<string, string[]> = Reflect.get(global, HotConfigKeys);
|
|
41
|
+
|
|
42
|
+
return m && m.get(filename);
|
|
43
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { RpcContext } from "@fastcar/rpc";
|
|
2
|
+
import Code from "@/common/Code";
|
|
3
|
+
import { ValidError } from "@fastcar/core";
|
|
4
|
+
import Result from "@/common/Result";
|
|
5
|
+
|
|
6
|
+
//针对表单校验抛出的错误进行处理
|
|
7
|
+
export default async function checkForm(context: RpcContext, next?: Function): Promise<void> {
|
|
8
|
+
if (next) {
|
|
9
|
+
try {
|
|
10
|
+
await next();
|
|
11
|
+
} catch (e: any) {
|
|
12
|
+
if (e instanceof ValidError) {
|
|
13
|
+
context.body = Result.errorCode(Code.COMMON.PARAMETER_ERROR, e?.message);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
throw e;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import Result from "@/common/Result";
|
|
2
|
+
import { ClientSession, RpcContext } from "@fastcar/rpc";
|
|
3
|
+
import Code from "@/common/Code";
|
|
4
|
+
import { SessionAttribute } from "../types/SessionAttribute";
|
|
5
|
+
|
|
6
|
+
//未登录请求的白名单
|
|
7
|
+
const whiteUrls = ["/remote/login", "/connect", "/disconnect", "/account/login"];
|
|
8
|
+
|
|
9
|
+
//校验登录
|
|
10
|
+
export default async function checkLogin(context: RpcContext & { forward?: boolean; session?: ClientSession }, next?: Function): Promise<void> {
|
|
11
|
+
let url = context.url;
|
|
12
|
+
if (url) {
|
|
13
|
+
if (!whiteUrls.includes(url)) {
|
|
14
|
+
//校验解析中的session
|
|
15
|
+
if (!context.session || !context.session.settings.get(SessionAttribute.logged)) {
|
|
16
|
+
context.body = Result.errorCode(Code.ACCOUNT.NOT_LOGIN);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (next) {
|
|
23
|
+
await next();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//解析session会话
|
|
2
|
+
import { CommonConstant, FastCarApplication } from "@fastcar/core";
|
|
3
|
+
import Code from "@/common/Code";
|
|
4
|
+
import { RpcContext } from "@fastcar/rpc";
|
|
5
|
+
import RouterService from "@/servers/base/service/RouterService";
|
|
6
|
+
import Result from "@/common/Result";
|
|
7
|
+
import { ClientSimpleSession } from "@/types/ClientSimpleSession";
|
|
8
|
+
|
|
9
|
+
export default async function parseSession(context: RpcContext & { forward?: boolean; session?: ClientSimpleSession }, next?: Function) {
|
|
10
|
+
let forward: boolean = !!context.data?.forward;
|
|
11
|
+
|
|
12
|
+
context.forward = forward;
|
|
13
|
+
//进行转义
|
|
14
|
+
let session = context.data?.session;
|
|
15
|
+
|
|
16
|
+
if (session) {
|
|
17
|
+
let app: FastCarApplication = Reflect.get(global, CommonConstant.FastcarApp);
|
|
18
|
+
let routerService = app.getComponentByTarget<RouterService>(RouterService);
|
|
19
|
+
|
|
20
|
+
if (!routerService) {
|
|
21
|
+
return Result.errorCode(Code.SYS.UNAVAILABLE);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//重新拆分赋值
|
|
25
|
+
if (context.data?.data) {
|
|
26
|
+
context.data = context.data?.data;
|
|
27
|
+
}
|
|
28
|
+
context.session = routerService.reqSessionToSession(session);
|
|
29
|
+
} else {
|
|
30
|
+
if (forward) {
|
|
31
|
+
return Result.errorCode(Code.ACCOUNT.NOT_LOGIN);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
context.session = {
|
|
35
|
+
sessionId: context.sessionId,
|
|
36
|
+
connectedTime: context.connectedTime,
|
|
37
|
+
settings: context.settings,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (next) {
|
|
42
|
+
await next();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { ServerKind, ServerMicroservices } from "@/common/Constant";
|
|
2
|
+
import { ServerGroupType } from "@/types/ServerMeta";
|
|
3
|
+
import { SessionAttribute } from "@/types/SessionAttribute";
|
|
4
|
+
import MicroservicesUtils from "@/utils/MicroservicesUtils";
|
|
5
|
+
import { CommonConstant, FastCarApplication } from "@fastcar/core";
|
|
6
|
+
import { ApplicationSetting, Autowired, ComponentScan, ResourcePath } from "@fastcar/core/annotation";
|
|
7
|
+
import ApplicationHook from "@fastcar/core/src/interface/ApplicationHook";
|
|
8
|
+
import { EnableKoa } from "@fastcar/koa/annotation";
|
|
9
|
+
import { RetryConfig, RpcConfig, RpcMetaData, SocketServerConfig } from "@fastcar/rpc";
|
|
10
|
+
import * as path from "path";
|
|
11
|
+
import { EnableRPC } from "@fastcar/rpc/annotation";
|
|
12
|
+
import ServerManager from "../center/service/ServerManager";
|
|
13
|
+
|
|
14
|
+
@ResourcePath(path.join(__dirname, "../../../resource"))
|
|
15
|
+
@ApplicationSetting({
|
|
16
|
+
log: {
|
|
17
|
+
rootPath: path.join(__dirname, "../../../logs"), //将日志移到最外层
|
|
18
|
+
},
|
|
19
|
+
})
|
|
20
|
+
@ComponentScan(path.join(__dirname))
|
|
21
|
+
export default class BaseServer implements ApplicationHook {
|
|
22
|
+
protected serviceId: string;
|
|
23
|
+
protected serviceType: string;
|
|
24
|
+
|
|
25
|
+
@Autowired
|
|
26
|
+
protected app!: FastCarApplication;
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
let l = process.argv.length;
|
|
30
|
+
let args = process.argv.slice(l - 2, l);
|
|
31
|
+
|
|
32
|
+
if (args.length < 2) {
|
|
33
|
+
throw new Error("not found serviceType and serviceId");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this.serviceType = args[0];
|
|
37
|
+
this.serviceId = args[1];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//重载微服务配置 二次解析
|
|
41
|
+
//兼容web应用
|
|
42
|
+
loadSysConfig() {
|
|
43
|
+
this.app.setSetting(SessionAttribute.serviceId, this.serviceId);
|
|
44
|
+
this.app.setSetting(SessionAttribute.serverType, this.serviceType);
|
|
45
|
+
this.app.setSetting(CommonConstant.APPId, this.serviceId);
|
|
46
|
+
|
|
47
|
+
const microservices: ServerGroupType = MicroservicesUtils.format(this.app.getSetting(ServerMicroservices));
|
|
48
|
+
this.app.setSetting(ServerMicroservices, microservices);
|
|
49
|
+
|
|
50
|
+
let list = microservices[this.serviceType] as any;
|
|
51
|
+
let koaConfig = list?.koa || {};
|
|
52
|
+
|
|
53
|
+
//赋值到rpc内 取服务器地址
|
|
54
|
+
let rpc: Partial<RpcConfig> = this.app.getSetting(RpcMetaData.RpcConfig);
|
|
55
|
+
if (!rpc) {
|
|
56
|
+
rpc = {
|
|
57
|
+
list: [],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
for (let item of list.servers) {
|
|
62
|
+
if (item.serviceId == this.serviceId) {
|
|
63
|
+
item.list.forEach((citem: SocketServerConfig, index: number) => {
|
|
64
|
+
if (["http", "https", "http2"].includes(citem.type)) {
|
|
65
|
+
if (!koaConfig.server) {
|
|
66
|
+
koaConfig.server = [];
|
|
67
|
+
}
|
|
68
|
+
koaConfig.server.push(
|
|
69
|
+
Object.assign(citem.server, {
|
|
70
|
+
protocol: citem.type,
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
} else {
|
|
74
|
+
//本质还是rpc服务
|
|
75
|
+
rpc.list?.push({
|
|
76
|
+
id: `${this.serviceId}-${index + 1}`, //这个id仅用作socket服务内部标识
|
|
77
|
+
type: citem.type,
|
|
78
|
+
server: citem.server,
|
|
79
|
+
extra: Object.assign({ front: !!citem.front }, citem.extra || {}),
|
|
80
|
+
serviceType: this.serviceType,
|
|
81
|
+
encode: citem.encode,
|
|
82
|
+
decode: citem.decode,
|
|
83
|
+
codeProtocol: citem.codeProtocol,
|
|
84
|
+
secure: citem.secure,
|
|
85
|
+
maxConnections: citem.maxConnections,
|
|
86
|
+
timeout: citem.timeout,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
rpc.retry = item.retry as Required<RetryConfig>;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!!koaConfig && koaConfig.server && koaConfig?.server.length > 0) {
|
|
96
|
+
this.app.setSetting("koa", koaConfig);
|
|
97
|
+
EnableKoa(BaseServer); //开启web应用
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!!rpc && rpc?.list && rpc?.list?.length > 0) {
|
|
101
|
+
this.app.setSetting(RpcMetaData.RpcConfig, rpc);
|
|
102
|
+
EnableRPC(BaseServer); //开启rpc服务
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
process.nextTick(() => {
|
|
106
|
+
if (this.serviceType == ServerKind.center) {
|
|
107
|
+
let serverManager = this.app.getComponentByTarget(ServerManager) as any;
|
|
108
|
+
serverManager.loadServerList();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
beforeStartServer(): void | Promise<void> {}
|
|
114
|
+
|
|
115
|
+
async beforeStopServer(): Promise<void> {}
|
|
116
|
+
|
|
117
|
+
async startServer(): Promise<void> {}
|
|
118
|
+
|
|
119
|
+
stopServer(): void {}
|
|
120
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Autowired, Controller } from "@fastcar/core/annotation";
|
|
2
|
+
import { RPC, RPCMethod } from "@fastcar/rpc/annotation";
|
|
3
|
+
import BackSessionService from "../service/BackSessionService";
|
|
4
|
+
import Result from "@/common/Result";
|
|
5
|
+
import { SessionAttribute } from "@/types/SessionAttribute";
|
|
6
|
+
import RouterService from "../service/RouterService";
|
|
7
|
+
import { ReqSession } from "@/types/ReqSession";
|
|
8
|
+
|
|
9
|
+
@Controller
|
|
10
|
+
@RPC("/backSession")
|
|
11
|
+
export default class BackSessionEntryController {
|
|
12
|
+
@Autowired
|
|
13
|
+
private backSessionService!: BackSessionService;
|
|
14
|
+
|
|
15
|
+
@Autowired
|
|
16
|
+
private routerService!: RouterService;
|
|
17
|
+
|
|
18
|
+
@RPCMethod()
|
|
19
|
+
join({ session }: { session: ReqSession }) {
|
|
20
|
+
this.backSessionService.join(this.routerService.reqSessionToSession(session));
|
|
21
|
+
|
|
22
|
+
return Result.ok();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@RPCMethod()
|
|
26
|
+
leave({ session }: { session: ReqSession }) {
|
|
27
|
+
let clientSession = this.routerService.reqSessionToSession(session);
|
|
28
|
+
let uid = clientSession.settings.get(SessionAttribute.uid);
|
|
29
|
+
this.backSessionService.remove(uid);
|
|
30
|
+
|
|
31
|
+
return Result.ok();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Autowired, Controller, Rule, ValidForm } from "@fastcar/core/annotation";
|
|
2
|
+
import { RpcContext, RpcServer } from "@fastcar/rpc";
|
|
3
|
+
import { RPC, RPCMethod } from "@fastcar/rpc/annotation";
|
|
4
|
+
import DataService from "@/servers/base/service/DataService";
|
|
5
|
+
import Result from "@/common/Result";
|
|
6
|
+
import Code from "@/common/Code";
|
|
7
|
+
import { SessionAttribute } from "@/types/SessionAttribute";
|
|
8
|
+
import ServerManager from "@/servers/center/service/ServerManager";
|
|
9
|
+
|
|
10
|
+
//内部服务公用的接口
|
|
11
|
+
@Controller
|
|
12
|
+
@RPC("/remote")
|
|
13
|
+
export default class EntryController {
|
|
14
|
+
@Autowired
|
|
15
|
+
private rpcServer!: RpcServer;
|
|
16
|
+
|
|
17
|
+
@Autowired
|
|
18
|
+
private dataService!: DataService;
|
|
19
|
+
|
|
20
|
+
@Autowired
|
|
21
|
+
private serverManager!: ServerManager;
|
|
22
|
+
|
|
23
|
+
@RPCMethod()
|
|
24
|
+
@ValidForm
|
|
25
|
+
async login(
|
|
26
|
+
@Rule({
|
|
27
|
+
serviceId: { required: true },
|
|
28
|
+
token: { required: true },
|
|
29
|
+
})
|
|
30
|
+
{ serviceId, token }: { serviceId: string; token: string },
|
|
31
|
+
ctx: RpcContext
|
|
32
|
+
) {
|
|
33
|
+
//进行校验是否相同
|
|
34
|
+
let serverMeta = this.dataService.getServerMeta(serviceId);
|
|
35
|
+
if (!serverMeta) {
|
|
36
|
+
return Result.errorCode(Code.CENTER.SERVER_NOT_FOUND);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (serverMeta.token != token) {
|
|
40
|
+
return Result.errorCode(Code.CENTER.SERVER_TOKEN_ERROR);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let serverKind = this.dataService.getServerKindByServerType(serverMeta.serverType);
|
|
44
|
+
|
|
45
|
+
//加入频道 绑定会话
|
|
46
|
+
this.rpcServer.getSocketManager().joinChannel(ctx.sessionId, this.dataService.getChannelKindByServerType(serverMeta.serverType));
|
|
47
|
+
ctx.settings.set(SessionAttribute.logged, true);
|
|
48
|
+
ctx.settings.set(SessionAttribute.serviceId, serviceId);
|
|
49
|
+
ctx.settings.set(SessionAttribute.serverKind, serverKind);
|
|
50
|
+
ctx.settings.set(SessionAttribute.serverType, serverMeta.serverType);
|
|
51
|
+
|
|
52
|
+
//便于客户端同步
|
|
53
|
+
return Result.ok();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@RPCMethod()
|
|
57
|
+
@ValidForm
|
|
58
|
+
async health({}, ctx: RpcContext) {
|
|
59
|
+
let logged = ctx.settings.get(SessionAttribute.logged);
|
|
60
|
+
if (logged) {
|
|
61
|
+
let serviceId = ctx.settings.get(SessionAttribute.serviceId);
|
|
62
|
+
if (!this.serverManager.updateServiceUpdateTime(serviceId)) {
|
|
63
|
+
// this.rpcServer.kickSessionId(ctx.sessionId, "status is error");
|
|
64
|
+
return Result.errorCode(Code.SYS.NOACCESS);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return Result.ok();
|
|
69
|
+
}
|
|
70
|
+
}
|