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