unetjs 3.1.4 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/unet.cjs +200 -115
- package/dist/esm/unet.js +200 -115
- package/dist/unetjs.js +199 -114
- package/dist/unetjs.js.map +1 -1
- package/dist/unetjs.min.js +1 -1
- package/dist/unetjs.min.js.map +1 -1
- package/package.json +3 -3
package/dist/esm/unet.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/* unet.js v3.
|
|
1
|
+
/* unet.js v3.2.0 2025-01-14T01:50:07.305Z */
|
|
2
2
|
|
|
3
|
-
/* fjage.js v1.
|
|
3
|
+
/* fjage.js v1.13.5 */
|
|
4
4
|
|
|
5
5
|
const isBrowser =
|
|
6
6
|
typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
@@ -25,9 +25,7 @@ const isJsDom =
|
|
|
25
25
|
(navigator.userAgent.includes("Node.js") ||
|
|
26
26
|
navigator.userAgent.includes("jsdom")));
|
|
27
27
|
|
|
28
|
-
typeof Deno !== "undefined" &&
|
|
29
|
-
typeof Deno.version !== "undefined" &&
|
|
30
|
-
typeof Deno.version.deno !== "undefined";
|
|
28
|
+
typeof Deno !== "undefined" && typeof Deno.core !== "undefined";
|
|
31
29
|
|
|
32
30
|
const SOCKET_OPEN = 'open';
|
|
33
31
|
const SOCKET_OPENING = 'opening';
|
|
@@ -39,29 +37,31 @@ var createConnection;
|
|
|
39
37
|
* @class
|
|
40
38
|
* @ignore
|
|
41
39
|
*/
|
|
42
|
-
class
|
|
40
|
+
class TCPConnector {
|
|
43
41
|
|
|
44
42
|
/**
|
|
45
43
|
* Create an TCPConnector to connect to a fjage master over TCP
|
|
46
44
|
* @param {Object} opts
|
|
47
|
-
* @param {string} opts.hostname - hostname/ip address of the master container to connect to
|
|
48
|
-
* @param {
|
|
49
|
-
* @param {boolean} opts.keepAlive - try to reconnect if the connection is lost
|
|
45
|
+
* @param {string} [opts.hostname='localhost'] - hostname/ip address of the master container to connect to
|
|
46
|
+
* @param {number} [opts.port=1100] - port number of the master container to connect to
|
|
47
|
+
* @param {boolean} [opts.keepAlive=true] - try to reconnect if the connection is lost
|
|
48
|
+
* @param {boolean} [opts.debug=false] - debug info to be logged to console?
|
|
50
49
|
* @param {number} [opts.reconnectTime=5000] - time before reconnection is attempted after an error
|
|
51
50
|
*/
|
|
52
51
|
constructor(opts = {}) {
|
|
53
|
-
let host = opts.hostname;
|
|
54
|
-
let port = opts.port;
|
|
52
|
+
let host = opts.hostname || 'localhost';
|
|
53
|
+
let port = opts.port || 1100;
|
|
55
54
|
this._keepAlive = opts.keepAlive;
|
|
56
55
|
this._reconnectTime = opts.reconnectTime || DEFAULT_RECONNECT_TIME$1;
|
|
57
56
|
this.url = new URL('tcp://localhost');
|
|
58
57
|
this.url.hostname = host;
|
|
59
|
-
this.url.port = port;
|
|
58
|
+
this.url.port = port.toString();
|
|
60
59
|
this._buf = '';
|
|
61
60
|
this._firstConn = true; // if the Gateway has managed to connect to a server before
|
|
62
61
|
this._firstReConn = true; // if the Gateway has attempted to reconnect to a server before
|
|
63
62
|
this.pendingOnOpen = []; // list of callbacks make as soon as gateway is open
|
|
64
63
|
this.connListeners = []; // external listeners wanting to listen connection events
|
|
64
|
+
this.debug = false;
|
|
65
65
|
this._sockInit(host, port);
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -75,6 +75,7 @@ class TCPconnector {
|
|
|
75
75
|
_sockInit(host, port){
|
|
76
76
|
if (!createConnection){
|
|
77
77
|
try {
|
|
78
|
+
// @ts-ignore
|
|
78
79
|
import('net').then(module => {
|
|
79
80
|
createConnection = module.createConnection;
|
|
80
81
|
this._sockSetup(host, port);
|
|
@@ -158,20 +159,20 @@ class TCPconnector {
|
|
|
158
159
|
return false;
|
|
159
160
|
}
|
|
160
161
|
|
|
162
|
+
/**
|
|
163
|
+
* @callback TCPConnectorReadCallback
|
|
164
|
+
* @ignore
|
|
165
|
+
* @param {string} s - incoming message string
|
|
166
|
+
*/
|
|
167
|
+
|
|
161
168
|
/**
|
|
162
169
|
* Set a callback for receiving incoming strings from the connector
|
|
163
|
-
* @param {
|
|
170
|
+
* @param {TCPConnectorReadCallback} cb - callback that is called when the connector gets a string
|
|
164
171
|
*/
|
|
165
172
|
setReadCallback(cb){
|
|
166
173
|
if (cb && {}.toString.call(cb) === '[object Function]') this._onSockRx = cb;
|
|
167
174
|
}
|
|
168
175
|
|
|
169
|
-
/**
|
|
170
|
-
* @callback TCPConnector~ReadCallback
|
|
171
|
-
* @ignore
|
|
172
|
-
* @param {string} s - incoming message string
|
|
173
|
-
*/
|
|
174
|
-
|
|
175
176
|
/**
|
|
176
177
|
* Add listener for connection events
|
|
177
178
|
* @param {function} listener - a listener callback that is called when the connection is opened/closed
|
|
@@ -228,17 +229,20 @@ class WSConnector {
|
|
|
228
229
|
/**
|
|
229
230
|
* Create an WSConnector to connect to a fjage master over WebSockets
|
|
230
231
|
* @param {Object} opts
|
|
231
|
-
* @param {string} opts.hostname - hostname/ip address of the master container to connect to
|
|
232
|
-
* @param {
|
|
233
|
-
* @param {string} opts.pathname - path of the master container to connect to
|
|
234
|
-
* @param {boolean} opts.keepAlive - try to reconnect if the connection is lost
|
|
232
|
+
* @param {string} [opts.hostname='localhost'] - hostname/ip address of the master container to connect to
|
|
233
|
+
* @param {number} [opts.port=80] - port number of the master container to connect to
|
|
234
|
+
* @param {string} [opts.pathname="/"] - path of the master container to connect to
|
|
235
|
+
* @param {boolean} [opts.keepAlive=true] - try to reconnect if the connection is lost
|
|
236
|
+
* @param {boolean} [opts.debug=false] - debug info to be logged to console?
|
|
235
237
|
* @param {number} [opts.reconnectTime=5000] - time before reconnection is attempted after an error
|
|
236
238
|
*/
|
|
237
239
|
constructor(opts = {}) {
|
|
240
|
+
let host = opts.hostname || 'localhost';
|
|
241
|
+
let port = opts.port || 80;
|
|
238
242
|
this.url = new URL('ws://localhost');
|
|
239
|
-
this.url.hostname =
|
|
240
|
-
this.url.port =
|
|
241
|
-
this.url.pathname = opts.pathname;
|
|
243
|
+
this.url.hostname = host;
|
|
244
|
+
this.url.port = port.toString();
|
|
245
|
+
this.url.pathname = opts.pathname || '/';
|
|
242
246
|
this._keepAlive = opts.keepAlive;
|
|
243
247
|
this._reconnectTime = opts.reconnectTime || DEFAULT_RECONNECT_TIME;
|
|
244
248
|
this.debug = opts.debug || false; // debug info to be logged to console?
|
|
@@ -313,19 +317,19 @@ class WSConnector {
|
|
|
313
317
|
}
|
|
314
318
|
|
|
315
319
|
/**
|
|
316
|
-
*
|
|
317
|
-
* @param {WSConnector~ReadCallback} cb - callback that is called when the connector gets a string
|
|
320
|
+
* @callback WSConnectorReadCallback
|
|
318
321
|
* @ignore
|
|
322
|
+
* @param {string} s - incoming message string
|
|
319
323
|
*/
|
|
320
|
-
setReadCallback(cb){
|
|
321
|
-
if (cb && {}.toString.call(cb) === '[object Function]') this._onWebsockRx = cb;
|
|
322
|
-
}
|
|
323
324
|
|
|
324
325
|
/**
|
|
325
|
-
*
|
|
326
|
+
* Set a callback for receiving incoming strings from the connector
|
|
327
|
+
* @param {WSConnectorReadCallback} cb - callback that is called when the connector gets a string
|
|
326
328
|
* @ignore
|
|
327
|
-
* @param {string} s - incoming message string
|
|
328
329
|
*/
|
|
330
|
+
setReadCallback(cb){
|
|
331
|
+
if (cb && {}.toString.call(cb) === '[object Function]') this._onWebsockRx = cb;
|
|
332
|
+
}
|
|
329
333
|
|
|
330
334
|
/**
|
|
331
335
|
* Add listener for connection events
|
|
@@ -376,7 +380,7 @@ const DEFAULT_QUEUE_SIZE = 128; // max number of old unreceived messages
|
|
|
376
380
|
/**
|
|
377
381
|
* An action represented by a message. The performative actions are a subset of the
|
|
378
382
|
* FIPA ACL recommendations for interagent communication.
|
|
379
|
-
* @
|
|
383
|
+
* @enum {string}
|
|
380
384
|
*/
|
|
381
385
|
const Performative = {
|
|
382
386
|
REQUEST: 'REQUEST', // Request an action to be performed
|
|
@@ -397,13 +401,13 @@ const Performative = {
|
|
|
397
401
|
* An identifier for an agent or a topic.
|
|
398
402
|
* @class
|
|
399
403
|
* @param {string} name - name of the agent
|
|
400
|
-
* @param {boolean} topic - name of topic
|
|
401
|
-
* @param {Gateway} owner - Gateway owner for this AgentID
|
|
404
|
+
* @param {boolean} [topic=false] - name of topic
|
|
405
|
+
* @param {Gateway} [owner] - Gateway owner for this AgentID
|
|
402
406
|
*/
|
|
403
407
|
class AgentID {
|
|
404
408
|
|
|
405
409
|
|
|
406
|
-
constructor(name, topic, owner) {
|
|
410
|
+
constructor(name, topic=false, owner) {
|
|
407
411
|
this.name = name;
|
|
408
412
|
this.topic = topic;
|
|
409
413
|
this.owner = owner;
|
|
@@ -430,12 +434,13 @@ class AgentID {
|
|
|
430
434
|
/**
|
|
431
435
|
* Sends a message to the agent represented by this id.
|
|
432
436
|
*
|
|
433
|
-
* @param {
|
|
437
|
+
* @param {Message} msg - message to send
|
|
434
438
|
* @returns {void}
|
|
435
439
|
*/
|
|
436
440
|
send(msg) {
|
|
437
441
|
msg.recipient = this.toJSON();
|
|
438
|
-
this.owner.send(msg);
|
|
442
|
+
if (this.owner) this.owner.send(msg);
|
|
443
|
+
else throw new Error('Unowned AgentID cannot send messages');
|
|
439
444
|
}
|
|
440
445
|
|
|
441
446
|
/**
|
|
@@ -447,7 +452,8 @@ class AgentID {
|
|
|
447
452
|
*/
|
|
448
453
|
async request(msg, timeout=1000) {
|
|
449
454
|
msg.recipient = this.toJSON();
|
|
450
|
-
return this.owner.request(msg, timeout);
|
|
455
|
+
if (this.owner) return this.owner.request(msg, timeout);
|
|
456
|
+
else throw new Error('Unowned AgentID cannot send messages');
|
|
451
457
|
}
|
|
452
458
|
|
|
453
459
|
/**
|
|
@@ -563,15 +569,27 @@ class AgentID {
|
|
|
563
569
|
}
|
|
564
570
|
}
|
|
565
571
|
|
|
572
|
+
// protected String msgID = UUID.randomUUID().toString();
|
|
573
|
+
// protected Performative perf;
|
|
574
|
+
// protected AgentID recipient;
|
|
575
|
+
// protected AgentID sender = null;
|
|
576
|
+
// protected String inReplyTo = null;
|
|
577
|
+
// protected Long sentAt = null;
|
|
578
|
+
|
|
566
579
|
/**
|
|
567
580
|
* Base class for messages transmitted by one agent to another. Creates an empty message.
|
|
568
581
|
* @class
|
|
569
|
-
* @param {
|
|
570
|
-
* @param {Performative} - performative
|
|
582
|
+
* @param {string} [msgID] - unique identifier for the message
|
|
583
|
+
* @param {Performative} [perf=Performative.INFORM] - performative
|
|
584
|
+
* @param {AgentID} [recipient] - recipient of the message
|
|
585
|
+
* @param {AgentID} [sender] - sender of the message
|
|
586
|
+
* @param {string} [inReplyTo] - message to which this response corresponds to
|
|
587
|
+
* @param {Message} [inReplyTo] - message to which this response corresponds to
|
|
588
|
+
* @param {number} [sentAt] - time at which the message was sent
|
|
571
589
|
*/
|
|
572
590
|
class Message {
|
|
573
591
|
|
|
574
|
-
constructor(inReplyTo={msgID:null, sender:null}, perf=
|
|
592
|
+
constructor(inReplyTo={msgID:null, sender:null}, perf=Performative.INFORM) {
|
|
575
593
|
this.__clazz__ = 'org.arl.fjage.Message';
|
|
576
594
|
this.msgID = _guid(8);
|
|
577
595
|
this.sender = null;
|
|
@@ -612,7 +630,11 @@ class Message {
|
|
|
612
630
|
// convert a message into a JSON string
|
|
613
631
|
// NOTE: we don't do any base64 encoding for TX as
|
|
614
632
|
// we don't know what data type is intended
|
|
615
|
-
/**
|
|
633
|
+
/**
|
|
634
|
+
* @private
|
|
635
|
+
*
|
|
636
|
+
* @return {string} - JSON string representation of the message
|
|
637
|
+
*/
|
|
616
638
|
_serialize() {
|
|
617
639
|
let clazz = this.__clazz__ || 'org.arl.fjage.Message';
|
|
618
640
|
let data = JSON.stringify(this, (k,v) => {
|
|
@@ -630,26 +652,27 @@ class Message {
|
|
|
630
652
|
}
|
|
631
653
|
|
|
632
654
|
// convert a dictionary (usually from decoding JSON) into a message
|
|
633
|
-
/**
|
|
634
|
-
|
|
635
|
-
|
|
655
|
+
/**
|
|
656
|
+
* @private
|
|
657
|
+
*
|
|
658
|
+
* @param {(string|Object)} json - JSON string or object to be converted to a message
|
|
659
|
+
* @returns {Message} - message created from the JSON string or object
|
|
660
|
+
* */
|
|
661
|
+
static _deserialize(json) {
|
|
662
|
+
let obj = null;
|
|
663
|
+
if (typeof json == 'string') {
|
|
636
664
|
try {
|
|
637
|
-
obj = JSON.parse(
|
|
665
|
+
obj = JSON.parse(json);
|
|
638
666
|
}catch(e){
|
|
639
667
|
return null;
|
|
640
668
|
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
return rv;
|
|
649
|
-
} catch (err) {
|
|
650
|
-
console.warn('Error trying to deserialize JSON object : ', obj, err);
|
|
651
|
-
return null;
|
|
652
|
-
}
|
|
669
|
+
} else obj = json;
|
|
670
|
+
let qclazz = obj.clazz;
|
|
671
|
+
let clazz = qclazz.replace(/^.*\./, '');
|
|
672
|
+
let rv = MessageClass[clazz] ? new MessageClass[clazz] : new Message();
|
|
673
|
+
rv.__clazz__ = qclazz;
|
|
674
|
+
rv._inflate(obj.data);
|
|
675
|
+
return rv;
|
|
653
676
|
}
|
|
654
677
|
}
|
|
655
678
|
|
|
@@ -660,36 +683,18 @@ class Message {
|
|
|
660
683
|
*
|
|
661
684
|
* @class
|
|
662
685
|
* @param {Object} opts
|
|
663
|
-
* @param {string}
|
|
664
|
-
* @param {
|
|
665
|
-
* @param {string}
|
|
666
|
-
* @param {
|
|
667
|
-
* @param {number}
|
|
668
|
-
* @param {number}
|
|
686
|
+
* @param {string} [opts.hostname="localhost"] - hostname/ip address of the master container to connect to
|
|
687
|
+
* @param {number} [opts.port=1100] - port number of the master container to connect to
|
|
688
|
+
* @param {string} [opts.pathname=""] - path of the master container to connect to (for WebSockets)
|
|
689
|
+
* @param {string} [opts.keepAlive=true] - try to reconnect if the connection is lost
|
|
690
|
+
* @param {number} [opts.queueSize=128] - size of the queue of received messages that haven't been consumed yet
|
|
691
|
+
* @param {number} [opts.timeout=1000] - timeout for fjage level messages in ms
|
|
669
692
|
* @param {boolean} [opts.returnNullOnFailedResponse=true] - return null instead of throwing an error when a parameter is not found
|
|
670
|
-
* @param {string} [hostname="localhost"] - <strike>Deprecated : hostname/ip address of the master container to connect to</strike>
|
|
671
|
-
* @param {number} [port=] - <strike>Deprecated : port number of the master container to connect to</strike>
|
|
672
|
-
* @param {string} [pathname=="/ws/"] - <strike>Deprecated : path of the master container to connect to (for WebSockets)</strike>
|
|
673
|
-
* @param {number} [timeout=1000] - <strike>Deprecated : timeout for fjage level messages in ms</strike>
|
|
674
693
|
*/
|
|
675
694
|
class Gateway {
|
|
676
695
|
|
|
677
|
-
constructor(opts = {}
|
|
678
|
-
|
|
679
|
-
if (typeof opts === 'string' || opts instanceof String){
|
|
680
|
-
opts = {
|
|
681
|
-
'hostname': opts,
|
|
682
|
-
'port' : port,
|
|
683
|
-
'pathname' : pathname,
|
|
684
|
-
'timeout' : timeout
|
|
685
|
-
};
|
|
686
|
-
console.warn('Deprecated use of Gateway constructor');
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
// Set defaults
|
|
690
|
-
for (var key in GATEWAY_DEFAULTS){
|
|
691
|
-
if (opts[key] == undefined || opts[key] === '') opts[key] = GATEWAY_DEFAULTS[key];
|
|
692
|
-
}
|
|
696
|
+
constructor(opts = {}) {
|
|
697
|
+
opts = Object.assign({}, GATEWAY_DEFAULTS, opts);
|
|
693
698
|
var url = DEFAULT_URL;
|
|
694
699
|
url.hostname = opts.hostname;
|
|
695
700
|
url.port = opts.port;
|
|
@@ -705,13 +710,19 @@ class Gateway {
|
|
|
705
710
|
this.listener = {}; // set of callbacks that want to listen to incoming messages
|
|
706
711
|
this.eventListeners = {}; // external listeners wanting to listen internal events
|
|
707
712
|
this.queue = []; // incoming message queue
|
|
713
|
+
this.connected = false; // connection status
|
|
708
714
|
this.debug = false; // debug info to be logged to console?
|
|
709
715
|
this.aid = new AgentID((isBrowser ? 'WebGW-' : 'NodeGW-')+_guid(4)); // gateway agent name
|
|
710
716
|
this.connector = this._createConnector(url);
|
|
711
717
|
this._addGWCache(this);
|
|
712
718
|
}
|
|
713
719
|
|
|
714
|
-
/**
|
|
720
|
+
/**
|
|
721
|
+
* Sends an event to all registered listeners of the given type.
|
|
722
|
+
* @private
|
|
723
|
+
* @param {string} type - type of event
|
|
724
|
+
* @param {Object|Message|string} val - value to be sent to the listeners
|
|
725
|
+
*/
|
|
715
726
|
_sendEvent(type, val) {
|
|
716
727
|
if (Array.isArray(this.eventListeners[type])) {
|
|
717
728
|
this.eventListeners[type].forEach(l => {
|
|
@@ -726,7 +737,11 @@ class Gateway {
|
|
|
726
737
|
}
|
|
727
738
|
}
|
|
728
739
|
|
|
729
|
-
/**
|
|
740
|
+
/**
|
|
741
|
+
* @private
|
|
742
|
+
* @param {string} data - stringfied JSON data received from the master container to be processed
|
|
743
|
+
* @returns {void}
|
|
744
|
+
*/
|
|
730
745
|
_onMsgRx(data) {
|
|
731
746
|
var obj;
|
|
732
747
|
if (this.debug) console.log('< '+data);
|
|
@@ -743,6 +758,7 @@ class Gateway {
|
|
|
743
758
|
delete this.pending[obj.id];
|
|
744
759
|
} else if (obj.action == 'send') {
|
|
745
760
|
// incoming message from master
|
|
761
|
+
// @ts-ignore
|
|
746
762
|
let msg = Message._deserialize(obj.message);
|
|
747
763
|
if (!msg) return;
|
|
748
764
|
this._sendEvent('rxmsg', msg);
|
|
@@ -803,7 +819,12 @@ class Gateway {
|
|
|
803
819
|
}
|
|
804
820
|
}
|
|
805
821
|
|
|
806
|
-
/**
|
|
822
|
+
/**
|
|
823
|
+
* Sends a message out to the master container.
|
|
824
|
+
* @private
|
|
825
|
+
* @param {string|Object} s - JSON object (either stringified or not) to be sent to the master container
|
|
826
|
+
* @returns {boolean} - true if the message was sent successfully
|
|
827
|
+
*/
|
|
807
828
|
_msgTx(s) {
|
|
808
829
|
if (typeof s != 'string' && !(s instanceof String)) s = JSON.stringify(s);
|
|
809
830
|
if(this.debug) console.log('> '+s);
|
|
@@ -811,7 +832,11 @@ class Gateway {
|
|
|
811
832
|
return this.connector.write(s);
|
|
812
833
|
}
|
|
813
834
|
|
|
814
|
-
/**
|
|
835
|
+
/**
|
|
836
|
+
* @private
|
|
837
|
+
* @param {Object} rq - request to be sent to the master container as a JSON object
|
|
838
|
+
* @returns {Promise<Object>} - a promise which returns the response from the master container
|
|
839
|
+
*/
|
|
815
840
|
_msgTxRx(rq) {
|
|
816
841
|
rq.id = _guid(8);
|
|
817
842
|
return new Promise(resolve => {
|
|
@@ -833,25 +858,32 @@ class Gateway {
|
|
|
833
858
|
});
|
|
834
859
|
}
|
|
835
860
|
|
|
836
|
-
/**
|
|
861
|
+
/**
|
|
862
|
+
* @private
|
|
863
|
+
* @param {URL} url - URL object of the master container to connect to
|
|
864
|
+
* @returns {TCPConnector|WSConnector} - connector object to connect to the master container
|
|
865
|
+
*/
|
|
837
866
|
_createConnector(url){
|
|
838
867
|
let conn;
|
|
839
868
|
if (url.protocol.startsWith('ws')){
|
|
840
869
|
conn = new WSConnector({
|
|
841
870
|
'hostname':url.hostname,
|
|
842
|
-
'port':url.port,
|
|
871
|
+
'port':parseInt(url.port),
|
|
843
872
|
'pathname':url.pathname,
|
|
844
|
-
'keepAlive': this._keepAlive
|
|
873
|
+
'keepAlive': this._keepAlive,
|
|
874
|
+
'debug': this.debug
|
|
845
875
|
});
|
|
846
876
|
}else if (url.protocol.startsWith('tcp')){
|
|
847
|
-
conn = new
|
|
877
|
+
conn = new TCPConnector({
|
|
848
878
|
'hostname':url.hostname,
|
|
849
|
-
'port':url.port,
|
|
850
|
-
'keepAlive': this._keepAlive
|
|
879
|
+
'port':parseInt(url.port),
|
|
880
|
+
'keepAlive': this._keepAlive,
|
|
881
|
+
'debug': this.debug
|
|
851
882
|
});
|
|
852
883
|
} else return null;
|
|
853
884
|
conn.setReadCallback(this._onMsgRx.bind(this));
|
|
854
885
|
conn.addConnectionListener(state => {
|
|
886
|
+
this.connected = !!state;
|
|
855
887
|
if (state == true){
|
|
856
888
|
this.flush();
|
|
857
889
|
this.connector.write('{"alive": true}');
|
|
@@ -862,7 +894,13 @@ class Gateway {
|
|
|
862
894
|
return conn;
|
|
863
895
|
}
|
|
864
896
|
|
|
865
|
-
/**
|
|
897
|
+
/**
|
|
898
|
+
* Checks if the object is a constructor.
|
|
899
|
+
*
|
|
900
|
+
* @private
|
|
901
|
+
* @param {Object} value - an object to be checked if it is a constructor
|
|
902
|
+
* @returns {boolean} - if the object is a constructor
|
|
903
|
+
*/
|
|
866
904
|
_isConstructor(value) {
|
|
867
905
|
try {
|
|
868
906
|
new new Proxy(value, {construct() { return {}; }});
|
|
@@ -872,7 +910,13 @@ class Gateway {
|
|
|
872
910
|
}
|
|
873
911
|
}
|
|
874
912
|
|
|
875
|
-
/**
|
|
913
|
+
/**
|
|
914
|
+
* Matches a message with a filter.
|
|
915
|
+
* @private
|
|
916
|
+
* @param {string|Object|function} filter - filter to be matched
|
|
917
|
+
* @param {Message} msg - message to be matched to the filter
|
|
918
|
+
* @returns {boolean} - true if the message matches the filter
|
|
919
|
+
*/
|
|
876
920
|
_matchMessage(filter, msg){
|
|
877
921
|
if (typeof filter == 'string' || filter instanceof String) {
|
|
878
922
|
return 'inReplyTo' in msg && msg.inReplyTo == filter;
|
|
@@ -892,18 +936,25 @@ class Gateway {
|
|
|
892
936
|
}
|
|
893
937
|
}
|
|
894
938
|
|
|
895
|
-
/**
|
|
939
|
+
/**
|
|
940
|
+
* Gets the next message from the queue that matches the filter.
|
|
941
|
+
* @private
|
|
942
|
+
* @param {string|Object|function} filter - filter to be matched
|
|
943
|
+
*/
|
|
896
944
|
_getMessageFromQueue(filter) {
|
|
897
945
|
if (!this.queue.length) return;
|
|
898
946
|
if (!filter) return this.queue.shift();
|
|
899
|
-
|
|
900
947
|
let matchedMsg = this.queue.find( msg => this._matchMessage(filter, msg));
|
|
901
948
|
if (matchedMsg) this.queue.splice(this.queue.indexOf(matchedMsg), 1);
|
|
902
|
-
|
|
903
949
|
return matchedMsg;
|
|
904
950
|
}
|
|
905
951
|
|
|
906
|
-
/**
|
|
952
|
+
/**
|
|
953
|
+
* Gets a cached gateway object for the given URL (if it exists).
|
|
954
|
+
* @private
|
|
955
|
+
* @param {URL} url - URL object of the master container to connect to
|
|
956
|
+
* @returns {Gateway|void} - gateway object for the given URL
|
|
957
|
+
*/
|
|
907
958
|
_getGWCache(url){
|
|
908
959
|
if (!gObj.fjage || !gObj.fjage.gateways) return null;
|
|
909
960
|
var f = gObj.fjage.gateways.filter(g => g.connector.url.toString() == url.toString());
|
|
@@ -911,13 +962,21 @@ class Gateway {
|
|
|
911
962
|
return null;
|
|
912
963
|
}
|
|
913
964
|
|
|
914
|
-
/**
|
|
965
|
+
/**
|
|
966
|
+
* Adds a gateway object to the cache if it doesn't already exist.
|
|
967
|
+
* @private
|
|
968
|
+
* @param {Gateway} gw - gateway object to be added to the cache
|
|
969
|
+
*/
|
|
915
970
|
_addGWCache(gw){
|
|
916
971
|
if (!gObj.fjage || !gObj.fjage.gateways) return;
|
|
917
972
|
gObj.fjage.gateways.push(gw);
|
|
918
973
|
}
|
|
919
974
|
|
|
920
|
-
/**
|
|
975
|
+
/**
|
|
976
|
+
* Removes a gateway object from the cache if it exists.
|
|
977
|
+
* @private
|
|
978
|
+
* @param {Gateway} gw - gateway object to be removed from the cache
|
|
979
|
+
*/
|
|
921
980
|
_removeGWCache(gw){
|
|
922
981
|
if (!gObj.fjage || !gObj.fjage.gateways) return;
|
|
923
982
|
var index = gObj.fjage.gateways.indexOf(gw);
|
|
@@ -1005,7 +1064,7 @@ class Gateway {
|
|
|
1005
1064
|
/**
|
|
1006
1065
|
* Gets the agent ID associated with the gateway.
|
|
1007
1066
|
*
|
|
1008
|
-
* @returns {
|
|
1067
|
+
* @returns {AgentID} - agent ID
|
|
1009
1068
|
*/
|
|
1010
1069
|
getAgentID() {
|
|
1011
1070
|
return this.aid;
|
|
@@ -1025,7 +1084,7 @@ class Gateway {
|
|
|
1025
1084
|
* Returns an object representing the named topic.
|
|
1026
1085
|
*
|
|
1027
1086
|
* @param {string|AgentID} topic - name of the topic or AgentID
|
|
1028
|
-
* @param {string} topic2 - name of the topic if the topic param is an AgentID
|
|
1087
|
+
* @param {string} [topic2] - name of the topic if the topic param is an AgentID
|
|
1029
1088
|
* @returns {AgentID} - object representing the topic
|
|
1030
1089
|
*/
|
|
1031
1090
|
topic(topic, topic2) {
|
|
@@ -1046,6 +1105,7 @@ class Gateway {
|
|
|
1046
1105
|
if (!topic.isTopic()) topic = new AgentID(topic.getName() + '__ntf', true, this);
|
|
1047
1106
|
this.subscriptions[topic.toJSON()] = true;
|
|
1048
1107
|
this._update_watch();
|
|
1108
|
+
return true;
|
|
1049
1109
|
}
|
|
1050
1110
|
|
|
1051
1111
|
/**
|
|
@@ -1137,6 +1197,7 @@ class Gateway {
|
|
|
1137
1197
|
}
|
|
1138
1198
|
this._sendEvent('txmsg', msg);
|
|
1139
1199
|
let rq = JSON.stringify({ action: 'send', relay: true, message: '###MSG###' });
|
|
1200
|
+
// @ts-ignore
|
|
1140
1201
|
rq = rq.replace('"###MSG###"', msg._serialize());
|
|
1141
1202
|
return !!this._msgTx(rq);
|
|
1142
1203
|
}
|
|
@@ -1154,9 +1215,9 @@ class Gateway {
|
|
|
1154
1215
|
* Sends a request and waits for a response. This method returns a {Promise} which resolves when a response
|
|
1155
1216
|
* is received or if no response is received after the timeout.
|
|
1156
1217
|
*
|
|
1157
|
-
* @param {
|
|
1218
|
+
* @param {Message} msg - message to send
|
|
1158
1219
|
* @param {number} [timeout=1000] - timeout in milliseconds
|
|
1159
|
-
* @returns {Promise
|
|
1220
|
+
* @returns {Promise<Message|void>} - a promise which resolves with the received response message, null on timeout
|
|
1160
1221
|
*/
|
|
1161
1222
|
async request(msg, timeout=1000) {
|
|
1162
1223
|
this.send(msg);
|
|
@@ -1167,10 +1228,10 @@ class Gateway {
|
|
|
1167
1228
|
* Returns a response message received by the gateway. This method returns a {Promise} which resolves when
|
|
1168
1229
|
* a response is received or if no response is received after the timeout.
|
|
1169
1230
|
*
|
|
1170
|
-
* @param {function}
|
|
1231
|
+
* @param {function|Message|typeof Message} filter - original message to which a response is expected, or a MessageClass of the type
|
|
1171
1232
|
* of message to match, or a closure to use to match against the message
|
|
1172
1233
|
* @param {number} [timeout=0] - timeout in milliseconds
|
|
1173
|
-
* @returns {Promise
|
|
1234
|
+
* @returns {Promise<Message|void>} - received response message, null on timeout
|
|
1174
1235
|
*/
|
|
1175
1236
|
async receive(filter, timeout=0) {
|
|
1176
1237
|
return new Promise(resolve => {
|
|
@@ -1225,8 +1286,8 @@ const Services = {
|
|
|
1225
1286
|
/**
|
|
1226
1287
|
* Creates a unqualified message class based on a fully qualified name.
|
|
1227
1288
|
* @param {string} name - fully qualified name of the message class to be created
|
|
1228
|
-
* @param {
|
|
1229
|
-
* @
|
|
1289
|
+
* @param {typeof Message} [parent] - class of the parent MessageClass to inherit from
|
|
1290
|
+
* @constructs Message
|
|
1230
1291
|
* @example
|
|
1231
1292
|
* const ParameterReq = MessageClass('org.arl.fjage.param.ParameterReq');
|
|
1232
1293
|
* let pReq = new ParameterReq()
|
|
@@ -1235,6 +1296,9 @@ function MessageClass(name, parent=Message) {
|
|
|
1235
1296
|
let sname = name.replace(/^.*\./, '');
|
|
1236
1297
|
if (MessageClass[sname]) return MessageClass[sname];
|
|
1237
1298
|
let cls = class extends parent {
|
|
1299
|
+
/**
|
|
1300
|
+
* @param {{ [x: string]: any; }} params
|
|
1301
|
+
*/
|
|
1238
1302
|
constructor(params) {
|
|
1239
1303
|
super();
|
|
1240
1304
|
this.__clazz__ = name;
|
|
@@ -1290,7 +1354,7 @@ function _b64toArray(base64, dtype, littleEndian=true) {
|
|
|
1290
1354
|
break;
|
|
1291
1355
|
case '[J': // long array
|
|
1292
1356
|
for (i = 0; i < len; i+=8)
|
|
1293
|
-
rv.push(view.
|
|
1357
|
+
rv.push(view.getBigInt64(i, littleEndian));
|
|
1294
1358
|
break;
|
|
1295
1359
|
case '[F': // float array
|
|
1296
1360
|
for (i = 0; i < len; i+=4)
|
|
@@ -1325,6 +1389,8 @@ function _decodeBase64(k, d) {
|
|
|
1325
1389
|
////// global
|
|
1326
1390
|
|
|
1327
1391
|
const GATEWAY_DEFAULTS = {};
|
|
1392
|
+
|
|
1393
|
+
/** @type {Window & globalThis & Object} */
|
|
1328
1394
|
let gObj = {};
|
|
1329
1395
|
let DEFAULT_URL;
|
|
1330
1396
|
if (isBrowser || isWebWorker){
|
|
@@ -1341,7 +1407,7 @@ if (isBrowser || isWebWorker){
|
|
|
1341
1407
|
DEFAULT_URL = new URL('ws://localhost');
|
|
1342
1408
|
// Enable caching of Gateways
|
|
1343
1409
|
if (typeof gObj.fjage === 'undefined') gObj.fjage = {};
|
|
1344
|
-
if (typeof gObj.fjage.gateways == 'undefined')gObj.fjage.gateways = [];
|
|
1410
|
+
if (typeof gObj.fjage.gateways == 'undefined') gObj.fjage.gateways = [];
|
|
1345
1411
|
} else if (isJsDom || isNode){
|
|
1346
1412
|
gObj = global;
|
|
1347
1413
|
Object.assign(GATEWAY_DEFAULTS, {
|
|
@@ -1357,10 +1423,28 @@ if (isBrowser || isWebWorker){
|
|
|
1357
1423
|
gObj.atob = a => Buffer.from(a, 'base64').toString('binary');
|
|
1358
1424
|
}
|
|
1359
1425
|
|
|
1426
|
+
/**
|
|
1427
|
+
* @typedef {Object} ParameterReq.Entry
|
|
1428
|
+
* @property {string} param - parameter name
|
|
1429
|
+
* @property {Object} value - parameter value
|
|
1430
|
+
* @exports ParameterReq.Entry
|
|
1431
|
+
*/
|
|
1432
|
+
|
|
1433
|
+
|
|
1434
|
+
/**
|
|
1435
|
+
* A message that requests one or more parameters of an agent.
|
|
1436
|
+
* @typedef {Message} ParameterReq
|
|
1437
|
+
* @property {string} param - parameters name to be get/set if only a single parameter is to be get/set
|
|
1438
|
+
* @property {Object} value - parameters value to be set if only a single parameter is to be set
|
|
1439
|
+
* @property {Array<ParameterReq.Entry>} requests - a list of multiple parameters to be get/set
|
|
1440
|
+
* @property {number} [index=-1] - index of parameter(s) to be set
|
|
1441
|
+
* @exports ParameterReq
|
|
1442
|
+
*/
|
|
1360
1443
|
const ParameterReq = MessageClass('org.arl.fjage.param.ParameterReq');
|
|
1361
1444
|
|
|
1362
1445
|
const DatagramReq$1 = MessageClass('org.arl.unet.DatagramReq');
|
|
1363
1446
|
const DatagramNtf$1 = MessageClass('org.arl.unet.DatagramNtf');
|
|
1447
|
+
const RxFrameNtf$1 = MessageClass('org.arl.unet.phy.RxFrameNtf', DatagramNtf$1);
|
|
1364
1448
|
const BasebandSignal = MessageClass('org.arl.unet.bb.BasebandSignal');
|
|
1365
1449
|
|
|
1366
1450
|
let UnetServices = {
|
|
@@ -1432,7 +1516,8 @@ let UnetMessages = {
|
|
|
1432
1516
|
|
|
1433
1517
|
// phy
|
|
1434
1518
|
'FecDecodeReq' : MessageClass('org.arl.unet.phy.FecDecodeReq'),
|
|
1435
|
-
'
|
|
1519
|
+
'RxSWiG1FrameNtf' : MessageClass('org.arl.unet.phy.RxSWiG1FrameNtf', RxFrameNtf$1),
|
|
1520
|
+
'RxJanusFrameNtf' : MessageClass('org.arl.unet.phy.RxJanusFrameNtf', RxFrameNtf$1),
|
|
1436
1521
|
'TxJanusFrameReq' : MessageClass('org.arl.unet.phy.TxJanusFrameReq'),
|
|
1437
1522
|
'BadFrameNtf' : MessageClass('org.arl.unet.phy.BadFrameNtf'),
|
|
1438
1523
|
'BadRangeNtf' : MessageClass('org.arl.unet.phy.BadRangeNtf'),
|