oox 0.3.2 → 0.3.4
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/bin/argv.js +10 -1
- package/bin/cli.js +40 -13
- package/bin/configurer.js +3 -1
- package/bin/register.js +9 -23
- package/bin/starter.js +2 -2
- package/index.js +32 -48
- package/keepalive-connection.js +96 -0
- package/modules/http/index.js +2 -2
- package/modules/socketio/adapter.js +37 -0
- package/modules/socketio/index.js +4 -152
- package/modules/socketio/server.js +34 -40
- package/modules/socketio/socket.js +1 -1
- package/modules/socketio/utils.js +39 -0
- package/package.json +4 -2
- package/registry.js +61 -0
- package/samples/index.js +1 -0
- package/samples/keepalive-connection-sample.js +130 -0
- package/types/app.d.ts +1 -1
- package/types/index.d.ts +19 -41
- package/types/keepalive-connection.d.ts +79 -0
- package/types/modules/http/index.d.ts +2 -2
- package/types/modules/socketio/adapter.d.ts +14 -0
- package/types/modules/socketio/index.d.ts +2 -35
- package/types/modules/socketio/server.d.ts +10 -12
- package/types/modules/socketio/socket.d.ts +8 -11
- package/types/modules/socketio/utils.d.ts +8 -0
- package/types/registry.d.ts +16 -0
- package/types/samples/index.d.ts +1 -0
- package/types/samples/keepalive-connection-sample.d.ts +46 -0
- package/modules/socketio/client.js +0 -97
- package/types/modules/socketio/client.d.ts +0 -23
package/bin/argv.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as FS from 'node:fs';
|
|
2
|
+
import * as PATH from 'node:path';
|
|
1
3
|
export function getAllEnvArgs() {
|
|
2
4
|
const args = process.argv.slice(2);
|
|
3
5
|
const env = {};
|
|
@@ -9,7 +11,14 @@ export function getAllEnvArgs() {
|
|
|
9
11
|
env[arg.slice(1)] = true;
|
|
10
12
|
}
|
|
11
13
|
else if (!arg.includes('=')) {
|
|
12
|
-
|
|
14
|
+
// index.js
|
|
15
|
+
const path = PATH.resolve(process.cwd(), arg);
|
|
16
|
+
if (FS.existsSync(path)) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
env[arg] = true;
|
|
21
|
+
}
|
|
13
22
|
}
|
|
14
23
|
else {
|
|
15
24
|
const index = arg.indexOf('=');
|
package/bin/cli.js
CHANGED
|
@@ -27,23 +27,26 @@ if (execFilename.endsWith('oox') || fileURLToPath(import.meta.url) === execFilen
|
|
|
27
27
|
console.log();
|
|
28
28
|
console.log(' oox entry.js port=8080');
|
|
29
29
|
console.log();
|
|
30
|
-
console.log(' oox
|
|
30
|
+
console.log(' oox entry.js group=app/ registry=:6000');
|
|
31
|
+
console.log(' oox app/entry/index.js group=app/ env=envs/prod.js ignore=core');
|
|
31
32
|
console.log();
|
|
32
33
|
console.log(chalk.bold('Params:'));
|
|
33
34
|
const params = [
|
|
34
|
-
['
|
|
35
|
-
['
|
|
36
|
-
['
|
|
37
|
-
['
|
|
38
|
-
['
|
|
39
|
-
['
|
|
40
|
-
['
|
|
41
|
-
['
|
|
42
|
-
['
|
|
43
|
-
['
|
|
44
|
-
['
|
|
35
|
+
['default-env', 'file', '.js or .json file, merge to oox.config'],
|
|
36
|
+
['env', 'file', `${chalk.bold.red('default-env')}.js or .json file, merge to oox.config, ${chalk.bold('(after default-env)')}`],
|
|
37
|
+
['port', 'int', `default is ${chalk.bold('0')}, for random port, or any integer > 0`],
|
|
38
|
+
['group', 'dir', 'service group directory, all LocalCall transform to RPC'],
|
|
39
|
+
['ignore', 'name', 'set a name for LocalCall do not transform to RPC, support string | array<string>'],
|
|
40
|
+
['http', 'json', 'HTTP server options, support flat name, ex: http.path=/api'],
|
|
41
|
+
['socketio', 'json', 'SocketIO server options, support flat name'],
|
|
42
|
+
['isRegistry', 'bool', `default is ${chalk.bold.red('true')}, set no to disable service registry`],
|
|
43
|
+
['registryAdapter', 'name', 'set service registry adapter name'],
|
|
44
|
+
['registry', 'urls', 'registry service url, support string | array<string>'],
|
|
45
|
+
['origin', 'urls', `set ${chalk.bold('*')}, allow any connections <Access-Control-Allow-Origin>`],
|
|
46
|
+
['errorStack', 'bool', 'set no to hidden error stack return'],
|
|
45
47
|
];
|
|
46
|
-
|
|
48
|
+
console.log(mergeCommandParams(params));
|
|
49
|
+
console.log(' ...', 'set params as', chalk.bold('foo=bar') + ',', 'usage as', chalk.bold('oox.config.foo'));
|
|
47
50
|
console.log();
|
|
48
51
|
}
|
|
49
52
|
if (isStartup) {
|
|
@@ -55,3 +58,27 @@ if (execFilename.endsWith('oox') || fileURLToPath(import.meta.url) === execFilen
|
|
|
55
58
|
await startup();
|
|
56
59
|
}
|
|
57
60
|
}
|
|
61
|
+
function mergeCommandParams(params) {
|
|
62
|
+
let result = '';
|
|
63
|
+
const perLinePrefix = ' '.repeat(2);
|
|
64
|
+
const nameMaxLength = 12;
|
|
65
|
+
const typeMaxLength = 6;
|
|
66
|
+
for (const param of params) {
|
|
67
|
+
const name = param[0];
|
|
68
|
+
const type = param[1];
|
|
69
|
+
const desc = param.slice(2).join(' ');
|
|
70
|
+
result += perLinePrefix + name;
|
|
71
|
+
if (name.length > nameMaxLength) {
|
|
72
|
+
result += '\n' + perLinePrefix;
|
|
73
|
+
result += ' '.repeat(nameMaxLength);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
result += ' '.repeat(nameMaxLength - name.length);
|
|
77
|
+
}
|
|
78
|
+
result += '[' + type + ']';
|
|
79
|
+
result += ' '.repeat(typeMaxLength - type.length);
|
|
80
|
+
result += desc;
|
|
81
|
+
result += '\n';
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
}
|
package/bin/configurer.js
CHANGED
|
@@ -19,6 +19,7 @@ function mergeFlatEnv(env) {
|
|
|
19
19
|
tmpEnv = tmpEnv[subKey];
|
|
20
20
|
}
|
|
21
21
|
tmpEnv[valueKey] = env[key];
|
|
22
|
+
delete env[key];
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
}
|
|
@@ -32,12 +33,13 @@ async function readEnvFile(filePath) {
|
|
|
32
33
|
else {
|
|
33
34
|
const finalPath = path.resolve(filePath).replace(/\\/g, '/');
|
|
34
35
|
env = await import(`file://${finalPath}`);
|
|
36
|
+
env = env.default || env;
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
39
|
else {
|
|
38
40
|
throw new Error('Env file not found: ' + filePath);
|
|
39
41
|
}
|
|
40
|
-
return env
|
|
42
|
+
return env;
|
|
41
43
|
}
|
|
42
44
|
export async function buildConfig(mergeEnv) {
|
|
43
45
|
const env = Object.create(null);
|
package/bin/register.js
CHANGED
|
@@ -1,25 +1,11 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import * as oox from '../index.js';
|
|
3
|
-
import { default as SocketIOModule } from '../modules/socketio/index.js';
|
|
4
3
|
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
5
|
-
function urlFormatter(url) {
|
|
6
|
-
let _url = SocketIOModule.genWebSocketUrl(url);
|
|
7
|
-
const urlObject = new URL(_url);
|
|
8
|
-
if (urlObject.pathname === '/' && !url.endsWith('/'))
|
|
9
|
-
_url += '/socket.io';
|
|
10
|
-
return _url;
|
|
11
|
-
}
|
|
12
4
|
async function connect(url, prevError = null) {
|
|
13
|
-
const
|
|
14
|
-
const { host } = oox.config;
|
|
15
|
-
const { port, path } = socketio.config;
|
|
16
|
-
const urlObject = new URL(url);
|
|
17
|
-
// check if url is self
|
|
18
|
-
if (urlObject.host === host && urlObject.port === String(port))
|
|
19
|
-
return;
|
|
5
|
+
const adapter = oox.keepAliveConnectionAdapters.get(oox.config.registryAdapter);
|
|
20
6
|
try {
|
|
21
|
-
const
|
|
22
|
-
onConnection(
|
|
7
|
+
const connection = await adapter.open(url);
|
|
8
|
+
onConnection(connection, url);
|
|
23
9
|
}
|
|
24
10
|
catch (error) {
|
|
25
11
|
if (!prevError)
|
|
@@ -28,19 +14,19 @@ async function connect(url, prevError = null) {
|
|
|
28
14
|
connect(url, error);
|
|
29
15
|
}
|
|
30
16
|
}
|
|
31
|
-
async function onConnection(
|
|
32
|
-
const { name } =
|
|
33
|
-
|
|
34
|
-
console.log(chalk.red('[Registry]'), `Service<${name}>`, chalk.underline.red(`${url}`), 'disconnected.');
|
|
17
|
+
async function onConnection(connection, url) {
|
|
18
|
+
const { name } = connection.data;
|
|
19
|
+
connection.once('disconnect', async () => {
|
|
20
|
+
console.log(chalk.red('[Registry]'), `Service<${name}>`, chalk.underline.red(`${connection.data.url || url}`), 'disconnected.');
|
|
35
21
|
await delay(1000);
|
|
36
22
|
connect(url);
|
|
37
23
|
});
|
|
38
|
-
console.log(chalk.green('[Registry]'), `Service<${name}>`, chalk.underline.green(`${url}`), 'connected.');
|
|
24
|
+
console.log(chalk.green('[Registry]'), `Service<${name}>`, chalk.underline.green(`${connection.data.url || url}`), 'connected.');
|
|
39
25
|
}
|
|
40
26
|
export async function registry(urls) {
|
|
41
27
|
if ('string' === typeof urls)
|
|
42
28
|
urls = [urls];
|
|
43
29
|
for (const url of urls) {
|
|
44
|
-
connect(
|
|
30
|
+
connect(url);
|
|
45
31
|
}
|
|
46
32
|
}
|
package/bin/starter.js
CHANGED
|
@@ -53,9 +53,9 @@ export async function startup() {
|
|
|
53
53
|
console.log();
|
|
54
54
|
console.log('Service', chalk.bold(`${oox.config.name}`), 'running.');
|
|
55
55
|
if (http.config.enabled)
|
|
56
|
-
console.log(' at', chalk.underline.green(http.
|
|
56
|
+
console.log(' at', chalk.underline.green(http.getURL()));
|
|
57
57
|
if (socketio.config.enabled)
|
|
58
|
-
console.log(' at', chalk.underline.green(socketio.
|
|
58
|
+
console.log(' at', chalk.underline.green(socketio.getURL()));
|
|
59
59
|
console.log();
|
|
60
60
|
// 服务注册
|
|
61
61
|
if (config.registry)
|
package/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import * as app from './app.js';
|
|
3
3
|
import { getIPAddress } from './utils.js';
|
|
4
|
+
import * as registry from './registry.js';
|
|
4
5
|
import Module, { ModuleConfig } from './modules/module.js';
|
|
5
|
-
import
|
|
6
|
-
export { Module, ModuleConfig };
|
|
7
|
-
export const modules = new Modules;
|
|
8
|
-
export const { asyncStore, setMethods, getMethods, kvMethods, sourceKVMethods, call, execute, logger, on, once, off, emit, } = app;
|
|
6
|
+
import { KeepAliveConnection, keepAliveConnectionAdapters, keepAliveConnections, enabledKeepAliveConnections } from './keepalive-connection.js';
|
|
9
7
|
export class Context extends app.Context {
|
|
10
8
|
// 请求溯源IP
|
|
11
9
|
sourceIP = '';
|
|
@@ -24,6 +22,8 @@ export class Context extends app.Context {
|
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
24
|
export class Config {
|
|
25
|
+
// 服务ID
|
|
26
|
+
id = randomUUID();
|
|
27
27
|
// 服务名称
|
|
28
28
|
name = 'local';
|
|
29
29
|
// 服务列表路径
|
|
@@ -45,6 +45,12 @@ export class Config {
|
|
|
45
45
|
origin = '';
|
|
46
46
|
// 默认返回错误调用栈信息信息
|
|
47
47
|
errorStack = true;
|
|
48
|
+
// 是否开启服务注册功能
|
|
49
|
+
isRegistry = true;
|
|
50
|
+
// 服务注册列表
|
|
51
|
+
registry = [];
|
|
52
|
+
// 服务注册适配器
|
|
53
|
+
registryAdapter = 'socketio';
|
|
48
54
|
}
|
|
49
55
|
export const config = new Config();
|
|
50
56
|
let genTraceIdFunction = () => randomUUID();
|
|
@@ -78,55 +84,26 @@ export async function serve() {
|
|
|
78
84
|
export async function stop() {
|
|
79
85
|
await modules.stop();
|
|
80
86
|
}
|
|
81
|
-
export class RPCKeepAliveConnection {
|
|
82
|
-
data;
|
|
83
|
-
nativeConnection = null;
|
|
84
|
-
adapter = null;
|
|
85
|
-
constructor(adapter, nativeConnection, data) {
|
|
86
|
-
this.adapter = adapter;
|
|
87
|
-
this.nativeConnection = nativeConnection;
|
|
88
|
-
if (data)
|
|
89
|
-
this.data = data;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
export const keepAliveConnections = new Map();
|
|
93
|
-
export function getKeepAliveConnections(name) {
|
|
94
|
-
return keepAliveConnections.get(name) || new Map();
|
|
95
|
-
}
|
|
96
|
-
export function getKeepAliveConnection(name, id) {
|
|
97
|
-
const connections = keepAliveConnections.get(name);
|
|
98
|
-
if (!connections)
|
|
99
|
-
return null;
|
|
100
|
-
return connections.get(id);
|
|
101
|
-
}
|
|
102
87
|
export function addKeepAliveConnection(connection) {
|
|
103
|
-
|
|
104
|
-
if (keepAliveConnections.has(name)) {
|
|
105
|
-
keepAliveConnections.get(name).set(id, connection);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
keepAliveConnections.set(name, new Map([[id, connection]]));
|
|
109
|
-
}
|
|
88
|
+
keepAliveConnections.add(connection);
|
|
110
89
|
}
|
|
111
|
-
export function removeKeepAliveConnection(
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
90
|
+
export function removeKeepAliveConnection(arg1, arg2) {
|
|
91
|
+
if (typeof arg1 === 'string') {
|
|
92
|
+
keepAliveConnections.remove(arg1, arg2);
|
|
93
|
+
enabledKeepAliveConnections.remove(arg1, arg2);
|
|
115
94
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (!group.size)
|
|
120
|
-
keepAliveConnections.delete(name);
|
|
95
|
+
else {
|
|
96
|
+
keepAliveConnections.remove(arg1);
|
|
97
|
+
enabledKeepAliveConnections.remove(arg1);
|
|
121
98
|
}
|
|
122
99
|
}
|
|
123
100
|
/**
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
101
|
+
* random connection select for default load balance policy
|
|
102
|
+
* @param name service name
|
|
103
|
+
* @returns selected connection
|
|
104
|
+
*/
|
|
128
105
|
let loadBalancePolicy = (name) => {
|
|
129
|
-
const connections =
|
|
106
|
+
const connections = enabledKeepAliveConnections.getConnectionsOfService(name);
|
|
130
107
|
if (!connections || !connections.size)
|
|
131
108
|
return null;
|
|
132
109
|
const arrayConnections = Array.from(connections.values());
|
|
@@ -141,7 +118,7 @@ export async function rpc(arg1, action, params, context) {
|
|
|
141
118
|
context = getContext();
|
|
142
119
|
}
|
|
143
120
|
let connection;
|
|
144
|
-
if (arg1 instanceof
|
|
121
|
+
if (arg1 instanceof KeepAliveConnection) {
|
|
145
122
|
connection = arg1;
|
|
146
123
|
}
|
|
147
124
|
else if ('string' === typeof arg1) {
|
|
@@ -151,5 +128,12 @@ export async function rpc(arg1, action, params, context) {
|
|
|
151
128
|
}
|
|
152
129
|
else
|
|
153
130
|
throw new Error(`Unknown rpc arg1<${arg1}>`);
|
|
154
|
-
return connection.adapter.rpc(connection
|
|
131
|
+
return connection.adapter.rpc(connection, action, params, context);
|
|
155
132
|
}
|
|
133
|
+
export { KeepAliveConnection, keepAliveConnectionAdapters, keepAliveConnections, enabledKeepAliveConnections };
|
|
134
|
+
export { Module, ModuleConfig };
|
|
135
|
+
export { registry };
|
|
136
|
+
export const { asyncStore, setMethods, getMethods, kvMethods, sourceKVMethods, call, execute, logger, on, once, off, emit, } = app;
|
|
137
|
+
// 放在最后导入,解决循环依赖问题
|
|
138
|
+
import Modules from './modules/index.js';
|
|
139
|
+
export const modules = new Modules;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import EventEmitter from 'node:events';
|
|
2
|
+
export class KeepAliveConnection extends EventEmitter {
|
|
3
|
+
// 连接是否可用
|
|
4
|
+
#enabled = false;
|
|
5
|
+
data;
|
|
6
|
+
nativeConnection;
|
|
7
|
+
adapter;
|
|
8
|
+
constructor(adapter, nativeConnection, data) {
|
|
9
|
+
super();
|
|
10
|
+
this.adapter = adapter;
|
|
11
|
+
this.nativeConnection = nativeConnection;
|
|
12
|
+
this.data = Object.assign(data, {
|
|
13
|
+
adapter: adapter.name,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 设置连接是否可用,并自动触发enabled或disabled事件
|
|
18
|
+
* @param enabled 是否可用
|
|
19
|
+
*/
|
|
20
|
+
set enabled(enabled) {
|
|
21
|
+
if (enabled !== this.#enabled) {
|
|
22
|
+
this.#enabled = enabled;
|
|
23
|
+
this.emit(enabled ? 'enabled' : 'disabled');
|
|
24
|
+
if (enabled) {
|
|
25
|
+
enabledKeepAliveConnections.add(this);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
enabledKeepAliveConnections.remove(this);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
get enabled() {
|
|
33
|
+
return this.#enabled;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* enable & mount connection
|
|
37
|
+
* @param params
|
|
38
|
+
* @returns
|
|
39
|
+
*/
|
|
40
|
+
ready(params) {
|
|
41
|
+
// 连接已就绪,不允许重复就绪
|
|
42
|
+
if (this.enabled)
|
|
43
|
+
return;
|
|
44
|
+
const { id, name } = params;
|
|
45
|
+
keepAliveConnections.remove(this);
|
|
46
|
+
// 更新连接数据
|
|
47
|
+
this.data.id = id;
|
|
48
|
+
this.data.name = name;
|
|
49
|
+
keepAliveConnections.add(this);
|
|
50
|
+
this.enabled = true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export class KeepAliveConnectionStore {
|
|
54
|
+
#map = new Map();
|
|
55
|
+
entries() {
|
|
56
|
+
return this.#map.entries();
|
|
57
|
+
}
|
|
58
|
+
getConnectionsOfService(name) {
|
|
59
|
+
return this.#map.get(name) || new Map();
|
|
60
|
+
}
|
|
61
|
+
has(name, id) {
|
|
62
|
+
const connections = this.#map.get(name);
|
|
63
|
+
if (!connections)
|
|
64
|
+
return false;
|
|
65
|
+
return connections.has(id);
|
|
66
|
+
}
|
|
67
|
+
get(name, id) {
|
|
68
|
+
const connections = this.#map.get(name);
|
|
69
|
+
if (!connections)
|
|
70
|
+
return null;
|
|
71
|
+
return connections.get(id) || null;
|
|
72
|
+
}
|
|
73
|
+
add(connection) {
|
|
74
|
+
const { name, id } = connection.data;
|
|
75
|
+
const connections = this.#map.get(name);
|
|
76
|
+
if (connections) {
|
|
77
|
+
connections.set(id, connection);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.#map.set(name, new Map([[id, connection]]));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
remove(name, id) {
|
|
84
|
+
if (name instanceof KeepAliveConnection) {
|
|
85
|
+
id = name.data.id;
|
|
86
|
+
name = name.data.name;
|
|
87
|
+
}
|
|
88
|
+
const connections = this.#map.get(name);
|
|
89
|
+
if (connections && id !== undefined) {
|
|
90
|
+
connections.delete(id);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export const keepAliveConnectionAdapters = new Map();
|
|
95
|
+
export const keepAliveConnections = new KeepAliveConnectionStore();
|
|
96
|
+
export const enabledKeepAliveConnections = new KeepAliveConnectionStore();
|
package/modules/http/index.js
CHANGED
|
@@ -28,11 +28,11 @@ export default class HTTPModule extends Module {
|
|
|
28
28
|
config = new HTTPConfig;
|
|
29
29
|
server = null;
|
|
30
30
|
router = new Router();
|
|
31
|
-
|
|
31
|
+
getURL() {
|
|
32
32
|
const { host } = oox.config;
|
|
33
33
|
const { port, path } = this.config;
|
|
34
34
|
const protocol = this.config.ssl.enabled ? `https:` : `http:`;
|
|
35
|
-
return `${protocol}//${host}:${port}${path}
|
|
35
|
+
return new URL(`${protocol}//${host}:${port}${path}`);
|
|
36
36
|
}
|
|
37
37
|
// 注册GET路由
|
|
38
38
|
get(path, ...args) {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as SocketIOClient from 'socket.io-client';
|
|
2
|
+
import * as oox from '../../index.js';
|
|
3
|
+
import { OOXEvent, genWebSocketURL } from './utils.js';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { SampleKeepAliveConnectionAdapter } from '../../samples/index.js';
|
|
6
|
+
export default class SocketIOAdapter extends SampleKeepAliveConnectionAdapter {
|
|
7
|
+
name = 'socketio';
|
|
8
|
+
OOXEvent = OOXEvent;
|
|
9
|
+
nativeEvent = { CONNECT: 'connect', DISCONNECT: 'disconnect', ERROR: 'connect_error' };
|
|
10
|
+
newConnection(url) {
|
|
11
|
+
const { id, host, name } = oox.config;
|
|
12
|
+
const headers = {
|
|
13
|
+
'x-ip': host,
|
|
14
|
+
'x-caller': name,
|
|
15
|
+
'x-caller-id': id,
|
|
16
|
+
};
|
|
17
|
+
let mURL;
|
|
18
|
+
if ('string' === typeof url) {
|
|
19
|
+
mURL = genWebSocketURL(url);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
mURL = url;
|
|
23
|
+
}
|
|
24
|
+
const socket = SocketIOClient.io(mURL.origin, {
|
|
25
|
+
extraHeaders: headers,
|
|
26
|
+
path: mURL.pathname,
|
|
27
|
+
autoConnect: false,
|
|
28
|
+
});
|
|
29
|
+
const connection = new oox.KeepAliveConnection(this, socket, {
|
|
30
|
+
name: 'anonymous',
|
|
31
|
+
id: randomUUID(),
|
|
32
|
+
host: mURL.host,
|
|
33
|
+
url: mURL
|
|
34
|
+
});
|
|
35
|
+
return connection;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import SocketIOClient from './client.js';
|
|
1
|
+
import * as PATH from 'node:path';
|
|
3
2
|
import * as oox from '../../index.js';
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
export { sockets };
|
|
7
|
-
export default class SocketIOModule extends SocketIOClient {
|
|
8
|
-
sockets = sockets;
|
|
3
|
+
import SocketINServer from './server.js';
|
|
4
|
+
export default class SocketIOModule extends SocketINServer {
|
|
9
5
|
async serve() {
|
|
10
6
|
await this.stop();
|
|
11
7
|
const _http = oox.modules.builtins.http;
|
|
@@ -18,154 +14,10 @@ export default class SocketIOModule extends SocketIOClient {
|
|
|
18
14
|
// http 模块未被禁用
|
|
19
15
|
isShareServer &&= httpConfig.enabled;
|
|
20
16
|
if (isShareServer) {
|
|
21
|
-
config.path =
|
|
17
|
+
config.path = PATH.posix.join(httpConfig.path, config.path);
|
|
22
18
|
this.server = _http.server;
|
|
23
19
|
this.config.ssl = _http.config.ssl;
|
|
24
20
|
}
|
|
25
21
|
await super.serve();
|
|
26
22
|
}
|
|
27
|
-
onSyncConnection(socket) {
|
|
28
|
-
const mSockets = Array.from(sockets.values())
|
|
29
|
-
.filter(s => s !== socket &&
|
|
30
|
-
s.data.name !== socket.data.name &&
|
|
31
|
-
/^wss?:\/\/.+$/.test(s.data.id));
|
|
32
|
-
return mSockets.map(s => s.data);
|
|
33
|
-
}
|
|
34
|
-
serverOnDisconnect(socket, reason) {
|
|
35
|
-
super.serverOnDisconnect(socket, reason);
|
|
36
|
-
removeKeepAliveConnection(socket.data.name, socket.data.id);
|
|
37
|
-
}
|
|
38
|
-
clientOnDisconnect(socket, reason) {
|
|
39
|
-
super.clientOnDisconnect(socket, reason);
|
|
40
|
-
removeKeepAliveConnection(socket.data.name, socket.data.id);
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
*
|
|
44
|
-
* @param socket 是由哪个通道发送过来的
|
|
45
|
-
* @param connectionDatas
|
|
46
|
-
*/
|
|
47
|
-
clientOnSyncConnection(socket, connectionDatas) {
|
|
48
|
-
for (const data of connectionDatas)
|
|
49
|
-
if (!sockets.has(data.id))
|
|
50
|
-
this.connect(data.id).catch((error) => console.error(error));
|
|
51
|
-
}
|
|
52
|
-
onFetchActions(socket, search) {
|
|
53
|
-
const data = [];
|
|
54
|
-
for (const key of oox.kvMethods.keys())
|
|
55
|
-
if (!key.endsWith('_proxy') && key.includes(search))
|
|
56
|
-
data.push(key);
|
|
57
|
-
return data;
|
|
58
|
-
}
|
|
59
|
-
fetchActions(id, search = '') {
|
|
60
|
-
let socket = sockets.get(id);
|
|
61
|
-
if (!socket) {
|
|
62
|
-
const connections = getKeepAliveConnections(id);
|
|
63
|
-
if (!connections || !connections.size)
|
|
64
|
-
throw new Error(`Unknown service identify<${id}>`);
|
|
65
|
-
id = connections.keys().next().value;
|
|
66
|
-
socket = sockets.get(id);
|
|
67
|
-
}
|
|
68
|
-
if (!socket)
|
|
69
|
-
throw new Error(`Unknown service identify<${id}>`);
|
|
70
|
-
return this.emit(socket.data.id, 'fetchActions', [search]);
|
|
71
|
-
}
|
|
72
|
-
onConnection(socket) {
|
|
73
|
-
const { id, name, host } = socket.data;
|
|
74
|
-
const connection = new RPCKeepAliveConnection(this, id, socket.data);
|
|
75
|
-
addKeepAliveConnection(connection);
|
|
76
|
-
const connectionContext = {
|
|
77
|
-
sourceIP: '',
|
|
78
|
-
ip: host,
|
|
79
|
-
caller: name,
|
|
80
|
-
callerId: id,
|
|
81
|
-
connection
|
|
82
|
-
};
|
|
83
|
-
socket.on('fetchActions', async (search, fn) => {
|
|
84
|
-
if ('function' !== typeof fn)
|
|
85
|
-
return;
|
|
86
|
-
const data = await this.onFetchActions(socket, search);
|
|
87
|
-
fn(data);
|
|
88
|
-
});
|
|
89
|
-
socket.on('call', async (action, params, context, callback) => {
|
|
90
|
-
if ('object' !== typeof context)
|
|
91
|
-
context = oox.genContext(connectionContext);
|
|
92
|
-
else
|
|
93
|
-
context = oox.genContext(Object.assign(context, connectionContext));
|
|
94
|
-
this.call(action, params, context, callback);
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
*
|
|
99
|
-
* @param {Socket} socket
|
|
100
|
-
*/
|
|
101
|
-
serverOnConnection(socket) {
|
|
102
|
-
super.serverOnConnection(socket);
|
|
103
|
-
socket.setMaxListeners(0);
|
|
104
|
-
socket.on('syncConnection', async (fn) => {
|
|
105
|
-
if ('function' !== typeof fn)
|
|
106
|
-
return;
|
|
107
|
-
const data = this.onSyncConnection(socket);
|
|
108
|
-
fn(data);
|
|
109
|
-
});
|
|
110
|
-
this.onConnection(socket);
|
|
111
|
-
}
|
|
112
|
-
async call(action, params, context, callback) {
|
|
113
|
-
const returns = await oox.call(action, params, context);
|
|
114
|
-
if (!oox.config.errorStack && returns.error) {
|
|
115
|
-
// 不返回错误调用栈信息
|
|
116
|
-
delete returns.error.stack;
|
|
117
|
-
}
|
|
118
|
-
'function' === typeof callback && callback(returns);
|
|
119
|
-
return returns;
|
|
120
|
-
}
|
|
121
|
-
clientOnConnection(socket) {
|
|
122
|
-
super.clientOnConnection(socket);
|
|
123
|
-
socket.emit('syncConnection', (socketDatas) => this.clientOnSyncConnection(socket, socketDatas));
|
|
124
|
-
this.onConnection(socket);
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* socketio emit
|
|
128
|
-
*/
|
|
129
|
-
async emit(url, event, params) {
|
|
130
|
-
let socket = null;
|
|
131
|
-
try {
|
|
132
|
-
socket = await this.connect(url);
|
|
133
|
-
}
|
|
134
|
-
catch (error) {
|
|
135
|
-
// try again
|
|
136
|
-
socket = await this.connect(url);
|
|
137
|
-
}
|
|
138
|
-
try {
|
|
139
|
-
return await new Promise((resolve, reject) => {
|
|
140
|
-
const onError = (reason) => {
|
|
141
|
-
const message = 'string' === typeof reason ? reason : reason instanceof Error ? reason.message : 'connect error';
|
|
142
|
-
reject(new Error(message));
|
|
143
|
-
};
|
|
144
|
-
// RPC 执行时中断连接
|
|
145
|
-
socket.once('disconnect', onError);
|
|
146
|
-
socket.emit(event, ...params, (returns) => {
|
|
147
|
-
socket.off('disconnect', onError);
|
|
148
|
-
resolve(returns);
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
catch (error) {
|
|
153
|
-
throw new Error(error.message);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* RPC
|
|
158
|
-
*/
|
|
159
|
-
async rpc(url, action, params, context) {
|
|
160
|
-
if (!context || !context.traceId) {
|
|
161
|
-
context = oox.getContext();
|
|
162
|
-
}
|
|
163
|
-
const { success, error, body } = await this.emit(url, 'call', [action, params, context]);
|
|
164
|
-
if (success)
|
|
165
|
-
return body;
|
|
166
|
-
else if (error)
|
|
167
|
-
throw new Error(error.message);
|
|
168
|
-
else
|
|
169
|
-
throw new Error('[RPC] Unknown Error');
|
|
170
|
-
}
|
|
171
23
|
}
|