mm_socket_server 1.0.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -96
- package/example/demo.js +63 -0
- package/index.js +2 -4
- package/lib/socket.js +607 -184
- package/package.json +8 -8
- package/lib/message.js +0 -150
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_socket_server",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "TCP/UDP
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "最薄的 TCP/UDP 套接字服务器入站适配器:按 topic 分帧后直达 mm_event 事件管理器,不做路由与插件。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"超级美眉",
|
|
7
7
|
"入站适配器",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"main": "index.js",
|
|
23
23
|
"files": [
|
|
24
24
|
"index.js",
|
|
25
|
-
"lib"
|
|
25
|
+
"lib",
|
|
26
|
+
"example"
|
|
26
27
|
],
|
|
27
28
|
"engines": {
|
|
28
29
|
"node": ">=22.5.0"
|
|
@@ -38,12 +39,11 @@
|
|
|
38
39
|
"scripts": {
|
|
39
40
|
"start": "node example/demo.js",
|
|
40
41
|
"demo": "node example/demo.js",
|
|
41
|
-
"test": "
|
|
42
|
+
"test": "node --test \"test/*.test.js\""
|
|
42
43
|
},
|
|
43
44
|
"dependencies": {
|
|
44
|
-
"mm_corejs": "^1.1.4"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"jest": "^30.5.2"
|
|
45
|
+
"mm_corejs": "^1.1.4",
|
|
46
|
+
"mm_event": "^2.2.2",
|
|
47
|
+
"mm_mod": "^1.0.1"
|
|
48
48
|
}
|
|
49
49
|
}
|
package/lib/message.js
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { JsonRpc } = require('mm_corejs');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* MessagePlugin —— JSON-RPC 2.0 消息插件(mm_socket_server 的可选业务组件)。
|
|
7
|
-
*
|
|
8
|
-
* 职责:
|
|
9
|
-
* 1. 方法表:内部持有 JsonRpc 核心,addMethod / delMethod / listMethods 登记可调用方法;
|
|
10
|
-
* 2. 管道挂载:bind(socket) 后向消息管道注册 main 钩子 "json_rpc"(sort 100,
|
|
11
|
-
* 先于内置 emit_message 执行),命中 JSON-RPC 请求时以响应对象作为管道 result,
|
|
12
|
-
* 由 SocketServer 自动回发来源客户端;
|
|
13
|
-
* 3. 通知回推:通知(无 id)处理函数返回非 undefined 结果时,产出服务器发起的
|
|
14
|
-
* 通知对象 { jsonrpc, method, params: result } 回推来源客户端;无结果或出错时
|
|
15
|
-
* 不产出;非 JSON-RPC 消息(解析失败、缺 jsonrpc 字段)透传,控制权交还管道;
|
|
16
|
-
* 4. 主动推送:push(client_id, data) 委托 SocketServer.send,处理函数或服务器代码
|
|
17
|
-
* 可在任意时刻(如异步任务完成后)向指定客户端回推结果;
|
|
18
|
-
* 5. 反向调用:call(client_id, method, params, options) 向客户端发起 JSON-RPC 请求
|
|
19
|
-
* 并等待其反馈;入站消息为响应形态(含 result/error、无 method)时被优先识别
|
|
20
|
-
* 并结算待响应调用,实现服务器实时调用客户端方法;
|
|
21
|
-
* 6. 编码适配:json 模式产出对象(由 send 序列化),文本模式字符串原样、其余 JSON 序列化。
|
|
22
|
-
*
|
|
23
|
-
* 用法:
|
|
24
|
-
* const socket = new SocketServer({ name: 'socket', port: 9100, json: true }, server);
|
|
25
|
-
* const rpc = new MessagePlugin();
|
|
26
|
-
* socket.use(rpc);
|
|
27
|
-
* rpc.addMethod('echo', (params) => params);
|
|
28
|
-
* await socket.init();
|
|
29
|
-
* await socket.start();
|
|
30
|
-
*/
|
|
31
|
-
class MessagePlugin {
|
|
32
|
-
/**
|
|
33
|
-
* JSON-RPC 协议核心
|
|
34
|
-
*/
|
|
35
|
-
#rpc = new JsonRpc();
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 已挂载的 SocketServer 实例,未挂载时为 null
|
|
39
|
-
*/
|
|
40
|
-
#server = null;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* 挂载到 SocketServer 的消息管道,注册内置 main 钩子
|
|
44
|
-
* @param {Object} server 具备 getHandle() 的 SocketServer 实例
|
|
45
|
-
* @returns {MessagePlugin} 当前实例
|
|
46
|
-
* @throws {TypeError} server 不具备 getHandle 方法时
|
|
47
|
-
*/
|
|
48
|
-
bind(server) {
|
|
49
|
-
if (!server || typeof server.getHandle !== 'function') {
|
|
50
|
-
throw new TypeError('[MessagePlugin] server must provide getHandle()');
|
|
51
|
-
}
|
|
52
|
-
this.#server = server;
|
|
53
|
-
server.getHandle().on('main', (params, ctx, options) => {
|
|
54
|
-
return this._execute(params, ctx, options);
|
|
55
|
-
}, 100, 'json_rpc');
|
|
56
|
-
return this;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* 判断是否已挂载
|
|
61
|
-
* @returns {boolean} 是否已挂载到 SocketServer
|
|
62
|
-
*/
|
|
63
|
-
isBound() {
|
|
64
|
-
return this.#server !== null;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* 登记 RPC 方法
|
|
69
|
-
* @param {string} name 方法名
|
|
70
|
-
* @param {Function} handler 处理函数,签名 handler(params, extra, options),extra 含 client_id,options 为管道请求选项
|
|
71
|
-
* @returns {MessagePlugin} 当前实例
|
|
72
|
-
*/
|
|
73
|
-
addMethod(name, handler) {
|
|
74
|
-
this.#rpc.addMethod(name, handler);
|
|
75
|
-
return this;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* 删除 RPC 方法
|
|
80
|
-
* @param {string} name 方法名
|
|
81
|
-
* @returns {boolean} 是否删除成功
|
|
82
|
-
*/
|
|
83
|
-
delMethod(name) {
|
|
84
|
-
return this.#rpc.delMethod(name);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* 列出 RPC 方法(支持 Store 条件查询与分页)
|
|
89
|
-
* @param {Object} [query] 查询条件,缺省时列出全部
|
|
90
|
-
* @returns {Array<Object>} 方法列表,含 name
|
|
91
|
-
*/
|
|
92
|
-
listMethods(query) {
|
|
93
|
-
return this.#rpc.listMethods(query);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* 主动推送:向指定客户端回推数据(可用于异步任务完成后通知)
|
|
98
|
-
* @param {string} client_id 目标客户端 ID
|
|
99
|
-
* @param {string|Object} data 待推送数据,对象时按编码模式序列化
|
|
100
|
-
* @returns {boolean} 是否发送成功
|
|
101
|
-
* @throws {Error} 插件尚未挂载到服务器时
|
|
102
|
-
*/
|
|
103
|
-
push(client_id, data) {
|
|
104
|
-
if (!this.#server) throw new Error('[MessagePlugin] not bound to a server');
|
|
105
|
-
const payload = this._format(data);
|
|
106
|
-
return this.#server.send(client_id, payload);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* 实时调用客户端方法:发送 JSON-RPC 请求并等待客户端反馈 result
|
|
111
|
-
* @param {string} client_id 目标客户端 ID
|
|
112
|
-
* @param {string} method 客户端方法名
|
|
113
|
-
* @param {*} [params] 调用参数
|
|
114
|
-
* @param {Object} [options] 选项,含 timeout_ms(缺省 30000,0 为不超时)
|
|
115
|
-
* @returns {Promise<*>} 客户端反馈的 result;错误响应、送达失败或超时时 reject
|
|
116
|
-
* @throws {Error} 插件尚未挂载到服务器时
|
|
117
|
-
*/
|
|
118
|
-
call(client_id, method, params, options = {}) {
|
|
119
|
-
if (!this.#server) throw new Error('[MessagePlugin] not bound to a server');
|
|
120
|
-
return this.#rpc.call((request) => this.#server.send(client_id, this._format(request)), method, params, options);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* 内置 main 钩子逻辑:优先识别客户端反馈,其次执行 RPC 请求并格式化响应
|
|
125
|
-
* @param {Object} ctx 执行上下文
|
|
126
|
-
* @param {Object} params 消息参数,含 client_id 与 data
|
|
127
|
-
* @param {Object} [options] 管道请求选项(连接级,如 user_id / device_id / agent_id),透传给处理函数
|
|
128
|
-
* @returns {Promise<Object|string|undefined>} 响应对象或 JSON 字符串;反馈、透传与无结果通知时为 undefined
|
|
129
|
-
*/
|
|
130
|
-
async _execute(params, ctx, options) {
|
|
131
|
-
if (this.#rpc.acceptResponse(params.data)) return undefined;
|
|
132
|
-
const extra = { client_id: params.client_id };
|
|
133
|
-
const response = await this.#rpc.handle(params.data, extra, options);
|
|
134
|
-
if (response === undefined) return undefined;
|
|
135
|
-
return this._format(response);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* 按服务器 json 配置格式化数据
|
|
140
|
-
* @param {Object|string} data 响应对象或待推送数据
|
|
141
|
-
* @returns {Object|string} json 模式返回原值,文本模式字符串原样、其余 JSON 序列化
|
|
142
|
-
*/
|
|
143
|
-
_format(data) {
|
|
144
|
-
if (this.#server.config.json) return data;
|
|
145
|
-
if (typeof data === 'string') return data;
|
|
146
|
-
return JSON.stringify(data);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
module.exports = MessagePlugin;
|