@yu_robotics/remote-cli-router 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/LICENSE +21 -0
- package/README.md +115 -0
- package/bin/remote-cli-router.js +2 -0
- package/dist/binding/BindingManager.d.ts +62 -0
- package/dist/binding/BindingManager.d.ts.map +1 -0
- package/dist/binding/BindingManager.js +119 -0
- package/dist/binding/BindingManager.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +32 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/config.d.ts +19 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +206 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/start.d.ts +5 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +65 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +103 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +5 -0
- package/dist/commands/stop.d.ts.map +1 -0
- package/dist/commands/stop.js +56 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/config/ConfigManager.d.ts +46 -0
- package/dist/config/ConfigManager.d.ts.map +1 -0
- package/dist/config/ConfigManager.js +101 -0
- package/dist/config/ConfigManager.js.map +1 -0
- package/dist/feishu/FeishuClient.d.ts +46 -0
- package/dist/feishu/FeishuClient.d.ts.map +1 -0
- package/dist/feishu/FeishuClient.js +130 -0
- package/dist/feishu/FeishuClient.js.map +1 -0
- package/dist/feishu/FeishuLongConnHandler.d.ts +149 -0
- package/dist/feishu/FeishuLongConnHandler.d.ts.map +1 -0
- package/dist/feishu/FeishuLongConnHandler.js +632 -0
- package/dist/feishu/FeishuLongConnHandler.js.map +1 -0
- package/dist/server.d.ts +80 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +533 -0
- package/dist/server.js.map +1 -0
- package/dist/storage/JsonStore.d.ts +90 -0
- package/dist/storage/JsonStore.d.ts.map +1 -0
- package/dist/storage/JsonStore.js +215 -0
- package/dist/storage/JsonStore.js.map +1 -0
- package/dist/storage/MemoryStore.d.ts +69 -0
- package/dist/storage/MemoryStore.d.ts.map +1 -0
- package/dist/storage/MemoryStore.js +117 -0
- package/dist/storage/MemoryStore.js.map +1 -0
- package/dist/types/config.d.ts +53 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +31 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +93 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +18 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/PidManager.d.ts +28 -0
- package/dist/utils/PidManager.d.ts.map +1 -0
- package/dist/utils/PidManager.js +90 -0
- package/dist/utils/PidManager.js.map +1 -0
- package/dist/utils/ToolFormatter.d.ts +41 -0
- package/dist/utils/ToolFormatter.d.ts.map +1 -0
- package/dist/utils/ToolFormatter.js +273 -0
- package/dist/utils/ToolFormatter.js.map +1 -0
- package/dist/websocket/ConnectionHub.d.ts +73 -0
- package/dist/websocket/ConnectionHub.d.ts.map +1 -0
- package/dist/websocket/ConnectionHub.js +177 -0
- package/dist/websocket/ConnectionHub.js.map +1 -0
- package/package.json +70 -0
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ConfigManager } from './config/ConfigManager';
|
|
2
|
+
import { JsonStore } from './storage/JsonStore';
|
|
3
|
+
/**
|
|
4
|
+
* Router Server
|
|
5
|
+
* Handles Feishu WebSocket long connection, local WebSocket connections, and message routing
|
|
6
|
+
*/
|
|
7
|
+
export declare class RouterServer {
|
|
8
|
+
private app;
|
|
9
|
+
private httpServer;
|
|
10
|
+
private wss;
|
|
11
|
+
private config;
|
|
12
|
+
private store;
|
|
13
|
+
private feishuLongConnHandler;
|
|
14
|
+
private connectionHub;
|
|
15
|
+
private bindingManager;
|
|
16
|
+
private cleanupInterval;
|
|
17
|
+
private streamingMessages;
|
|
18
|
+
private readonly STREAMING_SESSION_TIMEOUT_MS;
|
|
19
|
+
constructor(config: ConfigManager, store: JsonStore);
|
|
20
|
+
/**
|
|
21
|
+
* Setup Koa middleware
|
|
22
|
+
*/
|
|
23
|
+
private setupMiddleware;
|
|
24
|
+
/**
|
|
25
|
+
* Setup HTTP routes
|
|
26
|
+
*/
|
|
27
|
+
private setupRoutes;
|
|
28
|
+
/**
|
|
29
|
+
* Setup WebSocket server
|
|
30
|
+
*/
|
|
31
|
+
private setupWebSocket;
|
|
32
|
+
/**
|
|
33
|
+
* Start the server
|
|
34
|
+
*/
|
|
35
|
+
start(): Promise<void>;
|
|
36
|
+
private lastStreamUpdateTime;
|
|
37
|
+
private readonly STREAM_UPDATE_INTERVAL_MS;
|
|
38
|
+
private readonly STREAM_UPDATE_MIN_LENGTH;
|
|
39
|
+
/**
|
|
40
|
+
* Handle streaming chunk from device
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Handle text streaming chunk
|
|
44
|
+
*/
|
|
45
|
+
private handleTextChunk;
|
|
46
|
+
/**
|
|
47
|
+
* Handle tool use event
|
|
48
|
+
*/
|
|
49
|
+
private handleToolUse;
|
|
50
|
+
/**
|
|
51
|
+
* Handle tool result event
|
|
52
|
+
*/
|
|
53
|
+
private handleToolResult;
|
|
54
|
+
/**
|
|
55
|
+
* Finalize streaming message
|
|
56
|
+
*/
|
|
57
|
+
private finalizeStreamingMessage;
|
|
58
|
+
/**
|
|
59
|
+
* Cleanup stale streaming sessions that have timed out
|
|
60
|
+
* This prevents memory leaks when devices disconnect without sending a response
|
|
61
|
+
*/
|
|
62
|
+
private cleanupStaleStreamingSessions;
|
|
63
|
+
/**
|
|
64
|
+
* Cleanup streaming sessions for a specific device when it disconnects
|
|
65
|
+
* @param deviceId Device ID that disconnected
|
|
66
|
+
*/
|
|
67
|
+
private cleanupStreamingSessionsForDevice;
|
|
68
|
+
/**
|
|
69
|
+
* Stop the server
|
|
70
|
+
*/
|
|
71
|
+
stop(): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Get connection statistics
|
|
74
|
+
*/
|
|
75
|
+
getStats(): {
|
|
76
|
+
totalConnections: number;
|
|
77
|
+
deviceIds: string[];
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAOhD;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,qBAAqB,CAAwB;IACrD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,eAAe,CAA+B;IAEtD,OAAO,CAAC,iBAAiB,CAQV;IACf,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAkB;gBAEnD,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS;IAsCnD;;OAEG;IACH,OAAO,CAAC,eAAe;IA0BvB;;OAEG;IACH,OAAO,CAAC,WAAW;IA2DnB;;OAEG;IACH,OAAO,CAAC,cAAc;IA8KtB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmC5B,OAAO,CAAC,oBAAoB,CAAkC;IAC9D,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAO;IACjD,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAM;IAE/C;;OAEG;IACH;;OAEG;YACW,eAAe;IAiD7B;;OAEG;YACW,aAAa;IA+B3B;;OAEG;YACW,gBAAgB;IA+B9B;;OAEG;YACW,wBAAwB;IA2CtC;;;OAGG;IACH,OAAO,CAAC,6BAA6B;IAkBrC;;;OAGG;IACH,OAAO,CAAC,iCAAiC;IAiBzC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuC3B;;OAEG;IACH,QAAQ;;;;CAGT"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RouterServer = void 0;
|
|
7
|
+
const koa_1 = __importDefault(require("koa"));
|
|
8
|
+
const koa_bodyparser_1 = __importDefault(require("koa-bodyparser"));
|
|
9
|
+
const router_1 = __importDefault(require("@koa/router"));
|
|
10
|
+
const ws_1 = require("ws");
|
|
11
|
+
const FeishuLongConnHandler_1 = require("./feishu/FeishuLongConnHandler");
|
|
12
|
+
const ConnectionHub_1 = require("./websocket/ConnectionHub");
|
|
13
|
+
const BindingManager_1 = require("./binding/BindingManager");
|
|
14
|
+
const types_1 = require("./types");
|
|
15
|
+
const ToolFormatter_1 = require("./utils/ToolFormatter");
|
|
16
|
+
/**
|
|
17
|
+
* Router Server
|
|
18
|
+
* Handles Feishu WebSocket long connection, local WebSocket connections, and message routing
|
|
19
|
+
*/
|
|
20
|
+
class RouterServer {
|
|
21
|
+
app;
|
|
22
|
+
httpServer = null;
|
|
23
|
+
wss = null;
|
|
24
|
+
config;
|
|
25
|
+
store;
|
|
26
|
+
feishuLongConnHandler;
|
|
27
|
+
connectionHub;
|
|
28
|
+
bindingManager;
|
|
29
|
+
cleanupInterval = null;
|
|
30
|
+
// Track streaming messages: messageId -> { openId, feishuMessageId, elements, currentTextContent, hasUpdated, createdAt, deviceId }
|
|
31
|
+
streamingMessages = new Map();
|
|
32
|
+
STREAMING_SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes timeout
|
|
33
|
+
constructor(config, store) {
|
|
34
|
+
this.config = config;
|
|
35
|
+
this.store = store;
|
|
36
|
+
this.app = new koa_1.default();
|
|
37
|
+
this.connectionHub = new ConnectionHub_1.ConnectionHub();
|
|
38
|
+
this.bindingManager = new BindingManager_1.BindingManager(store);
|
|
39
|
+
// Initialize FeishuLongConnHandler (WebSocket mode)
|
|
40
|
+
this.feishuLongConnHandler = new FeishuLongConnHandler_1.FeishuLongConnHandler({
|
|
41
|
+
appId: config.get('feishu', 'appId'),
|
|
42
|
+
appSecret: config.get('feishu', 'appSecret'),
|
|
43
|
+
store: this.store
|
|
44
|
+
});
|
|
45
|
+
// Share ConnectionHub with Feishu handler
|
|
46
|
+
this.feishuLongConnHandler.setConnectionHub(this.connectionHub);
|
|
47
|
+
// Register callback for streaming message start
|
|
48
|
+
this.feishuLongConnHandler.setOnStartStreaming((messageId, openId, feishuMessageId, deviceId) => {
|
|
49
|
+
console.log(`[RouterServer] Registering streaming session: msgId=${messageId}, feishuMsgId=${feishuMessageId}, deviceId=${deviceId}`);
|
|
50
|
+
// Register this message as a streaming message so chunks and response update the same card
|
|
51
|
+
// hasUpdated starts as false to ensure first content is immediately shown
|
|
52
|
+
this.streamingMessages.set(messageId, {
|
|
53
|
+
openId,
|
|
54
|
+
feishuMessageId,
|
|
55
|
+
elements: [],
|
|
56
|
+
currentTextContent: '',
|
|
57
|
+
hasUpdated: false,
|
|
58
|
+
createdAt: Date.now(),
|
|
59
|
+
deviceId
|
|
60
|
+
});
|
|
61
|
+
console.log(`[RouterServer] Total streaming sessions: ${this.streamingMessages.size}`);
|
|
62
|
+
});
|
|
63
|
+
this.setupMiddleware();
|
|
64
|
+
this.setupRoutes();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Setup Koa middleware
|
|
68
|
+
*/
|
|
69
|
+
setupMiddleware() {
|
|
70
|
+
this.app.use((0, koa_bodyparser_1.default)());
|
|
71
|
+
// Error handling
|
|
72
|
+
this.app.use(async (ctx, next) => {
|
|
73
|
+
try {
|
|
74
|
+
await next();
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
console.error('Request error:', error);
|
|
78
|
+
ctx.status = error.status || 500;
|
|
79
|
+
ctx.body = {
|
|
80
|
+
success: false,
|
|
81
|
+
error: error.message || 'Internal server error'
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
// Request logging
|
|
86
|
+
this.app.use(async (ctx, next) => {
|
|
87
|
+
const start = Date.now();
|
|
88
|
+
await next();
|
|
89
|
+
const ms = Date.now() - start;
|
|
90
|
+
console.log(`${ctx.method} ${ctx.url} - ${ctx.status} (${ms}ms)`);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Setup HTTP routes
|
|
95
|
+
*/
|
|
96
|
+
setupRoutes() {
|
|
97
|
+
const router = new router_1.default();
|
|
98
|
+
// Health check endpoint
|
|
99
|
+
router.get('/health', (ctx) => {
|
|
100
|
+
const stats = this.connectionHub.getConnectionStats();
|
|
101
|
+
ctx.body = {
|
|
102
|
+
status: 'ok',
|
|
103
|
+
timestamp: Date.now(),
|
|
104
|
+
connections: stats.totalConnections,
|
|
105
|
+
devices: stats.deviceIds
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
// Binding code request endpoint
|
|
109
|
+
router.post('/api/bind/request', async (ctx) => {
|
|
110
|
+
const { deviceId, deviceName, platform } = ctx.request.body;
|
|
111
|
+
// Validate required fields
|
|
112
|
+
if (!deviceId) {
|
|
113
|
+
ctx.status = 400;
|
|
114
|
+
ctx.body = {
|
|
115
|
+
success: false,
|
|
116
|
+
error: 'deviceId is required'
|
|
117
|
+
};
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
// Generate binding code
|
|
122
|
+
const bindingCode = await this.bindingManager.generateBindingCode(deviceId, deviceName || 'Unknown Device');
|
|
123
|
+
ctx.body = {
|
|
124
|
+
success: true,
|
|
125
|
+
bindingCode: bindingCode.code,
|
|
126
|
+
expiresAt: bindingCode.expiresAt,
|
|
127
|
+
expiresIn: Math.floor((bindingCode.expiresAt - Date.now()) / 1000) // seconds
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.error('Failed to generate binding code:', error);
|
|
132
|
+
ctx.status = 500;
|
|
133
|
+
ctx.body = {
|
|
134
|
+
success: false,
|
|
135
|
+
error: error.message || 'Failed to generate binding code'
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
this.app.use(router.routes());
|
|
140
|
+
this.app.use(router.allowedMethods());
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Setup WebSocket server
|
|
144
|
+
*/
|
|
145
|
+
setupWebSocket(server) {
|
|
146
|
+
this.wss = new ws_1.WebSocketServer({
|
|
147
|
+
server,
|
|
148
|
+
path: '/ws'
|
|
149
|
+
});
|
|
150
|
+
this.wss.on('connection', (ws, req) => {
|
|
151
|
+
console.log('New WebSocket connection from:', req.socket.remoteAddress);
|
|
152
|
+
let deviceId = null;
|
|
153
|
+
let heartbeatTimeout = null;
|
|
154
|
+
// Reset heartbeat timeout
|
|
155
|
+
const resetHeartbeat = () => {
|
|
156
|
+
if (heartbeatTimeout)
|
|
157
|
+
clearTimeout(heartbeatTimeout);
|
|
158
|
+
// If no heartbeat received within 3x interval, consider connection dead
|
|
159
|
+
const interval = this.config.get('websocket', 'heartbeatInterval');
|
|
160
|
+
heartbeatTimeout = setTimeout(() => {
|
|
161
|
+
console.log('Heartbeat timeout for device:', deviceId);
|
|
162
|
+
ws.close();
|
|
163
|
+
}, interval * 3);
|
|
164
|
+
};
|
|
165
|
+
resetHeartbeat();
|
|
166
|
+
// Handle incoming messages
|
|
167
|
+
ws.on('message', async (data) => {
|
|
168
|
+
try {
|
|
169
|
+
const message = JSON.parse(data.toString());
|
|
170
|
+
// Update heartbeat on any message
|
|
171
|
+
resetHeartbeat();
|
|
172
|
+
switch (message.type) {
|
|
173
|
+
case types_1.MessageType.BINDING_REQUEST:
|
|
174
|
+
// Device sends binding request with deviceId
|
|
175
|
+
deviceId = message.data.deviceId;
|
|
176
|
+
if (deviceId) {
|
|
177
|
+
this.connectionHub.registerConnection(deviceId, ws);
|
|
178
|
+
console.log('Device registered:', deviceId);
|
|
179
|
+
// Send confirmation
|
|
180
|
+
ws.send(JSON.stringify({
|
|
181
|
+
type: types_1.MessageType.BINDING_CONFIRM,
|
|
182
|
+
messageId: message.messageId,
|
|
183
|
+
timestamp: Date.now(),
|
|
184
|
+
data: { success: true }
|
|
185
|
+
}));
|
|
186
|
+
}
|
|
187
|
+
break;
|
|
188
|
+
case types_1.MessageType.HEARTBEAT:
|
|
189
|
+
// Update last active time for the device
|
|
190
|
+
if (deviceId) {
|
|
191
|
+
this.connectionHub.updateLastActive(deviceId);
|
|
192
|
+
}
|
|
193
|
+
// Respond to heartbeat
|
|
194
|
+
ws.send(JSON.stringify({
|
|
195
|
+
type: types_1.MessageType.HEARTBEAT,
|
|
196
|
+
messageId: message.messageId,
|
|
197
|
+
timestamp: Date.now(),
|
|
198
|
+
data: {}
|
|
199
|
+
}));
|
|
200
|
+
break;
|
|
201
|
+
case types_1.MessageType.RESPONSE:
|
|
202
|
+
// Device sends response to command - forward to Feishu via long connection
|
|
203
|
+
const responseOpenId = message.openId || message.data?.openId;
|
|
204
|
+
const responseMessageId = message.messageId;
|
|
205
|
+
const sessionAbbr = message.sessionAbbr || message.data?.sessionAbbr;
|
|
206
|
+
if (responseMessageId && responseOpenId) {
|
|
207
|
+
// Check if this was a streaming message (stream chunks were sent)
|
|
208
|
+
if (this.streamingMessages.has(responseMessageId)) {
|
|
209
|
+
await this.finalizeStreamingMessage(responseMessageId, message.success ?? message.data?.success, message.output || message.data?.output, message.error || message.data?.error, sessionAbbr);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
// No streaming session found - session should have been created when command was sent
|
|
213
|
+
// This might happen if there was an error. Just send the result as plain text.
|
|
214
|
+
const output = message.output || message.data?.output;
|
|
215
|
+
const success = message.success ?? message.data?.success;
|
|
216
|
+
const errorMsg = message.error || message.data?.error;
|
|
217
|
+
if (success) {
|
|
218
|
+
await this.feishuLongConnHandler.sendMessage(responseOpenId, output || '✅ Command completed successfully');
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
await this.feishuLongConnHandler.sendMessage(responseOpenId, `❌ Command failed:\n${errorMsg || 'Unknown error'}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
break;
|
|
226
|
+
case 'stream':
|
|
227
|
+
// Handle streaming output from device
|
|
228
|
+
if (message.messageId && message.openId) {
|
|
229
|
+
const streamType = message.streamType || 'text';
|
|
230
|
+
switch (streamType) {
|
|
231
|
+
case 'text':
|
|
232
|
+
await this.handleTextChunk(message.messageId, message.openId, message.chunk || '');
|
|
233
|
+
break;
|
|
234
|
+
case 'tool_use':
|
|
235
|
+
if (message.toolUse) {
|
|
236
|
+
await this.handleToolUse(message.messageId, message.openId, message.toolUse);
|
|
237
|
+
}
|
|
238
|
+
break;
|
|
239
|
+
case 'tool_result':
|
|
240
|
+
if (message.toolResult) {
|
|
241
|
+
await this.handleToolResult(message.messageId, message.openId, message.toolResult);
|
|
242
|
+
}
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
break;
|
|
247
|
+
case types_1.MessageType.NOTIFICATION:
|
|
248
|
+
// Handle notification from device - only forward actionable notifications
|
|
249
|
+
// that require user intervention (authorization, input required)
|
|
250
|
+
if (message.openId && message.title && message.message) {
|
|
251
|
+
const actionablePrefixes = ['🔒', '⌨️']; // Authorization Required, Waiting for Input
|
|
252
|
+
const isActionable = actionablePrefixes.some(prefix => message.title.startsWith(prefix));
|
|
253
|
+
if (isActionable) {
|
|
254
|
+
console.log(`[RouterServer] Forwarding actionable notification to ${message.openId}: ${message.title}`);
|
|
255
|
+
await this.feishuLongConnHandler.sendMessage(message.openId, `**${message.title}**\n\n${message.message}`);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
// Log non-actionable notifications but don't forward to user
|
|
259
|
+
console.log(`[RouterServer] Ignoring notification (non-actionable): ${message.title}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
break;
|
|
263
|
+
default:
|
|
264
|
+
console.log('Unknown message type:', message.type);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
console.error('Error processing message:', error);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
// Handle connection close
|
|
272
|
+
ws.on('close', () => {
|
|
273
|
+
if (heartbeatTimeout)
|
|
274
|
+
clearTimeout(heartbeatTimeout);
|
|
275
|
+
if (deviceId) {
|
|
276
|
+
this.connectionHub.unregisterConnection(deviceId);
|
|
277
|
+
// Clean up any streaming sessions for this device
|
|
278
|
+
this.cleanupStreamingSessionsForDevice(deviceId);
|
|
279
|
+
console.log('Device disconnected:', deviceId);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
// Handle errors
|
|
283
|
+
ws.on('error', (error) => {
|
|
284
|
+
console.error('WebSocket error:', error);
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
console.log('WebSocket server listening on /ws');
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Start the server
|
|
291
|
+
*/
|
|
292
|
+
async start() {
|
|
293
|
+
const port = this.config.get('server', 'port');
|
|
294
|
+
const host = this.config.get('server', 'host');
|
|
295
|
+
// Create HTTP server
|
|
296
|
+
this.httpServer = this.app.listen(port, host);
|
|
297
|
+
// Setup WebSocket server
|
|
298
|
+
this.setupWebSocket(this.httpServer);
|
|
299
|
+
// Start Feishu WebSocket long connection
|
|
300
|
+
try {
|
|
301
|
+
await this.feishuLongConnHandler.start();
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
console.error('⚠️ Failed to start Feishu long connection:', error);
|
|
305
|
+
console.log(' Server will continue without Feishu integration');
|
|
306
|
+
}
|
|
307
|
+
// Start periodic cleanup of stale connections
|
|
308
|
+
const heartbeatInterval = this.config.get('websocket', 'heartbeatInterval');
|
|
309
|
+
this.cleanupInterval = setInterval(() => {
|
|
310
|
+
// Cleanup connections that haven't sent heartbeat in 3x interval
|
|
311
|
+
this.connectionHub.cleanupStaleConnections(heartbeatInterval * 3);
|
|
312
|
+
// Cleanup stale streaming sessions
|
|
313
|
+
this.cleanupStaleStreamingSessions();
|
|
314
|
+
}, heartbeatInterval);
|
|
315
|
+
console.log(`\n🚀 Router server started successfully!`);
|
|
316
|
+
console.log(` HTTP: http://${host}:${port}`);
|
|
317
|
+
console.log(` WebSocket: ws://${host}:${port}/ws`);
|
|
318
|
+
console.log(` Environment: ${this.config.get('server', 'nodeEnv')}`);
|
|
319
|
+
console.log(`\n✅ Ready to receive connections from local clients\n`);
|
|
320
|
+
}
|
|
321
|
+
// Track last update time for each streaming message to enable time-based updates
|
|
322
|
+
lastStreamUpdateTime = new Map();
|
|
323
|
+
STREAM_UPDATE_INTERVAL_MS = 500; // Update at least every 500ms
|
|
324
|
+
STREAM_UPDATE_MIN_LENGTH = 10; // Update every 10 characters
|
|
325
|
+
/**
|
|
326
|
+
* Handle streaming chunk from device
|
|
327
|
+
*/
|
|
328
|
+
/**
|
|
329
|
+
* Handle text streaming chunk
|
|
330
|
+
*/
|
|
331
|
+
async handleTextChunk(messageId, openId, chunk) {
|
|
332
|
+
console.log(`[RouterServer] Received text chunk for ${messageId}, chunk length: ${chunk.length}`);
|
|
333
|
+
const streamData = this.streamingMessages.get(messageId);
|
|
334
|
+
// If no streaming session exists, ignore the chunk
|
|
335
|
+
if (!streamData) {
|
|
336
|
+
console.log(`[RouterServer] No streaming session found for ${messageId}, ignoring chunk`);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
// Accumulate text content
|
|
340
|
+
streamData.currentTextContent += chunk;
|
|
341
|
+
streamData.createdAt = Date.now(); // Update activity timestamp
|
|
342
|
+
// Determine if we should update the card now
|
|
343
|
+
const now = Date.now();
|
|
344
|
+
const lastUpdate = this.lastStreamUpdateTime.get(messageId) || 0;
|
|
345
|
+
const timeSinceLastUpdate = now - lastUpdate;
|
|
346
|
+
const contentLength = streamData.currentTextContent.length;
|
|
347
|
+
// Update if:
|
|
348
|
+
// 1. We have a feishuMessageId
|
|
349
|
+
// 2. Either:
|
|
350
|
+
// a. It's the first content (hasUpdated is false) - show immediately
|
|
351
|
+
// b. We've accumulated enough characters since last update
|
|
352
|
+
// c. Enough time has passed since last update
|
|
353
|
+
const shouldUpdate = streamData.feishuMessageId && (!streamData.hasUpdated || // First content - always show immediately
|
|
354
|
+
(contentLength % this.STREAM_UPDATE_MIN_LENGTH === 0) || // Every N characters
|
|
355
|
+
(timeSinceLastUpdate >= this.STREAM_UPDATE_INTERVAL_MS) // Time-based
|
|
356
|
+
);
|
|
357
|
+
if (shouldUpdate && streamData.feishuMessageId) {
|
|
358
|
+
// Build current element list: existing elements + current text (if any)
|
|
359
|
+
const elements = [...streamData.elements];
|
|
360
|
+
if (streamData.currentTextContent.trim()) {
|
|
361
|
+
elements.push((0, ToolFormatter_1.createMarkdownElement)(streamData.currentTextContent));
|
|
362
|
+
}
|
|
363
|
+
await this.feishuLongConnHandler.updateStreamingMessage(streamData.feishuMessageId, elements, openId);
|
|
364
|
+
this.lastStreamUpdateTime.set(messageId, now);
|
|
365
|
+
streamData.hasUpdated = true;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Handle tool use event
|
|
370
|
+
*/
|
|
371
|
+
async handleToolUse(messageId, openId, toolUse) {
|
|
372
|
+
console.log(`[RouterServer] Received tool_use for ${messageId}: ${toolUse.name}`);
|
|
373
|
+
const streamData = this.streamingMessages.get(messageId);
|
|
374
|
+
if (!streamData) {
|
|
375
|
+
console.log(`[RouterServer] No streaming session found for ${messageId}`);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
// Flush current text content to elements if any
|
|
379
|
+
if (streamData.currentTextContent.trim()) {
|
|
380
|
+
streamData.elements.push((0, ToolFormatter_1.createMarkdownElement)(streamData.currentTextContent));
|
|
381
|
+
streamData.currentTextContent = '';
|
|
382
|
+
}
|
|
383
|
+
// Add tool use elements (divider + markdown)
|
|
384
|
+
const toolUseElements = (0, ToolFormatter_1.createToolUseElement)(toolUse);
|
|
385
|
+
streamData.elements.push(...toolUseElements);
|
|
386
|
+
streamData.createdAt = Date.now();
|
|
387
|
+
// Immediately update card to show tool use
|
|
388
|
+
if (streamData.feishuMessageId) {
|
|
389
|
+
await this.feishuLongConnHandler.updateStreamingMessage(streamData.feishuMessageId, streamData.elements, openId);
|
|
390
|
+
streamData.hasUpdated = true;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Handle tool result event
|
|
395
|
+
*/
|
|
396
|
+
async handleToolResult(messageId, openId, toolResult) {
|
|
397
|
+
console.log(`[RouterServer] Received tool_result for ${messageId}: ${toolResult.tool_use_id}`);
|
|
398
|
+
const streamData = this.streamingMessages.get(messageId);
|
|
399
|
+
if (!streamData) {
|
|
400
|
+
console.log(`[RouterServer] No streaming session found for ${messageId}`);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
// Flush current text content to elements if any
|
|
404
|
+
if (streamData.currentTextContent.trim()) {
|
|
405
|
+
streamData.elements.push((0, ToolFormatter_1.createMarkdownElement)(streamData.currentTextContent));
|
|
406
|
+
streamData.currentTextContent = '';
|
|
407
|
+
}
|
|
408
|
+
// Add tool result elements (markdown + status div)
|
|
409
|
+
const toolResultElements = (0, ToolFormatter_1.createToolResultElement)(toolResult);
|
|
410
|
+
streamData.elements.push(...toolResultElements);
|
|
411
|
+
streamData.createdAt = Date.now();
|
|
412
|
+
// Immediately update card to show tool result
|
|
413
|
+
if (streamData.feishuMessageId) {
|
|
414
|
+
await this.feishuLongConnHandler.updateStreamingMessage(streamData.feishuMessageId, streamData.elements, openId);
|
|
415
|
+
streamData.hasUpdated = true;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Finalize streaming message
|
|
420
|
+
*/
|
|
421
|
+
async finalizeStreamingMessage(messageId, success, output, error, sessionAbbr) {
|
|
422
|
+
const streamData = this.streamingMessages.get(messageId);
|
|
423
|
+
if (!streamData)
|
|
424
|
+
return;
|
|
425
|
+
const { feishuMessageId, openId } = streamData;
|
|
426
|
+
if (feishuMessageId) {
|
|
427
|
+
// Flush any remaining text content
|
|
428
|
+
if (streamData.currentTextContent.trim()) {
|
|
429
|
+
streamData.elements.push((0, ToolFormatter_1.createMarkdownElement)(streamData.currentTextContent));
|
|
430
|
+
streamData.currentTextContent = '';
|
|
431
|
+
}
|
|
432
|
+
// If there are no elements at all, use the output parameter as fallback
|
|
433
|
+
if (streamData.elements.length === 0 && output) {
|
|
434
|
+
streamData.elements.push((0, ToolFormatter_1.createMarkdownElement)(output));
|
|
435
|
+
}
|
|
436
|
+
if (success) {
|
|
437
|
+
await this.feishuLongConnHandler.finalizeStreamingMessage(feishuMessageId, streamData.elements, sessionAbbr, openId);
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
// Add error message to elements
|
|
441
|
+
const errorMsg = error || 'Command failed';
|
|
442
|
+
streamData.elements.push((0, ToolFormatter_1.createMarkdownElement)(`\n\n❌ **Error:** ${errorMsg}`));
|
|
443
|
+
await this.feishuLongConnHandler.finalizeStreamingMessage(feishuMessageId, streamData.elements, undefined, openId);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
// Clean up
|
|
447
|
+
this.streamingMessages.delete(messageId);
|
|
448
|
+
this.lastStreamUpdateTime.delete(messageId);
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Cleanup stale streaming sessions that have timed out
|
|
452
|
+
* This prevents memory leaks when devices disconnect without sending a response
|
|
453
|
+
*/
|
|
454
|
+
cleanupStaleStreamingSessions() {
|
|
455
|
+
const now = Date.now();
|
|
456
|
+
let cleanedCount = 0;
|
|
457
|
+
for (const [messageId, session] of this.streamingMessages.entries()) {
|
|
458
|
+
if (now - session.createdAt > this.STREAMING_SESSION_TIMEOUT_MS) {
|
|
459
|
+
console.log(`[RouterServer] Cleaning up stale streaming session: ${messageId}`);
|
|
460
|
+
this.streamingMessages.delete(messageId);
|
|
461
|
+
this.lastStreamUpdateTime.delete(messageId);
|
|
462
|
+
cleanedCount++;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (cleanedCount > 0) {
|
|
466
|
+
console.log(`[RouterServer] Cleaned up ${cleanedCount} stale streaming sessions, remaining: ${this.streamingMessages.size}`);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Cleanup streaming sessions for a specific device when it disconnects
|
|
471
|
+
* @param deviceId Device ID that disconnected
|
|
472
|
+
*/
|
|
473
|
+
cleanupStreamingSessionsForDevice(deviceId) {
|
|
474
|
+
let cleanedCount = 0;
|
|
475
|
+
for (const [messageId, session] of this.streamingMessages.entries()) {
|
|
476
|
+
if (session.deviceId === deviceId) {
|
|
477
|
+
console.log(`[RouterServer] Cleaning up streaming session for disconnected device: ${messageId}`);
|
|
478
|
+
this.streamingMessages.delete(messageId);
|
|
479
|
+
this.lastStreamUpdateTime.delete(messageId);
|
|
480
|
+
cleanedCount++;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (cleanedCount > 0) {
|
|
484
|
+
console.log(`[RouterServer] Cleaned up ${cleanedCount} streaming sessions for device ${deviceId}, remaining: ${this.streamingMessages.size}`);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Stop the server
|
|
489
|
+
*/
|
|
490
|
+
async stop() {
|
|
491
|
+
console.log('Stopping router server...');
|
|
492
|
+
// Stop cleanup interval
|
|
493
|
+
if (this.cleanupInterval) {
|
|
494
|
+
clearInterval(this.cleanupInterval);
|
|
495
|
+
this.cleanupInterval = null;
|
|
496
|
+
}
|
|
497
|
+
// Stop Feishu long connection
|
|
498
|
+
try {
|
|
499
|
+
await this.feishuLongConnHandler.stop();
|
|
500
|
+
}
|
|
501
|
+
catch (error) {
|
|
502
|
+
console.error('Error stopping Feishu long connection:', error);
|
|
503
|
+
}
|
|
504
|
+
// Close all WebSocket connections
|
|
505
|
+
this.connectionHub.closeAllConnections();
|
|
506
|
+
// Close WebSocket server
|
|
507
|
+
if (this.wss) {
|
|
508
|
+
this.wss.close();
|
|
509
|
+
this.wss = null;
|
|
510
|
+
}
|
|
511
|
+
// Close HTTP server
|
|
512
|
+
if (this.httpServer) {
|
|
513
|
+
await new Promise((resolve, reject) => {
|
|
514
|
+
this.httpServer.close((err) => {
|
|
515
|
+
if (err)
|
|
516
|
+
reject(err);
|
|
517
|
+
else
|
|
518
|
+
resolve();
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
this.httpServer = null;
|
|
522
|
+
}
|
|
523
|
+
console.log('✅ Router server stopped');
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Get connection statistics
|
|
527
|
+
*/
|
|
528
|
+
getStats() {
|
|
529
|
+
return this.connectionHub.getConnectionStats();
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
exports.RouterServer = RouterServer;
|
|
533
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|