@matter-server/dashboard 0.2.7-alpha.0-20260118-993a1c7 → 0.2.7-alpha.0-20260119-49e7237
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/dist/esm/components/dialogs/binding/node-binding-dialog.d.ts.map +1 -1
- package/dist/esm/components/dialogs/binding/node-binding-dialog.js +3 -2
- package/dist/esm/components/dialogs/binding/node-binding-dialog.js.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.d.ts.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.js +2 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.js.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.d.ts.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js +3 -2
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.d.ts.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js +5 -4
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js.map +1 -1
- package/dist/esm/components/dialogs/settings/log-level-dialog.d.ts +33 -0
- package/dist/esm/components/dialogs/settings/log-level-dialog.d.ts.map +1 -0
- package/dist/esm/components/dialogs/settings/log-level-dialog.js +189 -0
- package/dist/esm/components/dialogs/settings/log-level-dialog.js.map +6 -0
- package/dist/esm/components/dialogs/settings/show-log-level-dialog.d.ts +8 -0
- package/dist/esm/components/dialogs/settings/show-log-level-dialog.d.ts.map +1 -0
- package/dist/esm/components/dialogs/settings/show-log-level-dialog.js +15 -0
- package/dist/esm/components/dialogs/settings/show-log-level-dialog.js.map +6 -0
- package/dist/esm/pages/cluster-commands/clusters/level-control-commands.d.ts.map +1 -1
- package/dist/esm/pages/cluster-commands/clusters/level-control-commands.js +5 -2
- package/dist/esm/pages/cluster-commands/clusters/level-control-commands.js.map +1 -1
- package/dist/esm/pages/cluster-commands/clusters/on-off-commands.d.ts.map +1 -1
- package/dist/esm/pages/cluster-commands/clusters/on-off-commands.js +6 -3
- package/dist/esm/pages/cluster-commands/clusters/on-off-commands.js.map +1 -1
- package/dist/esm/pages/components/header.d.ts +1 -0
- package/dist/esm/pages/components/header.d.ts.map +1 -1
- package/dist/esm/pages/components/header.js +13 -1
- package/dist/esm/pages/components/header.js.map +1 -1
- package/dist/esm/pages/components/node-details.d.ts.map +1 -1
- package/dist/esm/pages/components/node-details.js +6 -5
- package/dist/esm/pages/components/node-details.js.map +1 -1
- package/dist/esm/pages/components/server-details.d.ts.map +1 -1
- package/dist/esm/pages/components/server-details.js +3 -2
- package/dist/esm/pages/components/server-details.js.map +1 -1
- package/dist/esm/pages/matter-server-view.d.ts.map +1 -1
- package/dist/esm/pages/matter-server-view.js +14 -1
- package/dist/esm/pages/matter-server-view.js.map +1 -1
- package/dist/esm/util/async-handler.d.ts +50 -0
- package/dist/esm/util/async-handler.d.ts.map +1 -0
- package/dist/esm/util/async-handler.js +33 -0
- package/dist/esm/util/async-handler.js.map +6 -0
- package/dist/esm/util/fire_event.d.ts.map +1 -1
- package/dist/esm/util/fire_event.js +1 -2
- package/dist/esm/util/fire_event.js.map +1 -1
- package/dist/esm/util/format_hex.d.ts +13 -2
- package/dist/esm/util/format_hex.d.ts.map +1 -1
- package/dist/esm/util/format_hex.js +6 -1
- package/dist/esm/util/format_hex.js.map +1 -1
- package/dist/web/js/{commission-node-dialog-DGw5qDgH.js → commission-node-dialog-B4_wgFye.js} +5 -5
- package/dist/web/js/{commission-node-existing-CHyyeC8y.js → commission-node-existing-BktL7vHX.js} +6 -5
- package/dist/web/js/{commission-node-thread-iRDSlidy.js → commission-node-thread-ox6fB3dO.js} +7 -6
- package/dist/web/js/{commission-node-wifi-C4YNR3bG.js → commission-node-wifi-Dlayi41Z.js} +9 -8
- package/dist/web/js/{dialog-box-ag-xOaYh.js → dialog-box-DFs0hcPv.js} +2 -2
- package/dist/web/js/{fire_event-BeiEbHcE.js → fire_event-oVtV3_P5.js} +2 -3
- package/dist/web/js/log-level-dialog-BVxKJJ49.js +3235 -0
- package/dist/web/js/main.js +170 -69
- package/dist/web/js/{matter-dashboard-app-BxQ4W_uT.js → matter-dashboard-app-Dr-IYMsD.js} +138 -17
- package/dist/web/js/{node-binding-dialog-ClziphM0.js → node-binding-dialog-CqE3VuZN.js} +6 -5
- package/dist/web/js/outlined-text-field-BVcHUxiS.js +968 -0
- package/dist/web/js/{prevent_default-Bs2sUnny.js → prevent_default-tLhqZmsK.js} +1 -1
- package/dist/web/js/validator-muF28wYx.js +1122 -0
- package/package.json +4 -4
- package/src/components/dialogs/binding/node-binding-dialog.ts +3 -2
- package/src/components/dialogs/commission-node-dialog/commission-node-existing.ts +2 -1
- package/src/components/dialogs/commission-node-dialog/commission-node-thread.ts +3 -2
- package/src/components/dialogs/commission-node-dialog/commission-node-wifi.ts +5 -4
- package/src/components/dialogs/settings/log-level-dialog.ts +183 -0
- package/src/components/dialogs/settings/show-log-level-dialog.ts +14 -0
- package/src/pages/cluster-commands/clusters/level-control-commands.ts +5 -2
- package/src/pages/cluster-commands/clusters/on-off-commands.ts +6 -3
- package/src/pages/components/header.ts +16 -1
- package/src/pages/components/node-details.ts +6 -5
- package/src/pages/components/server-details.ts +3 -3
- package/src/pages/matter-server-view.ts +17 -2
- package/src/util/async-handler.ts +74 -0
- package/src/util/fire_event.ts +1 -3
- package/src/util/format_hex.ts +17 -2
- package/dist/web/js/outlined-text-field-B-CiqgEJ.js +0 -2086
package/dist/web/js/main.js
CHANGED
|
@@ -146,6 +146,8 @@ class Connection {
|
|
|
146
146
|
};
|
|
147
147
|
this.socket.onclose = () => {
|
|
148
148
|
console.log("WebSocket Closed");
|
|
149
|
+
this.socket = void 0;
|
|
150
|
+
this.serverInfo = void 0;
|
|
149
151
|
onConnectionLost();
|
|
150
152
|
};
|
|
151
153
|
this.socket.onerror = error => {
|
|
@@ -170,6 +172,7 @@ class Connection {
|
|
|
170
172
|
this.socket.close();
|
|
171
173
|
this.socket = void 0;
|
|
172
174
|
}
|
|
175
|
+
this.serverInfo = void 0;
|
|
173
176
|
}
|
|
174
177
|
sendMessage(message) {
|
|
175
178
|
if (!this.socket) {
|
|
@@ -187,6 +190,20 @@ class Connection {
|
|
|
187
190
|
*/
|
|
188
191
|
class MatterError extends Error {}
|
|
189
192
|
class InvalidServerVersion extends MatterError {}
|
|
193
|
+
class CommandTimeoutError extends MatterError {
|
|
194
|
+
constructor(command, timeoutMs) {
|
|
195
|
+
super(`Command '${command}' timed out after ${timeoutMs}ms`);
|
|
196
|
+
this.command = command;
|
|
197
|
+
this.timeoutMs = timeoutMs;
|
|
198
|
+
this.name = "CommandTimeoutError";
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
class ConnectionClosedError extends MatterError {
|
|
202
|
+
constructor(message = "Connection closed while command was pending") {
|
|
203
|
+
super(message);
|
|
204
|
+
this.name = "ConnectionClosedError";
|
|
205
|
+
}
|
|
206
|
+
}
|
|
190
207
|
|
|
191
208
|
/**
|
|
192
209
|
* @license
|
|
@@ -255,6 +272,7 @@ class MatterNode {
|
|
|
255
272
|
function toNodeKey(nodeId) {
|
|
256
273
|
return String(nodeId);
|
|
257
274
|
}
|
|
275
|
+
const DEFAULT_COMMAND_TIMEOUT = 5 * 60 * 1e3;
|
|
258
276
|
class MatterClient {
|
|
259
277
|
/**
|
|
260
278
|
* Create a new MatterClient.
|
|
@@ -274,9 +292,12 @@ class MatterClient {
|
|
|
274
292
|
serverBaseAddress;
|
|
275
293
|
/** Whether this client is connected to a production server (optional, for UI purposes) */
|
|
276
294
|
isProduction = false;
|
|
295
|
+
/** Default timeout for commands in milliseconds. Set to 0 to disable timeouts. */
|
|
296
|
+
commandTimeout = DEFAULT_COMMAND_TIMEOUT;
|
|
277
297
|
// Using 'unknown' for resolve since the actual types vary by command
|
|
278
298
|
result_futures = {};
|
|
279
|
-
|
|
299
|
+
// Start with random offset for defense-in-depth and easier debugging across sessions
|
|
300
|
+
msgId = Math.floor(Math.random() * 2147483647);
|
|
280
301
|
eventListeners = {};
|
|
281
302
|
get serverInfo() {
|
|
282
303
|
return this.connection.serverInfo;
|
|
@@ -290,112 +311,112 @@ class MatterClient {
|
|
|
290
311
|
this.eventListeners[event] = this.eventListeners[event].filter(l => l !== listener);
|
|
291
312
|
};
|
|
292
313
|
}
|
|
293
|
-
async commissionWithCode(code, networkOnly = true) {
|
|
314
|
+
async commissionWithCode(code, networkOnly = true, timeout) {
|
|
294
315
|
return await this.sendCommand("commission_with_code", 0, {
|
|
295
316
|
code,
|
|
296
317
|
network_only: networkOnly
|
|
297
|
-
});
|
|
318
|
+
}, timeout);
|
|
298
319
|
}
|
|
299
|
-
async setWifiCredentials(ssid, credentials) {
|
|
320
|
+
async setWifiCredentials(ssid, credentials, timeout) {
|
|
300
321
|
await this.sendCommand("set_wifi_credentials", 0, {
|
|
301
322
|
ssid,
|
|
302
323
|
credentials
|
|
303
|
-
});
|
|
324
|
+
}, timeout);
|
|
304
325
|
}
|
|
305
|
-
async setThreadOperationalDataset(dataset) {
|
|
326
|
+
async setThreadOperationalDataset(dataset, timeout) {
|
|
306
327
|
await this.sendCommand("set_thread_dataset", 0, {
|
|
307
328
|
dataset
|
|
308
|
-
});
|
|
329
|
+
}, timeout);
|
|
309
330
|
}
|
|
310
|
-
async openCommissioningWindow(nodeId,
|
|
331
|
+
async openCommissioningWindow(nodeId, windowTimeout, iteration, option, discriminator, timeout) {
|
|
311
332
|
return await this.sendCommand("open_commissioning_window", 0, {
|
|
312
333
|
node_id: nodeId,
|
|
313
|
-
timeout,
|
|
334
|
+
timeout: windowTimeout,
|
|
314
335
|
iteration,
|
|
315
336
|
option,
|
|
316
337
|
discriminator
|
|
317
|
-
});
|
|
338
|
+
}, timeout);
|
|
318
339
|
}
|
|
319
|
-
async discoverCommissionableNodes() {
|
|
320
|
-
return await this.sendCommand("discover_commissionable_nodes", 0, {});
|
|
340
|
+
async discoverCommissionableNodes(timeout) {
|
|
341
|
+
return await this.sendCommand("discover_commissionable_nodes", 0, {}, timeout);
|
|
321
342
|
}
|
|
322
|
-
async getMatterFabrics(nodeId) {
|
|
343
|
+
async getMatterFabrics(nodeId, timeout) {
|
|
323
344
|
return await this.sendCommand("get_matter_fabrics", 3, {
|
|
324
345
|
node_id: nodeId
|
|
325
|
-
});
|
|
346
|
+
}, timeout);
|
|
326
347
|
}
|
|
327
|
-
async removeMatterFabric(nodeId, fabricIndex) {
|
|
348
|
+
async removeMatterFabric(nodeId, fabricIndex, timeout) {
|
|
328
349
|
await this.sendCommand("remove_matter_fabric", 3, {
|
|
329
350
|
node_id: nodeId,
|
|
330
351
|
fabric_index: fabricIndex
|
|
331
|
-
});
|
|
352
|
+
}, timeout);
|
|
332
353
|
}
|
|
333
|
-
async pingNode(nodeId, attempts = 1) {
|
|
354
|
+
async pingNode(nodeId, attempts = 1, timeout) {
|
|
334
355
|
return await this.sendCommand("ping_node", 0, {
|
|
335
356
|
node_id: nodeId,
|
|
336
357
|
attempts
|
|
337
|
-
});
|
|
358
|
+
}, timeout);
|
|
338
359
|
}
|
|
339
|
-
async getNodeIPAddresses(nodeId, preferCache, scoped) {
|
|
360
|
+
async getNodeIPAddresses(nodeId, preferCache, scoped, timeout) {
|
|
340
361
|
return await this.sendCommand("get_node_ip_addresses", 8, {
|
|
341
362
|
node_id: nodeId,
|
|
342
363
|
prefer_cache: preferCache,
|
|
343
364
|
scoped
|
|
344
|
-
});
|
|
365
|
+
}, timeout);
|
|
345
366
|
}
|
|
346
|
-
async removeNode(nodeId) {
|
|
367
|
+
async removeNode(nodeId, timeout) {
|
|
347
368
|
await this.sendCommand("remove_node", 0, {
|
|
348
369
|
node_id: nodeId
|
|
349
|
-
});
|
|
370
|
+
}, timeout);
|
|
350
371
|
}
|
|
351
|
-
async interviewNode(nodeId) {
|
|
372
|
+
async interviewNode(nodeId, timeout) {
|
|
352
373
|
await this.sendCommand("interview_node", 0, {
|
|
353
374
|
node_id: nodeId
|
|
354
|
-
});
|
|
375
|
+
}, timeout);
|
|
355
376
|
}
|
|
356
|
-
async importTestNode(dump) {
|
|
377
|
+
async importTestNode(dump, timeout) {
|
|
357
378
|
await this.sendCommand("import_test_node", 0, {
|
|
358
379
|
dump
|
|
359
|
-
});
|
|
380
|
+
}, timeout);
|
|
360
381
|
}
|
|
361
|
-
async readAttribute(nodeId, attributePath) {
|
|
382
|
+
async readAttribute(nodeId, attributePath, timeout) {
|
|
362
383
|
return await this.sendCommand("read_attribute", 0, {
|
|
363
384
|
node_id: nodeId,
|
|
364
385
|
attribute_path: attributePath
|
|
365
|
-
});
|
|
386
|
+
}, timeout);
|
|
366
387
|
}
|
|
367
|
-
async writeAttribute(nodeId, attributePath, value) {
|
|
388
|
+
async writeAttribute(nodeId, attributePath, value, timeout) {
|
|
368
389
|
return await this.sendCommand("write_attribute", 0, {
|
|
369
390
|
node_id: nodeId,
|
|
370
391
|
attribute_path: attributePath,
|
|
371
392
|
value
|
|
372
|
-
});
|
|
393
|
+
}, timeout);
|
|
373
394
|
}
|
|
374
|
-
async checkNodeUpdate(nodeId) {
|
|
395
|
+
async checkNodeUpdate(nodeId, timeout) {
|
|
375
396
|
return await this.sendCommand("check_node_update", 10, {
|
|
376
397
|
node_id: nodeId
|
|
377
|
-
});
|
|
398
|
+
}, timeout);
|
|
378
399
|
}
|
|
379
|
-
async updateNode(nodeId, softwareVersion) {
|
|
400
|
+
async updateNode(nodeId, softwareVersion, timeout) {
|
|
380
401
|
await this.sendCommand("update_node", 10, {
|
|
381
402
|
node_id: nodeId,
|
|
382
403
|
software_version: softwareVersion
|
|
383
|
-
});
|
|
404
|
+
}, timeout);
|
|
384
405
|
}
|
|
385
|
-
async setACLEntry(nodeId, entry) {
|
|
406
|
+
async setACLEntry(nodeId, entry, timeout) {
|
|
386
407
|
return await this.sendCommand("set_acl_entry", 0, {
|
|
387
408
|
node_id: nodeId,
|
|
388
409
|
entry
|
|
389
|
-
});
|
|
410
|
+
}, timeout);
|
|
390
411
|
}
|
|
391
|
-
async setNodeBinding(nodeId, endpoint, bindings) {
|
|
412
|
+
async setNodeBinding(nodeId, endpoint, bindings, timeout) {
|
|
392
413
|
return await this.sendCommand("set_node_binding", 0, {
|
|
393
414
|
node_id: nodeId,
|
|
394
415
|
endpoint,
|
|
395
416
|
bindings
|
|
396
|
-
});
|
|
417
|
+
}, timeout);
|
|
397
418
|
}
|
|
398
|
-
async deviceCommand(nodeId, endpointId, clusterId, commandName, payload = {}) {
|
|
419
|
+
async deviceCommand(nodeId, endpointId, clusterId, commandName, payload = {}, timeout) {
|
|
399
420
|
return await this.sendCommand("device_command", 0, {
|
|
400
421
|
node_id: nodeId,
|
|
401
422
|
endpoint_id: endpointId,
|
|
@@ -403,59 +424,147 @@ class MatterClient {
|
|
|
403
424
|
command_name: commandName,
|
|
404
425
|
payload,
|
|
405
426
|
response_type: null
|
|
406
|
-
});
|
|
427
|
+
}, timeout);
|
|
407
428
|
}
|
|
408
|
-
async getNodes(onlyAvailable = false) {
|
|
429
|
+
async getNodes(onlyAvailable = false, timeout) {
|
|
409
430
|
return await this.sendCommand("get_nodes", 0, {
|
|
410
431
|
only_available: onlyAvailable
|
|
411
|
-
});
|
|
432
|
+
}, timeout);
|
|
412
433
|
}
|
|
413
|
-
async getNode(nodeId) {
|
|
434
|
+
async getNode(nodeId, timeout) {
|
|
414
435
|
return await this.sendCommand("get_node", 0, {
|
|
415
436
|
node_id: nodeId
|
|
416
|
-
});
|
|
437
|
+
}, timeout);
|
|
417
438
|
}
|
|
418
|
-
async getVendorNames(filterVendors) {
|
|
439
|
+
async getVendorNames(filterVendors, timeout) {
|
|
419
440
|
return await this.sendCommand("get_vendor_names", 0, {
|
|
420
441
|
filter_vendors: filterVendors
|
|
421
|
-
});
|
|
442
|
+
}, timeout);
|
|
422
443
|
}
|
|
423
|
-
async fetchServerInfo() {
|
|
424
|
-
return await this.sendCommand("server_info", 0, {});
|
|
444
|
+
async fetchServerInfo(timeout) {
|
|
445
|
+
return await this.sendCommand("server_info", 0, {}, timeout);
|
|
425
446
|
}
|
|
426
|
-
async setDefaultFabricLabel(label) {
|
|
447
|
+
async setDefaultFabricLabel(label, timeout) {
|
|
427
448
|
await this.sendCommand("set_default_fabric_label", 0, {
|
|
428
449
|
label
|
|
429
|
-
});
|
|
450
|
+
}, timeout);
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Get the current log levels for console and file logging.
|
|
454
|
+
* @param timeout Optional command timeout in milliseconds
|
|
455
|
+
* @returns The current log level configuration
|
|
456
|
+
*/
|
|
457
|
+
async getLogLevel(timeout) {
|
|
458
|
+
return await this.sendCommand("get_loglevel", 0, {}, timeout);
|
|
430
459
|
}
|
|
431
|
-
|
|
460
|
+
/**
|
|
461
|
+
* Set the log level for console and/or file logging.
|
|
462
|
+
* Changes are temporary and will be reset when the server restarts.
|
|
463
|
+
* @param consoleLoglevel Console log level to set (optional)
|
|
464
|
+
* @param fileLoglevel File log level to set, only applied if file logging is enabled (optional)
|
|
465
|
+
* @param timeout Optional command timeout in milliseconds
|
|
466
|
+
* @returns The log level configuration after the change
|
|
467
|
+
*/
|
|
468
|
+
async setLogLevel(consoleLoglevel, fileLoglevel, timeout) {
|
|
469
|
+
return await this.sendCommand("set_loglevel", 0, {
|
|
470
|
+
console_loglevel: consoleLoglevel,
|
|
471
|
+
file_loglevel: fileLoglevel
|
|
472
|
+
}, timeout);
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Send a command to the Matter server.
|
|
476
|
+
* @param command The command name
|
|
477
|
+
* @param require_schema Minimum schema version required (0 for any version)
|
|
478
|
+
* @param args Command arguments
|
|
479
|
+
* @param timeout Optional timeout in milliseconds. Defaults to `commandTimeout`. Set to 0 to disable.
|
|
480
|
+
* @returns Promise that resolves with the command result
|
|
481
|
+
* @throws Error if the command times out or fails
|
|
482
|
+
*/
|
|
483
|
+
sendCommand(command, require_schema = void 0, args, timeout = this.commandTimeout) {
|
|
432
484
|
if (require_schema && this.serverInfo.schema_version < require_schema) {
|
|
433
485
|
throw new InvalidServerVersion(`Command not available due to incompatible server version. Update the Matter Server to a version that supports at least api schema ${require_schema}.`);
|
|
434
486
|
}
|
|
435
|
-
|
|
487
|
+
if (this.msgId >= Number.MAX_SAFE_INTEGER) {
|
|
488
|
+
this.msgId = 0;
|
|
489
|
+
}
|
|
490
|
+
const messageId = String(++this.msgId);
|
|
436
491
|
const message = {
|
|
437
|
-
message_id: messageId
|
|
492
|
+
message_id: messageId,
|
|
438
493
|
command,
|
|
439
494
|
args
|
|
440
495
|
};
|
|
441
|
-
|
|
496
|
+
return new Promise((resolve, reject) => {
|
|
497
|
+
let timeoutId;
|
|
498
|
+
if (timeout > 0) {
|
|
499
|
+
timeoutId = setTimeout(() => {
|
|
500
|
+
const pending = this.result_futures[messageId];
|
|
501
|
+
if (pending) {
|
|
502
|
+
if (pending.timeoutId) {
|
|
503
|
+
clearTimeout(pending.timeoutId);
|
|
504
|
+
}
|
|
505
|
+
delete this.result_futures[messageId];
|
|
506
|
+
reject(new CommandTimeoutError(command, timeout));
|
|
507
|
+
}
|
|
508
|
+
}, timeout);
|
|
509
|
+
}
|
|
442
510
|
this.result_futures[messageId] = {
|
|
443
511
|
resolve,
|
|
444
|
-
reject
|
|
512
|
+
reject,
|
|
513
|
+
timeoutId
|
|
445
514
|
};
|
|
446
515
|
this.connection.sendMessage(message);
|
|
447
516
|
});
|
|
448
|
-
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Safely resolve a pending command, ensuring it's only resolved once.
|
|
520
|
+
* Clears timeout and removes from pending futures before resolving.
|
|
521
|
+
*/
|
|
522
|
+
_resolvePendingCommand(messageId, result) {
|
|
523
|
+
const pending = this.result_futures[messageId];
|
|
524
|
+
if (pending) {
|
|
525
|
+
if (pending.timeoutId) {
|
|
526
|
+
clearTimeout(pending.timeoutId);
|
|
527
|
+
}
|
|
449
528
|
delete this.result_futures[messageId];
|
|
450
|
-
|
|
529
|
+
pending.resolve(result);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Safely reject a pending command, ensuring it's only rejected once.
|
|
534
|
+
* Clears timeout and removes from pending futures before rejecting.
|
|
535
|
+
*/
|
|
536
|
+
_rejectPendingCommand(messageId, error) {
|
|
537
|
+
const pending = this.result_futures[messageId];
|
|
538
|
+
if (pending) {
|
|
539
|
+
if (pending.timeoutId) {
|
|
540
|
+
clearTimeout(pending.timeoutId);
|
|
541
|
+
}
|
|
542
|
+
delete this.result_futures[messageId];
|
|
543
|
+
pending.reject(error);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Reject all pending commands with a ConnectionClosedError.
|
|
548
|
+
* Called when the connection is closed or lost.
|
|
549
|
+
*/
|
|
550
|
+
_rejectAllPendingCommands() {
|
|
551
|
+
const error = new ConnectionClosedError();
|
|
552
|
+
const pendingIds = Object.keys(this.result_futures);
|
|
553
|
+
for (const messageId of pendingIds) {
|
|
554
|
+
this._rejectPendingCommand(messageId, error);
|
|
555
|
+
}
|
|
451
556
|
}
|
|
452
557
|
async connect() {
|
|
453
558
|
if (this.connection.connected) {
|
|
454
559
|
return;
|
|
455
560
|
}
|
|
456
|
-
await this.connection.connect(msg => this._handleIncomingMessage(msg), () =>
|
|
561
|
+
await this.connection.connect(msg => this._handleIncomingMessage(msg), () => {
|
|
562
|
+
this._rejectAllPendingCommands();
|
|
563
|
+
this.fireEvent("connection_lost");
|
|
564
|
+
});
|
|
457
565
|
}
|
|
458
566
|
disconnect(clearStorage = false) {
|
|
567
|
+
this._rejectAllPendingCommands();
|
|
459
568
|
if (this.connection && this.connection.connected) {
|
|
460
569
|
this.connection.disconnect();
|
|
461
570
|
}
|
|
@@ -479,19 +588,11 @@ class MatterClient {
|
|
|
479
588
|
return;
|
|
480
589
|
}
|
|
481
590
|
if ("error_code" in msg) {
|
|
482
|
-
|
|
483
|
-
if (promise) {
|
|
484
|
-
promise.reject(new Error(msg.details));
|
|
485
|
-
delete this.result_futures[msg.message_id];
|
|
486
|
-
}
|
|
591
|
+
this._rejectPendingCommand(msg.message_id, new Error(msg.details));
|
|
487
592
|
return;
|
|
488
593
|
}
|
|
489
594
|
if ("result" in msg) {
|
|
490
|
-
|
|
491
|
-
if (promise) {
|
|
492
|
-
promise.resolve(msg.result);
|
|
493
|
-
delete this.result_futures[msg.message_id];
|
|
494
|
-
}
|
|
595
|
+
this._resolvePendingCommand(msg.message_id, msg.result);
|
|
495
596
|
return;
|
|
496
597
|
}
|
|
497
598
|
console.warn("Received message with unknown format", msg);
|
|
@@ -641,7 +742,7 @@ const ThemeService = new ThemeServiceImpl();
|
|
|
641
742
|
* SPDX-License-Identifier: Apache-2.0
|
|
642
743
|
*/
|
|
643
744
|
async function main() {
|
|
644
|
-
import('./matter-dashboard-app-
|
|
745
|
+
import('./matter-dashboard-app-Dr-IYMsD.js').then(function (n) { return n.C; });
|
|
645
746
|
let url = "";
|
|
646
747
|
const isProductionServer = location.origin.includes(":5580") || location.href.includes("hassio_ingress") || location.href.includes("/api/ingress/");
|
|
647
748
|
if (!isProductionServer) {
|