@honor-claw/yoyo 1.1.2 → 1.1.4-beta.1

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.
Files changed (66) hide show
  1. package/index.ts +25 -25
  2. package/package.json +5 -5
  3. package/src/apis/claw-cloud.ts +124 -124
  4. package/src/apis/helpers.ts +10 -10
  5. package/src/apis/honor-auth.ts +158 -158
  6. package/src/apis/http-client.ts +239 -239
  7. package/src/apis/index.ts +8 -8
  8. package/src/apis/types.ts +77 -73
  9. package/src/cloud-channel/channel.ts +117 -117
  10. package/src/cloud-channel/client.ts +3 -3
  11. package/src/cloud-channel/index.ts +4 -4
  12. package/src/cloud-channel/message-handler.ts +50 -42
  13. package/src/cloud-channel/session-manager.ts +14 -9
  14. package/src/cloud-channel/types.ts +115 -115
  15. package/src/commands/env/impl.ts +58 -58
  16. package/src/commands/env/index.ts +1 -1
  17. package/src/commands/index.ts +30 -30
  18. package/src/commands/login/impl.ts +30 -30
  19. package/src/commands/login/index.ts +1 -1
  20. package/src/commands/logout/index.ts +1 -1
  21. package/src/commands/status/index.ts +194 -194
  22. package/src/gateway-client/client.ts +90 -90
  23. package/src/gateway-client/device/auth.ts +57 -57
  24. package/src/gateway-client/device/builder.ts +105 -105
  25. package/src/gateway-client/device/helpers.ts +40 -40
  26. package/src/gateway-client/device/identity.ts +251 -251
  27. package/src/gateway-client/device/index.ts +40 -40
  28. package/src/gateway-client/device/types.ts +57 -57
  29. package/src/gateway-client/index.ts +5 -5
  30. package/src/gateway-client/protocol-client.ts +49 -34
  31. package/src/honor-auth/browser.ts +2 -2
  32. package/src/honor-auth/callback-server.ts +109 -109
  33. package/src/honor-auth/cloud.ts +57 -57
  34. package/src/honor-auth/config.ts +43 -43
  35. package/src/honor-auth/index.ts +3 -3
  36. package/src/honor-auth/token-manager.ts +90 -90
  37. package/src/honor-auth/types.ts +50 -50
  38. package/src/index.ts +10 -10
  39. package/src/modules/claw-configs/config-manager.ts +409 -409
  40. package/src/modules/claw-configs/hosts.ts +48 -48
  41. package/src/modules/claw-configs/index.ts +8 -8
  42. package/src/modules/claw-configs/provider.ts +394 -394
  43. package/src/modules/claw-configs/types.ts +34 -34
  44. package/src/modules/device/device-info.ts +1 -1
  45. package/src/modules/device/index.ts +3 -3
  46. package/src/modules/device/providers/base.ts +32 -32
  47. package/src/modules/device/providers/pad.ts +107 -107
  48. package/src/modules/device/providers/windows.ts +130 -130
  49. package/src/modules/device/registry.ts +48 -43
  50. package/src/modules/login/impl.ts +31 -26
  51. package/src/modules/login/index.ts +6 -6
  52. package/src/schemas.ts +23 -23
  53. package/src/services/connection/impl.ts +339 -339
  54. package/src/services/connection/status-tracker/events.ts +127 -127
  55. package/src/services/connection/status-tracker/index.ts +31 -31
  56. package/src/services/connection/status-tracker/storage.ts +133 -133
  57. package/src/services/connection/status-tracker/tracker.ts +370 -370
  58. package/src/services/connection/status-tracker/types.ts +131 -131
  59. package/src/services/connection/types.ts +20 -20
  60. package/src/types.ts +64 -64
  61. package/src/utils/id.ts +8 -8
  62. package/src/utils/jwt.ts +37 -37
  63. package/src/utils/logger.ts +20 -20
  64. package/src/utils/proxy.ts +58 -58
  65. package/src/utils/version.ts +29 -29
  66. package/src/utils/ws.ts +21 -21
@@ -1,370 +1,370 @@
1
- /**
2
- * 状态跟踪器
3
- * 核心状态跟踪逻辑,处理所有状态事件并维护状态数据
4
- */
5
-
6
- import type {
7
- ConnectionStatusData,
8
- GatewayConnectionInfo,
9
- } from './types.js';
10
- import { createEmptyStatusData } from './types.js';
11
- import { StatusStorage } from './storage.js';
12
- import {
13
- StatusEventType,
14
- type StatusEvent,
15
- type CloudSocketConnectedData,
16
- type CloudSocketDisconnectedData,
17
- type CloudSocketErrorData,
18
- type CloudSocketRetryData,
19
- type GatewayClientConnectedData,
20
- type GatewayClientDisconnectedData,
21
- type DevicePairingData,
22
- type DeviceUnpairingData,
23
- type ConnectionStatusChangedData,
24
- } from './events.js';
25
-
26
- /**
27
- * 状态跟踪器类
28
- */
29
- export class StatusTracker {
30
- private currentStatus: ConnectionStatusData;
31
- private storage: StatusStorage;
32
- private autoSave: boolean;
33
- private saveTimer: NodeJS.Timeout | null;
34
-
35
- constructor(autoSave = true) {
36
- this.currentStatus = createEmptyStatusData();
37
- this.storage = new StatusStorage();
38
- this.autoSave = autoSave;
39
- this.saveTimer = null;
40
- }
41
-
42
- /**
43
- * 处理状态事件
44
- */
45
- async handleEvent(event: StatusEvent): Promise<void> {
46
- const { type, timestamp, data } = event;
47
-
48
- switch (type) {
49
- case StatusEventType.CLOUD_SOCKET_CONNECTING:
50
- this.handleCloudSocketConnecting(data, timestamp);
51
- break;
52
-
53
- case StatusEventType.CLOUD_SOCKET_CONNECTED:
54
- this.handleCloudSocketConnected(data, timestamp);
55
- break;
56
-
57
- case StatusEventType.CLOUD_SOCKET_DISCONNECTED:
58
- this.handleCloudSocketDisconnected(data, timestamp);
59
- break;
60
-
61
- case StatusEventType.CLOUD_SOCKET_ERROR:
62
- this.handleCloudSocketError(data, timestamp);
63
- break;
64
-
65
- case StatusEventType.CLOUD_SOCKET_RETRY:
66
- this.handleCloudSocketRetry(data, timestamp);
67
- break;
68
-
69
- case StatusEventType.GATEWAY_CLIENT_CONNECTED:
70
- this.handleGatewayClientConnected(data, timestamp);
71
- break;
72
-
73
- case StatusEventType.GATEWAY_CLIENT_DISCONNECTED:
74
- this.handleGatewayClientDisconnected(data, timestamp);
75
- break;
76
-
77
- case StatusEventType.DEVICE_PAIRING:
78
- this.handleDevicePairing(data, timestamp);
79
- break;
80
-
81
- case StatusEventType.DEVICE_UNPAIRING:
82
- this.handleDeviceUnpairing(data, timestamp);
83
- break;
84
-
85
- case StatusEventType.CONNECTION_STATUS_CHANGED:
86
- this.handleConnectionStatusChanged(data, timestamp);
87
- break;
88
-
89
- default:
90
- console.warn(`[StatusTracker] Unknown event type: ${type}`);
91
- }
92
-
93
- // 更新时间戳
94
- this.currentStatus.updatedAt = new Date(timestamp).toISOString();
95
-
96
- // 自动保存
97
- if (this.autoSave) {
98
- this.scheduleSave();
99
- }
100
- }
101
-
102
- /**
103
- * 获取当前状态
104
- */
105
- getStatus(): ConnectionStatusData {
106
- return { ...this.currentStatus };
107
- }
108
-
109
- /**
110
- * 加载已保存的状态
111
- */
112
- async loadStatus(): Promise<ConnectionStatusData> {
113
- const savedStatus = await this.storage.load();
114
- if (savedStatus) {
115
- this.currentStatus = savedStatus;
116
- }
117
- return this.getStatus();
118
- }
119
-
120
- /**
121
- * 加载并清理状态
122
- * 在服务启动时调用,清除临时的连接状态(gateway连接和物理设备)
123
- * 保留持久化的状态(云socket状态和连接历史)
124
- */
125
- async loadAndCleanStatus(): Promise<ConnectionStatusData> {
126
- const savedStatus = await this.storage.load();
127
- if (savedStatus) {
128
- // 保留云socket状态和连接历史
129
- const cloudSocketStatus = savedStatus.cloudSocket;
130
- const connectionHistory = savedStatus.history;
131
-
132
- // 创建新的空状态
133
- this.currentStatus = createEmptyStatusData();
134
-
135
- // 恢复云socket状态
136
- this.currentStatus.cloudSocket = cloudSocketStatus;
137
-
138
- // 恢复连接历史
139
- this.currentStatus.history = connectionHistory;
140
-
141
- // 重置云socket的连接状态(因为重启后连接会断开)
142
- this.currentStatus.cloudSocket.connected = false;
143
- this.currentStatus.cloudSocket.readyState = 3; // WebSocket.CLOSED
144
-
145
- // 保存清理后的状态
146
- await this.saveStatus();
147
- }
148
- return this.getStatus();
149
- }
150
-
151
- /**
152
- * 保存当前状态
153
- */
154
- async saveStatus(): Promise<void> {
155
- await this.storage.save(this.currentStatus);
156
- }
157
-
158
- /**
159
- * 清除状态
160
- */
161
- async clearStatus(): Promise<void> {
162
- this.currentStatus = createEmptyStatusData();
163
- await this.storage.clear();
164
- }
165
-
166
- // ==================== 事件处理方法 ====================
167
-
168
- private handleCloudSocketConnecting(data: any, timestamp: number): void {
169
- this.currentStatus.cloudSocket.url = data.url || '';
170
- this.currentStatus.cloudSocket.connected = false;
171
- }
172
-
173
- private handleCloudSocketConnected(
174
- data: CloudSocketConnectedData,
175
- timestamp: number
176
- ): void {
177
- this.currentStatus.cloudSocket.connected = true;
178
- this.currentStatus.cloudSocket.connectedAt = data.connectedAt;
179
- this.currentStatus.cloudSocket.readyState = 1; // WebSocket.OPEN
180
- this.currentStatus.cloudSocket.url = data.url;
181
- this.currentStatus.cloudSocket.retryCount = 0;
182
- this.currentStatus.cloudSocket.lastError = null;
183
-
184
- // 更新连接历史
185
- this.currentStatus.history.connectionCount++;
186
- this.currentStatus.history.lastConnectionAt = data.connectedAt;
187
- }
188
-
189
- private handleCloudSocketDisconnected(
190
- data: CloudSocketDisconnectedData,
191
- timestamp: number
192
- ): void {
193
- this.currentStatus.cloudSocket.connected = false;
194
- this.currentStatus.cloudSocket.lastDisconnectedAt = data.disconnectedAt;
195
- this.currentStatus.cloudSocket.readyState = 3; // WebSocket.CLOSED
196
-
197
- // 更新连接历史
198
- this.currentStatus.history.disconnectionCount++;
199
- this.currentStatus.history.lastDisconnectionAt = data.disconnectedAt;
200
- }
201
-
202
- private handleCloudSocketError(
203
- data: CloudSocketErrorData,
204
- timestamp: number
205
- ): void {
206
- this.currentStatus.cloudSocket.lastError = data.error;
207
- }
208
-
209
- private handleCloudSocketRetry(
210
- data: CloudSocketRetryData,
211
- timestamp: number
212
- ): void {
213
- this.currentStatus.cloudSocket.retryCount = data.retryCount;
214
- if (data.lastError) {
215
- this.currentStatus.cloudSocket.lastError = data.lastError;
216
- }
217
- }
218
-
219
- private handleGatewayClientConnected(
220
- data: GatewayClientConnectedData,
221
- timestamp: number
222
- ): void {
223
- const connectionInfo: GatewayConnectionInfo = {
224
- sessionId: data.sessionId,
225
- hardwareDeviceId: data.hardwareDeviceId,
226
- connectedAt: data.connectedAt,
227
- deviceInfo: data.deviceInfo,
228
- };
229
-
230
- // 添加到连接列表
231
- this.currentStatus.gateway.connections.push(connectionInfo);
232
- this.currentStatus.gateway.totalConnections++;
233
- this.currentStatus.gateway.activeConnections++;
234
-
235
- // 更新设备信息
236
- this.updateDeviceInfo(data.hardwareDeviceId, data.deviceInfo, timestamp);
237
- }
238
-
239
- private handleGatewayClientDisconnected(
240
- data: GatewayClientDisconnectedData,
241
- timestamp: number
242
- ): void {
243
- // 从连接列表中移除
244
- const index = this.currentStatus.gateway.connections.findIndex(
245
- (c) => c.sessionId === data.sessionId
246
- );
247
-
248
- if (index !== -1) {
249
- this.currentStatus.gateway.connections.splice(index, 1);
250
- this.currentStatus.gateway.activeConnections--;
251
- }
252
-
253
- // 更新设备信息
254
- this.updateDeviceInfo(data.hardwareDeviceId, null, timestamp);
255
- }
256
-
257
- private handleDevicePairing(data: DevicePairingData, timestamp: number): void {
258
- // 设备配对时更新设备信息
259
- this.updateDeviceInfo(data.hardwareDeviceId, data.deviceInfo, timestamp);
260
- }
261
-
262
- private handleDeviceUnpairing(
263
- data: DeviceUnpairingData,
264
- timestamp: number
265
- ): void {
266
- // 设备取消配对时从设备列表中移除
267
- const index = this.currentStatus.devices.devices.findIndex(
268
- (d) => d.hardwareDeviceId === data.hardwareDeviceId
269
- );
270
-
271
- if (index !== -1) {
272
- this.currentStatus.devices.devices.splice(index, 1);
273
- this.recalculateDeviceStats();
274
- }
275
- }
276
-
277
- private handleConnectionStatusChanged(
278
- data: ConnectionStatusChangedData,
279
- timestamp: number
280
- ): void {
281
- this.currentStatus.status = data.status;
282
- }
283
-
284
- // ==================== 辅助方法 ====================
285
-
286
- /**
287
- * 更新设备信息
288
- */
289
- private updateDeviceInfo(
290
- hardwareDeviceId: string,
291
- deviceInfo: any,
292
- timestamp: number
293
- ): void {
294
- let device = this.currentStatus.devices.devices.find(
295
- (d) => d.hardwareDeviceId === hardwareDeviceId
296
- );
297
-
298
- if (!device) {
299
- // 创建新设备记录
300
- device = {
301
- hardwareDeviceId,
302
- sessions: 0,
303
- lastActiveAt: new Date(timestamp).toISOString(),
304
- deviceInfo,
305
- };
306
- this.currentStatus.devices.devices.push(device);
307
- } else {
308
- // 更新现有设备记录
309
- device.lastActiveAt = new Date(timestamp).toISOString();
310
- if (deviceInfo) {
311
- device.deviceInfo = deviceInfo;
312
- }
313
- }
314
-
315
- // 重新计算设备统计
316
- this.recalculateDeviceStats();
317
- }
318
-
319
- /**
320
- * 重新计算设备统计信息
321
- */
322
- private recalculateDeviceStats(): void {
323
- this.currentStatus.devices.totalDevices =
324
- this.currentStatus.devices.devices.length;
325
- this.currentStatus.devices.uniqueHardwareDevices =
326
- this.currentStatus.devices.devices.length;
327
-
328
- // 更新每个设备的会话数
329
- for (const device of this.currentStatus.devices.devices) {
330
- const sessionCount = this.currentStatus.gateway.connections.filter(
331
- (c) => c.hardwareDeviceId === device.hardwareDeviceId
332
- ).length;
333
- device.sessions = sessionCount;
334
- }
335
- }
336
-
337
- /**
338
- * 调度保存(防抖)
339
- */
340
- private scheduleSave(): void {
341
- if (this.saveTimer) {
342
- clearTimeout(this.saveTimer);
343
- }
344
-
345
- this.saveTimer = setTimeout(async () => {
346
- try {
347
- await this.saveStatus();
348
- } catch (error) {
349
- console.error(
350
- `[StatusTracker] Failed to save status: ${
351
- error instanceof Error ? error.message : String(error)
352
- }`
353
- );
354
- }
355
- }, 100); // 100ms 防抖
356
- }
357
-
358
- /**
359
- * 销毁跟踪器
360
- */
361
- async destroy(): Promise<void> {
362
- if (this.saveTimer) {
363
- clearTimeout(this.saveTimer);
364
- this.saveTimer = null;
365
- }
366
-
367
- // 最后保存一次
368
- await this.saveStatus();
369
- }
370
- }
1
+ /**
2
+ * 状态跟踪器
3
+ * 核心状态跟踪逻辑,处理所有状态事件并维护状态数据
4
+ */
5
+
6
+ import type {
7
+ ConnectionStatusData,
8
+ GatewayConnectionInfo,
9
+ } from './types.js';
10
+ import { createEmptyStatusData } from './types.js';
11
+ import { StatusStorage } from './storage.js';
12
+ import {
13
+ StatusEventType,
14
+ type StatusEvent,
15
+ type CloudSocketConnectedData,
16
+ type CloudSocketDisconnectedData,
17
+ type CloudSocketErrorData,
18
+ type CloudSocketRetryData,
19
+ type GatewayClientConnectedData,
20
+ type GatewayClientDisconnectedData,
21
+ type DevicePairingData,
22
+ type DeviceUnpairingData,
23
+ type ConnectionStatusChangedData,
24
+ } from './events.js';
25
+
26
+ /**
27
+ * 状态跟踪器类
28
+ */
29
+ export class StatusTracker {
30
+ private currentStatus: ConnectionStatusData;
31
+ private storage: StatusStorage;
32
+ private autoSave: boolean;
33
+ private saveTimer: NodeJS.Timeout | null;
34
+
35
+ constructor(autoSave = true) {
36
+ this.currentStatus = createEmptyStatusData();
37
+ this.storage = new StatusStorage();
38
+ this.autoSave = autoSave;
39
+ this.saveTimer = null;
40
+ }
41
+
42
+ /**
43
+ * 处理状态事件
44
+ */
45
+ async handleEvent(event: StatusEvent): Promise<void> {
46
+ const { type, timestamp, data } = event;
47
+
48
+ switch (type) {
49
+ case StatusEventType.CLOUD_SOCKET_CONNECTING:
50
+ this.handleCloudSocketConnecting(data, timestamp);
51
+ break;
52
+
53
+ case StatusEventType.CLOUD_SOCKET_CONNECTED:
54
+ this.handleCloudSocketConnected(data, timestamp);
55
+ break;
56
+
57
+ case StatusEventType.CLOUD_SOCKET_DISCONNECTED:
58
+ this.handleCloudSocketDisconnected(data, timestamp);
59
+ break;
60
+
61
+ case StatusEventType.CLOUD_SOCKET_ERROR:
62
+ this.handleCloudSocketError(data, timestamp);
63
+ break;
64
+
65
+ case StatusEventType.CLOUD_SOCKET_RETRY:
66
+ this.handleCloudSocketRetry(data, timestamp);
67
+ break;
68
+
69
+ case StatusEventType.GATEWAY_CLIENT_CONNECTED:
70
+ this.handleGatewayClientConnected(data, timestamp);
71
+ break;
72
+
73
+ case StatusEventType.GATEWAY_CLIENT_DISCONNECTED:
74
+ this.handleGatewayClientDisconnected(data, timestamp);
75
+ break;
76
+
77
+ case StatusEventType.DEVICE_PAIRING:
78
+ this.handleDevicePairing(data, timestamp);
79
+ break;
80
+
81
+ case StatusEventType.DEVICE_UNPAIRING:
82
+ this.handleDeviceUnpairing(data, timestamp);
83
+ break;
84
+
85
+ case StatusEventType.CONNECTION_STATUS_CHANGED:
86
+ this.handleConnectionStatusChanged(data, timestamp);
87
+ break;
88
+
89
+ default:
90
+ console.warn(`[StatusTracker] Unknown event type: ${type}`);
91
+ }
92
+
93
+ // 更新时间戳
94
+ this.currentStatus.updatedAt = new Date(timestamp).toISOString();
95
+
96
+ // 自动保存
97
+ if (this.autoSave) {
98
+ this.scheduleSave();
99
+ }
100
+ }
101
+
102
+ /**
103
+ * 获取当前状态
104
+ */
105
+ getStatus(): ConnectionStatusData {
106
+ return { ...this.currentStatus };
107
+ }
108
+
109
+ /**
110
+ * 加载已保存的状态
111
+ */
112
+ async loadStatus(): Promise<ConnectionStatusData> {
113
+ const savedStatus = await this.storage.load();
114
+ if (savedStatus) {
115
+ this.currentStatus = savedStatus;
116
+ }
117
+ return this.getStatus();
118
+ }
119
+
120
+ /**
121
+ * 加载并清理状态
122
+ * 在服务启动时调用,清除临时的连接状态(gateway连接和物理设备)
123
+ * 保留持久化的状态(云socket状态和连接历史)
124
+ */
125
+ async loadAndCleanStatus(): Promise<ConnectionStatusData> {
126
+ const savedStatus = await this.storage.load();
127
+ if (savedStatus) {
128
+ // 保留云socket状态和连接历史
129
+ const cloudSocketStatus = savedStatus.cloudSocket;
130
+ const connectionHistory = savedStatus.history;
131
+
132
+ // 创建新的空状态
133
+ this.currentStatus = createEmptyStatusData();
134
+
135
+ // 恢复云socket状态
136
+ this.currentStatus.cloudSocket = cloudSocketStatus;
137
+
138
+ // 恢复连接历史
139
+ this.currentStatus.history = connectionHistory;
140
+
141
+ // 重置云socket的连接状态(因为重启后连接会断开)
142
+ this.currentStatus.cloudSocket.connected = false;
143
+ this.currentStatus.cloudSocket.readyState = 3; // WebSocket.CLOSED
144
+
145
+ // 保存清理后的状态
146
+ await this.saveStatus();
147
+ }
148
+ return this.getStatus();
149
+ }
150
+
151
+ /**
152
+ * 保存当前状态
153
+ */
154
+ async saveStatus(): Promise<void> {
155
+ await this.storage.save(this.currentStatus);
156
+ }
157
+
158
+ /**
159
+ * 清除状态
160
+ */
161
+ async clearStatus(): Promise<void> {
162
+ this.currentStatus = createEmptyStatusData();
163
+ await this.storage.clear();
164
+ }
165
+
166
+ // ==================== 事件处理方法 ====================
167
+
168
+ private handleCloudSocketConnecting(data: any, timestamp: number): void {
169
+ this.currentStatus.cloudSocket.url = data.url || '';
170
+ this.currentStatus.cloudSocket.connected = false;
171
+ }
172
+
173
+ private handleCloudSocketConnected(
174
+ data: CloudSocketConnectedData,
175
+ timestamp: number
176
+ ): void {
177
+ this.currentStatus.cloudSocket.connected = true;
178
+ this.currentStatus.cloudSocket.connectedAt = data.connectedAt;
179
+ this.currentStatus.cloudSocket.readyState = 1; // WebSocket.OPEN
180
+ this.currentStatus.cloudSocket.url = data.url;
181
+ this.currentStatus.cloudSocket.retryCount = 0;
182
+ this.currentStatus.cloudSocket.lastError = null;
183
+
184
+ // 更新连接历史
185
+ this.currentStatus.history.connectionCount++;
186
+ this.currentStatus.history.lastConnectionAt = data.connectedAt;
187
+ }
188
+
189
+ private handleCloudSocketDisconnected(
190
+ data: CloudSocketDisconnectedData,
191
+ timestamp: number
192
+ ): void {
193
+ this.currentStatus.cloudSocket.connected = false;
194
+ this.currentStatus.cloudSocket.lastDisconnectedAt = data.disconnectedAt;
195
+ this.currentStatus.cloudSocket.readyState = 3; // WebSocket.CLOSED
196
+
197
+ // 更新连接历史
198
+ this.currentStatus.history.disconnectionCount++;
199
+ this.currentStatus.history.lastDisconnectionAt = data.disconnectedAt;
200
+ }
201
+
202
+ private handleCloudSocketError(
203
+ data: CloudSocketErrorData,
204
+ timestamp: number
205
+ ): void {
206
+ this.currentStatus.cloudSocket.lastError = data.error;
207
+ }
208
+
209
+ private handleCloudSocketRetry(
210
+ data: CloudSocketRetryData,
211
+ timestamp: number
212
+ ): void {
213
+ this.currentStatus.cloudSocket.retryCount = data.retryCount;
214
+ if (data.lastError) {
215
+ this.currentStatus.cloudSocket.lastError = data.lastError;
216
+ }
217
+ }
218
+
219
+ private handleGatewayClientConnected(
220
+ data: GatewayClientConnectedData,
221
+ timestamp: number
222
+ ): void {
223
+ const connectionInfo: GatewayConnectionInfo = {
224
+ sessionId: data.sessionId,
225
+ hardwareDeviceId: data.hardwareDeviceId,
226
+ connectedAt: data.connectedAt,
227
+ deviceInfo: data.deviceInfo,
228
+ };
229
+
230
+ // 添加到连接列表
231
+ this.currentStatus.gateway.connections.push(connectionInfo);
232
+ this.currentStatus.gateway.totalConnections++;
233
+ this.currentStatus.gateway.activeConnections++;
234
+
235
+ // 更新设备信息
236
+ this.updateDeviceInfo(data.hardwareDeviceId, data.deviceInfo, timestamp);
237
+ }
238
+
239
+ private handleGatewayClientDisconnected(
240
+ data: GatewayClientDisconnectedData,
241
+ timestamp: number
242
+ ): void {
243
+ // 从连接列表中移除
244
+ const index = this.currentStatus.gateway.connections.findIndex(
245
+ (c) => c.sessionId === data.sessionId
246
+ );
247
+
248
+ if (index !== -1) {
249
+ this.currentStatus.gateway.connections.splice(index, 1);
250
+ this.currentStatus.gateway.activeConnections--;
251
+ }
252
+
253
+ // 更新设备信息
254
+ this.updateDeviceInfo(data.hardwareDeviceId, null, timestamp);
255
+ }
256
+
257
+ private handleDevicePairing(data: DevicePairingData, timestamp: number): void {
258
+ // 设备配对时更新设备信息
259
+ this.updateDeviceInfo(data.hardwareDeviceId, data.deviceInfo, timestamp);
260
+ }
261
+
262
+ private handleDeviceUnpairing(
263
+ data: DeviceUnpairingData,
264
+ timestamp: number
265
+ ): void {
266
+ // 设备取消配对时从设备列表中移除
267
+ const index = this.currentStatus.devices.devices.findIndex(
268
+ (d) => d.hardwareDeviceId === data.hardwareDeviceId
269
+ );
270
+
271
+ if (index !== -1) {
272
+ this.currentStatus.devices.devices.splice(index, 1);
273
+ this.recalculateDeviceStats();
274
+ }
275
+ }
276
+
277
+ private handleConnectionStatusChanged(
278
+ data: ConnectionStatusChangedData,
279
+ timestamp: number
280
+ ): void {
281
+ this.currentStatus.status = data.status;
282
+ }
283
+
284
+ // ==================== 辅助方法 ====================
285
+
286
+ /**
287
+ * 更新设备信息
288
+ */
289
+ private updateDeviceInfo(
290
+ hardwareDeviceId: string,
291
+ deviceInfo: any,
292
+ timestamp: number
293
+ ): void {
294
+ let device = this.currentStatus.devices.devices.find(
295
+ (d) => d.hardwareDeviceId === hardwareDeviceId
296
+ );
297
+
298
+ if (!device) {
299
+ // 创建新设备记录
300
+ device = {
301
+ hardwareDeviceId,
302
+ sessions: 0,
303
+ lastActiveAt: new Date(timestamp).toISOString(),
304
+ deviceInfo,
305
+ };
306
+ this.currentStatus.devices.devices.push(device);
307
+ } else {
308
+ // 更新现有设备记录
309
+ device.lastActiveAt = new Date(timestamp).toISOString();
310
+ if (deviceInfo) {
311
+ device.deviceInfo = deviceInfo;
312
+ }
313
+ }
314
+
315
+ // 重新计算设备统计
316
+ this.recalculateDeviceStats();
317
+ }
318
+
319
+ /**
320
+ * 重新计算设备统计信息
321
+ */
322
+ private recalculateDeviceStats(): void {
323
+ this.currentStatus.devices.totalDevices =
324
+ this.currentStatus.devices.devices.length;
325
+ this.currentStatus.devices.uniqueHardwareDevices =
326
+ this.currentStatus.devices.devices.length;
327
+
328
+ // 更新每个设备的会话数
329
+ for (const device of this.currentStatus.devices.devices) {
330
+ const sessionCount = this.currentStatus.gateway.connections.filter(
331
+ (c) => c.hardwareDeviceId === device.hardwareDeviceId
332
+ ).length;
333
+ device.sessions = sessionCount;
334
+ }
335
+ }
336
+
337
+ /**
338
+ * 调度保存(防抖)
339
+ */
340
+ private scheduleSave(): void {
341
+ if (this.saveTimer) {
342
+ clearTimeout(this.saveTimer);
343
+ }
344
+
345
+ this.saveTimer = setTimeout(async () => {
346
+ try {
347
+ await this.saveStatus();
348
+ } catch (error) {
349
+ console.error(
350
+ `[StatusTracker] Failed to save status: ${
351
+ error instanceof Error ? error.message : String(error)
352
+ }`
353
+ );
354
+ }
355
+ }, 100); // 100ms 防抖
356
+ }
357
+
358
+ /**
359
+ * 销毁跟踪器
360
+ */
361
+ async destroy(): Promise<void> {
362
+ if (this.saveTimer) {
363
+ clearTimeout(this.saveTimer);
364
+ this.saveTimer = null;
365
+ }
366
+
367
+ // 最后保存一次
368
+ await this.saveStatus();
369
+ }
370
+ }