@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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/package.json +35 -0
  4. package/template/.prettierrc +9 -0
  5. package/template/.vscode/launch.json +183 -0
  6. package/template/README.md +1 -0
  7. package/template/package.json +47 -0
  8. package/template/resource/application-dev.yml +56 -0
  9. package/template/resource/application.yml +2 -0
  10. package/template/src/annotation/AuthServiceRole.ts +76 -0
  11. package/template/src/annotation/EnableHotConfig.ts +13 -0
  12. package/template/src/app-node.ts +94 -0
  13. package/template/src/app-pm2.ts +191 -0
  14. package/template/src/common/Code.ts +26 -0
  15. package/template/src/common/Constant.ts +28 -0
  16. package/template/src/common/Result.ts +40 -0
  17. package/template/src/common/TaskAsync.ts +17 -0
  18. package/template/src/hotconfig/ExampleConfigService.ts +29 -0
  19. package/template/src/hotconfig/HotConfigInterface.ts +43 -0
  20. package/template/src/middleware/checkForm.ts +20 -0
  21. package/template/src/middleware/checkLogin.ts +25 -0
  22. package/template/src/middleware/parseSession.ts +44 -0
  23. package/template/src/servers/base/BaseServer.ts +120 -0
  24. package/template/src/servers/base/common/BackSessionEntryController.ts +33 -0
  25. package/template/src/servers/base/common/RemoteController.ts +70 -0
  26. package/template/src/servers/base/service/BackSessionService.ts +97 -0
  27. package/template/src/servers/base/service/CenterClient.ts +457 -0
  28. package/template/src/servers/base/service/DataService.ts +85 -0
  29. package/template/src/servers/base/service/RouterService.ts +185 -0
  30. package/template/src/servers/center/app.ts +14 -0
  31. package/template/src/servers/center/controller/EntryController.ts +89 -0
  32. package/template/src/servers/center/controller/ServerController.ts +62 -0
  33. package/template/src/servers/center/service/ServerManager.ts +336 -0
  34. package/template/src/servers/chat/RoomHandler.ts +65 -0
  35. package/template/src/servers/chat/RoomService.ts +24 -0
  36. package/template/src/servers/chat/app.ts +11 -0
  37. package/template/src/servers/connector/app.ts +13 -0
  38. package/template/src/servers/connector/controller/AccountHandler.ts +80 -0
  39. package/template/src/servers/connector/controller/ChannelRemote.ts +63 -0
  40. package/template/src/servers/connector/middleware/forwardMsg.ts +54 -0
  41. package/template/src/servers/web/HelloController.ts +51 -0
  42. package/template/src/servers/web/SyncConfigService.ts +13 -0
  43. package/template/src/servers/web/app.ts +15 -0
  44. package/template/src/types/ClientSimpleSession.ts +3 -0
  45. package/template/src/types/ForwardRpcContext.ts +3 -0
  46. package/template/src/types/ReqSession.ts +8 -0
  47. package/template/src/types/ResultType.ts +5 -0
  48. package/template/src/types/ServerMeta.ts +48 -0
  49. package/template/src/types/SessionAttribute.ts +13 -0
  50. package/template/src/utils/ConnectorUtils.ts +25 -0
  51. package/template/src/utils/MicroservicesUtils.ts +101 -0
  52. package/template/src/utils/NetWork.ts +31 -0
  53. package/template/src/utils/SessionUtil.ts +46 -0
  54. package/template/test/connector-test.ts +64 -0
  55. package/template/test/hello.ts +71 -0
  56. package/template/tsconfig.json +39 -0
@@ -0,0 +1,97 @@
1
+ import { DataMap, Logger } from "@fastcar/core";
2
+ import { Autowired, Log, Service } from "@fastcar/core/annotation";
3
+ import { InteractiveMode } from "@fastcar/rpc";
4
+ import CenterClient from "./CenterClient";
5
+ import RouterService from "./RouterService";
6
+ import { SessionAttribute } from "@/types/SessionAttribute";
7
+ import SessionUtil from "@/utils/SessionUtil";
8
+ import { ClientSimpleSession } from "@/types/ClientSimpleSession";
9
+
10
+ @Service
11
+ export default class BackSessionService {
12
+ private sidMap: DataMap<number, ClientSimpleSession>;
13
+
14
+ @Log()
15
+ private logger!: Logger;
16
+
17
+ @Autowired
18
+ private client!: CenterClient;
19
+
20
+ @Autowired
21
+ private routerService!: RouterService;
22
+
23
+ constructor() {
24
+ this.sidMap = new DataMap();
25
+ }
26
+
27
+ hasUser(uid: number) {
28
+ return this.sidMap.has(uid);
29
+ }
30
+
31
+ getUids(): Array<number> {
32
+ return [...this.sidMap.keys()];
33
+ }
34
+
35
+ getSessionByUid(uid: number) {
36
+ return this.sidMap.get(uid);
37
+ }
38
+
39
+ join(session: ClientSimpleSession) {
40
+ let uid = session.settings.get(SessionAttribute.uid);
41
+ this.sidMap.set(uid, session);
42
+ }
43
+
44
+ remove(uid: number) {
45
+ this.sidMap.delete(uid);
46
+ }
47
+
48
+ removeByTid(uid: number, tid: string) {
49
+ let session = this.getSessionByUid(uid);
50
+ if (session && session.settings.get(SessionAttribute.tid) == tid) {
51
+ this.remove(uid);
52
+ }
53
+ }
54
+
55
+ //异步通知根据渠道
56
+ notifyByChannel({ channel, data, url }: { channel: string; data?: any; url: string }) {
57
+ let m = this.client.getServerMap();
58
+ let list = m.findByAtts({ serverType: "connector", status: true });
59
+
60
+ list.forEach((item) => {
61
+ this.routerService.request({
62
+ serverType: "connector",
63
+ session: SessionUtil.createSessionByServiceId({ serviceId: item.serviceId }),
64
+ data: {
65
+ channel,
66
+ msg: {
67
+ url,
68
+ data,
69
+ mode: InteractiveMode.notify,
70
+ },
71
+ },
72
+ url: "/channelRemote/broadcastByChannel",
73
+ });
74
+ });
75
+ }
76
+
77
+ notifyByUid({ uid, data, url }: { uid: number; data?: any; url: string }) {
78
+ let session = this.sidMap.get(uid);
79
+ if (!session) {
80
+ // this.logger.error(`not found session ${uid}`)
81
+ return;
82
+ }
83
+ this.routerService.request({
84
+ serverType: "connector",
85
+ session,
86
+ data: {
87
+ data: {
88
+ url,
89
+ data,
90
+ mode: InteractiveMode.notify,
91
+ },
92
+ uid,
93
+ },
94
+ url: "/channelRemote/broadcastByUid",
95
+ });
96
+ }
97
+ }
@@ -0,0 +1,457 @@
1
+ import ConnectorUtils from "@/utils/ConnectorUtils";
2
+ import { ServerCommonUrl, ServerKind } from "@/common/Constant";
3
+ import DataService from "@/servers/base/service/DataService";
4
+ import { ServerMeta, ServerStatus } from "@/types/ServerMeta";
5
+ import { BootPriority, DataMap, FastCarApplication, Logger } from "@fastcar/core";
6
+ import { ApplicationStart, ApplicationStop, Autowired, Log } from "@fastcar/core/annotation";
7
+ import { ClientRequestStatic, RpcAsyncService, RpcClient } from "@fastcar/rpc";
8
+ import Code from "@/common/Code";
9
+ import { EnableScheduling, ScheduledInterval, TimeUnit, TimeUnitNum } from "@fastcar/timer";
10
+ import TaskAsync from "@/common/TaskAsync";
11
+
12
+ //中心注册客户端服务
13
+ @ApplicationStart(BootPriority.Lowest, "start")
14
+ @ApplicationStop(BootPriority.Base, "stop")
15
+ @EnableScheduling
16
+ export default class CenterClient implements RpcAsyncService {
17
+ private client: RpcClient | null;
18
+ private serverMap: DataMap<string, ServerStatus>;
19
+ private remoteClient: DataMap<string, RpcClient>;
20
+ private pendingRemoteClient: string[];
21
+
22
+ @Autowired
23
+ private dataService!: DataService;
24
+
25
+ @Log()
26
+ private logger!: Logger;
27
+
28
+ @Autowired
29
+ private app!: FastCarApplication;
30
+
31
+ private checkFlag: boolean; //防止多次连接
32
+
33
+ private pendingClients: Map<
34
+ string,
35
+ Array<{
36
+ cb: TaskAsync;
37
+ timer: NodeJS.Timeout;
38
+ }>
39
+ > = new Map();
40
+
41
+ constructor() {
42
+ this.serverMap = new DataMap();
43
+ this.client = null; //中心管理服务器客户端
44
+ this.checkFlag = false;
45
+ this.remoteClient = new DataMap();
46
+ this.pendingRemoteClient = [];
47
+ }
48
+
49
+ //上报至注册服务中心 随机选择一台
50
+ start() {}
51
+
52
+ //上报注册服务中心 告诉其将要停止
53
+ stop() {
54
+ this.checkCenter(0, true);
55
+ this.client?.close();
56
+ }
57
+
58
+ private getRandomServiceId(serviceId: string, mod: number) {
59
+ let strList = serviceId.split("-");
60
+ let index = parseInt(strList[strList.length - 1]);
61
+ if (!isNaN(index)) {
62
+ return index % mod;
63
+ }
64
+
65
+ return Math.floor(Math.random() * mod);
66
+ }
67
+
68
+ //根据hash权重进行负载均衡
69
+ getBestCenter(): Array<ServerMeta> {
70
+ let centerList = this.dataService.getServerGroup(ServerKind.center);
71
+ let randomList = [...centerList.servers];
72
+
73
+ //仅过滤已有正常的
74
+ if (this.serverMap.size > 0) {
75
+ randomList = randomList.filter((item) => {
76
+ let s = this.serverMap.get(item.serviceId);
77
+ if (s && s.status) {
78
+ return true;
79
+ }
80
+ return false;
81
+ });
82
+ if (randomList.length == 0) {
83
+ randomList = [...centerList.servers];
84
+ }
85
+ }
86
+
87
+ let sindex = this.getRandomServiceId(this.dataService.getCurrServiceId(), randomList.length);
88
+ return [...randomList.slice(sindex), ...randomList.slice(0, sindex)];
89
+ }
90
+
91
+ async connectCenter() {
92
+ if (this.checkFlag) {
93
+ return;
94
+ }
95
+
96
+ if (this.client) {
97
+ this.client.close();
98
+ }
99
+
100
+ this.checkFlag = true;
101
+ let list = this.getBestCenter();
102
+ let currServiceID = this.dataService.getCurrServiceId();
103
+
104
+ for (let item of list) {
105
+ let clist = item.list;
106
+ if (clist.length == 0) {
107
+ continue;
108
+ }
109
+
110
+ if (item.serviceId == currServiceID && clist.length > 1) {
111
+ continue;
112
+ }
113
+
114
+ for (let citem of clist) {
115
+ if (citem.type) {
116
+ let client = new RpcClient(
117
+ {
118
+ url: ConnectorUtils.getConnectUrl(citem, item.host), //连接地址
119
+ type: citem.type, //具体为哪一种型号的连接器
120
+ extra: citem.clientExtra, //第三方拓展参数
121
+ encode: citem.encode, //解码器
122
+ decode: citem.decode,
123
+ secure: citem.secure,
124
+ ssl: citem.server.ssl,
125
+ connectionLimit: 1,
126
+ disconnectInterval: citem.disconnectInterval,
127
+ },
128
+ {
129
+ handleMsg: async (url: string, data: Object) => {
130
+ this.handleMsg(url, data);
131
+ },
132
+ loginAfter: async (clientIndex) => {
133
+ let selfConfig = this.dataService.getServerGroup();
134
+ if (!client.isConnect()) {
135
+ return false;
136
+ }
137
+
138
+ let res = await ClientRequestStatic<{ serviceId: string; token: string }, { code: number; data: { serverList: ServerStatus[] } }>({
139
+ url: "/login",
140
+ data: {
141
+ serviceId: currServiceID,
142
+ token: selfConfig.token,
143
+ },
144
+ client,
145
+ opts: {
146
+ timeout: 1000,
147
+ retryCount: 1,
148
+ clientIndex,
149
+ },
150
+ });
151
+ if (!res || res.code != Code.SYS.OK) {
152
+ this.logger.error(`login center error`);
153
+ client.close();
154
+ return false;
155
+ } else {
156
+ //同步list
157
+ res.data.serverList.forEach((s) => {
158
+ this.updateServerStatus(s);
159
+ });
160
+ this.logger.debug(`connected central sererver`);
161
+ return true;
162
+ }
163
+ },
164
+ },
165
+ citem.retry
166
+ );
167
+ await client.start();
168
+ if (client.isConnect()) {
169
+ this.client = client;
170
+ break;
171
+ } else {
172
+ client.close();
173
+ }
174
+ }
175
+ }
176
+
177
+ if (this.client?.isConnect()) {
178
+ break;
179
+ }
180
+ }
181
+
182
+ this.checkFlag = false;
183
+ }
184
+
185
+ //监听服务端的消息
186
+ async handleMsg(url: string, data: Object): Promise<void | Object> {
187
+ switch (url) {
188
+ //监听来自服务端的消息了
189
+ case ServerCommonUrl.ServiceStatusNotify: {
190
+ this.updateServerStatus(data as ServerStatus);
191
+ break;
192
+ }
193
+ case ServerCommonUrl.ServiceStatusAllNotify: {
194
+ let list = data as ServerStatus[];
195
+ this.serverMap.clear();
196
+ list.forEach((item) => {
197
+ this.updateServerStatus(item);
198
+ });
199
+ break;
200
+ }
201
+ case ServerCommonUrl.ServiceBalance: {
202
+ //进行重新处理
203
+ if (!this.checkFlag) {
204
+ this.connectCenter();
205
+ }
206
+ break;
207
+ }
208
+ case ServerCommonUrl.Connect: {
209
+ break;
210
+ }
211
+ case ServerCommonUrl.ServiceSyncConfig: {
212
+ let m: {
213
+ key: string;
214
+ data: any[];
215
+ } = data as any;
216
+
217
+ let configService = this.app.getComponentByName(m.key);
218
+ if (configService && Reflect.has(configService, "load")) {
219
+ Reflect.apply(Reflect.get(configService, "load"), configService, m.data);
220
+ }
221
+ break;
222
+ }
223
+ default: {
224
+ this.logger.warn(`unknown url ${url}`);
225
+ break;
226
+ }
227
+ }
228
+ }
229
+
230
+ //更新其余服务状态
231
+ updateServerStatus(s: ServerStatus) {
232
+ let beforeStatus = this.serverMap.get(s.serviceId);
233
+ if (!beforeStatus) {
234
+ this.setServerMap(s);
235
+ } else {
236
+ if (s.createTime > beforeStatus.createTime) {
237
+ this.setServerMap(s);
238
+ }
239
+ }
240
+ }
241
+
242
+ setServerMap(s: ServerStatus) {
243
+ this.serverMap.set(s.serviceId, s);
244
+
245
+ //重新连接远程
246
+ let remoteClient = this.remoteClient.get(s.serviceId);
247
+ if (remoteClient) {
248
+ remoteClient.close();
249
+ this.remoteClient.delete(s.serviceId);
250
+ }
251
+ }
252
+
253
+ //这边有一个超时检测 每1秒检测一次是否连上了中心服务
254
+ @ScheduledInterval({ fixedRate: 1, fixedRateString: TimeUnit.second, initialDelay: Math.floor(500 + Math.random() * 1500) })
255
+ async checkCenter(diff: number, stop?: boolean) {
256
+ if (!this.client?.isConnect()) {
257
+ await this.connectCenter();
258
+ }
259
+
260
+ //检测已连接的远程服务
261
+ this.remoteClient.forEach((client, id) => {
262
+ if (this.pendingRemoteClient.includes(id)) {
263
+ return;
264
+ }
265
+ let status = this.serverMap.get(id);
266
+ if (!status || !status.status) {
267
+ return;
268
+ }
269
+
270
+ if (client.isConnect()) {
271
+ return;
272
+ }
273
+
274
+ this.createRemoteClient(id);
275
+ });
276
+ }
277
+
278
+ @ScheduledInterval({ fixedRate: 1, fixedRateString: TimeUnit.minute, initialDelay: Math.floor(TimeUnitNum.second * (10 + Math.random() * 20)) })
279
+ reportHealth() {
280
+ if (this.client && this.client.isConnect()) {
281
+ ClientRequestStatic<
282
+ void,
283
+ {
284
+ code: number;
285
+ }
286
+ >({
287
+ url: "/remote/health",
288
+ client: this.client,
289
+ opts: {
290
+ timeout: 1000,
291
+ retryCount: 1,
292
+ },
293
+ }).then((res) => {
294
+ if (res.code != 200) {
295
+ this.logger.debug(`检查健康状况----------------${res.code}`);
296
+ this.client?.close();
297
+ }
298
+ });
299
+ }
300
+ }
301
+
302
+ isOnline() {
303
+ return this.client && this.client.isConnect();
304
+ }
305
+
306
+ getServerMap() {
307
+ return this.serverMap;
308
+ }
309
+
310
+ async createRemoteClient(id: string): Promise<RpcClient | null> {
311
+ let item = this.dataService.getServerMeta(id);
312
+
313
+ if (!item) {
314
+ return null;
315
+ }
316
+
317
+ let clist = item.list;
318
+ if (clist.length == 0) {
319
+ return null;
320
+ }
321
+
322
+ if (this.pendingRemoteClient.includes(id)) {
323
+ //这边保留一个等待时长
324
+ return new Promise((resolve) => {
325
+ let items = this.pendingClients.get(id);
326
+ if (!items) {
327
+ items = [];
328
+ this.pendingClients.set(id, items);
329
+ }
330
+
331
+ let cb = new TaskAsync(resolve);
332
+ let timer = setTimeout(() => {
333
+ cb.done(null);
334
+ }, 3000);
335
+
336
+ items?.push({
337
+ timer,
338
+ cb,
339
+ });
340
+ });
341
+ }
342
+
343
+ this.pendingRemoteClient.push(id);
344
+
345
+ for (let citem of clist) {
346
+ //进行连接
347
+ let url = ConnectorUtils.getConnectUrl(citem, item.host);
348
+ if (!url || (citem.front && clist.length > 1)) {
349
+ continue;
350
+ }
351
+ let client = new RpcClient(
352
+ {
353
+ url, //连接地址
354
+ type: citem.type, //具体为哪一种型号的连接器
355
+ extra: citem.clientExtra, //第三方拓展参数
356
+ encode: citem.encode, //解码器
357
+ decode: citem.decode,
358
+ secure: citem.secure,
359
+ ssl: citem.server.ssl,
360
+ disconnectInterval: citem.disconnectInterval,
361
+ connectionLimit: citem.connectionLimit || 1,
362
+ },
363
+ {
364
+ handleMsg: async (url: string, data: Object) => {
365
+ this.handleMsg(url, data);
366
+ },
367
+ loginAfter: async (clientIndex) => {
368
+ if (!client.isConnect()) {
369
+ return false;
370
+ }
371
+
372
+ let serverMeta = this.dataService.getServerMeta();
373
+ if (!serverMeta) {
374
+ return false;
375
+ }
376
+ let res = await ClientRequestStatic<{ serviceId: string; token: string }, { code: number; data: { serverList: ServerStatus[] } }>({
377
+ url: "/remote/login",
378
+ data: {
379
+ serviceId: this.dataService.getCurrServiceId(),
380
+ token: serverMeta?.token,
381
+ },
382
+ client,
383
+ opts: {
384
+ timeout: 1000,
385
+ retryCount: 1,
386
+ clientIndex,
387
+ },
388
+ });
389
+ if (res.code != Code.SYS.OK) {
390
+ this.logger.error(`login remote ${id} error`);
391
+ } else {
392
+ this.logger.debug(`登录完成 连接服务ID:${id}`);
393
+ return true;
394
+ }
395
+ return false;
396
+ },
397
+ },
398
+ citem.retry
399
+ );
400
+ await client.start();
401
+ if (client.isConnect()) {
402
+ let oldClient = this.remoteClient.get(id);
403
+ if (oldClient) {
404
+ oldClient.close();
405
+ }
406
+ this.remoteClient.set(id, client);
407
+ break;
408
+ } else {
409
+ this.logger.debug("连接失败");
410
+ client.close();
411
+ }
412
+ }
413
+
414
+ let index = this.pendingRemoteClient.indexOf(id);
415
+ this.pendingRemoteClient.splice(index, 1);
416
+
417
+ //处理连接的远程客户端
418
+ let remoteClient = this.remoteClient.get(id) || null;
419
+ let pendings = this.pendingClients.get(id);
420
+ if (pendings && pendings?.length > 0) {
421
+ pendings.forEach((c) => {
422
+ c.cb.done(remoteClient);
423
+ clearTimeout(c.timer);
424
+ });
425
+
426
+ this.pendingClients.delete(id);
427
+ }
428
+
429
+ return remoteClient;
430
+ }
431
+
432
+ async getRemoteClientByserviceId(serviceId: string): Promise<RpcClient | null> {
433
+ let status = this.serverMap.get(serviceId);
434
+ if (!status || !status.status) {
435
+ return null;
436
+ }
437
+
438
+ let client = this.remoteClient.get(serviceId);
439
+ if (!client || !client.isConnect()) {
440
+ //创建一个等待
441
+ return await this.createRemoteClient(serviceId);
442
+ }
443
+
444
+ return client;
445
+ }
446
+
447
+ async sendBalance() {
448
+ if (this.client) {
449
+ return await ClientRequestStatic<any, any>({
450
+ client: this.client,
451
+ url: ServerCommonUrl.ServiceBalance,
452
+ });
453
+ }
454
+
455
+ return null;
456
+ }
457
+ }
@@ -0,0 +1,85 @@
1
+ import { Autowired, Service } from "@fastcar/core/annotation";
2
+ import { FastCarApplication } from "@fastcar/core";
3
+ import { ServerGroupType, ServerMeta } from "@/types/ServerMeta";
4
+ import { ServerKind, ServerMicroservices } from "@/common/Constant";
5
+ import { ChannelKind } from "@/common/Constant";
6
+ import { SessionAttribute } from "@/types/SessionAttribute";
7
+
8
+ /**
9
+ * 实现对当前服务的管理
10
+ */
11
+ @Service
12
+ export default class DataService {
13
+ @Autowired
14
+ private app!: FastCarApplication;
15
+
16
+ //获取当前服务的id
17
+ getCurrServiceId(): string {
18
+ return this.app.getSetting(SessionAttribute.serviceId);
19
+ }
20
+
21
+ getCurrServerType() {
22
+ return this.app.getSetting(SessionAttribute.serverType);
23
+ }
24
+
25
+ getMicroservices(): ServerGroupType {
26
+ const microservices: ServerGroupType = this.app.getSetting(ServerMicroservices);
27
+ return microservices;
28
+ }
29
+
30
+ getServerGroup(serverType: string = this.getCurrServerType()): { token: string; servers: ServerMeta[] } {
31
+ let services = this.getMicroservices();
32
+ return services[serverType];
33
+ }
34
+
35
+ getServerMeta(serviceId: string = this.getCurrServiceId()): (ServerMeta & { serverType: string; token: string }) | null {
36
+ let services = this.getMicroservices();
37
+ for (let serverType in services) {
38
+ let item = services[serverType];
39
+ for (let server of item.servers) {
40
+ if (server.serviceId == serviceId) {
41
+ return Object.assign({ token: item.token, serverType }, server);
42
+ }
43
+ }
44
+ }
45
+
46
+ return null;
47
+ }
48
+
49
+ getServerKindByServerType(serverType: string = this.getCurrServerType()): ServerKind {
50
+ let services = this.getMicroservices();
51
+ if (!Reflect.has(services, serverType)) {
52
+ return ServerKind.front;
53
+ }
54
+
55
+ if (serverType.toLowerCase() == ServerKind.center) {
56
+ return ServerKind.center;
57
+ }
58
+
59
+ return ServerKind.remote;
60
+ }
61
+
62
+ getChannelKindByServerType(serverType: string = this.getCurrServerType()): ChannelKind {
63
+ let services = this.getMicroservices();
64
+ if (!Reflect.has(services, serverType)) {
65
+ return ChannelKind.FRONT;
66
+ }
67
+
68
+ if (serverType.toLowerCase() == ServerKind.center) {
69
+ return ChannelKind.CENTER;
70
+ }
71
+
72
+ return ChannelKind.REMOTE;
73
+ }
74
+
75
+ getServiceIdByIndex(serverType: string, index: number) {
76
+ let services = this.getMicroservices();
77
+ let item = services[serverType];
78
+
79
+ let citem = item?.servers?.[index];
80
+ if (citem?.id != index) {
81
+ console.error(`server route index error ${serverType} ${index}`);
82
+ }
83
+ return citem?.serviceId || "";
84
+ }
85
+ }