aes70 2.0.14 → 2.0.16
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/AES70.es5.js +398 -145
- package/package.json +1 -1
- package/src/OCP1/message_generator.js +9 -1
- package/src/connection.d.ts +17 -0
- package/src/connection.js +36 -16
- package/src/controller/abstract_udp_connection.js +83 -86
- package/src/controller/client_connection.js +63 -19
- package/src/controller/fetch_device_content.js +4 -0
- package/src/controller/node_udp.js +71 -36
- package/src/controller/property.js +13 -21
- package/src/events.js +10 -5
- package/src/utils/subscribeEvent.js +32 -0
- package/src/utils/subscriptions.js +27 -0
- package/src/utils/timer.js +123 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
/* eslint-env node */
|
|
2
2
|
|
|
3
3
|
import { createSocket } from 'dgram';
|
|
4
|
-
import { isIP } from 'net';
|
|
4
|
+
import { isIP, isIPv4 } from 'net';
|
|
5
5
|
import { lookup } from 'dns';
|
|
6
|
+
import { Subscriptions } from '../utils/subscriptions.js';
|
|
7
|
+
import { subscribeEvent } from '../utils/subscribeEvent.js';
|
|
6
8
|
|
|
7
|
-
function lookup_address(host) {
|
|
9
|
+
function lookup_address(host, family) {
|
|
8
10
|
if (isIP(host)) return Promise.resolve(host);
|
|
9
11
|
|
|
10
12
|
return new Promise((resolve, reject) => {
|
|
11
|
-
lookup(host, { family
|
|
13
|
+
lookup(host, { family }, (err, address) => {
|
|
12
14
|
if (err) reject(err);
|
|
13
15
|
else resolve(address);
|
|
14
16
|
});
|
|
@@ -52,7 +54,11 @@ export class NodeUDP {
|
|
|
52
54
|
this._inbuf = [];
|
|
53
55
|
|
|
54
56
|
for (let i = 0; i < inbuf.length; i++) {
|
|
55
|
-
|
|
57
|
+
try {
|
|
58
|
+
onmessage(inbuf[i].buffer);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error(err);
|
|
61
|
+
}
|
|
56
62
|
}
|
|
57
63
|
}
|
|
58
64
|
|
|
@@ -73,30 +79,11 @@ export class NodeUDP {
|
|
|
73
79
|
this.socket.send(Buffer.from(buf));
|
|
74
80
|
}
|
|
75
81
|
|
|
76
|
-
receiveMessage(timeout) {
|
|
77
|
-
return new Promise((resolve, reject) => {
|
|
78
|
-
if (this._error) {
|
|
79
|
-
reject(this._error);
|
|
80
|
-
} else if (this._inbuf.length) {
|
|
81
|
-
resolve(this._inbuf.shift());
|
|
82
|
-
} else {
|
|
83
|
-
this.onmessage = (msg) => {
|
|
84
|
-
this.onmessage = null;
|
|
85
|
-
this.onerror = null;
|
|
86
|
-
resolve(msg);
|
|
87
|
-
};
|
|
88
|
-
this.onerror = (err) => {
|
|
89
|
-
this.onmessage = null;
|
|
90
|
-
this.onerror = null;
|
|
91
|
-
reject(err);
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
82
|
close() {
|
|
98
|
-
this.socket
|
|
99
|
-
|
|
83
|
+
if (this.socket) {
|
|
84
|
+
this.socket.close();
|
|
85
|
+
this.socket = null;
|
|
86
|
+
}
|
|
100
87
|
}
|
|
101
88
|
|
|
102
89
|
constructor(socket) {
|
|
@@ -114,14 +101,63 @@ export class NodeUDP {
|
|
|
114
101
|
});
|
|
115
102
|
}
|
|
116
103
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Creates a new udp socket and connects it to the target address.
|
|
106
|
+
* @param {string} options.host
|
|
107
|
+
* The hostname or ip address to connect to.
|
|
108
|
+
* @param {number} options.port
|
|
109
|
+
* The port.
|
|
110
|
+
* @param {'udp4' | 'udp6'} [options.type]
|
|
111
|
+
* The ip protocol to use. This is only relevant if host is
|
|
112
|
+
* not an ip address and hostname lookup is used.
|
|
113
|
+
* @param {Abortsignal} [options.signal]
|
|
114
|
+
* An optional AbortSignal to abort the connect operation.
|
|
115
|
+
* @returns
|
|
116
|
+
*/
|
|
117
|
+
static connect(options) {
|
|
118
|
+
const { host, port, type, signal } = options;
|
|
119
|
+
|
|
120
|
+
signal?.throwIfAborted();
|
|
121
|
+
|
|
122
|
+
const subscriptions = new Subscriptions();
|
|
123
|
+
|
|
124
|
+
return new Promise((resolve, reject) => {
|
|
125
|
+
let socket;
|
|
126
|
+
|
|
127
|
+
if (signal) {
|
|
128
|
+
subscriptions.add(
|
|
129
|
+
subscribeEvent(signal, 'abort', (reason) => {
|
|
130
|
+
const err = signal.reason;
|
|
131
|
+
reject(err);
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const lookupFamily =
|
|
137
|
+
type === 'udp4' ? 4 : type === 'udp6' ? 6 : undefined;
|
|
138
|
+
lookup_address(host, lookupFamily).then((ip) => {
|
|
139
|
+
if (signal?.aborted) {
|
|
140
|
+
// IF the abort signal was triggered during the ip lookup,
|
|
141
|
+
// we have to simply ignore the resolve result.
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const type = isIPv4(ip) ? 'udp4' : 'udp6';
|
|
145
|
+
socket = createSocket(type);
|
|
146
|
+
|
|
147
|
+
if (signal) {
|
|
148
|
+
subscriptions.add(
|
|
149
|
+
subscribeEvent(signal, 'abort', () => {
|
|
150
|
+
socket.close();
|
|
151
|
+
})
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
121
155
|
const onerror = function (ev) {
|
|
122
156
|
reject(ev);
|
|
157
|
+
socket.close();
|
|
123
158
|
};
|
|
124
|
-
|
|
159
|
+
subscriptions.add(subscribeEvent(socket, 'error', onerror));
|
|
160
|
+
|
|
125
161
|
socket.bind(
|
|
126
162
|
{
|
|
127
163
|
exclusive: true,
|
|
@@ -129,12 +165,11 @@ export class NodeUDP {
|
|
|
129
165
|
() => {
|
|
130
166
|
socket.on('connect', () => {
|
|
131
167
|
resolve(new this(socket));
|
|
132
|
-
socket.removeListener('error', onerror);
|
|
133
168
|
});
|
|
134
|
-
socket.connect(port,
|
|
169
|
+
socket.connect(port, ip);
|
|
135
170
|
}
|
|
136
171
|
);
|
|
137
|
-
});
|
|
138
|
-
});
|
|
172
|
+
}, reject);
|
|
173
|
+
}).finally(() => subscriptions.unsubscribe());
|
|
139
174
|
}
|
|
140
175
|
}
|
|
@@ -56,8 +56,7 @@ export class Property {
|
|
|
56
56
|
* @returns {Function} The getter. If none could be found, null is returned.
|
|
57
57
|
*/
|
|
58
58
|
getter(o, no_bind) {
|
|
59
|
-
|
|
60
|
-
let i = 0;
|
|
59
|
+
const name = this.name;
|
|
61
60
|
const aliases = this.aliases;
|
|
62
61
|
const accessors = this.accessors;
|
|
63
62
|
|
|
@@ -99,10 +98,13 @@ export class Property {
|
|
|
99
98
|
return no_bind ? fun : fun.bind(o);
|
|
100
99
|
}
|
|
101
100
|
|
|
102
|
-
|
|
101
|
+
// iterate all possible names
|
|
102
|
+
const possibleNames = aliases ? [name, ...aliases] : [name];
|
|
103
|
+
|
|
104
|
+
for (const possibleName of possibleNames) {
|
|
103
105
|
if (this.static) {
|
|
104
106
|
const c = o.constructor;
|
|
105
|
-
const v = c[
|
|
107
|
+
const v = c[possibleName];
|
|
106
108
|
|
|
107
109
|
if (v !== void 0) {
|
|
108
110
|
return function () {
|
|
@@ -110,16 +112,11 @@ export class Property {
|
|
|
110
112
|
};
|
|
111
113
|
}
|
|
112
114
|
} else {
|
|
113
|
-
const fun = o['Get' +
|
|
115
|
+
const fun = o['Get' + possibleName];
|
|
114
116
|
|
|
115
117
|
if (fun) return no_bind ? fun : fun.bind(o);
|
|
116
118
|
}
|
|
117
|
-
|
|
118
|
-
if (aliases && i < aliases.length) {
|
|
119
|
-
name = aliases[i++];
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
} while (false);
|
|
119
|
+
}
|
|
123
120
|
|
|
124
121
|
return null;
|
|
125
122
|
}
|
|
@@ -135,20 +132,15 @@ export class Property {
|
|
|
135
132
|
setter(o, no_bind) {
|
|
136
133
|
if (this.readonly || this.static) return null;
|
|
137
134
|
|
|
138
|
-
|
|
139
|
-
i = 0;
|
|
135
|
+
const name = this.name;
|
|
140
136
|
const aliases = this.aliases;
|
|
137
|
+
const possibleNames = aliases ? [name, ...aliases] : [name];
|
|
141
138
|
|
|
142
|
-
|
|
143
|
-
const fun = o['Set' +
|
|
139
|
+
for (const possibleName of possibleNames) {
|
|
140
|
+
const fun = o['Set' + possibleName];
|
|
144
141
|
|
|
145
142
|
if (fun) return no_bind ? fun : fun.bind(o);
|
|
146
|
-
|
|
147
|
-
if (aliases && i < aliases.length) {
|
|
148
|
-
name = aliases[i++];
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
} while (false);
|
|
143
|
+
}
|
|
152
144
|
|
|
153
145
|
return null;
|
|
154
146
|
}
|
package/src/events.js
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
export class Events {
|
|
5
5
|
constructor() {
|
|
6
6
|
this.event_handlers = new Map();
|
|
7
|
+
this.event_handlers_cleared = false;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Emit an event.
|
|
11
12
|
*
|
|
12
|
-
* @param {
|
|
13
|
+
* @param {string} name - Name of the event.
|
|
13
14
|
* @param {...*} args - Extra arguments.
|
|
14
15
|
*/
|
|
15
16
|
emit(name) {
|
|
@@ -30,7 +31,7 @@ export class Events {
|
|
|
30
31
|
/**
|
|
31
32
|
* Subscribe to an event.
|
|
32
33
|
*
|
|
33
|
-
* @param {
|
|
34
|
+
* @param {string} name - Name of the event.
|
|
34
35
|
* @param {Function} cb - Callback function.
|
|
35
36
|
*/
|
|
36
37
|
on(name, cb) {
|
|
@@ -54,14 +55,17 @@ export class Events {
|
|
|
54
55
|
/**
|
|
55
56
|
* Removes an event handler.
|
|
56
57
|
*
|
|
57
|
-
* @param {
|
|
58
|
+
* @param {string} name - Name of the event.
|
|
58
59
|
* @param {Function} cb - Callback function.
|
|
59
60
|
*/
|
|
60
61
|
removeEventListener(name, cb) {
|
|
61
62
|
const handlers = this.event_handlers.get(name);
|
|
62
63
|
|
|
63
64
|
if (!handlers || !handlers.has(cb)) {
|
|
64
|
-
|
|
65
|
+
if (!this.event_handlers_cleared) {
|
|
66
|
+
console.warn('removeEventListeners(): not installed:', name, cb);
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
handlers.delete(cb);
|
|
@@ -70,7 +74,7 @@ export class Events {
|
|
|
70
74
|
/**
|
|
71
75
|
* Removes an event handler.
|
|
72
76
|
*
|
|
73
|
-
* @param {
|
|
77
|
+
* @param {string} name
|
|
74
78
|
* @param {Function} cb
|
|
75
79
|
*/
|
|
76
80
|
off(name, cb) {
|
|
@@ -82,6 +86,7 @@ export class Events {
|
|
|
82
86
|
*/
|
|
83
87
|
removeAllEventListeners() {
|
|
84
88
|
this.event_handlers.clear();
|
|
89
|
+
this.event_handlers_cleared = true;
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
/**
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
function addEvent(target, name, callback) {
|
|
2
|
+
if (target.addEventListener) {
|
|
3
|
+
target.addEventListener(name, callback);
|
|
4
|
+
} else if (target.on) {
|
|
5
|
+
target.on(name, callback);
|
|
6
|
+
} else {
|
|
7
|
+
throw new TypeError('Unsupported event target ', target);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function removeEvent(target, name, callback) {
|
|
12
|
+
if (target.removeEventListener) {
|
|
13
|
+
target.removeEventListener(name, callback);
|
|
14
|
+
} else if (target.off) {
|
|
15
|
+
target.off(name, callback);
|
|
16
|
+
} else {
|
|
17
|
+
throw new TypeError('Unsupported event target ', target);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @param {EventTarget|Events} target
|
|
24
|
+
* @param {string} name
|
|
25
|
+
* @param {callback} callback
|
|
26
|
+
*/
|
|
27
|
+
export function subscribeEvent(target, name, callback) {
|
|
28
|
+
addEvent(target, name, callback);
|
|
29
|
+
return () => {
|
|
30
|
+
removeEvent(target, name, callback);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export class Subscriptions {
|
|
2
|
+
constructor() {
|
|
3
|
+
this._callbacks = [];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Add a subscription.
|
|
8
|
+
*
|
|
9
|
+
* @param {Function[]} cbs
|
|
10
|
+
*/
|
|
11
|
+
add(...cbs) {
|
|
12
|
+
cbs.forEach((cb) => {
|
|
13
|
+
this._callbacks.push(cb);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
unsubscribe() {
|
|
18
|
+
this._callbacks.forEach((cb) => {
|
|
19
|
+
try {
|
|
20
|
+
cb();
|
|
21
|
+
} catch (err) {
|
|
22
|
+
console.error(err);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
this._callbacks.length = 0;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
function isItTime(target, now) {
|
|
2
|
+
// We are ok with 1ms accuracy.
|
|
3
|
+
return target - now < 1;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export class Timer {
|
|
7
|
+
constructor(callback, getNow) {
|
|
8
|
+
this._callback = callback;
|
|
9
|
+
this._getNow = getNow;
|
|
10
|
+
this._targetTime = undefined;
|
|
11
|
+
this._timerId = undefined;
|
|
12
|
+
this._timerAt = undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
poll() {
|
|
16
|
+
const now = this._getNow();
|
|
17
|
+
|
|
18
|
+
if (this._targetTime === undefined) return;
|
|
19
|
+
|
|
20
|
+
if (isItTime(this._targetTime, now)) {
|
|
21
|
+
this._targetTime = undefined;
|
|
22
|
+
try {
|
|
23
|
+
this._callback();
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.error('Timer callback threw an exception', err);
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
this._reschedule();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
_reschedule() {
|
|
33
|
+
const target = this._targetTime;
|
|
34
|
+
const interval = target - this._getNow();
|
|
35
|
+
|
|
36
|
+
if (this._timerId !== undefined) {
|
|
37
|
+
if (target >= this._timerAt) {
|
|
38
|
+
// The timer will fire before target. We will then reschedule it.
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
clearTimeout(this._timerId);
|
|
43
|
+
this._timerId = undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this._timerAt = target;
|
|
47
|
+
this._timerId = setTimeout(() => {
|
|
48
|
+
this._timerId = undefined;
|
|
49
|
+
this._timerAt = undefined;
|
|
50
|
+
this.poll();
|
|
51
|
+
}, Math.max(0, interval));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
*
|
|
56
|
+
* @param {number} interval
|
|
57
|
+
* Interval in milliseconds.
|
|
58
|
+
*/
|
|
59
|
+
scheduleIn(interval) {
|
|
60
|
+
if (!(interval >= 0)) {
|
|
61
|
+
throw new TypeError(`Expected positive interval.`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this._targetTime = this._getNow() + interval;
|
|
65
|
+
this._reschedule();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Schedule the timer in a given number of milliseconds. If the timer
|
|
70
|
+
* is already running and scheduled to run before, do not modify it.
|
|
71
|
+
*
|
|
72
|
+
* @param {number} interval
|
|
73
|
+
*/
|
|
74
|
+
scheduleDeadlineIn(interval) {
|
|
75
|
+
if (!(interval >= 0)) {
|
|
76
|
+
throw new TypeError(`Expected positive interval.`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const target = this._getNow() + interval;
|
|
80
|
+
|
|
81
|
+
if (this._targetTime !== undefined && this._targetTime <= target) {
|
|
82
|
+
this.poll();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.scheduleAt(target);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
*
|
|
91
|
+
* @param {number} target
|
|
92
|
+
* Target time in milliseconds.
|
|
93
|
+
*/
|
|
94
|
+
scheduleAt(target) {
|
|
95
|
+
if (!(target >= 0)) {
|
|
96
|
+
throw new TypeError();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this._targetTime = target;
|
|
100
|
+
this._reschedule();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
stop() {
|
|
104
|
+
this._targetTime = undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
cancel() {
|
|
108
|
+
this.stop();
|
|
109
|
+
this._clearTimeout();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
_clearTimeout() {
|
|
113
|
+
if (this._timerId) {
|
|
114
|
+
clearTimeout(this._timerId);
|
|
115
|
+
this._timerId = undefined;
|
|
116
|
+
this._timerAt = undefined;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
dispose() {
|
|
121
|
+
this.cancel();
|
|
122
|
+
}
|
|
123
|
+
}
|