oox 0.3.4 → 0.3.6
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/README.md +13 -0
- package/app.js +1 -7
- package/bin/cli.js +45 -12
- package/bin/configurer.js +6 -9
- package/bin/proxy-require.js +1 -23
- package/bin/register.js +48 -15
- package/bin/starter.js +8 -0
- package/config.js +145 -0
- package/context.js +58 -0
- package/index.js +14 -133
- package/keepalive-connection.js +73 -0
- package/logger.js +2 -1
- package/modules/http/index.js +52 -63
- package/modules/http/router.js +9 -4
- package/modules/index.js +78 -74
- package/modules/module.js +1 -10
- package/modules/socketio/adapter.js +24 -13
- package/modules/socketio/server.js +37 -16
- package/modules/socketio/utils.js +12 -7
- package/package.json +13 -6
- package/proxy.js +30 -0
- package/registry.js +91 -7
- package/samples/index.js +1 -1
- package/samples/keepalive-connection-sample.js +62 -41
- package/types/app.d.ts +18 -24
- package/types/bin/configurer.d.ts +3 -1
- package/types/bin/register.d.ts +2 -1
- package/types/config.d.ts +66 -0
- package/types/context.d.ts +30 -0
- package/types/index.d.ts +10 -53
- package/types/keepalive-connection.d.ts +52 -16
- package/types/modules/http/index.d.ts +5 -8
- package/types/modules/index.d.ts +37 -22
- package/types/modules/module.d.ts +9 -9
- package/types/modules/socketio/adapter.d.ts +9 -4
- package/types/modules/socketio/server.d.ts +6 -4
- package/types/modules/socketio/utils.d.ts +12 -6
- package/types/proxy.d.ts +1 -0
- package/types/registry.d.ts +28 -3
- package/types/samples/index.d.ts +1 -1
- package/types/samples/keepalive-connection-sample.d.ts +33 -23
- package/utils.js +2 -2
|
@@ -2,10 +2,12 @@ import * as http from 'node:http';
|
|
|
2
2
|
import * as https from 'node:https';
|
|
3
3
|
import { Server } from 'socket.io';
|
|
4
4
|
import * as oox from '../../index.js';
|
|
5
|
-
import { Module
|
|
5
|
+
import { Module } from '../module.js';
|
|
6
6
|
import SocketIOAdapter from './adapter.js';
|
|
7
7
|
import { OOXEvent } from './utils.js';
|
|
8
|
-
|
|
8
|
+
import { randomUUID } from 'node:crypto';
|
|
9
|
+
export class SocketIOConfig {
|
|
10
|
+
enabled = true;
|
|
9
11
|
// listen port
|
|
10
12
|
port = 0;
|
|
11
13
|
// service path
|
|
@@ -34,6 +36,10 @@ export default class SocketIOServer extends Module {
|
|
|
34
36
|
server = null;
|
|
35
37
|
socketServer = null;
|
|
36
38
|
adapter = new SocketIOAdapter();
|
|
39
|
+
constructor() {
|
|
40
|
+
super();
|
|
41
|
+
oox.keepAliveConnectionAdapters.set(this.name, this.adapter);
|
|
42
|
+
}
|
|
37
43
|
getURL() {
|
|
38
44
|
const { host } = oox.config;
|
|
39
45
|
const { port, path } = this.config;
|
|
@@ -53,21 +59,22 @@ export default class SocketIOServer extends Module {
|
|
|
53
59
|
return this.config;
|
|
54
60
|
}
|
|
55
61
|
async serve() {
|
|
56
|
-
oox.keepAliveConnectionAdapters.set(this.name, this.adapter);
|
|
57
62
|
await this.stop();
|
|
58
63
|
const { port, ssl } = this.config;
|
|
59
64
|
const isSelfServer = this.#isSelfServer = this.server ? true : false;
|
|
60
|
-
let server;
|
|
65
|
+
let server = null;
|
|
61
66
|
if (isSelfServer) {
|
|
67
|
+
if (!this.server)
|
|
68
|
+
throw new Error('HTTP Server is not created');
|
|
62
69
|
server = this.server;
|
|
63
70
|
}
|
|
64
71
|
else {
|
|
65
72
|
if (ssl.enabled) {
|
|
66
73
|
const fs = await import('node:fs');
|
|
67
74
|
const options = {
|
|
68
|
-
key: ssl.key ? fs.readFileSync(ssl.key) :
|
|
69
|
-
cert: ssl.cert ? fs.readFileSync(ssl.cert) :
|
|
70
|
-
ca: ssl.ca ? fs.readFileSync(ssl.ca) :
|
|
75
|
+
key: ssl.key ? fs.readFileSync(ssl.key) : undefined,
|
|
76
|
+
cert: ssl.cert ? fs.readFileSync(ssl.cert) : undefined,
|
|
77
|
+
ca: ssl.ca ? fs.readFileSync(ssl.ca) : undefined
|
|
71
78
|
};
|
|
72
79
|
if (!options.key || !options.cert) {
|
|
73
80
|
throw new Error('HTTPS enabled but missing key or cert');
|
|
@@ -88,10 +95,11 @@ export default class SocketIOServer extends Module {
|
|
|
88
95
|
this.createSocketIOServer();
|
|
89
96
|
}
|
|
90
97
|
async stop() {
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
const { server, socketServer } = this;
|
|
99
|
+
if (socketServer)
|
|
100
|
+
await new Promise((resolve, reject) => socketServer.close(error => error ? reject(error) : resolve()));
|
|
93
101
|
if (this.#isSelfServer)
|
|
94
|
-
await new Promise((resolve, reject) =>
|
|
102
|
+
await new Promise((resolve, reject) => server?.close(error => error ? reject(error) : resolve()));
|
|
95
103
|
}
|
|
96
104
|
genSocketIOServerOptions() {
|
|
97
105
|
const options = {
|
|
@@ -127,7 +135,12 @@ export default class SocketIOServer extends Module {
|
|
|
127
135
|
return options;
|
|
128
136
|
}
|
|
129
137
|
createSocketIOServer() {
|
|
130
|
-
const
|
|
138
|
+
const { server } = this;
|
|
139
|
+
if (!server)
|
|
140
|
+
throw new Error('HTTP Server is not created');
|
|
141
|
+
const socketServer = this.socketServer = new Server(server, {
|
|
142
|
+
...this.genSocketIOServerOptions(),
|
|
143
|
+
});
|
|
131
144
|
socketServer.on('connection', async (socket) => {
|
|
132
145
|
try {
|
|
133
146
|
this.serverOnSocketConnection(socket);
|
|
@@ -143,24 +156,32 @@ export default class SocketIOServer extends Module {
|
|
|
143
156
|
*/
|
|
144
157
|
serverOnSocketConnection(socket) {
|
|
145
158
|
const headers = socket.handshake.headers;
|
|
146
|
-
const callerId = String(headers['x-caller-id'] ||
|
|
159
|
+
const callerId = String(headers['x-caller-id'] || randomUUID());
|
|
147
160
|
// client ip or caller service ip
|
|
148
|
-
const ip = String(headers['x-real-ip'] ||
|
|
161
|
+
const ip = String(headers['x-real-ip'] || socket.handshake.address);
|
|
149
162
|
// service name
|
|
150
163
|
const caller = String(headers['x-caller'] || 'anonymous');
|
|
164
|
+
const token = String(headers['x-token'] || '');
|
|
165
|
+
// check token
|
|
166
|
+
const { allow, reason } = oox.checkAllow(ip, caller, token);
|
|
167
|
+
if (!allow) {
|
|
168
|
+
socket.send(reason).disconnect(true);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
151
171
|
const connection = new oox.KeepAliveConnection(this.adapter, socket, {
|
|
152
|
-
|
|
172
|
+
ip,
|
|
153
173
|
name: caller,
|
|
154
174
|
id: callerId,
|
|
175
|
+
token,
|
|
155
176
|
});
|
|
156
177
|
oox.addKeepAliveConnection(connection);
|
|
157
178
|
this.bindServerConnectionEvents(connection);
|
|
158
179
|
this.adapter.bindCall(connection);
|
|
159
|
-
connection.enabled = true;
|
|
160
180
|
socket.emit(OOXEvent.READY, {
|
|
161
181
|
id: oox.config.id,
|
|
162
182
|
name: oox.config.name
|
|
163
183
|
});
|
|
184
|
+
connection.enabled = true;
|
|
164
185
|
}
|
|
165
186
|
/**
|
|
166
187
|
* 绑定服务器连接事件
|
|
@@ -168,7 +189,7 @@ export default class SocketIOServer extends Module {
|
|
|
168
189
|
*/
|
|
169
190
|
bindServerConnectionEvents(connection) {
|
|
170
191
|
const socket = connection.nativeConnection;
|
|
171
|
-
socket.on(OOXEvent.
|
|
192
|
+
socket.on(OOXEvent.REGISTRY_SYNC_CONNECTIONS, async (fn) => {
|
|
172
193
|
if ('function' !== typeof fn)
|
|
173
194
|
return;
|
|
174
195
|
oox.registry.onSyncConnections(connection, {}, fn);
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
export const OOXEvent = {
|
|
2
|
+
CONNECT: 'connect',
|
|
3
|
+
DISCONNECT: 'disconnect',
|
|
4
|
+
ERROR: 'error',
|
|
5
|
+
CALL: 'call',
|
|
6
|
+
READY: 'oox:ready',
|
|
7
|
+
ENABLED: 'oox:enabled',
|
|
8
|
+
DISABLED: 'oox:disabled',
|
|
9
|
+
REGISTRY_SYNC_CONNECTIONS: 'oox:registry:sync_connections',
|
|
10
|
+
REGISTRY_SUBSCRIBE: 'oox:registry:subscribe',
|
|
11
|
+
REGISTRY_NOTIFY: 'oox:registry:notify',
|
|
12
|
+
};
|
|
8
13
|
export function isWebSocketURL(url) {
|
|
9
14
|
if ('string' === typeof url) {
|
|
10
15
|
return /^wss?:\/\/.+$/.test(url);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oox",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "OOX Service Engine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"http",
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
"framework",
|
|
11
11
|
"microservice",
|
|
12
12
|
"distributed",
|
|
13
|
-
"tracing"
|
|
13
|
+
"tracing",
|
|
14
|
+
"service-discovery",
|
|
15
|
+
"load-balancing"
|
|
14
16
|
],
|
|
15
17
|
"type": "module",
|
|
16
18
|
"main": "./index.js",
|
|
@@ -22,15 +24,20 @@
|
|
|
22
24
|
"types": "./types/index.d.ts"
|
|
23
25
|
},
|
|
24
26
|
"./loader": "./bin/loader.mjs",
|
|
25
|
-
"./cli":
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
"./cli": {
|
|
28
|
+
"default": "./bin/cli.js",
|
|
29
|
+
"types": "./types/bin/cli.d.ts"
|
|
30
|
+
},
|
|
31
|
+
"./samples": {
|
|
32
|
+
"types": "./types/samples/index.d.ts",
|
|
33
|
+
"default": "./samples/index.js"
|
|
34
|
+
}
|
|
28
35
|
},
|
|
29
36
|
"bin": {
|
|
30
37
|
"oox": "./bin/cli.js"
|
|
31
38
|
},
|
|
32
39
|
"author": "lipingruan",
|
|
33
|
-
"homepage": "https://
|
|
40
|
+
"homepage": "https://gitee.com/lipingruan/oox",
|
|
34
41
|
"license": "MIT",
|
|
35
42
|
"dependencies": {
|
|
36
43
|
"chalk": "^5.6.2",
|
package/proxy.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { rpc } from './keepalive-connection.js';
|
|
2
|
+
/**
|
|
3
|
+
* 为了不重复创建Proxy,这个对象用于保存各个RPC服务的各个属性Proxy
|
|
4
|
+
*/
|
|
5
|
+
const rpcServiceAttrMap = Object.create(null);
|
|
6
|
+
export function proxy(name, action = '') {
|
|
7
|
+
return new Proxy(function () { }, {
|
|
8
|
+
get(target, key) {
|
|
9
|
+
if (typeof key !== 'string')
|
|
10
|
+
return undefined;
|
|
11
|
+
const attrKey = action ? action + '.' + key : key;
|
|
12
|
+
const attrKeyPath = name + '.' + attrKey;
|
|
13
|
+
if (attrKeyPath in rpcServiceAttrMap) {
|
|
14
|
+
// 不重复创建Proxy
|
|
15
|
+
return rpcServiceAttrMap[attrKeyPath];
|
|
16
|
+
}
|
|
17
|
+
const attrProxy = proxy(name, attrKey);
|
|
18
|
+
rpcServiceAttrMap[attrKeyPath] = attrProxy;
|
|
19
|
+
return attrProxy;
|
|
20
|
+
},
|
|
21
|
+
has(target, key) {
|
|
22
|
+
if (typeof key !== 'string')
|
|
23
|
+
return false;
|
|
24
|
+
return true;
|
|
25
|
+
},
|
|
26
|
+
apply(target, thisArg, args) {
|
|
27
|
+
return rpc(name, action, args);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
package/registry.js
CHANGED
|
@@ -1,5 +1,71 @@
|
|
|
1
|
-
import { config } from './
|
|
1
|
+
import { config } from './config.js';
|
|
2
2
|
import { enabledKeepAliveConnections, keepAliveConnectionAdapters, keepAliveConnections } from './keepalive-connection.js';
|
|
3
|
+
const unsubscribeListeners = new Map();
|
|
4
|
+
const subscribes = new Map();
|
|
5
|
+
let broadcastTimer = null;
|
|
6
|
+
/**
|
|
7
|
+
* 取消订阅连接列表
|
|
8
|
+
* @param connection
|
|
9
|
+
*/
|
|
10
|
+
export function unsubscribe(connection) {
|
|
11
|
+
subscribes.delete(connection);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 订阅连接列表
|
|
15
|
+
* @param connection
|
|
16
|
+
* @param query
|
|
17
|
+
* @returns
|
|
18
|
+
*/
|
|
19
|
+
export function subscribe(connection, query) {
|
|
20
|
+
if (!config.isRegistry)
|
|
21
|
+
return;
|
|
22
|
+
if (!unsubscribeListeners.has(connection)) {
|
|
23
|
+
const listener = () => {
|
|
24
|
+
unsubscribe(connection);
|
|
25
|
+
};
|
|
26
|
+
unsubscribeListeners.set(connection, listener);
|
|
27
|
+
connection.once('disconnect', listener);
|
|
28
|
+
}
|
|
29
|
+
subscribes.set(connection, query);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 停止广播连接列表
|
|
33
|
+
*/
|
|
34
|
+
export function stopBroadcastTimer() {
|
|
35
|
+
if (!broadcastTimer)
|
|
36
|
+
return;
|
|
37
|
+
clearInterval(broadcastTimer);
|
|
38
|
+
broadcastTimer = null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 开始广播连接列表
|
|
42
|
+
*/
|
|
43
|
+
export function startBroadcastTimer() {
|
|
44
|
+
if (!config.isRegistry)
|
|
45
|
+
return;
|
|
46
|
+
if (broadcastTimer)
|
|
47
|
+
clearInterval(broadcastTimer);
|
|
48
|
+
broadcastTimer = setInterval(broadcast, 1000);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 广播连接列表
|
|
52
|
+
*/
|
|
53
|
+
export function broadcast() {
|
|
54
|
+
if (!config.isRegistry)
|
|
55
|
+
return;
|
|
56
|
+
for (const [connection, query] of subscribes.entries()) {
|
|
57
|
+
try {
|
|
58
|
+
onSyncConnections(connection, query, returns => {
|
|
59
|
+
if (!returns.success)
|
|
60
|
+
return;
|
|
61
|
+
connection.adapter['registry:notify'](connection, returns.body || []);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
console.error(error);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
3
69
|
/**
|
|
4
70
|
* 服务器发送连接列表
|
|
5
71
|
* @param connection
|
|
@@ -8,8 +74,16 @@ import { enabledKeepAliveConnections, keepAliveConnectionAdapters, keepAliveConn
|
|
|
8
74
|
*/
|
|
9
75
|
export function onSyncConnections(connection, query, callback) {
|
|
10
76
|
// 检查是否开启服务注册功能
|
|
11
|
-
if (!config.isRegistry)
|
|
12
|
-
|
|
77
|
+
if (!config.isRegistry) {
|
|
78
|
+
const returns = {
|
|
79
|
+
success: false,
|
|
80
|
+
error: {
|
|
81
|
+
message: 'Service registration is not enabled',
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
callback(returns);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
13
87
|
const datas = [];
|
|
14
88
|
if (query.name) {
|
|
15
89
|
const names = Array.isArray(query.name) ? query.name : [query.name];
|
|
@@ -34,14 +108,24 @@ export function onSyncConnections(connection, query, callback) {
|
|
|
34
108
|
}
|
|
35
109
|
}
|
|
36
110
|
}
|
|
37
|
-
|
|
111
|
+
const returns = {
|
|
112
|
+
success: true,
|
|
113
|
+
body: datas,
|
|
114
|
+
};
|
|
115
|
+
callback(returns);
|
|
38
116
|
}
|
|
39
117
|
/**
|
|
40
118
|
* 同步连接列表
|
|
41
119
|
* @param datas 连接参数列表
|
|
42
120
|
*/
|
|
43
|
-
export function syncConnections(
|
|
44
|
-
|
|
121
|
+
export function syncConnections(returns) {
|
|
122
|
+
if (!returns.success) {
|
|
123
|
+
if (returns.error) {
|
|
124
|
+
console.error(new Error(returns.error.message || 'Sync connections failed'));
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
for (const data of returns.body || []) {
|
|
45
129
|
// 获取适配器
|
|
46
130
|
const adapter = keepAliveConnectionAdapters.get(data.adapter);
|
|
47
131
|
if (!adapter)
|
|
@@ -56,6 +140,6 @@ export function syncConnections(datas) {
|
|
|
56
140
|
if (keepAliveConnections.has(data.name, data.id))
|
|
57
141
|
continue;
|
|
58
142
|
// 建立连接
|
|
59
|
-
adapter.open(data
|
|
143
|
+
adapter.open(data).catch((error) => console.error(error));
|
|
60
144
|
}
|
|
61
145
|
}
|
package/samples/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from './keepalive-connection-sample.js';
|
|
@@ -1,22 +1,44 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as registry from '../registry.js';
|
|
2
|
+
import { config } from '../config.js';
|
|
3
|
+
import { getContext, genContext, } from '../context.js';
|
|
4
|
+
import { KeepAliveConnectionError, addKeepAliveConnection, removeKeepAliveConnection, } from '../keepalive-connection.js';
|
|
5
|
+
import { call, } from '../app.js';
|
|
2
6
|
export class SampleKeepAliveConnectionAdapter {
|
|
3
|
-
name;
|
|
4
7
|
OOXEvent = {
|
|
5
|
-
READY: 'oox:ready',
|
|
6
|
-
ENABLED: 'oox:enabled',
|
|
7
|
-
DISABLED: 'oox:disabled',
|
|
8
|
-
SYNC_CONNECTIONS: 'oox:sync_connections',
|
|
9
|
-
};
|
|
10
|
-
nativeEvent = {
|
|
11
8
|
CONNECT: 'connect',
|
|
12
9
|
DISCONNECT: 'disconnect',
|
|
13
10
|
ERROR: 'error',
|
|
11
|
+
CALL: 'call',
|
|
12
|
+
READY: 'oox:ready',
|
|
13
|
+
ENABLED: 'oox:enabled',
|
|
14
|
+
DISABLED: 'oox:disabled',
|
|
15
|
+
REGISTRY_SYNC_CONNECTIONS: 'oox:registry:sync_connections',
|
|
16
|
+
REGISTRY_SUBSCRIBE: 'oox:registry:subscribe',
|
|
17
|
+
REGISTRY_NOTIFY: 'oox:registry:notify',
|
|
14
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* 通知连接列表
|
|
21
|
+
*/
|
|
22
|
+
['registry:notify'](connection, datas) {
|
|
23
|
+
connection.nativeConnection.emit(this.OOXEvent.REGISTRY_NOTIFY, datas);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 订阅连接列表
|
|
27
|
+
*/
|
|
28
|
+
['registry:subscribe'](connection, query) {
|
|
29
|
+
connection.nativeConnection.emit(this.OOXEvent.REGISTRY_SUBSCRIBE, query);
|
|
30
|
+
}
|
|
15
31
|
bindConnectionEvents(connection) {
|
|
16
32
|
const socket = connection.nativeConnection;
|
|
17
33
|
socket.on(this.OOXEvent.READY, (params) => {
|
|
18
34
|
connection.ready(params);
|
|
19
|
-
socket.emit(this.OOXEvent.
|
|
35
|
+
socket.emit(this.OOXEvent.REGISTRY_SYNC_CONNECTIONS, registry.syncConnections);
|
|
36
|
+
});
|
|
37
|
+
socket.on(this.OOXEvent.REGISTRY_NOTIFY, (datas) => {
|
|
38
|
+
registry.syncConnections({
|
|
39
|
+
success: true,
|
|
40
|
+
body: datas,
|
|
41
|
+
});
|
|
20
42
|
});
|
|
21
43
|
socket.on(this.OOXEvent.ENABLED, () => {
|
|
22
44
|
connection.enabled = true;
|
|
@@ -24,25 +46,23 @@ export class SampleKeepAliveConnectionAdapter {
|
|
|
24
46
|
socket.on(this.OOXEvent.DISABLED, () => {
|
|
25
47
|
connection.enabled = false;
|
|
26
48
|
});
|
|
27
|
-
socket.on(this.
|
|
28
|
-
connection
|
|
29
|
-
oox.removeKeepAliveConnection(connection);
|
|
49
|
+
socket.on(this.OOXEvent.DISCONNECT, () => {
|
|
50
|
+
removeKeepAliveConnection(connection);
|
|
30
51
|
socket.removeAllListeners();
|
|
31
|
-
|
|
52
|
+
connection.emit('disconnect');
|
|
32
53
|
});
|
|
33
|
-
socket.on(this.
|
|
54
|
+
socket.on(this.OOXEvent.CONNECT, () => {
|
|
34
55
|
connection.emit('connect');
|
|
35
56
|
});
|
|
36
|
-
socket.on(this.
|
|
37
|
-
connection
|
|
38
|
-
oox.removeKeepAliveConnection(connection);
|
|
57
|
+
socket.on(this.OOXEvent.ERROR, (error) => {
|
|
58
|
+
removeKeepAliveConnection(connection);
|
|
39
59
|
socket.removeAllListeners();
|
|
40
|
-
|
|
60
|
+
connection.emit('error', new KeepAliveConnectionError(error.message, connection));
|
|
41
61
|
});
|
|
42
62
|
}
|
|
43
|
-
async open(
|
|
44
|
-
const connection = this.newConnection(
|
|
45
|
-
|
|
63
|
+
async open(identify) {
|
|
64
|
+
const connection = this.newConnection(identify);
|
|
65
|
+
addKeepAliveConnection(connection);
|
|
46
66
|
this.bindConnectionEvents(connection);
|
|
47
67
|
this.bindCall(connection);
|
|
48
68
|
await new Promise((resolve, reject) => {
|
|
@@ -76,9 +96,9 @@ export class SampleKeepAliveConnectionAdapter {
|
|
|
76
96
|
reject(new Error(message));
|
|
77
97
|
};
|
|
78
98
|
// RPC 执行时中断连接
|
|
79
|
-
socket.once(this.
|
|
99
|
+
socket.once(this.OOXEvent.DISCONNECT, onError);
|
|
80
100
|
socket.emit(event, ...params, (returns) => {
|
|
81
|
-
socket.off(this.
|
|
101
|
+
socket.off(this.OOXEvent.DISCONNECT, onError);
|
|
82
102
|
resolve(returns);
|
|
83
103
|
});
|
|
84
104
|
});
|
|
@@ -88,8 +108,12 @@ export class SampleKeepAliveConnectionAdapter {
|
|
|
88
108
|
*/
|
|
89
109
|
async rpc(connection, action, params, context) {
|
|
90
110
|
if (!context)
|
|
91
|
-
context =
|
|
92
|
-
const
|
|
111
|
+
context = getContext();
|
|
112
|
+
const miniContext = {
|
|
113
|
+
sourceIP: context.sourceIP,
|
|
114
|
+
traceId: context.traceId,
|
|
115
|
+
};
|
|
116
|
+
const { success, error, body } = await this.emit(connection.nativeConnection, this.OOXEvent.CALL, [action, params, miniContext]);
|
|
93
117
|
if (success)
|
|
94
118
|
return body;
|
|
95
119
|
else if (error)
|
|
@@ -102,25 +126,22 @@ export class SampleKeepAliveConnectionAdapter {
|
|
|
102
126
|
* @param connection
|
|
103
127
|
*/
|
|
104
128
|
bindCall(connection) {
|
|
105
|
-
const { id, name,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
else
|
|
117
|
-
context = oox.genContext(Object.assign(context, connectionContext));
|
|
118
|
-
this.call(action, params, context, callback);
|
|
129
|
+
const { id, name, ip } = connection.data;
|
|
130
|
+
connection.nativeConnection.on(this.OOXEvent.CALL, async (action, params, context, callback) => {
|
|
131
|
+
const validContext = genContext({
|
|
132
|
+
sourceIP: ip,
|
|
133
|
+
...context,
|
|
134
|
+
ip: ip,
|
|
135
|
+
caller: name,
|
|
136
|
+
callerId: id,
|
|
137
|
+
connection
|
|
138
|
+
});
|
|
139
|
+
this.call(action, params, validContext, callback);
|
|
119
140
|
});
|
|
120
141
|
}
|
|
121
142
|
async call(action, params, context, callback) {
|
|
122
|
-
const returns = await
|
|
123
|
-
if (returns.error && !
|
|
143
|
+
const returns = await call(action, params, context);
|
|
144
|
+
if (returns.error && !config.errorStack) {
|
|
124
145
|
// 不返回错误调用栈信息
|
|
125
146
|
delete returns.error.stack;
|
|
126
147
|
}
|
package/types/app.d.ts
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
|
-
import {
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
traceId: string;
|
|
2
|
+
import { AppContext } from './context.js';
|
|
3
|
+
export interface ReturnsBody<T = any> {
|
|
4
|
+
traceId?: string;
|
|
6
5
|
success: boolean;
|
|
7
|
-
body?:
|
|
6
|
+
body?: T;
|
|
8
7
|
error?: {
|
|
9
8
|
message: string;
|
|
10
9
|
stack?: string;
|
|
11
10
|
};
|
|
12
11
|
}
|
|
13
|
-
export declare class Context {
|
|
14
|
-
[x: string]: any;
|
|
15
|
-
traceId?: string;
|
|
16
|
-
}
|
|
17
|
-
export declare const asyncStore: AsyncLocalStorage<Context>;
|
|
18
12
|
export declare const eventHub: EventEmitter<[never]>;
|
|
19
13
|
/**
|
|
20
14
|
* the kvMethods is all actions refs [has bind this]
|
|
@@ -24,21 +18,21 @@ export declare const sourceKVMethods: Map<string, Function>;
|
|
|
24
18
|
export declare function setMethods(methods: any): void;
|
|
25
19
|
export declare function getMethods(): any;
|
|
26
20
|
export declare function on(event: 'app:configured' | 'app:served' | 'app:stopped', listener: () => void): void;
|
|
27
|
-
export declare function on(event: 'call:start', listener: (timestamp: number, action: string, params: any[], context:
|
|
28
|
-
export declare function on(event: 'call:success', listener: (timestamp: number, action: string, params: any[], context:
|
|
29
|
-
export declare function on(event: 'call:fail', listener: (timestamp: number, action: string, params: any[], context:
|
|
30
|
-
export declare function on(event: 'log', listener: (timestamp: number, context:
|
|
21
|
+
export declare function on(event: 'call:start', listener: (timestamp: number, action: string, params: any[], context: AppContext) => void): void;
|
|
22
|
+
export declare function on(event: 'call:success', listener: (timestamp: number, action: string, params: any[], context: AppContext, result: ReturnsBody) => void): void;
|
|
23
|
+
export declare function on(event: 'call:fail', listener: (timestamp: number, action: string, params: any[], context: AppContext, error: Error) => void): void;
|
|
24
|
+
export declare function on(event: 'log', listener: (timestamp: number, context: AppContext | null, level: string, msgs: any[]) => void): void;
|
|
31
25
|
export declare function once(event: 'app:configured' | 'app:served' | 'app:stopped', listener: (...args: any[]) => void): void;
|
|
32
|
-
export declare function once(event: 'call:start', listener: (timestamp: number, action: string, params: any[], context:
|
|
33
|
-
export declare function once(event: 'call:success', listener: (timestamp: number, action: string, params: any[], context:
|
|
34
|
-
export declare function once(event: 'call:fail', listener: (timestamp: number, action: string, params: any[], context:
|
|
35
|
-
export declare function once(event: 'log', listener: (timestamp: number, context:
|
|
26
|
+
export declare function once(event: 'call:start', listener: (timestamp: number, action: string, params: any[], context: AppContext) => void): void;
|
|
27
|
+
export declare function once(event: 'call:success', listener: (timestamp: number, action: string, params: any[], context: AppContext, result: ReturnsBody) => void): void;
|
|
28
|
+
export declare function once(event: 'call:fail', listener: (timestamp: number, action: string, params: any[], context: AppContext, error: Error) => void): void;
|
|
29
|
+
export declare function once(event: 'log', listener: (timestamp: number, context: AppContext | null, level: string, msgs: any[]) => void): void;
|
|
36
30
|
export declare function off(event: 'app:configured' | 'app:served' | 'app:stopped' | 'call:start' | 'call:success' | 'call:fail' | 'log', listener: (...args: any[]) => void): void;
|
|
37
31
|
export declare function emit(event: 'app:configured' | 'app:served' | 'app:stopped'): boolean;
|
|
38
|
-
export declare function emit(event: 'call:start', timestamp: number, action: string, params: any[], context:
|
|
39
|
-
export declare function emit(event: 'call:success', timestamp: number, action: string, params: any[], context:
|
|
40
|
-
export declare function emit(event: 'call:fail', timestamp: number, action: string, params: any[], context:
|
|
41
|
-
export declare function emit(event: 'log', timestamp: number, context:
|
|
32
|
+
export declare function emit(event: 'call:start', timestamp: number, action: string, params: any[], context: AppContext): boolean;
|
|
33
|
+
export declare function emit(event: 'call:success', timestamp: number, action: string, params: any[], context: AppContext, result: ReturnsBody): boolean;
|
|
34
|
+
export declare function emit(event: 'call:fail', timestamp: number, action: string, params: any[], context: AppContext, error: Error): boolean;
|
|
35
|
+
export declare function emit(event: 'log', timestamp: number, context: AppContext | null, level: string, content: any): boolean;
|
|
42
36
|
/**
|
|
43
37
|
* Call an Function on RPC server
|
|
44
38
|
* @param action
|
|
@@ -46,5 +40,5 @@ export declare function emit(event: 'log', timestamp: number, context: Context |
|
|
|
46
40
|
* @param context
|
|
47
41
|
* @returns
|
|
48
42
|
*/
|
|
49
|
-
export declare function call(action: string, params: any[], context:
|
|
50
|
-
export declare function execute(action: string, params: Array<any>, context:
|
|
43
|
+
export declare function call(action: string, params: any[] | undefined, context: AppContext): Promise<ReturnsBody>;
|
|
44
|
+
export declare function execute(action: string, params: Array<any>, context: AppContext): Promise<any>;
|
package/types/bin/register.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import * as oox from '../index.js';
|
|
2
|
+
export declare function registry(identifies: string[] | oox.KeepAliveConnectionData[]): Promise<void>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { KeepAliveConnectionData } from "./keepalive-connection.js";
|
|
2
|
+
export interface ConfigAllow {
|
|
3
|
+
untrusted: boolean;
|
|
4
|
+
ip: string[];
|
|
5
|
+
caller: string[];
|
|
6
|
+
}
|
|
7
|
+
interface ConfigInterface {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
group: string;
|
|
11
|
+
ignore: string[];
|
|
12
|
+
entryInfo: {
|
|
13
|
+
path: string;
|
|
14
|
+
group: string;
|
|
15
|
+
};
|
|
16
|
+
host: string;
|
|
17
|
+
port: number;
|
|
18
|
+
origin: string | string[];
|
|
19
|
+
errorStack: boolean;
|
|
20
|
+
isRegistry: boolean;
|
|
21
|
+
registry: string[] | KeepAliveConnectionData[];
|
|
22
|
+
registryToken: string;
|
|
23
|
+
registryAdapter: string;
|
|
24
|
+
token: string;
|
|
25
|
+
allow: ConfigAllow;
|
|
26
|
+
}
|
|
27
|
+
export declare class Config implements ConfigInterface {
|
|
28
|
+
[x: string]: any;
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
group: string;
|
|
32
|
+
ignore: string[];
|
|
33
|
+
entryInfo: {
|
|
34
|
+
path: string;
|
|
35
|
+
group: string;
|
|
36
|
+
};
|
|
37
|
+
host: string;
|
|
38
|
+
port: number;
|
|
39
|
+
origin: string | string[];
|
|
40
|
+
errorStack: boolean;
|
|
41
|
+
isRegistry: boolean;
|
|
42
|
+
registry: string[] | KeepAliveConnectionData[];
|
|
43
|
+
registryToken: string;
|
|
44
|
+
registryAdapter: string;
|
|
45
|
+
token: string;
|
|
46
|
+
allow: ConfigAllow;
|
|
47
|
+
}
|
|
48
|
+
type StrictFormatter<T> = {
|
|
49
|
+
[K in keyof T]: (value: any) => T[K];
|
|
50
|
+
};
|
|
51
|
+
export declare const configFormatters: StrictFormatter<ConfigInterface> & {
|
|
52
|
+
[x: string]: (v: any) => any;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* 检查连接是否被允许
|
|
56
|
+
* @param ip 连接主机 IP
|
|
57
|
+
* @param caller 连接服务名称
|
|
58
|
+
* @param token 令牌
|
|
59
|
+
* @returns 是否被允许
|
|
60
|
+
*/
|
|
61
|
+
export declare function checkAllow(ip: string, caller: string, token: string): {
|
|
62
|
+
allow: boolean;
|
|
63
|
+
reason?: string;
|
|
64
|
+
};
|
|
65
|
+
export declare const config: Config;
|
|
66
|
+
export {};
|