rol-websocket-channel 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MQTT-API.md +967 -0
- package/dist/index.js +430 -0
- package/dist/message-handler.js +327 -0
- package/dist/src/admin/cli.js +43 -0
- package/dist/src/admin/jsonrpc.js +60 -0
- package/dist/src/admin/lib/fs.js +30 -0
- package/dist/src/admin/lib/paths.js +46 -0
- package/dist/src/admin/methods/admin.js +60 -0
- package/dist/src/admin/methods/agents-extended.js +235 -0
- package/dist/src/admin/methods/index.js +69 -0
- package/dist/src/admin/methods/memory.js +360 -0
- package/dist/src/admin/methods/models-extended.js +107 -0
- package/dist/src/admin/methods/models.js +39 -0
- package/dist/src/admin/methods/sessions-extended.js +207 -0
- package/dist/src/admin/methods/sessions.js +64 -0
- package/dist/src/admin/methods/skills-extended.js +157 -0
- package/dist/src/admin/methods/skills-toggle.js +182 -0
- package/dist/src/admin/methods/skills.js +384 -0
- package/dist/src/admin/methods/system.js +178 -0
- package/dist/src/admin/methods/usage.js +1170 -0
- package/dist/src/admin/types.js +1 -0
- package/dist/src/mqtt/connection-manager.js +155 -0
- package/dist/src/mqtt/index.js +5 -0
- package/dist/src/mqtt/mqtt-client.js +86 -0
- package/dist/src/mqtt/types.js +2 -0
- package/dist/src/shared/context.js +24 -0
- package/dist/src/shared/wrapper.js +23 -0
- package/index.ts +514 -0
- package/message-handler.ts +415 -0
- package/openclaw.plugin.json +84 -0
- package/package.json +35 -0
- package/readme.md +32 -0
- package/src/admin/cli.ts +60 -0
- package/src/admin/jsonrpc.ts +88 -0
- package/src/admin/lib/fs.ts +35 -0
- package/src/admin/lib/paths.ts +61 -0
- package/src/admin/methods/admin.ts +95 -0
- package/src/admin/methods/agents-extended.ts +310 -0
- package/src/admin/methods/index.ts +103 -0
- package/src/admin/methods/memory.ts +546 -0
- package/src/admin/methods/models-extended.ts +191 -0
- package/src/admin/methods/models.ts +103 -0
- package/src/admin/methods/sessions-extended.ts +313 -0
- package/src/admin/methods/sessions.ts +122 -0
- package/src/admin/methods/skills-extended.ts +249 -0
- package/src/admin/methods/skills-toggle.ts +235 -0
- package/src/admin/methods/skills.ts +651 -0
- package/src/admin/methods/system.ts +203 -0
- package/src/admin/methods/usage.ts +1491 -0
- package/src/admin/types.ts +46 -0
- package/src/mqtt/connection-manager.ts +188 -0
- package/src/mqtt/index.ts +6 -0
- package/src/mqtt/mqtt-client.ts +119 -0
- package/src/mqtt/types.ts +36 -0
- package/src/shared/context.ts +33 -0
- package/src/shared/wrapper.ts +35 -0
- package/tsconfig.json +16 -0
- package/types/openclaw.d.ts +74 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// MQTT 连接管理器
|
|
2
|
+
// 负责管理 MQTT 连接的建立和维护(使用 MQTT.js 自带的重连功能)
|
|
3
|
+
// 全局连接存储
|
|
4
|
+
const connections = new Map();
|
|
5
|
+
/**
|
|
6
|
+
* 获取连接
|
|
7
|
+
*/
|
|
8
|
+
export function getConnection(accountId) {
|
|
9
|
+
const conn = connections.get(accountId);
|
|
10
|
+
console.log(`[MQTT] getConnection(${accountId}): ${conn ? 'found' : 'not found'}`);
|
|
11
|
+
return conn;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 检查连接是否存在且已连接
|
|
15
|
+
*/
|
|
16
|
+
export function isConnected(accountId) {
|
|
17
|
+
const conn = connections.get(accountId);
|
|
18
|
+
const connected = !!(conn && conn.ws && conn.ws.connected);
|
|
19
|
+
console.log(`[MQTT] isConnected(${accountId}): ${connected}`);
|
|
20
|
+
return connected;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 删除连接
|
|
24
|
+
*/
|
|
25
|
+
export function removeConnection(accountId) {
|
|
26
|
+
console.log(`[MQTT] removeConnection(${accountId})`);
|
|
27
|
+
connections.delete(accountId);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 创建 MQTT 连接
|
|
31
|
+
* 使用 MQTT.js 自带的重连功能
|
|
32
|
+
*/
|
|
33
|
+
export async function createMqttConnection(config, callbacks) {
|
|
34
|
+
const { mqttUrl, mqttTopic, accountId } = config;
|
|
35
|
+
console.log(`[MQTT] createMqttConnection(${accountId}): url=${mqttUrl}, topic=${mqttTopic}`);
|
|
36
|
+
// 如果已有活跃连接,直接返回(防止重复创建)
|
|
37
|
+
const existingConn = connections.get(accountId);
|
|
38
|
+
if (existingConn && existingConn.ws && existingConn.ws.connected) {
|
|
39
|
+
console.log(`[MQTT] createMqttConnection(${accountId}): connection already exists and connected, skipping`);
|
|
40
|
+
return existingConn;
|
|
41
|
+
}
|
|
42
|
+
// 如果有未连接的旧连接,先关闭
|
|
43
|
+
if (existingConn) {
|
|
44
|
+
console.log(`[MQTT] createMqttConnection(${accountId}): closing existing disconnected connection`);
|
|
45
|
+
existingConn.ws.end(true);
|
|
46
|
+
connections.delete(accountId);
|
|
47
|
+
}
|
|
48
|
+
// 动态导入 mqtt 库
|
|
49
|
+
console.log(`[MQTT] createMqttConnection(${accountId}): importing mqtt library...`);
|
|
50
|
+
const mqtt = await import("mqtt");
|
|
51
|
+
console.log(`[MQTT] createMqttConnection(${accountId}): mqtt library imported`);
|
|
52
|
+
// 创建 MQTT 客户端,启用自带的重连功能
|
|
53
|
+
console.log(`[MQTT] createMqttConnection(${accountId}): creating client with reconnect...`);
|
|
54
|
+
const client = mqtt.default.connect(mqttUrl, {
|
|
55
|
+
reconnectPeriod: 5000, // 5秒后自动重连
|
|
56
|
+
connectTimeout: 30000, // 连接超时 30秒
|
|
57
|
+
keepalive: 30, // 心跳 30秒
|
|
58
|
+
clean: true, // 清理会话
|
|
59
|
+
});
|
|
60
|
+
console.log(`[MQTT] createMqttConnection(${accountId}): client created`);
|
|
61
|
+
// 存储连接
|
|
62
|
+
const connection = {
|
|
63
|
+
ws: client,
|
|
64
|
+
accountId,
|
|
65
|
+
mqttTopic,
|
|
66
|
+
};
|
|
67
|
+
connections.set(accountId, connection);
|
|
68
|
+
console.log(`[MQTT] createMqttConnection(${accountId}): connection stored, total connections=${connections.size}`);
|
|
69
|
+
// 设置事件处理器
|
|
70
|
+
setupEventHandlers(client, accountId, mqttTopic, callbacks);
|
|
71
|
+
console.log(`[MQTT] createMqttConnection(${accountId}): event handlers set up`);
|
|
72
|
+
return connection;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 设置 MQTT 事件处理器
|
|
76
|
+
*/
|
|
77
|
+
function setupEventHandlers(client, accountId, mqttTopic, callbacks) {
|
|
78
|
+
const { onConnect, onDisconnect, onError, onClose, onMessage } = callbacks;
|
|
79
|
+
// 连接成功
|
|
80
|
+
client.on("connect", () => {
|
|
81
|
+
console.log(`[MQTT] ✅ Connected to broker for account: ${accountId}`);
|
|
82
|
+
// 订阅 topic
|
|
83
|
+
console.log(`[MQTT] subscribing to topic: ${mqttTopic} for account: ${accountId}`);
|
|
84
|
+
client.subscribe(mqttTopic, (err) => {
|
|
85
|
+
if (err) {
|
|
86
|
+
console.error(`[MQTT] ❌ Failed to subscribe: ${err.message}`);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.log(`[MQTT] ✅ Subscribed to: ${mqttTopic}`);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
onConnect?.();
|
|
93
|
+
});
|
|
94
|
+
// 收到消息
|
|
95
|
+
client.on("message", (topic, payload) => {
|
|
96
|
+
console.log(`[MQTT] 📨 message received on topic: ${topic}, size: ${payload.length} bytes`);
|
|
97
|
+
onMessage?.(topic, payload);
|
|
98
|
+
});
|
|
99
|
+
// 连接错误
|
|
100
|
+
client.on("error", (err) => {
|
|
101
|
+
console.error(`[MQTT] ❌ Error for account ${accountId}: ${err.message}`);
|
|
102
|
+
onError?.(err);
|
|
103
|
+
// MQTT.js 会自动处理重连,不需要我们干预
|
|
104
|
+
});
|
|
105
|
+
// 连接断开
|
|
106
|
+
client.on("disconnect", () => {
|
|
107
|
+
console.log(`[MQTT] 🔴 Disconnected for account: ${accountId}`);
|
|
108
|
+
onDisconnect?.();
|
|
109
|
+
});
|
|
110
|
+
// 连接关闭
|
|
111
|
+
client.on("close", () => {
|
|
112
|
+
console.log(`[MQTT] 🔴 Connection closed for account: ${accountId}`);
|
|
113
|
+
// 注意:MQTT.js 会自动重连,不要在这里删除连接
|
|
114
|
+
// 只有在手动停止时才删除
|
|
115
|
+
onClose?.();
|
|
116
|
+
});
|
|
117
|
+
// 重连开始
|
|
118
|
+
client.on("reconnect", () => {
|
|
119
|
+
console.log(`[MQTT] 🔄 Reconnecting for account: ${accountId}...`);
|
|
120
|
+
});
|
|
121
|
+
// 离线
|
|
122
|
+
client.on("offline", () => {
|
|
123
|
+
console.log(`[MQTT] 😴 Client offline for account: ${accountId}`);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 关闭连接(手动停止时使用)
|
|
128
|
+
*/
|
|
129
|
+
export function closeConnection(accountId) {
|
|
130
|
+
console.log(`[MQTT] closeConnection(${accountId}): closing connection...`);
|
|
131
|
+
const conn = connections.get(accountId);
|
|
132
|
+
if (conn) {
|
|
133
|
+
console.log(`[MQTT] closeConnection(${accountId}): ending mqtt client...`);
|
|
134
|
+
// force=true 立即关闭,不触发重连
|
|
135
|
+
conn.ws.end(true);
|
|
136
|
+
removeConnection(accountId);
|
|
137
|
+
console.log(`[MQTT] closeConnection(${accountId}): connection closed`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
console.log(`[MQTT] closeConnection(${accountId}): no connection found`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 发布消息
|
|
145
|
+
*/
|
|
146
|
+
export function publishMessage(accountId, topic, message) {
|
|
147
|
+
const conn = connections.get(accountId);
|
|
148
|
+
if (!conn || !conn.ws || !conn.ws.connected) {
|
|
149
|
+
console.error(`[MQTT] ❌ No connection available for account: ${accountId}`);
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
console.log(`[MQTT] publishMessage(${accountId}): publishing to ${topic}`);
|
|
153
|
+
conn.ws.publish(topic, message);
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// MQTT 客户端类
|
|
2
|
+
// 封装 MQTT 连接和消息处理逻辑(使用 MQTT.js 自带的重连功能)
|
|
3
|
+
import * as ConnectionManager from "./connection-manager.js";
|
|
4
|
+
export class MqttClient {
|
|
5
|
+
constructor(options) {
|
|
6
|
+
this.config = options.config;
|
|
7
|
+
this.abortSignal = options.abortSignal;
|
|
8
|
+
this.onMessage = options.onMessage;
|
|
9
|
+
this.onConnect = options.onConnect;
|
|
10
|
+
this.onDisconnect = options.onDisconnect;
|
|
11
|
+
this.onError = options.onError;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 连接到 MQTT Broker
|
|
15
|
+
* 使用 MQTT.js 自带的重连功能
|
|
16
|
+
*/
|
|
17
|
+
async connect() {
|
|
18
|
+
const { accountId, mqttUrl, mqttTopic } = this.config;
|
|
19
|
+
console.log(`[MQTT] MqttClient.connect(${accountId}): starting connection to ${mqttUrl}...`);
|
|
20
|
+
// 检查是否已中止
|
|
21
|
+
if (this.abortSignal.aborted) {
|
|
22
|
+
console.log(`[MQTT] MqttClient.connect(${accountId}): aborted before starting`);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// 创建连接
|
|
26
|
+
await ConnectionManager.createMqttConnection(this.config, {
|
|
27
|
+
onConnect: () => {
|
|
28
|
+
console.log(`[MQTT] MqttClient(${accountId}): onConnect callback`);
|
|
29
|
+
this.onConnect?.();
|
|
30
|
+
},
|
|
31
|
+
onDisconnect: () => {
|
|
32
|
+
console.log(`[MQTT] MqttClient(${accountId}): onDisconnect callback`);
|
|
33
|
+
this.onDisconnect?.();
|
|
34
|
+
},
|
|
35
|
+
onError: (err) => {
|
|
36
|
+
console.error(`[MQTT] MqttClient(${accountId}): onError callback - ${err.message}`);
|
|
37
|
+
this.onError?.(err);
|
|
38
|
+
},
|
|
39
|
+
onClose: () => {
|
|
40
|
+
console.log(`[MQTT] MqttClient(${accountId}): onClose callback`);
|
|
41
|
+
// MQTT.js 会自动重连,不需要我们干预
|
|
42
|
+
// 只有在 abortSignal 触发时才真正关闭
|
|
43
|
+
if (this.abortSignal.aborted) {
|
|
44
|
+
console.log(`[MQTT] MqttClient(${accountId}): abort signaled, cleaning up`);
|
|
45
|
+
ConnectionManager.removeConnection(accountId);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
onMessage: this.onMessage,
|
|
49
|
+
});
|
|
50
|
+
console.log(`[MQTT] MqttClient.connect(${accountId}): connection created, waiting for abort signal...`);
|
|
51
|
+
// 等待中止信号
|
|
52
|
+
await new Promise((resolve) => {
|
|
53
|
+
const handleAbort = () => {
|
|
54
|
+
console.log(`[MQTT] MqttClient(${accountId}): abort signal received`);
|
|
55
|
+
this.disconnect();
|
|
56
|
+
resolve();
|
|
57
|
+
};
|
|
58
|
+
this.abortSignal.addEventListener("abort", handleAbort, { once: true });
|
|
59
|
+
});
|
|
60
|
+
console.log(`[MQTT] MqttClient.connect(${accountId}): connection loop ended`);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 断开连接(手动停止时使用)
|
|
64
|
+
*/
|
|
65
|
+
disconnect() {
|
|
66
|
+
const { accountId } = this.config;
|
|
67
|
+
console.log(`[MQTT] MqttClient.disconnect(${accountId}): disconnecting...`);
|
|
68
|
+
ConnectionManager.closeConnection(accountId);
|
|
69
|
+
console.log(`[MQTT] MqttClient.disconnect(${accountId}): disconnected`);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 发布消息
|
|
73
|
+
*/
|
|
74
|
+
publish(topic, message) {
|
|
75
|
+
const { accountId } = this.config;
|
|
76
|
+
console.log(`[MQTT] MqttClient.publish(${accountId}): publishing to ${topic}`);
|
|
77
|
+
return ConnectionManager.publishMessage(accountId, topic, message);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 检查是否已连接
|
|
81
|
+
*/
|
|
82
|
+
isConnected() {
|
|
83
|
+
const { accountId } = this.config;
|
|
84
|
+
return ConnectionManager.isConnected(accountId);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 共享 Context 管理
|
|
3
|
+
* 用于在 MQTT handler 和 admin 方法之间共享上下文
|
|
4
|
+
*/
|
|
5
|
+
import { getOpenClawRoot, getProjectRoot } from '../admin/lib/paths.js';
|
|
6
|
+
let cachedContext = null;
|
|
7
|
+
/**
|
|
8
|
+
* 初始化全局 context
|
|
9
|
+
*/
|
|
10
|
+
export function initializeContext() {
|
|
11
|
+
cachedContext = {
|
|
12
|
+
projectRoot: getProjectRoot(),
|
|
13
|
+
openclawRoot: getOpenClawRoot(),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 获取当前 context
|
|
18
|
+
*/
|
|
19
|
+
export function getContext() {
|
|
20
|
+
if (!cachedContext) {
|
|
21
|
+
initializeContext();
|
|
22
|
+
}
|
|
23
|
+
return cachedContext;
|
|
24
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 统一的方法调用包装器
|
|
3
|
+
* 提供统一的错误处理和返回格式
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 包装 admin 方法调用,统一返回格式
|
|
7
|
+
*/
|
|
8
|
+
export async function wrapAdminCall(fn) {
|
|
9
|
+
try {
|
|
10
|
+
const result = await fn();
|
|
11
|
+
return { ok: true, result };
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
return {
|
|
15
|
+
ok: false,
|
|
16
|
+
error: {
|
|
17
|
+
message: error instanceof Error ? error.message : String(error),
|
|
18
|
+
code: error.code,
|
|
19
|
+
data: error.data,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|