@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,185 @@
|
|
|
1
|
+
import { ReqSession } from "@/types/ReqSession";
|
|
2
|
+
import { Autowired, HotterCallBack, Log, Service } from "@fastcar/core/annotation";
|
|
3
|
+
import { ClientRequestStatic, ClientSession, RetryConfig } from "@fastcar/rpc";
|
|
4
|
+
import Result from "@/common/Result";
|
|
5
|
+
import Code from "@/common/Code";
|
|
6
|
+
import { ValidationUtil } from "@fastcar/core/utils";
|
|
7
|
+
import CenterClient from "@/servers/base/service/CenterClient";
|
|
8
|
+
import { ResultType } from "@/types/ResultType";
|
|
9
|
+
import { Logger } from "@fastcar/core";
|
|
10
|
+
import { nanoid } from "nanoid";
|
|
11
|
+
import { SessionAttribute } from "@/types/SessionAttribute";
|
|
12
|
+
import { ClientSimpleSession } from "@/types/ClientSimpleSession";
|
|
13
|
+
import CODE from "@/common/Code";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @version 1.0 路由导航
|
|
17
|
+
*/
|
|
18
|
+
@HotterCallBack("loadRouteNav")
|
|
19
|
+
@Service
|
|
20
|
+
export default class RouterService {
|
|
21
|
+
@Autowired
|
|
22
|
+
private client!: CenterClient;
|
|
23
|
+
|
|
24
|
+
@Log()
|
|
25
|
+
private logger!: Logger;
|
|
26
|
+
|
|
27
|
+
public routeNavigation: Record<string, (serverType: string, session: ClientSession) => string> = this.getRouteNav();
|
|
28
|
+
|
|
29
|
+
loadRouteNav() {
|
|
30
|
+
this.logger.debug(`加载导航路由`);
|
|
31
|
+
this.routeNavigation = this.getRouteNav();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//根据uid一致性找servers
|
|
35
|
+
getServerByUid(serverType: string, session: ClientSession) {
|
|
36
|
+
let uid: number = session.settings.get(SessionAttribute.uid);
|
|
37
|
+
if (!uid) {
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let m = this.client.getServerMap();
|
|
42
|
+
let list = m.findByAtts({ serverType }).sort((a, b) => {
|
|
43
|
+
return a.serviceId < b.serviceId ? -1 : 1;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (list.length == 0) {
|
|
47
|
+
return "";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return list[uid % list.length]?.serviceId;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getRouteNav() {
|
|
54
|
+
return {
|
|
55
|
+
common: (serverType: string) => {
|
|
56
|
+
let m = this.client.getServerMap();
|
|
57
|
+
let list = m.findByAtts({ serverType, status: true });
|
|
58
|
+
|
|
59
|
+
if (list.length == 0) {
|
|
60
|
+
return "";
|
|
61
|
+
}
|
|
62
|
+
if (list.length == 1) {
|
|
63
|
+
return list[0].serviceId;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let index = Math.floor(Math.random() * list.length);
|
|
67
|
+
|
|
68
|
+
return list[index].serviceId || "";
|
|
69
|
+
},
|
|
70
|
+
connector: (serverType: string, session: ClientSimpleSession) => {
|
|
71
|
+
return session.settings.get(SessionAttribute.serviceId);
|
|
72
|
+
},
|
|
73
|
+
user: (serverType: string, session: ClientSession) => {
|
|
74
|
+
let uid: number = session.settings.get(SessionAttribute.uid);
|
|
75
|
+
if (!uid) {
|
|
76
|
+
return "";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let m = this.client.getServerMap();
|
|
80
|
+
let list = m.findByAtts({ serverType }).sort((a, b) => {
|
|
81
|
+
return a.serviceId < b.serviceId ? -1 : 1;
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
if (list.length == 0) {
|
|
85
|
+
return "";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return list[uid % list.length]?.serviceId;
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @version 1.0 采用懒加载模式 当客户端连接没有时自动创建连接
|
|
95
|
+
*/
|
|
96
|
+
async request<T, K>({
|
|
97
|
+
forward = false,
|
|
98
|
+
serverType,
|
|
99
|
+
session,
|
|
100
|
+
data,
|
|
101
|
+
url,
|
|
102
|
+
opts,
|
|
103
|
+
customServiceId,
|
|
104
|
+
}: {
|
|
105
|
+
url: string;
|
|
106
|
+
data?: T;
|
|
107
|
+
opts?: RetryConfig;
|
|
108
|
+
session?: ClientSimpleSession;
|
|
109
|
+
serverType: string;
|
|
110
|
+
forward?: boolean;
|
|
111
|
+
customServiceId?: string;
|
|
112
|
+
//指定一个serviceID
|
|
113
|
+
}): Promise<ResultType<K>> {
|
|
114
|
+
//计算类型
|
|
115
|
+
let fn = Reflect.get(this.routeNavigation, serverType);
|
|
116
|
+
if (!fn) {
|
|
117
|
+
fn = this.routeNavigation.common;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!session) {
|
|
121
|
+
session = {
|
|
122
|
+
sessionId: nanoid(),
|
|
123
|
+
connectedTime: Date.now(),
|
|
124
|
+
settings: new Map(),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
let serviceId = customServiceId || (await Promise.resolve(Reflect.apply(fn, this, [serverType, session])));
|
|
129
|
+
if (!serviceId) {
|
|
130
|
+
return Result.errorCode(Code.SYS.UNAVAILABLE);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//找client
|
|
134
|
+
let rpcClient = await this.client.getRemoteClientByserviceId(serviceId);
|
|
135
|
+
if (!rpcClient) {
|
|
136
|
+
this.logger.info(`${serviceId} service unavailable cid:${customServiceId} serverType:${serverType} forward:${forward} url:${url}`);
|
|
137
|
+
return Result.errorCode(Code.SYS.UNAVAILABLE);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
let sendData: any = {
|
|
141
|
+
session: this.sessionTOReqSession(session),
|
|
142
|
+
forward,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
if (ValidationUtil.isNotNull(data)) {
|
|
146
|
+
Reflect.set(sendData, "data", data);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
//应该是存在code响应码
|
|
150
|
+
let res: ResultType<K> | null = await ClientRequestStatic({
|
|
151
|
+
client: rpcClient,
|
|
152
|
+
url,
|
|
153
|
+
data: sendData,
|
|
154
|
+
opts,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (!res) {
|
|
158
|
+
return Result.errorCode(CODE.SYS.FAIL);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return res;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
sessionTOReqSession(session: ClientSimpleSession): ReqSession {
|
|
165
|
+
let s: ReqSession = {
|
|
166
|
+
sessionId: session.sessionId,
|
|
167
|
+
connectedTime: session.connectedTime,
|
|
168
|
+
settings: Object.fromEntries(session.settings.entries()),
|
|
169
|
+
cid: session.cid,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
return s;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
reqSessionToSession(session: ReqSession): ClientSimpleSession {
|
|
176
|
+
let s: ClientSimpleSession = {
|
|
177
|
+
sessionId: session.sessionId,
|
|
178
|
+
connectedTime: session.connectedTime,
|
|
179
|
+
settings: new Map(Object.entries(session.settings)),
|
|
180
|
+
cid: session.cid,
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
return s;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Application } from "@fastcar/core/annotation";
|
|
2
|
+
import BaseServer from "../base/BaseServer";
|
|
3
|
+
import { RPCMiddleware } from "@fastcar/rpc/annotation";
|
|
4
|
+
import parseSession from "@/middleware/parseSession";
|
|
5
|
+
import checkForm from "@/middleware/checkForm";
|
|
6
|
+
|
|
7
|
+
@Application
|
|
8
|
+
@RPCMiddleware(checkForm, parseSession)
|
|
9
|
+
class APP extends BaseServer {
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export default new APP();
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Autowired, Controller, Log, Rule, ValidForm } from "@fastcar/core/annotation";
|
|
2
|
+
import { ClientSession, RpcContext, RpcServer } from "@fastcar/rpc";
|
|
3
|
+
import { 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 ServerManager from "../service/ServerManager";
|
|
8
|
+
import { SessionAttribute } from "@/types/SessionAttribute";
|
|
9
|
+
import { ValidationUtil } from "@fastcar/core/utils";
|
|
10
|
+
import { ServerKind } from "@/common/Constant";
|
|
11
|
+
import { Logger } from "@fastcar/core";
|
|
12
|
+
|
|
13
|
+
type DisconnectType = {
|
|
14
|
+
session: ClientSession;
|
|
15
|
+
reason: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
@Controller
|
|
19
|
+
export default class EntryController {
|
|
20
|
+
@Autowired
|
|
21
|
+
private rpcServer!: RpcServer;
|
|
22
|
+
|
|
23
|
+
@Autowired
|
|
24
|
+
private dataService!: DataService;
|
|
25
|
+
|
|
26
|
+
@Autowired
|
|
27
|
+
private serverManager!: ServerManager;
|
|
28
|
+
|
|
29
|
+
@Log()
|
|
30
|
+
private logger!: Logger;
|
|
31
|
+
|
|
32
|
+
@RPCMethod()
|
|
33
|
+
@ValidForm
|
|
34
|
+
async login(
|
|
35
|
+
@Rule({
|
|
36
|
+
serviceId: { required: true },
|
|
37
|
+
token: { required: true },
|
|
38
|
+
})
|
|
39
|
+
{ serviceId, token }: { serviceId: string; token: string },
|
|
40
|
+
ctx: RpcContext
|
|
41
|
+
) {
|
|
42
|
+
//进行校验是否相同
|
|
43
|
+
let serverMeta = this.dataService.getServerMeta(serviceId);
|
|
44
|
+
if (!serverMeta) {
|
|
45
|
+
return Result.errorCode(Code.CENTER.SERVER_NOT_FOUND);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (serverMeta.token != token) {
|
|
49
|
+
return Result.errorCode(Code.CENTER.SERVER_TOKEN_ERROR);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let serverKind = this.dataService.getServerKindByServerType(serverMeta.serverType);
|
|
53
|
+
this.serverManager.registrationService(serviceId, serverMeta.serverType);
|
|
54
|
+
|
|
55
|
+
//加入频道 绑定会话
|
|
56
|
+
this.rpcServer.getSocketManager().joinChannel(ctx.sessionId, this.dataService.getChannelKindByServerType(serverMeta.serverType));
|
|
57
|
+
if (serviceId != this.dataService.getCurrServiceId()) {
|
|
58
|
+
this.rpcServer.getSocketManager().bindCustomID(serviceId, ctx.sessionId);
|
|
59
|
+
this.rpcServer.getSocketManager().joinChannelByCustomId(serviceId, ServerKind.remote);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
ctx.settings.set(SessionAttribute.logged, true);
|
|
63
|
+
ctx.settings.set(SessionAttribute.serviceId, serviceId);
|
|
64
|
+
ctx.settings.set(SessionAttribute.center_serviceId, serviceId);
|
|
65
|
+
ctx.settings.set(SessionAttribute.serverKind, serverKind);
|
|
66
|
+
ctx.settings.set(SessionAttribute.serverType, serverMeta.serverType);
|
|
67
|
+
|
|
68
|
+
return Result.ok({ serverList: this.serverManager.getServerList() });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@RPCMethod()
|
|
72
|
+
disconnect({ session, reason }: DisconnectType, ctx: RpcContext) {
|
|
73
|
+
let serviceId = ctx.settings.get(SessionAttribute.center_serviceId);
|
|
74
|
+
if (!serviceId) {
|
|
75
|
+
return Result.ok();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let serverType = ctx.settings.get(SessionAttribute.serverType);
|
|
79
|
+
if (ValidationUtil.isNull(serviceId)) {
|
|
80
|
+
return Result.errorCode(Code.CENTER.SERVER_NOT_LOGIN);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.rpcServer.getSocketManager().leaveChannel(session.sessionId, this.dataService.getChannelKindByServerType(serverType));
|
|
84
|
+
this.logger.info(`disconnect---------${serviceId}`);
|
|
85
|
+
this.serverManager.removeService(serviceId);
|
|
86
|
+
|
|
87
|
+
return Result.ok();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import AuthServiceRole from "@/annotation/AuthServiceRole";
|
|
2
|
+
import { ChannelKind, ServerCommonUrl, ServerKind } from "@/common/Constant";
|
|
3
|
+
import Result from "@/common/Result";
|
|
4
|
+
import { Autowired, Controller, Log, Rule, ValidForm } from "@fastcar/core/annotation";
|
|
5
|
+
import { RPC, RPCMethod } from "@fastcar/rpc/annotation";
|
|
6
|
+
import ServerManager from "../service/ServerManager";
|
|
7
|
+
import { InteractiveMode, RpcServer } from "@fastcar/rpc";
|
|
8
|
+
import { Logger } from "@fastcar/core";
|
|
9
|
+
|
|
10
|
+
@Controller
|
|
11
|
+
@RPC("/center")
|
|
12
|
+
@AuthServiceRole(ServerKind.center, ServerKind.remote)
|
|
13
|
+
export default class ServerController {
|
|
14
|
+
@Autowired
|
|
15
|
+
private serverManager!: ServerManager;
|
|
16
|
+
|
|
17
|
+
@Autowired
|
|
18
|
+
private rpcServer!: RpcServer;
|
|
19
|
+
|
|
20
|
+
@Log()
|
|
21
|
+
private logger!: Logger;
|
|
22
|
+
|
|
23
|
+
@RPCMethod()
|
|
24
|
+
getServerList() {
|
|
25
|
+
return Result.ok(this.serverManager.getServerList());
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@RPCMethod()
|
|
29
|
+
rebalance() {
|
|
30
|
+
this.rpcServer.getSocketManager().sendMsgByChannel(ChannelKind.REMOTE, {
|
|
31
|
+
url: ServerCommonUrl.ServiceBalance,
|
|
32
|
+
mode: InteractiveMode.notify,
|
|
33
|
+
});
|
|
34
|
+
return Result.ok();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@RPCMethod()
|
|
38
|
+
@ValidForm
|
|
39
|
+
syncConfig(
|
|
40
|
+
@Rule({
|
|
41
|
+
key: { required: true },
|
|
42
|
+
data: {
|
|
43
|
+
required: true,
|
|
44
|
+
type: "array",
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
info: {
|
|
48
|
+
key: string;
|
|
49
|
+
data: Object;
|
|
50
|
+
}
|
|
51
|
+
) {
|
|
52
|
+
//如果有多个中心服务器 应该去通知其他中心服务对应的参数
|
|
53
|
+
this.logger.info(`同步配置-------------`);
|
|
54
|
+
this.rpcServer.getSocketManager().sendMsgToCustomIdByChannel(ServerKind.remote, {
|
|
55
|
+
url: ServerCommonUrl.ServiceSyncConfig,
|
|
56
|
+
mode: InteractiveMode.notify,
|
|
57
|
+
data: info,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return Result.ok();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import ConnectorUtils from "@/utils/ConnectorUtils";
|
|
2
|
+
import Code from "@/common/Code";
|
|
3
|
+
import { ChannelKind, ServerCommonUrl, ServerKind } from "@/common/Constant";
|
|
4
|
+
import DataService from "@/servers/base/service/DataService";
|
|
5
|
+
import { ServerStatus } from "@/types/ServerMeta";
|
|
6
|
+
import { SessionAttribute } from "@/types/SessionAttribute";
|
|
7
|
+
import { DataMap, Logger, FastCarApplication } from "@fastcar/core";
|
|
8
|
+
import { Autowired, Log, Service, Value } from "@fastcar/core/annotation";
|
|
9
|
+
import { ClientRequestStatic, InteractiveMode, RpcAsyncService, RpcClient, RpcServer } from "@fastcar/rpc";
|
|
10
|
+
import { EnableScheduling, ScheduledInterval, TimeUnit, TimeUnitNum } from "@fastcar/timer";
|
|
11
|
+
|
|
12
|
+
@Service
|
|
13
|
+
@EnableScheduling
|
|
14
|
+
export default class ServerManager implements RpcAsyncService {
|
|
15
|
+
private serverMap: DataMap<string, ServerStatus>;
|
|
16
|
+
|
|
17
|
+
@Autowired
|
|
18
|
+
private dataService!: DataService;
|
|
19
|
+
|
|
20
|
+
@Autowired
|
|
21
|
+
private rpcServer!: RpcServer;
|
|
22
|
+
|
|
23
|
+
@Log()
|
|
24
|
+
private logger!: Logger;
|
|
25
|
+
|
|
26
|
+
private centerClientMap: DataMap<string, RpcClient>;
|
|
27
|
+
|
|
28
|
+
@Autowired
|
|
29
|
+
private app!: FastCarApplication;
|
|
30
|
+
|
|
31
|
+
@Value("application.env")
|
|
32
|
+
env!: string;
|
|
33
|
+
|
|
34
|
+
constructor() {
|
|
35
|
+
this.serverMap = new DataMap();
|
|
36
|
+
this.centerClientMap = new DataMap();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
loadServerList() {
|
|
40
|
+
let obj = this.dataService.getMicroservices();
|
|
41
|
+
let existServerIds: string[] = [];
|
|
42
|
+
let change = false;
|
|
43
|
+
|
|
44
|
+
for (let serverType of Object.keys(obj)) {
|
|
45
|
+
let item = obj[serverType];
|
|
46
|
+
item.servers.forEach((citem) => {
|
|
47
|
+
existServerIds.push(citem.serviceId);
|
|
48
|
+
if (!this.serverMap.has(citem.serviceId)) {
|
|
49
|
+
change = true;
|
|
50
|
+
this.serverMap.set(citem.serviceId, {
|
|
51
|
+
serviceId: citem.serviceId,
|
|
52
|
+
status: false,
|
|
53
|
+
createTime: Date.now(),
|
|
54
|
+
updateTime: Date.now(),
|
|
55
|
+
serverType,
|
|
56
|
+
centerId: "",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
//刷新服务列表
|
|
63
|
+
let ids = [...this.serverMap.keys()];
|
|
64
|
+
for (let id of ids) {
|
|
65
|
+
if (!existServerIds.includes(id)) {
|
|
66
|
+
this.serverMap.delete(id);
|
|
67
|
+
change = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//广播全局
|
|
72
|
+
if (change) {
|
|
73
|
+
this.logger.debug(this.getServerList());
|
|
74
|
+
this.rpcServer.getSocketManager().sendMsgByChannel(ChannelKind.REMOTE, {
|
|
75
|
+
url: ServerCommonUrl.ServiceStatusAllNotify,
|
|
76
|
+
data: this.getServerList(),
|
|
77
|
+
mode: InteractiveMode.notify,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
//注册服务
|
|
83
|
+
registrationService(serviceId: string, serverType: string): ServerStatus {
|
|
84
|
+
this.logger.info(`${serviceId} Service Registration`);
|
|
85
|
+
|
|
86
|
+
let centerId = this.dataService.getCurrServiceId();
|
|
87
|
+
|
|
88
|
+
let serverStatus: ServerStatus = { serviceId, status: true, createTime: Date.now(), updateTime: Date.now(), serverType, centerId };
|
|
89
|
+
this.updateServerStatus(serverStatus);
|
|
90
|
+
this.broadcastUpdateService(serviceId);
|
|
91
|
+
return serverStatus;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//更新服务
|
|
95
|
+
updateServiceUpdateTime(serviceId: string) {
|
|
96
|
+
let item = this.serverMap.get(serviceId);
|
|
97
|
+
if (item) {
|
|
98
|
+
item.updateTime = Date.now();
|
|
99
|
+
if (item.status) {
|
|
100
|
+
//重新登录
|
|
101
|
+
return true;
|
|
102
|
+
} else {
|
|
103
|
+
this.logger.debug(`service status is error ${serviceId}`);
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
this.logger.debug(`service not found ${serviceId}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
//移除服务
|
|
113
|
+
removeService(serviceId: string): boolean {
|
|
114
|
+
let item = this.serverMap.get(serviceId);
|
|
115
|
+
|
|
116
|
+
if (!item) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
this.logger.debug(`${serviceId} Service Remove`);
|
|
121
|
+
item.status = false;
|
|
122
|
+
item.createTime = Date.now();
|
|
123
|
+
this.updateServerStatus(item);
|
|
124
|
+
|
|
125
|
+
//如果是中心服务则找出挂载在这个上面的服务
|
|
126
|
+
let kind = this.dataService.getServerKindByServerType(item.serverType);
|
|
127
|
+
if (kind == ServerKind.center) {
|
|
128
|
+
let statusList = this.serverMap.findByAtts({ centerId: serviceId });
|
|
129
|
+
statusList.forEach((citem: ServerStatus) => {
|
|
130
|
+
if (citem.serverType.toLowerCase() == ServerKind.center) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// this.logger.debug(`${citem.serviceId} Service Remove`);
|
|
135
|
+
citem.status = false;
|
|
136
|
+
this.updateServerStatus(citem);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
this.rpcServer.getSocketManager().sendMsgByChannel(ChannelKind.REMOTE, {
|
|
140
|
+
url: ServerCommonUrl.ServiceStatusAllNotify,
|
|
141
|
+
data: this.getServerList(),
|
|
142
|
+
mode: InteractiveMode.notify,
|
|
143
|
+
});
|
|
144
|
+
} else {
|
|
145
|
+
this.broadcastUpdateService(serviceId);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
//增量通知客户端
|
|
152
|
+
broadcastUpdateService(serviceId: string) {
|
|
153
|
+
let status = this.serverMap.get(serviceId);
|
|
154
|
+
|
|
155
|
+
if (status) {
|
|
156
|
+
this.rpcServer.getSocketManager().sendMsgByChannel(ChannelKind.REMOTE, {
|
|
157
|
+
url: ServerCommonUrl.ServiceStatusNotify,
|
|
158
|
+
data: status,
|
|
159
|
+
mode: InteractiveMode.notify,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
let kind = this.dataService.getServerKindByServerType(status.serverType);
|
|
163
|
+
if (kind == ServerKind.remote) {
|
|
164
|
+
this.rpcServer.getSocketManager().sendMsgByChannel(ChannelKind.CENTER, {
|
|
165
|
+
url: ServerCommonUrl.ServiceStatusNotify,
|
|
166
|
+
data: status,
|
|
167
|
+
mode: InteractiveMode.notify,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
getServerList() {
|
|
174
|
+
return this.serverMap.toValues().sort(); //字典排序
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
//这边有个定时任务检测中心服务是否
|
|
178
|
+
//1.找所有的中心服务器 并进行互连
|
|
179
|
+
//2.逐一进行登录 并将服务列表进行比对汇总
|
|
180
|
+
@ScheduledInterval({ fixedRate: 5, fixedRateString: TimeUnit.second, initialDelay: 500 })
|
|
181
|
+
async checkOtherCenter() {
|
|
182
|
+
let centerInfo = this.dataService.getServerGroup(ServerKind.center);
|
|
183
|
+
let serviceId = this.app.getSetting(SessionAttribute.serviceId);
|
|
184
|
+
let flag = false;
|
|
185
|
+
|
|
186
|
+
for (let server of centerInfo.servers) {
|
|
187
|
+
if (server.serviceId == serviceId) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
let client = this.centerClientMap.get(server.serviceId);
|
|
192
|
+
if (!client || !client.isConnect()) {
|
|
193
|
+
//先关掉前一个
|
|
194
|
+
if (client) {
|
|
195
|
+
client.close();
|
|
196
|
+
this.centerClientMap.delete(server.serviceId);
|
|
197
|
+
}
|
|
198
|
+
this.logger.debug("开始检测登录");
|
|
199
|
+
for (let citem of server.list) {
|
|
200
|
+
client = new RpcClient(
|
|
201
|
+
{
|
|
202
|
+
url: ConnectorUtils.getConnectUrl(citem, server.host), //连接地址
|
|
203
|
+
type: citem.type, //具体为哪一种型号的连接器
|
|
204
|
+
extra: citem.clientExtra, //第三方拓展参数
|
|
205
|
+
encode: citem.encode, //解码器
|
|
206
|
+
decode: citem.decode,
|
|
207
|
+
secure: citem.secure,
|
|
208
|
+
ssl: citem.server.ssl,
|
|
209
|
+
disconnectInterval: citem.disconnectInterval,
|
|
210
|
+
connectionLimit: citem.connectionLimit || 1,
|
|
211
|
+
},
|
|
212
|
+
this,
|
|
213
|
+
citem.retry
|
|
214
|
+
);
|
|
215
|
+
await client.start();
|
|
216
|
+
if (client.isConnect()) {
|
|
217
|
+
this.centerClientMap.set(server.serviceId, client);
|
|
218
|
+
let loginFlag = await this.loginOtherCenter(server.serviceId);
|
|
219
|
+
if (!flag && loginFlag) {
|
|
220
|
+
flag = true;
|
|
221
|
+
}
|
|
222
|
+
this.logger.debug("校验完毕");
|
|
223
|
+
break;
|
|
224
|
+
} else {
|
|
225
|
+
client.close();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (!this.centerClientMap.has(server.serviceId)) {
|
|
231
|
+
this.logger.error(`${server.serviceId} connection lost`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (flag) {
|
|
236
|
+
//全局消息广播
|
|
237
|
+
this.rpcServer.getSocketManager().sendMsgByChannel(ChannelKind.REMOTE, {
|
|
238
|
+
url: ServerCommonUrl.ServiceStatusAllNotify,
|
|
239
|
+
data: this.getServerList(),
|
|
240
|
+
mode: InteractiveMode.notify,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
//定时检测健康状态
|
|
246
|
+
@ScheduledInterval({ fixedRate: 1, fixedRateString: TimeUnit.minute, initialDelay: 500 })
|
|
247
|
+
checkHealth() {
|
|
248
|
+
let list = this.serverMap.toValues();
|
|
249
|
+
let nowTime = Date.now();
|
|
250
|
+
|
|
251
|
+
list.forEach((item) => {
|
|
252
|
+
if (item.centerId == this.dataService.getCurrServiceId()) {
|
|
253
|
+
//检测更新时间
|
|
254
|
+
if (nowTime - item.updateTime > TimeUnitNum.minute * 5 && item.status) {
|
|
255
|
+
this.logger.info(`removeService------------${item.serviceId}`);
|
|
256
|
+
this.removeService(item.serviceId);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async loginOtherCenter(serviceId: string) {
|
|
263
|
+
let client = this.centerClientMap.get(serviceId);
|
|
264
|
+
|
|
265
|
+
if (client) {
|
|
266
|
+
let centerInfo = this.dataService.getServerGroup(ServerKind.center);
|
|
267
|
+
|
|
268
|
+
let res = await ClientRequestStatic<{ serviceId: string; token: string }, { code: number; data: { serverList: ServerStatus[] } }>({
|
|
269
|
+
url: "/login",
|
|
270
|
+
data: {
|
|
271
|
+
serviceId: this.app.getSetting(SessionAttribute.serviceId),
|
|
272
|
+
token: centerInfo.token,
|
|
273
|
+
},
|
|
274
|
+
client,
|
|
275
|
+
// opts: {
|
|
276
|
+
// timeout: 1000,
|
|
277
|
+
// retryCount: 1,
|
|
278
|
+
// },
|
|
279
|
+
});
|
|
280
|
+
if (!res || res.code != Code.SYS.OK) {
|
|
281
|
+
this.logger.error(`login center error`);
|
|
282
|
+
client.close();
|
|
283
|
+
} else {
|
|
284
|
+
//同步list
|
|
285
|
+
let updateFlagNotify: boolean = false;
|
|
286
|
+
res.data.serverList.forEach((s) => {
|
|
287
|
+
let f = this.updateServerStatus(s);
|
|
288
|
+
if (!updateFlagNotify && f) {
|
|
289
|
+
updateFlagNotify = true;
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
return updateFlagNotify;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
updateServerStatus(s: ServerStatus): boolean {
|
|
301
|
+
let flag: boolean = false;
|
|
302
|
+
let serviceId = s.serviceId;
|
|
303
|
+
let beforeStatus = this.serverMap.get(serviceId);
|
|
304
|
+
|
|
305
|
+
if (!beforeStatus) {
|
|
306
|
+
this.serverMap.set(serviceId, s);
|
|
307
|
+
flag = true;
|
|
308
|
+
} else {
|
|
309
|
+
if (s.createTime > beforeStatus.createTime) {
|
|
310
|
+
this.serverMap.set(serviceId, s);
|
|
311
|
+
flag = true;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return flag;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
async handleMsg(url: string, data: Object): Promise<void | Object> {
|
|
319
|
+
switch (url) {
|
|
320
|
+
case ServerCommonUrl.ServiceStatusNotify: {
|
|
321
|
+
let m = data as ServerStatus;
|
|
322
|
+
if (this.updateServerStatus(m)) {
|
|
323
|
+
this.rpcServer.getSocketManager().sendMsgByChannel(ChannelKind.REMOTE, {
|
|
324
|
+
url: ServerCommonUrl.ServiceStatusNotify,
|
|
325
|
+
data: m,
|
|
326
|
+
mode: InteractiveMode.notify,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
default: {
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|