aes70 2.0.17 → 2.0.19
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/Changelog +99 -1
- package/README.md +13 -2
- package/bin/printDevice.js +14 -3
- package/dist/AES70.es5.js +64 -19
- package/package.json +1 -4
- package/src/close_error.d.ts +2 -1
- package/src/connection.js +2 -0
- package/src/controller/abstract_udp_connection.js +7 -0
- package/src/controller/client_connection.d.ts +13 -1
- package/src/controller/client_connection.js +21 -4
- package/src/controller/fetch_device_content.js +15 -8
- package/src/controller/remote_device.js +4 -3
- package/src/controller/websocket_connection.d.ts +9 -6
- package/src/controller/websocket_connection.js +17 -6
- package/src/controller/websocket_connection_base.d.ts +22 -0
- package/src/index.d.ts +1 -1
- package/src/index.js +1 -1
- package/src/timeout_error.d.ts +1 -0
- package/src/controller/websocket_connection_node.d.ts +0 -18
- package/src/controller/websocket_connection_node.js +0 -24
package/Changelog
CHANGED
|
@@ -2,6 +2,104 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes and version updates will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [2.0.19] - 2026-03-13
|
|
6
|
+
|
|
7
|
+
- Remove ws dependency. WebSocket connections can use a compatible
|
|
8
|
+
constructor passed to WebSocketConnection.connect() when needed.
|
|
9
|
+
|
|
10
|
+
- ClientConnection: Do not log unsubscribe errors when the connection
|
|
11
|
+
has been closed (CloseError).
|
|
12
|
+
|
|
13
|
+
- TypeScript: Add name property to error class declarations.
|
|
14
|
+
|
|
15
|
+
## [2.0.18] - 2026-03-11
|
|
16
|
+
|
|
17
|
+
- ClientConnection: Add command duration for UDP. Set expected duration
|
|
18
|
+
on the last command when the device needs time to process.
|
|
19
|
+
|
|
20
|
+
- Connection: Make set_keepalive_interval idempotent when called
|
|
21
|
+
multiple times with the same interval.
|
|
22
|
+
|
|
23
|
+
- printDevice: Add --progress.
|
|
24
|
+
|
|
25
|
+
- fetchDeviceContent: Handle BigInt and OcaStatus.BadMethod.
|
|
26
|
+
|
|
27
|
+
- AbstractUdpConnection: Fix retry logic.
|
|
28
|
+
|
|
29
|
+
## [2.0.17] - 2025-12-02
|
|
30
|
+
|
|
31
|
+
- Connection: Do not send keepalive after close.
|
|
32
|
+
|
|
33
|
+
- fetchDeviceContent: Handle BigInt data in JSON output.
|
|
34
|
+
|
|
35
|
+
- Refactor UDP command retry handling; batch commands and avoid spurious
|
|
36
|
+
timeouts with large write buffers.
|
|
37
|
+
|
|
38
|
+
## [2.0.15] - 2025-11-26
|
|
39
|
+
|
|
40
|
+
- Property: Fix and test alias lookup for renamed properties (e.g. 2023).
|
|
41
|
+
|
|
42
|
+
- Refactor UDP support: connection attempt can be aborted with AbortSignal;
|
|
43
|
+
DNS lookup configurable for IPv4 or IPv6.
|
|
44
|
+
|
|
45
|
+
- Events: Do not throw from removeEventHandler (fixes cleanup with
|
|
46
|
+
removeAllEventHandlers).
|
|
47
|
+
|
|
48
|
+
- OCP1/OcaInterval: Fix template class decoder.
|
|
49
|
+
|
|
50
|
+
## [2.0.9] - 2025-11-25
|
|
51
|
+
|
|
52
|
+
- AbstractUdpConnection: Close socket on failure when device does not
|
|
53
|
+
respond with keepalive in time.
|
|
54
|
+
|
|
55
|
+
## [2.0.8] - 2025-11-24
|
|
56
|
+
|
|
57
|
+
- RemoteDevice: Fix EV2 detection when implementations return status
|
|
58
|
+
codes other than NotImplemented for new EV2 methods.
|
|
59
|
+
|
|
60
|
+
- wait_for_keepalive: Handle error in unsubscribe.
|
|
61
|
+
|
|
62
|
+
## [2.0.7] - 2025-11-18
|
|
63
|
+
|
|
64
|
+
- OcaInterval: Fix OCP.1 encoder definition.
|
|
65
|
+
|
|
66
|
+
## [2.0.6] - 2025-11-12
|
|
67
|
+
|
|
68
|
+
- OcaInterval: Fix duplicate import.
|
|
69
|
+
|
|
70
|
+
## [2.0.5] - 2025-11-12
|
|
71
|
+
|
|
72
|
+
- TypeScript: Use explicit import paths for moduleResolution=nodenext.
|
|
73
|
+
|
|
74
|
+
- Remove deprecated types from AES70-2018.
|
|
75
|
+
|
|
76
|
+
## [2.0.4] - 2025-10-24
|
|
77
|
+
|
|
78
|
+
- ClientConnection: Add wait_for_keepalive to wait for a single keepalive
|
|
79
|
+
from the device.
|
|
80
|
+
|
|
81
|
+
- Connection: Warn when keepalive interval is large (common ms vs seconds
|
|
82
|
+
mistake).
|
|
83
|
+
|
|
84
|
+
## [2.0.3] - 2025-10-09
|
|
85
|
+
|
|
86
|
+
- Fix missing inout parameters in generated OCC model.
|
|
87
|
+
|
|
88
|
+
## [2.0.2] - 2025-10-07
|
|
89
|
+
|
|
90
|
+
- NotificationError: Fix payload parsing.
|
|
91
|
+
|
|
92
|
+
- BaseEvent: Fix error handling.
|
|
93
|
+
|
|
94
|
+
- PropertySync: Implement aliases so properties are available by alias.
|
|
95
|
+
|
|
96
|
+
## [2.0.1] - 2025-10-07
|
|
97
|
+
|
|
98
|
+
- PropertySync: Use observeProperty.
|
|
99
|
+
|
|
100
|
+
- Introduce CloseError and TimeoutError classes; emit them on close and
|
|
101
|
+
timeout. Suppress unhandled close error warning.
|
|
102
|
+
|
|
5
103
|
## [2.0.0] - 2025-10-07
|
|
6
104
|
|
|
7
105
|
- Updates to AES70-2024
|
|
@@ -13,7 +111,7 @@ All notable changes and version updates will be documented in this file.
|
|
|
13
111
|
|
|
14
112
|
## [1.6.1] - 2025-05-06
|
|
15
113
|
|
|
16
|
-
- TCPConnection.connect: Add
|
|
114
|
+
- TCPConnection.connect: Add connectSignal to abort
|
|
17
115
|
connection attempts.
|
|
18
116
|
|
|
19
117
|
- Encode arguments earlier. This means that when calling
|
package/README.md
CHANGED
|
@@ -96,12 +96,23 @@ NodeJS both TCP and UDP are available in addition to that.
|
|
|
96
96
|
port: 65000,
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
-
In a web browser using a WebSocket this looks similar
|
|
99
|
+
In a web browser using a WebSocket this looks similar (the global
|
|
100
|
+
`WebSocket` is used automatically):
|
|
100
101
|
|
|
101
102
|
const connection = await OCA.WebSocketConnection.connect({
|
|
102
103
|
url: 'ws://example.org',
|
|
103
104
|
});
|
|
104
105
|
|
|
106
|
+
On Node.js, WebSocket support requires passing the WebSocket constructor
|
|
107
|
+
as the second argument to `connect()`, since there is no built-in
|
|
108
|
+
WebSocket. For example, install the `ws` package and use:
|
|
109
|
+
|
|
110
|
+
import { WebSocket } from 'ws';
|
|
111
|
+
const connection = await WebSocketConnection.connect(
|
|
112
|
+
{ url: 'ws://example.org' },
|
|
113
|
+
WebSocket
|
|
114
|
+
);
|
|
115
|
+
|
|
105
116
|
The next step is to discover what kind of objects the device has. This can be
|
|
106
117
|
done using the method `RemoteDevice.get_device_tree()` method.
|
|
107
118
|
|
|
@@ -178,7 +189,7 @@ connection.on('receive', (pdu) => {
|
|
|
178
189
|
pendingCommand.name,
|
|
179
190
|
pendingCommand.get_arguments(),
|
|
180
191
|
'->',
|
|
181
|
-
Types.OcaStatus.getName(pdu.status_code)
|
|
192
|
+
Types.OcaStatus.getName(pdu.status_code),
|
|
182
193
|
);
|
|
183
194
|
}
|
|
184
195
|
} else {
|
package/bin/printDevice.js
CHANGED
|
@@ -7,19 +7,25 @@ import { UDPConnection } from '../src/controller/udp_connection.js';
|
|
|
7
7
|
import { fetchDeviceContent } from '../src/controller/fetch_device_content.js';
|
|
8
8
|
|
|
9
9
|
function badArguments() {
|
|
10
|
-
console.log(
|
|
10
|
+
console.log(
|
|
11
|
+
'Usage: node print_tree.js [--json] [--udp] [--progress] <ip> <port>'
|
|
12
|
+
);
|
|
11
13
|
exit(1);
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
let jsonMode = false;
|
|
15
17
|
let useUdp = false;
|
|
16
18
|
const rest = [];
|
|
19
|
+
let progress = false;
|
|
17
20
|
|
|
18
21
|
argv.slice(2).forEach((option) => {
|
|
19
22
|
switch (option) {
|
|
20
23
|
case '--json':
|
|
21
24
|
jsonMode = true;
|
|
22
25
|
break;
|
|
26
|
+
case '--progress':
|
|
27
|
+
progress = true;
|
|
28
|
+
break;
|
|
23
29
|
case '-h':
|
|
24
30
|
case '--help':
|
|
25
31
|
badArguments();
|
|
@@ -76,8 +82,13 @@ function printTreeJson(content) {
|
|
|
76
82
|
|
|
77
83
|
async function printDevice(device) {
|
|
78
84
|
try {
|
|
79
|
-
const
|
|
80
|
-
|
|
85
|
+
const reportProgress = progress
|
|
86
|
+
? (finished, total) => {
|
|
87
|
+
process.stderr.write(`\r${finished} of ${total}`);
|
|
88
|
+
}
|
|
89
|
+
: undefined;
|
|
90
|
+
const content = await fetchDeviceContent(device, reportProgress);
|
|
91
|
+
if (progress) process.stderr.write(`\ndone.\n`);
|
|
81
92
|
if (jsonMode) {
|
|
82
93
|
printTreeJson(content);
|
|
83
94
|
} else {
|
package/dist/AES70.es5.js
CHANGED
|
@@ -1382,6 +1382,8 @@
|
|
|
1382
1382
|
|
|
1383
1383
|
const t = seconds * 1000;
|
|
1384
1384
|
|
|
1385
|
+
if (this.keepalive_interval === t) return;
|
|
1386
|
+
|
|
1385
1387
|
this.keepalive_interval = t;
|
|
1386
1388
|
|
|
1387
1389
|
// Notify the other side about our new keepalive
|
|
@@ -1816,6 +1818,19 @@
|
|
|
1816
1818
|
this.name = name;
|
|
1817
1819
|
this.lastSent = 0;
|
|
1818
1820
|
this.retries = 0;
|
|
1821
|
+
this.duration = 0;
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
/**
|
|
1825
|
+
* Sets the expected processing time for this command on the device.
|
|
1826
|
+
* This duration is used when scheduling retries.
|
|
1827
|
+
* Only has an effect for UDP connections.
|
|
1828
|
+
*
|
|
1829
|
+
* @param {number} interval
|
|
1830
|
+
* The interval in milliseconds.
|
|
1831
|
+
*/
|
|
1832
|
+
set_duration(interval) {
|
|
1833
|
+
this.duration = interval;
|
|
1819
1834
|
}
|
|
1820
1835
|
|
|
1821
1836
|
get_arguments() {
|
|
@@ -1886,7 +1901,7 @@
|
|
|
1886
1901
|
this._scheduledPendingCommands = new Set();
|
|
1887
1902
|
// All pending commands wich have been sent.
|
|
1888
1903
|
this._sentPendingCommands = new Set();
|
|
1889
|
-
this.
|
|
1904
|
+
this._lastCommandHandle = 0;
|
|
1890
1905
|
this._subscribers = new Map();
|
|
1891
1906
|
this._sendCommandsTimer = new Timer(
|
|
1892
1907
|
() => {
|
|
@@ -1934,7 +1949,7 @@
|
|
|
1934
1949
|
|
|
1935
1950
|
const e = new CloseError(error);
|
|
1936
1951
|
pendingCommands.forEach((pendingCommand, id) => {
|
|
1937
|
-
pendingCommand.handleError(
|
|
1952
|
+
pendingCommand.handleError(e);
|
|
1938
1953
|
});
|
|
1939
1954
|
|
|
1940
1955
|
subscribers.forEach((cb) => {
|
|
@@ -1970,8 +1985,8 @@
|
|
|
1970
1985
|
}
|
|
1971
1986
|
|
|
1972
1987
|
do {
|
|
1973
|
-
handle = this.
|
|
1974
|
-
this.
|
|
1988
|
+
handle = this._lastCommandHandle;
|
|
1989
|
+
this._lastCommandHandle = (handle + 1) | 0;
|
|
1975
1990
|
} while (pendingCommands.has(handle));
|
|
1976
1991
|
|
|
1977
1992
|
return handle;
|
|
@@ -1993,6 +2008,10 @@
|
|
|
1993
2008
|
}
|
|
1994
2009
|
}
|
|
1995
2010
|
|
|
2011
|
+
get_last_pending_command() {
|
|
2012
|
+
return this._pendingCommands.get(this._lastCommandHandle);
|
|
2013
|
+
}
|
|
2014
|
+
|
|
1996
2015
|
send_command(command, returnTypes, callback, stack, name) {
|
|
1997
2016
|
const executor = (resolve, reject) => {
|
|
1998
2017
|
const handle = this._getNextCommandHandle();
|
|
@@ -28710,7 +28729,8 @@
|
|
|
28710
28729
|
} else if (S.version > 0 && !S.has_subscribers()) {
|
|
28711
28730
|
dropSubscribers();
|
|
28712
28731
|
this._doUnsubscribe(S, event).catch((error) => {
|
|
28713
|
-
|
|
28732
|
+
if (error.name === 'aes70.CloseError') return;
|
|
28733
|
+
console.error('Unsubscribe failed: %o', error);
|
|
28714
28734
|
});
|
|
28715
28735
|
}
|
|
28716
28736
|
};
|
|
@@ -29173,6 +29193,13 @@
|
|
|
29173
29193
|
|
|
29174
29194
|
_sentPendingCommands.delete(pendingCommand);
|
|
29175
29195
|
|
|
29196
|
+
if (pendingCommand.lastSent + pendingCommand.duration > retryTime) {
|
|
29197
|
+
// This command is expected to take longer. Simply push it back to the queue,
|
|
29198
|
+
// we will pick it up later.
|
|
29199
|
+
_sentPendingCommands.add(pendingCommand);
|
|
29200
|
+
continue;
|
|
29201
|
+
}
|
|
29202
|
+
|
|
29176
29203
|
if (pendingCommand.retries >= this.retry_count) {
|
|
29177
29204
|
failed.push(pendingCommand);
|
|
29178
29205
|
} else {
|
|
@@ -29346,9 +29373,9 @@
|
|
|
29346
29373
|
if (typeof value === 'object') {
|
|
29347
29374
|
if (value instanceof Arguments) {
|
|
29348
29375
|
return {
|
|
29349
|
-
[name]: value.item(0),
|
|
29350
|
-
['Min' + name]: value.item(1),
|
|
29351
|
-
['Max' + name]: value.item(2),
|
|
29376
|
+
[name]: formatValue(value.item(0)),
|
|
29377
|
+
['Min' + name]: formatValue(value.item(1)),
|
|
29378
|
+
['Max' + name]: formatValue(value.item(2)),
|
|
29352
29379
|
};
|
|
29353
29380
|
} else {
|
|
29354
29381
|
value = formatValue(value);
|
|
@@ -29356,7 +29383,7 @@
|
|
|
29356
29383
|
}
|
|
29357
29384
|
|
|
29358
29385
|
return {
|
|
29359
|
-
[name]: value,
|
|
29386
|
+
[name]: formatValue(value),
|
|
29360
29387
|
};
|
|
29361
29388
|
}
|
|
29362
29389
|
|
|
@@ -29388,7 +29415,11 @@
|
|
|
29388
29415
|
|
|
29389
29416
|
Object.assign(info, formatReturnValue(name, currentValue));
|
|
29390
29417
|
} catch (err) {
|
|
29391
|
-
|
|
29418
|
+
// 8 - NotImplemented
|
|
29419
|
+
// 11 - BadMethod
|
|
29420
|
+
// Note: Some implementations respond with BadMethod for methods which have been
|
|
29421
|
+
// defined in more recent vrsions of aes70
|
|
29422
|
+
if (err.status != 8 && err.status != 11)
|
|
29392
29423
|
console.error(
|
|
29393
29424
|
'Fetching property',
|
|
29394
29425
|
o.ClassName,
|
|
@@ -29416,10 +29447,13 @@
|
|
|
29416
29447
|
}
|
|
29417
29448
|
}
|
|
29418
29449
|
|
|
29419
|
-
async function fetchDeviceContentRec(objects) {
|
|
29450
|
+
async function fetchDeviceContentRec(objects, reportProgress) {
|
|
29420
29451
|
const result = [];
|
|
29421
29452
|
|
|
29422
29453
|
for (let i = 0; i < objects.length; i++) {
|
|
29454
|
+
if (reportProgress) {
|
|
29455
|
+
reportProgress(i, objects.length);
|
|
29456
|
+
}
|
|
29423
29457
|
const o = objects[i];
|
|
29424
29458
|
const info = await fetchObjectInfo(o);
|
|
29425
29459
|
|
|
@@ -29438,7 +29472,7 @@
|
|
|
29438
29472
|
return result;
|
|
29439
29473
|
}
|
|
29440
29474
|
|
|
29441
|
-
async function fetchDeviceContent(device) {
|
|
29475
|
+
async function fetchDeviceContent(device, reportProgress) {
|
|
29442
29476
|
const objects = await device.GetDeviceTree();
|
|
29443
29477
|
const managers = [
|
|
29444
29478
|
device.DeviceManager,
|
|
@@ -29460,7 +29494,7 @@
|
|
|
29460
29494
|
if (await managerExists(manager)) objects.push(manager);
|
|
29461
29495
|
}
|
|
29462
29496
|
|
|
29463
|
-
return await fetchDeviceContentRec(objects);
|
|
29497
|
+
return await fetchDeviceContentRec(objects, reportProgress);
|
|
29464
29498
|
}
|
|
29465
29499
|
|
|
29466
29500
|
/*
|
|
@@ -30670,21 +30704,32 @@
|
|
|
30670
30704
|
}
|
|
30671
30705
|
}
|
|
30672
30706
|
|
|
30707
|
+
const globalWebSocket =
|
|
30708
|
+
typeof globalThis !== 'undefined' ? globalThis.WebSocket : undefined;
|
|
30709
|
+
|
|
30673
30710
|
/**
|
|
30674
30711
|
* Connection which implements OCP.1 with WebSocket transport.
|
|
30712
|
+
* Works in both browser and Node.js. In the browser the global WebSocket
|
|
30713
|
+
* is used when not passed; on Node.js the WebSocket constructor must be
|
|
30714
|
+
* passed as the second argument (e.g. from the 'ws' package).
|
|
30675
30715
|
*/
|
|
30676
30716
|
class WebSocketConnection extends WebSocketConnectionBase {
|
|
30677
30717
|
/**
|
|
30678
30718
|
* Connect to the given endpoint.
|
|
30679
30719
|
*
|
|
30680
30720
|
* @param {object} options
|
|
30681
|
-
* @param {String} options.url
|
|
30682
|
-
*
|
|
30683
|
-
* @returns {Promise<WebSocketConnection>}
|
|
30684
|
-
* The connection.
|
|
30721
|
+
* @param {String} options.url - Endpoint WebSocket url.
|
|
30722
|
+
* @param {Function} [WebSocket] - WebSocket constructor. Optional in browser (global WebSocket is used). Required on Node.js (e.g. import WebSocket from 'ws').
|
|
30723
|
+
* @returns {Promise<WebSocketConnection>} - The connection.
|
|
30685
30724
|
*/
|
|
30686
|
-
static connect(options) {
|
|
30687
|
-
|
|
30725
|
+
static connect(options, WebSocket) {
|
|
30726
|
+
const Ctor = WebSocket !== undefined ? WebSocket : globalWebSocket;
|
|
30727
|
+
if (!Ctor) {
|
|
30728
|
+
throw new Error(
|
|
30729
|
+
'WebSocket constructor is required in this environment. Pass the WebSocket class as the second argument (e.g. from the "ws" package on Node.js).'
|
|
30730
|
+
);
|
|
30731
|
+
}
|
|
30732
|
+
return super.connect(Ctor, options);
|
|
30688
30733
|
}
|
|
30689
30734
|
|
|
30690
30735
|
_now() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aes70",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.19",
|
|
4
4
|
"description": "A controller library for the AES70 protocol.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -41,9 +41,6 @@
|
|
|
41
41
|
"url": "https://github.com/DeutscheSoft/AES70.js/issues"
|
|
42
42
|
},
|
|
43
43
|
"homepage": "https://github.com/DeutscheSoft/AES70.js#readme",
|
|
44
|
-
"optionalDependencies": {
|
|
45
|
-
"ws": "^5.2.4"
|
|
46
|
-
},
|
|
47
44
|
"sideEffects": [
|
|
48
45
|
"src/bundle.browser.js",
|
|
49
46
|
"dist/AES70.es5.js"
|
package/src/close_error.d.ts
CHANGED
package/src/connection.js
CHANGED
|
@@ -192,6 +192,13 @@ export class AbstractUDPConnection extends ClientConnection {
|
|
|
192
192
|
|
|
193
193
|
_sentPendingCommands.delete(pendingCommand);
|
|
194
194
|
|
|
195
|
+
if (pendingCommand.lastSent + pendingCommand.duration > retryTime) {
|
|
196
|
+
// This command is expected to take longer. Simply push it back to the queue,
|
|
197
|
+
// we will pick it up later.
|
|
198
|
+
_sentPendingCommands.add(pendingCommand);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
|
|
195
202
|
if (pendingCommand.retries >= this.retry_count) {
|
|
196
203
|
failed.push(pendingCommand);
|
|
197
204
|
} else {
|
|
@@ -25,7 +25,17 @@ export interface PendingCommand {
|
|
|
25
25
|
* If available, returns the arguments of this
|
|
26
26
|
* remote method call.
|
|
27
27
|
*/
|
|
28
|
-
get_arguments():
|
|
28
|
+
get_arguments(): unknown[] | undefined;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Sets the expected processing time for this command on the device.
|
|
32
|
+
* This duration is used when scheduling retries.
|
|
33
|
+
* Only has an effect for UDP connections.
|
|
34
|
+
*
|
|
35
|
+
* @param {number} interval
|
|
36
|
+
* The interval in milliseconds.
|
|
37
|
+
*/
|
|
38
|
+
set_duration(interval: number): void;
|
|
29
39
|
}
|
|
30
40
|
|
|
31
41
|
/**
|
|
@@ -42,4 +52,6 @@ export declare class ClientConnection extends Connection {
|
|
|
42
52
|
* Keepalive interval in seconds.
|
|
43
53
|
*/
|
|
44
54
|
wait_for_keepalive(interval: number): Promise<void>;
|
|
55
|
+
|
|
56
|
+
get_last_pending_command(): PendingCommand | undefined;
|
|
45
57
|
}
|
|
@@ -27,6 +27,19 @@ class PendingCommand {
|
|
|
27
27
|
this.name = name;
|
|
28
28
|
this.lastSent = 0;
|
|
29
29
|
this.retries = 0;
|
|
30
|
+
this.duration = 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Sets the expected processing time for this command on the device.
|
|
35
|
+
* This duration is used when scheduling retries.
|
|
36
|
+
* Only has an effect for UDP connections.
|
|
37
|
+
*
|
|
38
|
+
* @param {number} interval
|
|
39
|
+
* The interval in milliseconds.
|
|
40
|
+
*/
|
|
41
|
+
set_duration(interval) {
|
|
42
|
+
this.duration = interval;
|
|
30
43
|
}
|
|
31
44
|
|
|
32
45
|
get_arguments() {
|
|
@@ -97,7 +110,7 @@ export class ClientConnection extends Connection {
|
|
|
97
110
|
this._scheduledPendingCommands = new Set();
|
|
98
111
|
// All pending commands wich have been sent.
|
|
99
112
|
this._sentPendingCommands = new Set();
|
|
100
|
-
this.
|
|
113
|
+
this._lastCommandHandle = 0;
|
|
101
114
|
this._subscribers = new Map();
|
|
102
115
|
this._sendCommandsTimer = new Timer(
|
|
103
116
|
() => {
|
|
@@ -145,7 +158,7 @@ export class ClientConnection extends Connection {
|
|
|
145
158
|
|
|
146
159
|
const e = new CloseError(error);
|
|
147
160
|
pendingCommands.forEach((pendingCommand, id) => {
|
|
148
|
-
pendingCommand.handleError(
|
|
161
|
+
pendingCommand.handleError(e);
|
|
149
162
|
});
|
|
150
163
|
|
|
151
164
|
subscribers.forEach((cb) => {
|
|
@@ -181,8 +194,8 @@ export class ClientConnection extends Connection {
|
|
|
181
194
|
}
|
|
182
195
|
|
|
183
196
|
do {
|
|
184
|
-
handle = this.
|
|
185
|
-
this.
|
|
197
|
+
handle = this._lastCommandHandle;
|
|
198
|
+
this._lastCommandHandle = (handle + 1) | 0;
|
|
186
199
|
} while (pendingCommands.has(handle));
|
|
187
200
|
|
|
188
201
|
return handle;
|
|
@@ -204,6 +217,10 @@ export class ClientConnection extends Connection {
|
|
|
204
217
|
}
|
|
205
218
|
}
|
|
206
219
|
|
|
220
|
+
get_last_pending_command() {
|
|
221
|
+
return this._pendingCommands.get(this._lastCommandHandle);
|
|
222
|
+
}
|
|
223
|
+
|
|
207
224
|
send_command(command, returnTypes, callback, stack, name) {
|
|
208
225
|
const executor = (resolve, reject) => {
|
|
209
226
|
const handle = this._getNextCommandHandle();
|
|
@@ -37,9 +37,9 @@ function formatReturnValue(name, value) {
|
|
|
37
37
|
if (typeof value === 'object') {
|
|
38
38
|
if (value instanceof Arguments) {
|
|
39
39
|
return {
|
|
40
|
-
[name]: value.item(0),
|
|
41
|
-
['Min' + name]: value.item(1),
|
|
42
|
-
['Max' + name]: value.item(2),
|
|
40
|
+
[name]: formatValue(value.item(0)),
|
|
41
|
+
['Min' + name]: formatValue(value.item(1)),
|
|
42
|
+
['Max' + name]: formatValue(value.item(2)),
|
|
43
43
|
};
|
|
44
44
|
} else {
|
|
45
45
|
value = formatValue(value);
|
|
@@ -47,7 +47,7 @@ function formatReturnValue(name, value) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
return {
|
|
50
|
-
[name]: value,
|
|
50
|
+
[name]: formatValue(value),
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -79,7 +79,11 @@ async function fetchObjectInfo(o) {
|
|
|
79
79
|
|
|
80
80
|
Object.assign(info, formatReturnValue(name, currentValue));
|
|
81
81
|
} catch (err) {
|
|
82
|
-
|
|
82
|
+
// 8 - NotImplemented
|
|
83
|
+
// 11 - BadMethod
|
|
84
|
+
// Note: Some implementations respond with BadMethod for methods which have been
|
|
85
|
+
// defined in more recent vrsions of aes70
|
|
86
|
+
if (err.status != 8 && err.status != 11)
|
|
83
87
|
console.error(
|
|
84
88
|
'Fetching property',
|
|
85
89
|
o.ClassName,
|
|
@@ -107,10 +111,13 @@ async function managerExists(manager) {
|
|
|
107
111
|
}
|
|
108
112
|
}
|
|
109
113
|
|
|
110
|
-
async function fetchDeviceContentRec(objects) {
|
|
114
|
+
async function fetchDeviceContentRec(objects, reportProgress) {
|
|
111
115
|
const result = [];
|
|
112
116
|
|
|
113
117
|
for (let i = 0; i < objects.length; i++) {
|
|
118
|
+
if (reportProgress) {
|
|
119
|
+
reportProgress(i, objects.length);
|
|
120
|
+
}
|
|
114
121
|
const o = objects[i];
|
|
115
122
|
const info = await fetchObjectInfo(o);
|
|
116
123
|
|
|
@@ -129,7 +136,7 @@ async function fetchDeviceContentRec(objects) {
|
|
|
129
136
|
return result;
|
|
130
137
|
}
|
|
131
138
|
|
|
132
|
-
export async function fetchDeviceContent(device) {
|
|
139
|
+
export async function fetchDeviceContent(device, reportProgress) {
|
|
133
140
|
const objects = await device.GetDeviceTree();
|
|
134
141
|
const managers = [
|
|
135
142
|
device.DeviceManager,
|
|
@@ -151,5 +158,5 @@ export async function fetchDeviceContent(device) {
|
|
|
151
158
|
if (await managerExists(manager)) objects.push(manager);
|
|
152
159
|
}
|
|
153
160
|
|
|
154
|
-
return await fetchDeviceContentRec(objects);
|
|
161
|
+
return await fetchDeviceContentRec(objects, reportProgress);
|
|
155
162
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { warn
|
|
1
|
+
import { warn } from '../log.js';
|
|
2
2
|
|
|
3
3
|
import { Events } from '../events.js';
|
|
4
4
|
|
|
@@ -17,13 +17,13 @@ import { OcaCodingManager } from './ControlClasses/OcaCodingManager.js';
|
|
|
17
17
|
import { OcaDiagnosticManager } from './ControlClasses/OcaDiagnosticManager.js';
|
|
18
18
|
import { OcaBlock } from './ControlClasses/OcaBlock.js';
|
|
19
19
|
import { RemoteError } from './remote_error.js';
|
|
20
|
-
import { OcaStatus } from '../types/OcaStatus.js';
|
|
21
20
|
import tree_to_rolemap from './tree_to_rolemap.js';
|
|
22
21
|
|
|
23
22
|
import * as RemoteControlClasses from './ControlClasses.js';
|
|
24
23
|
|
|
25
24
|
import { OcaManagerDefaultObjectNumbers } from '../types/OcaManagerDefaultObjectNumbers.js';
|
|
26
25
|
import { OcaNotificationDeliveryMode } from '../types/OcaNotificationDeliveryMode.js';
|
|
26
|
+
import { CloseError } from '../close_error.js';
|
|
27
27
|
|
|
28
28
|
const emptyUint8Array = new Uint8Array(0);
|
|
29
29
|
|
|
@@ -314,7 +314,8 @@ export class RemoteDevice extends Events {
|
|
|
314
314
|
} else if (S.version > 0 && !S.has_subscribers()) {
|
|
315
315
|
dropSubscribers();
|
|
316
316
|
this._doUnsubscribe(S, event).catch((error) => {
|
|
317
|
-
|
|
317
|
+
if (error.name === 'aes70.CloseError') return;
|
|
318
|
+
console.error('Unsubscribe failed: %o', error);
|
|
318
319
|
});
|
|
319
320
|
}
|
|
320
321
|
};
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
WebSocketConnectionBase,
|
|
3
3
|
IWebSocketConnectionBaseOptions,
|
|
4
|
+
IWebSocketLike,
|
|
5
|
+
WebSocketConstructor,
|
|
4
6
|
} from './websocket_connection_base.js';
|
|
5
7
|
|
|
6
8
|
export type IWebSocketConnectionOptions = IWebSocketConnectionBaseOptions;
|
|
9
|
+
export type { IWebSocketLike, WebSocketConstructor };
|
|
7
10
|
|
|
8
11
|
export class WebSocketConnection extends WebSocketConnectionBase {
|
|
9
|
-
constructor(ws:
|
|
10
|
-
static connectWebSocket(
|
|
11
|
-
WebSocket: typeof WebSocket,
|
|
12
|
-
options: WebSocketConnectionOptions
|
|
13
|
-
): Promise<WebSocket>;
|
|
12
|
+
constructor(ws: IWebSocketLike, options: IWebSocketConnectionOptions);
|
|
14
13
|
static connect(
|
|
15
|
-
options:
|
|
14
|
+
options: IWebSocketConnectionOptions
|
|
15
|
+
): Promise<WebSocketConnection>;
|
|
16
|
+
static connect(
|
|
17
|
+
options: IWebSocketConnectionOptions,
|
|
18
|
+
WebSocket: WebSocketConstructor
|
|
16
19
|
): Promise<WebSocketConnection>;
|
|
17
20
|
}
|
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import { WebSocketConnectionBase } from './websocket_connection_base.js';
|
|
2
2
|
|
|
3
|
+
const globalWebSocket =
|
|
4
|
+
typeof globalThis !== 'undefined' ? globalThis.WebSocket : undefined;
|
|
5
|
+
|
|
3
6
|
/**
|
|
4
7
|
* Connection which implements OCP.1 with WebSocket transport.
|
|
8
|
+
* Works in both browser and Node.js. In the browser the global WebSocket
|
|
9
|
+
* is used when not passed; on Node.js the WebSocket constructor must be
|
|
10
|
+
* passed as the second argument (e.g. from the 'ws' package).
|
|
5
11
|
*/
|
|
6
12
|
export class WebSocketConnection extends WebSocketConnectionBase {
|
|
7
13
|
/**
|
|
8
14
|
* Connect to the given endpoint.
|
|
9
15
|
*
|
|
10
16
|
* @param {object} options
|
|
11
|
-
* @param {String} options.url
|
|
12
|
-
*
|
|
13
|
-
* @returns {Promise<WebSocketConnection>}
|
|
14
|
-
* The connection.
|
|
17
|
+
* @param {String} options.url - Endpoint WebSocket url.
|
|
18
|
+
* @param {Function} [WebSocket] - WebSocket constructor. Optional in browser (global WebSocket is used). Required on Node.js (e.g. import WebSocket from 'ws').
|
|
19
|
+
* @returns {Promise<WebSocketConnection>} - The connection.
|
|
15
20
|
*/
|
|
16
|
-
static connect(options) {
|
|
17
|
-
|
|
21
|
+
static connect(options, WebSocket) {
|
|
22
|
+
const Ctor = WebSocket !== undefined ? WebSocket : globalWebSocket;
|
|
23
|
+
if (!Ctor) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
'WebSocket constructor is required in this environment. Pass the WebSocket class as the second argument (e.g. from the "ws" package on Node.js).'
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return super.connect(Ctor, options);
|
|
18
29
|
}
|
|
19
30
|
|
|
20
31
|
_now() {
|
|
@@ -3,6 +3,27 @@ import {
|
|
|
3
3
|
ClientConnection,
|
|
4
4
|
} from './client_connection.js';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Minimal WebSocket-like interface supported by both browser WebSocket
|
|
8
|
+
* and the Node.js 'ws' library. Used for typing connection options and
|
|
9
|
+
* the optional WebSocket constructor passed to connect().
|
|
10
|
+
*/
|
|
11
|
+
export interface IWebSocketLike {
|
|
12
|
+
binaryType: string;
|
|
13
|
+
addEventListener(
|
|
14
|
+
type: string,
|
|
15
|
+
listener: (ev: { data?: ArrayBuffer | Buffer; type?: string }) => void
|
|
16
|
+
): void;
|
|
17
|
+
removeEventListener(
|
|
18
|
+
type: string,
|
|
19
|
+
listener: (ev: { data?: ArrayBuffer | Buffer; type?: string }) => void
|
|
20
|
+
): void;
|
|
21
|
+
send(data: ArrayBuffer | Buffer | ArrayBufferView): void;
|
|
22
|
+
close(): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type WebSocketConstructor = new (url: string) => IWebSocketLike;
|
|
26
|
+
|
|
6
27
|
export interface IWebSocketConnectionBaseOptions
|
|
7
28
|
extends IClientConnectionOptions {
|
|
8
29
|
url: string;
|
|
@@ -14,5 +35,6 @@ export interface IWebSocketConnectionBaseOptions
|
|
|
14
35
|
* Browser.
|
|
15
36
|
*/
|
|
16
37
|
export class WebSocketConnectionBase extends ClientConnection {
|
|
38
|
+
constructor(ws: IWebSocketLike, options: IWebSocketConnectionBaseOptions);
|
|
17
39
|
write(buf: ArrayBuffer): void;
|
|
18
40
|
}
|
package/src/index.d.ts
CHANGED
package/src/index.js
CHANGED
package/src/timeout_error.d.ts
CHANGED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
WebSocketConnectionBase,
|
|
3
|
-
IWebSocketConnectionBaseOptions,
|
|
4
|
-
} from './websocket_connection_base.js';
|
|
5
|
-
import WebSocket from 'ws';
|
|
6
|
-
|
|
7
|
-
export type IWebSocketConnectionOptions = IWebSocketConnectionBaseOptions;
|
|
8
|
-
|
|
9
|
-
export class WebSocketConnection extends WebSocketConnectionBase {
|
|
10
|
-
constructor(ws: WebSocket, options: WebSocketConnectionOptions);
|
|
11
|
-
static connectWebSocket(
|
|
12
|
-
WebSocket: typeof WebSocket,
|
|
13
|
-
options: WebSocketConnectionOptions
|
|
14
|
-
): Promise<WebSocket>;
|
|
15
|
-
static connect(
|
|
16
|
-
options: WebSocketConnectionOptions
|
|
17
|
-
): Promise<WebSocketConnection>;
|
|
18
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/* eslint-env node */
|
|
2
|
-
|
|
3
|
-
import WebSocket from 'ws';
|
|
4
|
-
import { performance } from 'perf_hooks';
|
|
5
|
-
import { WebSocketConnectionBase } from './websocket_connection_base.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Connection which implements OCP.1 with WebSocket transport.
|
|
9
|
-
*/
|
|
10
|
-
export class WebSocketConnection extends WebSocketConnectionBase {
|
|
11
|
-
/**
|
|
12
|
-
* Connect to the given endpoint.
|
|
13
|
-
*
|
|
14
|
-
* @param {String} options.url - Endpoint WebSocket url.
|
|
15
|
-
* @returns {Promise<WebSocketConnection>} - The connection.
|
|
16
|
-
*/
|
|
17
|
-
static async connect(options) {
|
|
18
|
-
return super.connect(WebSocket, options);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
_now() {
|
|
22
|
-
return performance.now();
|
|
23
|
-
}
|
|
24
|
-
}
|