@spider-mesh/core 1.0.9965 → 2.0.2
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/build/const.d.ts +1 -0
- package/build/const.js +2 -0
- package/build/const.js.map +1 -0
- package/build/src/SpiderMesh.d.ts +27 -41
- package/build/src/SpiderMesh.js +314 -381
- package/build/src/SpiderMesh.js.map +1 -1
- package/build/src/decorators/BeforeMicroserviceOnline.d.ts +4 -0
- package/build/src/decorators/BeforeMicroserviceOnline.js +10 -0
- package/build/src/decorators/BeforeMicroserviceOnline.js.map +1 -0
- package/build/src/decorators/LimitConcurrentRunning.d.ts +2 -3
- package/build/src/decorators/LimitConcurrentRunning.js +2 -22
- package/build/src/decorators/LimitConcurrentRunning.js.map +1 -1
- package/build/src/decorators/Microservice.d.ts +10 -24
- package/build/src/decorators/Microservice.js +12 -31
- package/build/src/decorators/Microservice.js.map +1 -1
- package/build/src/decorators/NestJSExposeMicroservice.d.ts +5 -0
- package/build/src/decorators/NestJSExposeMicroservice.js +14 -0
- package/build/src/decorators/NestJSExposeMicroservice.js.map +1 -0
- package/build/src/decorators/NestJSLinkEvent.d.ts +9 -0
- package/build/src/decorators/NestJSLinkEvent.js +7 -0
- package/build/src/decorators/NestJSLinkEvent.js.map +1 -0
- package/build/src/decorators/NestJSLinkMicroservice.d.ts +6 -0
- package/build/src/decorators/NestJSLinkMicroservice.js +7 -0
- package/build/src/decorators/NestJSLinkMicroservice.js.map +1 -0
- package/build/src/helpers/LimitConcurrency.d.ts +3 -0
- package/build/src/helpers/LimitConcurrency.js +34 -0
- package/build/src/helpers/LimitConcurrency.js.map +1 -0
- package/build/src/helpers/MicroserviceException.d.ts +8 -0
- package/build/src/helpers/MicroserviceException.js +9 -0
- package/build/src/helpers/MicroserviceException.js.map +1 -0
- package/build/src/helpers/MicroserviceNotFound copy.d.ts +5 -0
- package/build/src/helpers/MicroserviceNotFound copy.js +8 -0
- package/build/src/helpers/MicroserviceNotFound copy.js.map +1 -0
- package/build/src/helpers/MicroserviceNotFound.d.ts +5 -0
- package/build/src/helpers/MicroserviceNotFound.js +8 -0
- package/build/src/helpers/MicroserviceNotFound.js.map +1 -0
- package/build/src/helpers/MicroserviceOfflineException.d.ts +5 -0
- package/build/src/helpers/MicroserviceOfflineException.js +8 -0
- package/build/src/helpers/MicroserviceOfflineException.js.map +1 -0
- package/build/src/helpers/MicroserviceRpcTimeout.d.ts +5 -0
- package/build/src/helpers/MicroserviceRpcTimeout.js +8 -0
- package/build/src/helpers/MicroserviceRpcTimeout.js.map +1 -0
- package/build/src/helpers/randomUUID.d.ts +1 -0
- package/build/src/helpers/randomUUID.js +13 -0
- package/build/src/helpers/randomUUID.js.map +1 -0
- package/build/src/helpers/sleep.js +1 -1
- package/build/src/helpers/sleep.js.map +1 -1
- package/build/src/index.d.ts +16 -12
- package/build/src/index.js +16 -9
- package/build/src/index.js.map +1 -1
- package/build/src/interfaces/DiscoveryTransporter.d.ts +5 -0
- package/build/src/interfaces/DiscoveryTransporter.js +3 -0
- package/build/src/interfaces/DiscoveryTransporter.js.map +1 -0
- package/build/src/interfaces/PubsubTransporter.d.ts +10 -0
- package/build/src/interfaces/PubsubTransporter.js +3 -0
- package/build/src/interfaces/PubsubTransporter.js.map +1 -0
- package/build/src/interfaces/RemoteService.d.ts +12 -18
- package/build/src/interfaces/RpcTransporter.d.ts +30 -0
- package/build/src/interfaces/RpcTransporter.js +3 -0
- package/build/src/interfaces/RpcTransporter.js.map +1 -0
- package/build/src/interfaces/SpiderMeshNode.d.ts +14 -18
- package/build/tsconfig.tsbuildinfo +1 -0
- package/package.json +14 -9
- package/tsconfig.json +7 -3
- package/build/src/Encoder.d.ts +0 -5
- package/build/src/Encoder.js +0 -42
- package/build/src/Encoder.js.map +0 -1
- package/build/src/RPCOptions.d.ts +0 -11
- package/build/src/RPCOptions.js +0 -13
- package/build/src/RPCOptions.js.map +0 -1
- package/build/src/builtin-transporter/BuiltinTransporter.d.ts +0 -15
- package/build/src/builtin-transporter/BuiltinTransporter.js +0 -157
- package/build/src/builtin-transporter/BuiltinTransporter.js.map +0 -1
- package/build/src/builtin-transporter/RxjsTcpServer.d.ts +0 -11
- package/build/src/builtin-transporter/RxjsTcpServer.js +0 -31
- package/build/src/builtin-transporter/RxjsTcpServer.js.map +0 -1
- package/build/src/builtin-transporter/RxjsTcpSocket.d.ts +0 -18
- package/build/src/builtin-transporter/RxjsTcpSocket.js +0 -65
- package/build/src/builtin-transporter/RxjsTcpSocket.js.map +0 -1
- package/build/src/builtin-transporter/RxjsUdpBroadcaster.d.ts +0 -19
- package/build/src/builtin-transporter/RxjsUdpBroadcaster.js +0 -48
- package/build/src/builtin-transporter/RxjsUdpBroadcaster.js.map +0 -1
- package/build/src/const.d.ts +0 -6
- package/build/src/const.js +0 -8
- package/build/src/const.js.map +0 -1
- package/build/src/decorators/DeepProxy.d.ts +0 -7
- package/build/src/decorators/DeepProxy.js +0 -24
- package/build/src/decorators/DeepProxy.js.map +0 -1
- package/build/src/decorators/ListenEvent.d.ts +0 -17
- package/build/src/decorators/ListenEvent.js +0 -23
- package/build/src/decorators/ListenEvent.js.map +0 -1
- package/build/src/decorators/OnMicroserviceReady.d.ts +0 -6
- package/build/src/decorators/OnMicroserviceReady.js +0 -14
- package/build/src/decorators/OnMicroserviceReady.js.map +0 -1
- package/build/src/helpers/waitFirstEvent.d.ts +0 -3
- package/build/src/helpers/waitFirstEvent.js +0 -5
- package/build/src/helpers/waitFirstEvent.js.map +0 -1
- package/build/src/interfaces/SpiderMeshTransporter.d.ts +0 -24
- package/build/src/interfaces/SpiderMeshTransporter.js +0 -2
- package/build/src/interfaces/SpiderMeshTransporter.js.map +0 -1
- package/yarn.lock +0 -134
package/build/src/SpiderMesh.js
CHANGED
|
@@ -1,297 +1,237 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { BuiltinTransporter } from './builtin-transporter/BuiltinTransporter.js';
|
|
14
|
-
import { DEBUG, NAMEPSACE, NODE_ID } from './const.js';
|
|
15
|
-
export class SpiderMeshConfig {
|
|
16
|
-
namespace;
|
|
17
|
-
node_id;
|
|
18
|
-
transporter;
|
|
19
|
-
}
|
|
20
|
-
const PACKAGE_JSON = JSON.parse(readFileSync(`package.json`, 'utf8')) || {};
|
|
1
|
+
import { BehaviorSubject, catchError, EMPTY, filter, finalize, firstValueFrom, from, lastValueFrom, map, mergeAll, mergeMap, of, retry, tap, throwError, timeout, timer } from "rxjs";
|
|
2
|
+
import { listBeforeMicroserviceOnlineMethods } from "./decorators/BeforeMicroserviceOnline.js";
|
|
3
|
+
import { PubsubTransporter } from "./interfaces/PubsubTransporter.js";
|
|
4
|
+
import { RpcTransporter } from "./interfaces/RpcTransporter.js";
|
|
5
|
+
import { MicroserviceException } from "./helpers/MicroserviceException.js";
|
|
6
|
+
import { MicroserviceOfflineException } from "./helpers/MicroserviceOfflineException.js";
|
|
7
|
+
import { services$ } from "./decorators/Microservice.js";
|
|
8
|
+
import { networkInterfaces } from "os";
|
|
9
|
+
import { MicroserviceNotFound } from "./helpers/MicroserviceNotFound.js";
|
|
10
|
+
import { DiscoveryTransporter } from "./interfaces/DiscoveryTransporter.js";
|
|
11
|
+
import { SPIDERMESH_NAMESPACE } from "const.js";
|
|
12
|
+
import { MicroserviceRpcTimeout } from "./helpers/MicroserviceRpcTimeout.js";
|
|
21
13
|
export class SpiderMesh {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
38
|
-
if (ip && ip != 'Bad Gateway')
|
|
39
|
-
return s(ip);
|
|
40
|
-
await new Promise(s => setTimeout(s, 100));
|
|
41
|
-
}
|
|
42
|
-
return s(null);
|
|
14
|
+
node_id = `${Date.now()}`;
|
|
15
|
+
namespace = SPIDERMESH_NAMESPACE;
|
|
16
|
+
#rpcs = new Map();
|
|
17
|
+
#pubsubs = new BehaviorSubject(new Map());
|
|
18
|
+
#discovers = new Map();
|
|
19
|
+
#metadata$ = new BehaviorSubject({
|
|
20
|
+
ips: Object.values(networkInterfaces()).flat(2).filter(a => !a?.internal && !!a?.address).map(a => a?.address),
|
|
21
|
+
host: '',
|
|
22
|
+
namespace: SPIDERMESH_NAMESPACE,
|
|
23
|
+
node_id: this.node_id,
|
|
24
|
+
services: {},
|
|
25
|
+
topics: [],
|
|
26
|
+
transporters: {},
|
|
27
|
+
nodes: {},
|
|
28
|
+
version: 0
|
|
43
29
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
async $metadata(revalidate_on_join) {
|
|
55
|
-
const ips = Object.values(networkInterfaces()).map(itf => itf?.map(ip => ip.address) || []).flat(2);
|
|
56
|
-
const services = [...this.#local_rpc_services.entries()].reduce((p, [service_id, { metadata }]) => ({ ...p, [service_id]: metadata }), {});
|
|
57
|
-
const metadata = {
|
|
58
|
-
id: this.transporter.node_id,
|
|
59
|
-
name: PACKAGE_JSON?.name || 'UNKNOWN',
|
|
60
|
-
version: PACKAGE_JSON?.version || '1.0.0',
|
|
61
|
-
path: process.cwd(),
|
|
62
|
-
uptime: process.uptime(),
|
|
63
|
-
hostname: os.hostname(),
|
|
64
|
-
plaform: os.platform(),
|
|
65
|
-
node_version: process.version,
|
|
66
|
-
public_ip: await this.#public_ip,
|
|
67
|
-
ip_addresses: ips,
|
|
68
|
-
last_online: Date.now(),
|
|
69
|
-
active: true,
|
|
70
|
-
online: true,
|
|
71
|
-
services,
|
|
72
|
-
namespace: this.transporter.namespace,
|
|
73
|
-
linked: [...this.#linked_nodes.keys()],
|
|
74
|
-
isolated_nodes: [...new Set([...this.#linked_nodes.values()].filter(node => node.isolate).map(node => node.id))],
|
|
75
|
-
isolate: this.#$isolated.value,
|
|
76
|
-
revalidate_on_join
|
|
77
|
-
};
|
|
78
|
-
return metadata;
|
|
79
|
-
}
|
|
80
|
-
async $update_isolate_mode(active) {
|
|
81
|
-
this.#$isolated.next(active);
|
|
82
|
-
const me = await this.$metadata();
|
|
83
|
-
await this.publish('#join', me);
|
|
84
|
-
return me;
|
|
85
|
-
}
|
|
86
|
-
async #node_event_handler({ data: msg, sender_node_id }) {
|
|
87
|
-
if (msg.type == 'rpc') {
|
|
88
|
-
if (msg.service == 'SpiderMesh' && !msg.method.startsWith('$')) {
|
|
89
|
-
sender_node_id && this.transporter.publish({
|
|
90
|
-
data: [{
|
|
91
|
-
id: msg.id,
|
|
92
|
-
type: 'error',
|
|
93
|
-
error: 'NOT_ALLOW'
|
|
94
|
-
}],
|
|
95
|
-
event: sender_node_id,
|
|
96
|
-
node_id: sender_node_id
|
|
97
|
-
});
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
const instance = msg.service == 'SpiderMesh' ? this : this.#local_rpc_services.get(msg.service)?.instance;
|
|
101
|
-
if (!instance)
|
|
102
|
-
return this.transporter.publish({
|
|
103
|
-
data: [{
|
|
104
|
-
id: msg.id,
|
|
105
|
-
type: 'error',
|
|
106
|
-
error: 'SERVICE_NOT_FOUND'
|
|
107
|
-
}],
|
|
108
|
-
event: sender_node_id,
|
|
109
|
-
node_id: sender_node_id
|
|
110
|
-
});
|
|
111
|
-
if (typeof instance?.[msg.method] != 'function')
|
|
112
|
-
return this.transporter.publish({
|
|
113
|
-
data: [{
|
|
114
|
-
id: msg.id,
|
|
115
|
-
type: 'error',
|
|
116
|
-
error: 'SERVICE_METHOD_NOT_FOUND'
|
|
117
|
-
}],
|
|
118
|
-
event: sender_node_id,
|
|
119
|
-
node_id: sender_node_id
|
|
120
|
-
});
|
|
121
|
-
const args = msg.args.map(arg => arg != '__FUNCTION__' ? arg : (...args) => {
|
|
122
|
-
sender_node_id && this.transporter.publish({
|
|
123
|
-
event: sender_node_id,
|
|
124
|
-
node_id: sender_node_id,
|
|
125
|
-
data: [{ id: msg.id, type: 'callback', args }]
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
try {
|
|
129
|
-
const response = await instance?.[msg.method]?.(...args);
|
|
130
|
-
sender_node_id && this.transporter.publish({
|
|
131
|
-
event: sender_node_id,
|
|
132
|
-
node_id: sender_node_id,
|
|
133
|
-
data: [{ id: msg.id, type: 'response', response }]
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
sender_node_id && this.transporter.publish({
|
|
138
|
-
event: sender_node_id,
|
|
139
|
-
node_id: sender_node_id,
|
|
140
|
-
data: [{ id: msg.id, type: 'error', error: error?.code || error?.message || error || 'UNKNOWN' }]
|
|
141
|
-
});
|
|
30
|
+
#nodes = new BehaviorSubject({
|
|
31
|
+
nodes: new Map(),
|
|
32
|
+
last_updated_node_id: ''
|
|
33
|
+
});
|
|
34
|
+
#services$ = new BehaviorSubject(new Map());
|
|
35
|
+
constructor() {
|
|
36
|
+
services$.pipe(filter(list => Object.keys(list).length > 0), mergeMap(async (services) => {
|
|
37
|
+
for (const v of Object.values(services)) {
|
|
38
|
+
const metadata = v['$'] || (typeof v.metadata == 'function' ? await v.metadata() : v.metadata);
|
|
39
|
+
Object.defineProperty(v, '$', { value: metadata });
|
|
142
40
|
}
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
request.reject(msg.error);
|
|
158
|
-
this.#rpc_queue.delete(msg.id);
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
if (msg.type == 'response') {
|
|
162
|
-
request.success(msg.response);
|
|
163
|
-
this.#rpc_queue.delete(msg.id);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
async #init() {
|
|
168
|
-
await this.transporter.start();
|
|
169
|
-
this.listen(this.transporter.node_id).subscribe(evt => this.#node_event_handler(evt));
|
|
170
|
-
this.listen('#join').subscribe(({ data }) => {
|
|
171
|
-
this.#on_node_discovered(data);
|
|
172
|
-
});
|
|
173
|
-
this.transporter.$nodes_status.subscribe(async ({ node_id, online }) => {
|
|
174
|
-
!online && this.#on_node_offline(node_id);
|
|
175
|
-
online && this.transporter.publish({
|
|
176
|
-
event: '#join',
|
|
177
|
-
data: [await this.$metadata()],
|
|
178
|
-
node_id
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
serviceInstanceList.pipe(filter(i => i.namespace == this.transporter.namespace), mergeMap(async ({ instance, metadata }) => {
|
|
182
|
-
await this.#active_local_service(instance, metadata);
|
|
183
|
-
await this.#active_ready_hooks(instance);
|
|
184
|
-
}), throttleTime(1000), mergeMap(async () => {
|
|
185
|
-
const me = await this.$metadata();
|
|
186
|
-
await this.publish('#join', me);
|
|
187
|
-
})).subscribe();
|
|
41
|
+
return services;
|
|
42
|
+
}), tap(services => {
|
|
43
|
+
const metadata = {
|
|
44
|
+
...this.#metadata$.value,
|
|
45
|
+
services: Object.entries(services).reduce((p, [name, v]) => {
|
|
46
|
+
return {
|
|
47
|
+
...p,
|
|
48
|
+
[name]: v['$']
|
|
49
|
+
};
|
|
50
|
+
}, {}),
|
|
51
|
+
version: this.#metadata$.value.version + 1
|
|
52
|
+
};
|
|
53
|
+
this.#metadata$.next(metadata);
|
|
54
|
+
}), catchError(e => EMPTY)).subscribe();
|
|
188
55
|
}
|
|
189
|
-
|
|
190
|
-
if (
|
|
191
|
-
return;
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
56
|
+
#selectRpcTarget(filters = {}) {
|
|
57
|
+
if (!filters.service)
|
|
58
|
+
return null;
|
|
59
|
+
if (filters.node_id) {
|
|
60
|
+
const node = this.#nodes.value.nodes.get(filters.node_id);
|
|
61
|
+
if (!node)
|
|
62
|
+
return null;
|
|
63
|
+
if (!node.services[filters.service])
|
|
64
|
+
return null;
|
|
65
|
+
if (!node.rpc)
|
|
66
|
+
return null;
|
|
67
|
+
const transporter = this.#rpcs.get(node.rpc);
|
|
68
|
+
if (!transporter)
|
|
69
|
+
return null;
|
|
70
|
+
return { node, transporter };
|
|
71
|
+
}
|
|
72
|
+
const state = this.#services$.value.get(filters.service);
|
|
73
|
+
if (!state || state.nodes.length == 0)
|
|
74
|
+
return null;
|
|
75
|
+
const nodes = state.nodes.map(id => {
|
|
76
|
+
const node = this.#nodes.value.nodes.get(id);
|
|
77
|
+
const transporter = node && node.rpc && this.#rpcs.get(node.rpc);
|
|
78
|
+
if (node && transporter) {
|
|
79
|
+
if (filters.ip) {
|
|
80
|
+
if (!node.ips.includes(filters.ip))
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return { node, transporter };
|
|
214
84
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
85
|
+
}).filter(Boolean).map(e => e);
|
|
86
|
+
return nodes[state.index++ % nodes.length];
|
|
87
|
+
}
|
|
88
|
+
callRemoteService(options) {
|
|
89
|
+
return of(0).pipe(mergeMap(async () => {
|
|
90
|
+
await this.waitServiceOnline(options.service);
|
|
91
|
+
const target = this.#selectRpcTarget(options);
|
|
92
|
+
if (!target)
|
|
93
|
+
throw new MicroserviceOfflineException();
|
|
94
|
+
const force = !!options.node_id || !!options.ip;
|
|
95
|
+
return target.transporter.rpc(options, target.node, force);
|
|
96
|
+
}), mergeMap($ => $), retry({
|
|
97
|
+
delay: (e, count) => {
|
|
98
|
+
if (e instanceof MicroserviceOfflineException || e.message == MicroserviceOfflineException.code) {
|
|
99
|
+
if (options.retry && count < options.retry)
|
|
100
|
+
return timer(1000);
|
|
101
|
+
}
|
|
102
|
+
throw e;
|
|
218
103
|
}
|
|
219
|
-
|
|
220
|
-
|
|
104
|
+
}), options.timeout ? timeout({
|
|
105
|
+
each: options.timeout,
|
|
106
|
+
with: () => throwError(() => new MicroserviceRpcTimeout())
|
|
107
|
+
}) : tap(), catchError(e => {
|
|
108
|
+
if (options.fallback != undefined)
|
|
109
|
+
return of(options.fallback);
|
|
110
|
+
if (e.code) {
|
|
111
|
+
const error = new MicroserviceException(e);
|
|
112
|
+
error.stack = e.stack;
|
|
113
|
+
throw error;
|
|
221
114
|
}
|
|
222
|
-
|
|
223
|
-
|
|
115
|
+
throw e;
|
|
116
|
+
}));
|
|
224
117
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
118
|
+
linkTransporter(transporter) {
|
|
119
|
+
const transporter_name = Object.getPrototypeOf(transporter).constructor.name;
|
|
120
|
+
if (transporter instanceof RpcTransporter) {
|
|
121
|
+
const rpc = transporter;
|
|
122
|
+
if (this.#rpcs.has(transporter_name))
|
|
123
|
+
return;
|
|
124
|
+
this.#rpcs.set(transporter_name, rpc);
|
|
125
|
+
return transporter.link(this.#nodes).pipe(map(e => {
|
|
126
|
+
const rpc = e.rpc;
|
|
127
|
+
if (rpc) {
|
|
128
|
+
try {
|
|
129
|
+
const service = services$.value[rpc.service];
|
|
130
|
+
const instance = service?.instance;
|
|
131
|
+
if (!instance)
|
|
132
|
+
return rpc.callback(throwError(() => new MicroserviceNotFound()));
|
|
133
|
+
const response = instance[rpc.method](...rpc.args);
|
|
134
|
+
rpc.callback(response);
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
rpc.callback(throwError(() => err));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const online = e.online;
|
|
141
|
+
if (online) {
|
|
142
|
+
const node = this.#nodes.value.nodes.get(online);
|
|
143
|
+
if (node) {
|
|
144
|
+
node.rpc = transporter_name;
|
|
145
|
+
for (const service of Object.keys(node.services || {})) {
|
|
146
|
+
const services = this.#services$.value;
|
|
147
|
+
const target = services.get(service) || { index: 0, nodes: [] };
|
|
148
|
+
services.set(service, {
|
|
149
|
+
index: target.index,
|
|
150
|
+
nodes: [
|
|
151
|
+
...target.nodes.filter(id => id != node.node_id),
|
|
152
|
+
node.node_id
|
|
153
|
+
]
|
|
154
|
+
});
|
|
155
|
+
this.#services$.next(services);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const offline = e.offline;
|
|
160
|
+
if (offline) {
|
|
161
|
+
const nodes = this.#nodes.value.nodes;
|
|
162
|
+
const node = nodes.get(offline);
|
|
163
|
+
if (node) {
|
|
164
|
+
nodes.delete(offline);
|
|
165
|
+
this.#nodes.next({ nodes, last_updated_node_id: node.node_id });
|
|
166
|
+
for (const service of Object.values(node.services)) {
|
|
167
|
+
const services = this.#services$.value;
|
|
168
|
+
const target = services.get(service) || { index: 0, nodes: [] };
|
|
169
|
+
const nodes = target.nodes.filter(id => id != node.node_id);
|
|
170
|
+
nodes.length == 0 ? services.delete(service) : services.set(service, { ...target, nodes });
|
|
171
|
+
this.#services$.next(services);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const metadata = e.metadata;
|
|
176
|
+
if (metadata) {
|
|
177
|
+
this.#metadata$.next({
|
|
178
|
+
...this.#metadata$.value,
|
|
179
|
+
transporters: {
|
|
180
|
+
...this.#metadata$.value.transporters,
|
|
181
|
+
[transporter_name]: metadata
|
|
182
|
+
},
|
|
183
|
+
version: this.#metadata$.value.version + 1
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}), finalize(() => {
|
|
187
|
+
this.#rpcs.delete(transporter_name);
|
|
188
|
+
})).subscribe();
|
|
235
189
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
190
|
+
if (transporter instanceof PubsubTransporter) {
|
|
191
|
+
const transporters = this.#pubsubs.getValue();
|
|
192
|
+
transporters.set(transporter_name, transporter);
|
|
193
|
+
this.#pubsubs.next(transporters);
|
|
194
|
+
return transporter.link(this.#nodes).pipe(map(a => a.metadata), filter(Boolean), tap(metadata => {
|
|
195
|
+
this.#metadata$.next({
|
|
196
|
+
...this.#metadata$.value,
|
|
197
|
+
transporters: {
|
|
198
|
+
...this.#metadata$.value.transporters,
|
|
199
|
+
[transporter_name]: metadata
|
|
200
|
+
},
|
|
201
|
+
version: this.#metadata$.value.version + 1
|
|
202
|
+
});
|
|
203
|
+
}), finalize(() => {
|
|
204
|
+
transporters.delete(transporter_name);
|
|
205
|
+
this.#pubsubs.next(transporters);
|
|
206
|
+
})).subscribe();
|
|
247
207
|
}
|
|
248
|
-
if (
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
208
|
+
if (transporter instanceof DiscoveryTransporter) {
|
|
209
|
+
const discover = transporter;
|
|
210
|
+
this.#discovers.set(transporter_name, discover);
|
|
211
|
+
return discover.link(this.#metadata$).pipe(tap(node => {
|
|
212
|
+
const nodes = this.#nodes.value.nodes;
|
|
213
|
+
nodes.set(node.node_id, {
|
|
214
|
+
...nodes.get(node.node_id) || {},
|
|
215
|
+
...node
|
|
216
|
+
});
|
|
217
|
+
const last_updated_node_id = node.node_id;
|
|
218
|
+
this.#nodes.next({
|
|
219
|
+
nodes,
|
|
220
|
+
last_updated_node_id
|
|
221
|
+
});
|
|
222
|
+
}), finalize(() => this.#discovers.delete(transporter_name))).subscribe();
|
|
254
223
|
}
|
|
255
|
-
const index = ++current.last_call_index % current.nodes.length;
|
|
256
|
-
return current.nodes[index].id;
|
|
257
224
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
reject(new Error('TIMEOUT'));
|
|
265
|
-
this.#rpc_queue.delete(rid);
|
|
266
|
-
}, options.$timeout);
|
|
267
|
-
!options.$nevermind && this.#rpc_queue.set(rid, {
|
|
268
|
-
args,
|
|
269
|
-
last_ping: 0,
|
|
270
|
-
reject,
|
|
271
|
-
request_time: Date.now(),
|
|
272
|
-
success,
|
|
273
|
-
timeout: options.$timeout,
|
|
274
|
-
target_node_id: options.$node_id
|
|
275
|
-
});
|
|
276
|
-
const retry_count = options.$retry || 1;
|
|
277
|
-
for (let i = retry_count; i > 0; i--) {
|
|
278
|
-
try {
|
|
279
|
-
const node_id = this.#caculate_rpc_node_id(service, options);
|
|
280
|
-
if (!node_id)
|
|
281
|
-
return reject(Object.assign(new Error(`SERVICE_NOT_RUNNING:${service}`), { service }));
|
|
282
|
-
await this.publish(service, { type: 'rpc', id: rid, args, method, service }, node_id);
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
catch (e) { }
|
|
286
|
-
i > 1 && await new Promise(s => setTimeout(s, options.$retry_delay || 1000));
|
|
287
|
-
}
|
|
288
|
-
if (options.$fallback)
|
|
289
|
-
return success(options.$fallback);
|
|
290
|
-
});
|
|
225
|
+
waitServiceOnline(service, check = (nodes => nodes.length > 0)) {
|
|
226
|
+
return firstValueFrom(this.#services$.pipe(map(() => {
|
|
227
|
+
const targets = this.#services$.value.get(service)?.nodes || [];
|
|
228
|
+
const nodes = targets.map(id => this.#nodes.value.nodes.get(id)).filter(Boolean);
|
|
229
|
+
return nodes;
|
|
230
|
+
}), mergeMap(async (targets) => check(targets)), filter(Boolean)));
|
|
291
231
|
}
|
|
292
|
-
|
|
293
|
-
const
|
|
294
|
-
const
|
|
232
|
+
linkRemoteService(factory) {
|
|
233
|
+
const service = factory.name;
|
|
234
|
+
const omitProperties = new Set([
|
|
295
235
|
'caller',
|
|
296
236
|
'callee',
|
|
297
237
|
'arguments',
|
|
@@ -313,117 +253,110 @@ export class SpiderMesh {
|
|
|
313
253
|
'beforeApplicationShutdown',
|
|
314
254
|
'onApplicationShutdown'
|
|
315
255
|
]);
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
get: (_,
|
|
328
|
-
if (
|
|
329
|
-
return
|
|
256
|
+
const listRpcNodes = () => {
|
|
257
|
+
const targets = this.#services$.value.get(service);
|
|
258
|
+
if (!targets || targets.nodes.length == 0)
|
|
259
|
+
return [];
|
|
260
|
+
return targets.nodes.map(id => {
|
|
261
|
+
const node = this.#nodes.value.nodes.get(id);
|
|
262
|
+
if (node && node.rpc)
|
|
263
|
+
return node;
|
|
264
|
+
}).filter(Boolean).map(node => node);
|
|
265
|
+
};
|
|
266
|
+
const target = new Proxy({}, {
|
|
267
|
+
get: (_, $) => {
|
|
268
|
+
if (omitProperties.has($))
|
|
269
|
+
return null;
|
|
270
|
+
if ($ == 'wait$') {
|
|
271
|
+
return (fn) => this.waitServiceOnline(service, fn);
|
|
330
272
|
}
|
|
331
|
-
if (
|
|
332
|
-
return ()
|
|
333
|
-
if (
|
|
334
|
-
return (
|
|
273
|
+
if ($ == 'nodes')
|
|
274
|
+
return listRpcNodes();
|
|
275
|
+
if ($ == 'watch$')
|
|
276
|
+
return (fn = (nodes => nodes.length > 0)) => {
|
|
277
|
+
return this.#services$.pipe(map(services => services.get(service)?.nodes || []), map(targets => targets.map(id => this.#nodes.value.nodes.get(id)).filter(Boolean)));
|
|
278
|
+
};
|
|
279
|
+
if ($.startsWith('__batch__')) {
|
|
280
|
+
const method = $.split('__batch__')?.[1];
|
|
281
|
+
return (...args) => from(listRpcNodes()).pipe(mergeMap(node => (this.callRemoteService({
|
|
282
|
+
service,
|
|
283
|
+
args,
|
|
284
|
+
method,
|
|
285
|
+
node_id: node.node_id,
|
|
286
|
+
}).pipe(map(data => ({ node, data })), catchError(e => of({ node, e }))))));
|
|
335
287
|
}
|
|
336
|
-
if (
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
288
|
+
if ($ == 'set') {
|
|
289
|
+
return (options) => new Proxy({}, {
|
|
290
|
+
get: (_, method) => {
|
|
291
|
+
return (...args) => {
|
|
292
|
+
const response = this.callRemoteService({
|
|
293
|
+
...options,
|
|
294
|
+
args,
|
|
295
|
+
method,
|
|
296
|
+
service
|
|
297
|
+
});
|
|
298
|
+
return Object.assign(response, {
|
|
299
|
+
then: async (s, r) => {
|
|
300
|
+
try {
|
|
301
|
+
s(await firstValueFrom(response));
|
|
302
|
+
}
|
|
303
|
+
catch (e) {
|
|
304
|
+
r(e);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
return (...args) => {
|
|
313
|
+
const response = this.callRemoteService({
|
|
314
|
+
args,
|
|
315
|
+
method: $,
|
|
316
|
+
service
|
|
317
|
+
});
|
|
318
|
+
return Object.assign(response, {
|
|
319
|
+
then: async (s, r) => {
|
|
344
320
|
try {
|
|
345
|
-
|
|
346
|
-
return { data, node, error: null };
|
|
321
|
+
s(await firstValueFrom(response));
|
|
347
322
|
}
|
|
348
|
-
catch (
|
|
349
|
-
|
|
323
|
+
catch (e) {
|
|
324
|
+
r(e);
|
|
350
325
|
}
|
|
351
|
-
})).subscribe(o);
|
|
352
|
-
return o;
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
if (actions.has(method) || method.startsWith('$')) {
|
|
356
|
-
return new DeepProxy(method => RPCOptionsList.has(method), (method, options) => (async (...args) => {
|
|
357
|
-
const safe = options.$safe_mode;
|
|
358
|
-
try {
|
|
359
|
-
const data = await this.rpc(service_name, method, args, options);
|
|
360
|
-
return safe ? [null, data] : data;
|
|
361
326
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
return [e, null];
|
|
365
|
-
throw e;
|
|
366
|
-
}
|
|
367
|
-
})).nest()[method];
|
|
368
|
-
}
|
|
369
|
-
return null;
|
|
327
|
+
});
|
|
328
|
+
};
|
|
370
329
|
}
|
|
371
330
|
});
|
|
331
|
+
return new Proxy(target, {
|
|
332
|
+
get(target, p) {
|
|
333
|
+
if (p == 'then')
|
|
334
|
+
return target;
|
|
335
|
+
return target[p];
|
|
336
|
+
},
|
|
337
|
+
});
|
|
372
338
|
}
|
|
373
|
-
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
339
|
+
linkEvent(factory) {
|
|
340
|
+
const topic = factory.name;
|
|
341
|
+
return {
|
|
342
|
+
publish: (data) => lastValueFrom(from(this.#pubsubs.getValue().values()).pipe(mergeMap(t => t.publish(topic, data))), { defaultValue: undefined }),
|
|
343
|
+
listen: () => {
|
|
344
|
+
return this.#pubsubs.pipe(map(list => [...list.values()]), mergeAll(), mergeMap(t => t.listen(topic)));
|
|
345
|
+
}
|
|
380
346
|
};
|
|
381
|
-
return event_hub;
|
|
382
347
|
}
|
|
383
|
-
async
|
|
384
|
-
const
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
async #wait_service_online(service_name = 'all') {
|
|
396
|
-
if (this.#remote_rpc_services.size == 0)
|
|
397
|
-
return;
|
|
398
|
-
while (true) {
|
|
399
|
-
await sleep(500);
|
|
400
|
-
const nodes = service_name == 'all' ? ([...this.#remote_rpc_services.values()].map(s => s.nodes).flat(2)) : (this.#remote_rpc_services.get(service_name)?.nodes || []);
|
|
401
|
-
if (nodes.length > 0)
|
|
402
|
-
break;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
async #active_ready_hooks(instance) {
|
|
406
|
-
await this.#wait_service_online();
|
|
407
|
-
for (const { method } of listReadyHookMethods(Object.getPrototypeOf(instance))) {
|
|
408
|
-
instance[method]?.();
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
async publish(topic, payload, node_id) {
|
|
412
|
-
await this.#initing;
|
|
413
|
-
const event = typeof topic == 'string' ? topic : topic.name;
|
|
414
|
-
const data = Array.isArray(payload) ? payload : [payload];
|
|
415
|
-
this.transporter.publish({ event, data, node_id });
|
|
416
|
-
}
|
|
417
|
-
listen(topic) {
|
|
418
|
-
const topic_name = typeof topic == 'string' ? topic : topic.name;
|
|
419
|
-
return this.transporter.listen(topic_name).pipe(map(e => {
|
|
420
|
-
if (!Array.isArray(e.data))
|
|
421
|
-
return [];
|
|
422
|
-
return e.data.map(data => ({
|
|
423
|
-
data,
|
|
424
|
-
sender_node_id: e.sender_node_id
|
|
425
|
-
}));
|
|
426
|
-
}), mergeAll());
|
|
348
|
+
async exposeLocalService(name, instance) {
|
|
349
|
+
const hooks = listBeforeMicroserviceOnlineMethods(instance);
|
|
350
|
+
for (const method of hooks)
|
|
351
|
+
await instance[method];
|
|
352
|
+
services$.next({
|
|
353
|
+
...services$.value,
|
|
354
|
+
[name]: {
|
|
355
|
+
instance,
|
|
356
|
+
metadata: {},
|
|
357
|
+
name
|
|
358
|
+
}
|
|
359
|
+
});
|
|
427
360
|
}
|
|
428
361
|
}
|
|
429
362
|
//# sourceMappingURL=SpiderMesh.js.map
|