unetjs 3.1.5 → 3.2.1
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 +202 -113
- package/dist/esm/unet.js +202 -113
- package/dist/unetjs.js +201 -112
- 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 +2 -2
package/dist/esm/unet.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/* unet.js v3.1
|
|
1
|
+
/* unet.js v3.2.1 2025-01-31T16:55:08.538Z */
|
|
2
2
|
|
|
3
|
-
/* fjage.js v1.
|
|
3
|
+
/* fjage.js v1.13.7 */
|
|
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,33 +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
|
|
696
|
+
constructor(opts = {}) {
|
|
697
|
+
// Similar to Object.assign but also overwrites `undefined` and empty strings with defaults
|
|
690
698
|
for (var key in GATEWAY_DEFAULTS){
|
|
691
699
|
if (opts[key] == undefined || opts[key] === '') opts[key] = GATEWAY_DEFAULTS[key];
|
|
692
700
|
}
|
|
@@ -705,13 +713,19 @@ class Gateway {
|
|
|
705
713
|
this.listener = {}; // set of callbacks that want to listen to incoming messages
|
|
706
714
|
this.eventListeners = {}; // external listeners wanting to listen internal events
|
|
707
715
|
this.queue = []; // incoming message queue
|
|
716
|
+
this.connected = false; // connection status
|
|
708
717
|
this.debug = false; // debug info to be logged to console?
|
|
709
|
-
this.aid = new AgentID(
|
|
718
|
+
this.aid = new AgentID('gateway-'+_guid(4)); // gateway agent name
|
|
710
719
|
this.connector = this._createConnector(url);
|
|
711
720
|
this._addGWCache(this);
|
|
712
721
|
}
|
|
713
722
|
|
|
714
|
-
/**
|
|
723
|
+
/**
|
|
724
|
+
* Sends an event to all registered listeners of the given type.
|
|
725
|
+
* @private
|
|
726
|
+
* @param {string} type - type of event
|
|
727
|
+
* @param {Object|Message|string} val - value to be sent to the listeners
|
|
728
|
+
*/
|
|
715
729
|
_sendEvent(type, val) {
|
|
716
730
|
if (Array.isArray(this.eventListeners[type])) {
|
|
717
731
|
this.eventListeners[type].forEach(l => {
|
|
@@ -726,7 +740,11 @@ class Gateway {
|
|
|
726
740
|
}
|
|
727
741
|
}
|
|
728
742
|
|
|
729
|
-
/**
|
|
743
|
+
/**
|
|
744
|
+
* @private
|
|
745
|
+
* @param {string} data - stringfied JSON data received from the master container to be processed
|
|
746
|
+
* @returns {void}
|
|
747
|
+
*/
|
|
730
748
|
_onMsgRx(data) {
|
|
731
749
|
var obj;
|
|
732
750
|
if (this.debug) console.log('< '+data);
|
|
@@ -743,6 +761,7 @@ class Gateway {
|
|
|
743
761
|
delete this.pending[obj.id];
|
|
744
762
|
} else if (obj.action == 'send') {
|
|
745
763
|
// incoming message from master
|
|
764
|
+
// @ts-ignore
|
|
746
765
|
let msg = Message._deserialize(obj.message);
|
|
747
766
|
if (!msg) return;
|
|
748
767
|
this._sendEvent('rxmsg', msg);
|
|
@@ -803,7 +822,12 @@ class Gateway {
|
|
|
803
822
|
}
|
|
804
823
|
}
|
|
805
824
|
|
|
806
|
-
/**
|
|
825
|
+
/**
|
|
826
|
+
* Sends a message out to the master container.
|
|
827
|
+
* @private
|
|
828
|
+
* @param {string|Object} s - JSON object (either stringified or not) to be sent to the master container
|
|
829
|
+
* @returns {boolean} - true if the message was sent successfully
|
|
830
|
+
*/
|
|
807
831
|
_msgTx(s) {
|
|
808
832
|
if (typeof s != 'string' && !(s instanceof String)) s = JSON.stringify(s);
|
|
809
833
|
if(this.debug) console.log('> '+s);
|
|
@@ -811,7 +835,11 @@ class Gateway {
|
|
|
811
835
|
return this.connector.write(s);
|
|
812
836
|
}
|
|
813
837
|
|
|
814
|
-
/**
|
|
838
|
+
/**
|
|
839
|
+
* @private
|
|
840
|
+
* @param {Object} rq - request to be sent to the master container as a JSON object
|
|
841
|
+
* @returns {Promise<Object>} - a promise which returns the response from the master container
|
|
842
|
+
*/
|
|
815
843
|
_msgTxRx(rq) {
|
|
816
844
|
rq.id = _guid(8);
|
|
817
845
|
return new Promise(resolve => {
|
|
@@ -833,25 +861,32 @@ class Gateway {
|
|
|
833
861
|
});
|
|
834
862
|
}
|
|
835
863
|
|
|
836
|
-
/**
|
|
864
|
+
/**
|
|
865
|
+
* @private
|
|
866
|
+
* @param {URL} url - URL object of the master container to connect to
|
|
867
|
+
* @returns {TCPConnector|WSConnector} - connector object to connect to the master container
|
|
868
|
+
*/
|
|
837
869
|
_createConnector(url){
|
|
838
870
|
let conn;
|
|
839
871
|
if (url.protocol.startsWith('ws')){
|
|
840
872
|
conn = new WSConnector({
|
|
841
873
|
'hostname':url.hostname,
|
|
842
|
-
'port':url.port,
|
|
874
|
+
'port':parseInt(url.port),
|
|
843
875
|
'pathname':url.pathname,
|
|
844
|
-
'keepAlive': this._keepAlive
|
|
876
|
+
'keepAlive': this._keepAlive,
|
|
877
|
+
'debug': this.debug
|
|
845
878
|
});
|
|
846
879
|
}else if (url.protocol.startsWith('tcp')){
|
|
847
|
-
conn = new
|
|
880
|
+
conn = new TCPConnector({
|
|
848
881
|
'hostname':url.hostname,
|
|
849
|
-
'port':url.port,
|
|
850
|
-
'keepAlive': this._keepAlive
|
|
882
|
+
'port':parseInt(url.port),
|
|
883
|
+
'keepAlive': this._keepAlive,
|
|
884
|
+
'debug': this.debug
|
|
851
885
|
});
|
|
852
886
|
} else return null;
|
|
853
887
|
conn.setReadCallback(this._onMsgRx.bind(this));
|
|
854
888
|
conn.addConnectionListener(state => {
|
|
889
|
+
this.connected = !!state;
|
|
855
890
|
if (state == true){
|
|
856
891
|
this.flush();
|
|
857
892
|
this.connector.write('{"alive": true}');
|
|
@@ -862,7 +897,13 @@ class Gateway {
|
|
|
862
897
|
return conn;
|
|
863
898
|
}
|
|
864
899
|
|
|
865
|
-
/**
|
|
900
|
+
/**
|
|
901
|
+
* Checks if the object is a constructor.
|
|
902
|
+
*
|
|
903
|
+
* @private
|
|
904
|
+
* @param {Object} value - an object to be checked if it is a constructor
|
|
905
|
+
* @returns {boolean} - if the object is a constructor
|
|
906
|
+
*/
|
|
866
907
|
_isConstructor(value) {
|
|
867
908
|
try {
|
|
868
909
|
new new Proxy(value, {construct() { return {}; }});
|
|
@@ -872,7 +913,13 @@ class Gateway {
|
|
|
872
913
|
}
|
|
873
914
|
}
|
|
874
915
|
|
|
875
|
-
/**
|
|
916
|
+
/**
|
|
917
|
+
* Matches a message with a filter.
|
|
918
|
+
* @private
|
|
919
|
+
* @param {string|Object|function} filter - filter to be matched
|
|
920
|
+
* @param {Message} msg - message to be matched to the filter
|
|
921
|
+
* @returns {boolean} - true if the message matches the filter
|
|
922
|
+
*/
|
|
876
923
|
_matchMessage(filter, msg){
|
|
877
924
|
if (typeof filter == 'string' || filter instanceof String) {
|
|
878
925
|
return 'inReplyTo' in msg && msg.inReplyTo == filter;
|
|
@@ -892,18 +939,25 @@ class Gateway {
|
|
|
892
939
|
}
|
|
893
940
|
}
|
|
894
941
|
|
|
895
|
-
/**
|
|
942
|
+
/**
|
|
943
|
+
* Gets the next message from the queue that matches the filter.
|
|
944
|
+
* @private
|
|
945
|
+
* @param {string|Object|function} filter - filter to be matched
|
|
946
|
+
*/
|
|
896
947
|
_getMessageFromQueue(filter) {
|
|
897
948
|
if (!this.queue.length) return;
|
|
898
949
|
if (!filter) return this.queue.shift();
|
|
899
|
-
|
|
900
950
|
let matchedMsg = this.queue.find( msg => this._matchMessage(filter, msg));
|
|
901
951
|
if (matchedMsg) this.queue.splice(this.queue.indexOf(matchedMsg), 1);
|
|
902
|
-
|
|
903
952
|
return matchedMsg;
|
|
904
953
|
}
|
|
905
954
|
|
|
906
|
-
/**
|
|
955
|
+
/**
|
|
956
|
+
* Gets a cached gateway object for the given URL (if it exists).
|
|
957
|
+
* @private
|
|
958
|
+
* @param {URL} url - URL object of the master container to connect to
|
|
959
|
+
* @returns {Gateway|void} - gateway object for the given URL
|
|
960
|
+
*/
|
|
907
961
|
_getGWCache(url){
|
|
908
962
|
if (!gObj.fjage || !gObj.fjage.gateways) return null;
|
|
909
963
|
var f = gObj.fjage.gateways.filter(g => g.connector.url.toString() == url.toString());
|
|
@@ -911,13 +965,21 @@ class Gateway {
|
|
|
911
965
|
return null;
|
|
912
966
|
}
|
|
913
967
|
|
|
914
|
-
/**
|
|
968
|
+
/**
|
|
969
|
+
* Adds a gateway object to the cache if it doesn't already exist.
|
|
970
|
+
* @private
|
|
971
|
+
* @param {Gateway} gw - gateway object to be added to the cache
|
|
972
|
+
*/
|
|
915
973
|
_addGWCache(gw){
|
|
916
974
|
if (!gObj.fjage || !gObj.fjage.gateways) return;
|
|
917
975
|
gObj.fjage.gateways.push(gw);
|
|
918
976
|
}
|
|
919
977
|
|
|
920
|
-
/**
|
|
978
|
+
/**
|
|
979
|
+
* Removes a gateway object from the cache if it exists.
|
|
980
|
+
* @private
|
|
981
|
+
* @param {Gateway} gw - gateway object to be removed from the cache
|
|
982
|
+
*/
|
|
921
983
|
_removeGWCache(gw){
|
|
922
984
|
if (!gObj.fjage || !gObj.fjage.gateways) return;
|
|
923
985
|
var index = gObj.fjage.gateways.indexOf(gw);
|
|
@@ -1005,7 +1067,7 @@ class Gateway {
|
|
|
1005
1067
|
/**
|
|
1006
1068
|
* Gets the agent ID associated with the gateway.
|
|
1007
1069
|
*
|
|
1008
|
-
* @returns {
|
|
1070
|
+
* @returns {AgentID} - agent ID
|
|
1009
1071
|
*/
|
|
1010
1072
|
getAgentID() {
|
|
1011
1073
|
return this.aid;
|
|
@@ -1025,7 +1087,7 @@ class Gateway {
|
|
|
1025
1087
|
* Returns an object representing the named topic.
|
|
1026
1088
|
*
|
|
1027
1089
|
* @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
|
|
1090
|
+
* @param {string} [topic2] - name of the topic if the topic param is an AgentID
|
|
1029
1091
|
* @returns {AgentID} - object representing the topic
|
|
1030
1092
|
*/
|
|
1031
1093
|
topic(topic, topic2) {
|
|
@@ -1046,6 +1108,7 @@ class Gateway {
|
|
|
1046
1108
|
if (!topic.isTopic()) topic = new AgentID(topic.getName() + '__ntf', true, this);
|
|
1047
1109
|
this.subscriptions[topic.toJSON()] = true;
|
|
1048
1110
|
this._update_watch();
|
|
1111
|
+
return true;
|
|
1049
1112
|
}
|
|
1050
1113
|
|
|
1051
1114
|
/**
|
|
@@ -1137,6 +1200,7 @@ class Gateway {
|
|
|
1137
1200
|
}
|
|
1138
1201
|
this._sendEvent('txmsg', msg);
|
|
1139
1202
|
let rq = JSON.stringify({ action: 'send', relay: true, message: '###MSG###' });
|
|
1203
|
+
// @ts-ignore
|
|
1140
1204
|
rq = rq.replace('"###MSG###"', msg._serialize());
|
|
1141
1205
|
return !!this._msgTx(rq);
|
|
1142
1206
|
}
|
|
@@ -1154,9 +1218,9 @@ class Gateway {
|
|
|
1154
1218
|
* Sends a request and waits for a response. This method returns a {Promise} which resolves when a response
|
|
1155
1219
|
* is received or if no response is received after the timeout.
|
|
1156
1220
|
*
|
|
1157
|
-
* @param {
|
|
1221
|
+
* @param {Message} msg - message to send
|
|
1158
1222
|
* @param {number} [timeout=1000] - timeout in milliseconds
|
|
1159
|
-
* @returns {Promise
|
|
1223
|
+
* @returns {Promise<Message|void>} - a promise which resolves with the received response message, null on timeout
|
|
1160
1224
|
*/
|
|
1161
1225
|
async request(msg, timeout=1000) {
|
|
1162
1226
|
this.send(msg);
|
|
@@ -1167,10 +1231,10 @@ class Gateway {
|
|
|
1167
1231
|
* Returns a response message received by the gateway. This method returns a {Promise} which resolves when
|
|
1168
1232
|
* a response is received or if no response is received after the timeout.
|
|
1169
1233
|
*
|
|
1170
|
-
* @param {function}
|
|
1234
|
+
* @param {function|Message|typeof Message} filter - original message to which a response is expected, or a MessageClass of the type
|
|
1171
1235
|
* of message to match, or a closure to use to match against the message
|
|
1172
1236
|
* @param {number} [timeout=0] - timeout in milliseconds
|
|
1173
|
-
* @returns {Promise
|
|
1237
|
+
* @returns {Promise<Message|void>} - received response message, null on timeout
|
|
1174
1238
|
*/
|
|
1175
1239
|
async receive(filter, timeout=0) {
|
|
1176
1240
|
return new Promise(resolve => {
|
|
@@ -1225,8 +1289,8 @@ const Services = {
|
|
|
1225
1289
|
/**
|
|
1226
1290
|
* Creates a unqualified message class based on a fully qualified name.
|
|
1227
1291
|
* @param {string} name - fully qualified name of the message class to be created
|
|
1228
|
-
* @param {
|
|
1229
|
-
* @
|
|
1292
|
+
* @param {typeof Message} [parent] - class of the parent MessageClass to inherit from
|
|
1293
|
+
* @constructs Message
|
|
1230
1294
|
* @example
|
|
1231
1295
|
* const ParameterReq = MessageClass('org.arl.fjage.param.ParameterReq');
|
|
1232
1296
|
* let pReq = new ParameterReq()
|
|
@@ -1235,6 +1299,9 @@ function MessageClass(name, parent=Message) {
|
|
|
1235
1299
|
let sname = name.replace(/^.*\./, '');
|
|
1236
1300
|
if (MessageClass[sname]) return MessageClass[sname];
|
|
1237
1301
|
let cls = class extends parent {
|
|
1302
|
+
/**
|
|
1303
|
+
* @param {{ [x: string]: any; }} params
|
|
1304
|
+
*/
|
|
1238
1305
|
constructor(params) {
|
|
1239
1306
|
super();
|
|
1240
1307
|
this.__clazz__ = name;
|
|
@@ -1244,6 +1311,7 @@ function MessageClass(name, parent=Message) {
|
|
|
1244
1311
|
this[k] = params[k];
|
|
1245
1312
|
}
|
|
1246
1313
|
}
|
|
1314
|
+
if (name.endsWith('Req')) this.perf = Performative.REQUEST;
|
|
1247
1315
|
}
|
|
1248
1316
|
};
|
|
1249
1317
|
cls.__clazz__ = name;
|
|
@@ -1290,7 +1358,7 @@ function _b64toArray(base64, dtype, littleEndian=true) {
|
|
|
1290
1358
|
break;
|
|
1291
1359
|
case '[J': // long array
|
|
1292
1360
|
for (i = 0; i < len; i+=8)
|
|
1293
|
-
rv.push(view.
|
|
1361
|
+
rv.push(view.getBigInt64(i, littleEndian));
|
|
1294
1362
|
break;
|
|
1295
1363
|
case '[F': // float array
|
|
1296
1364
|
for (i = 0; i < len; i+=4)
|
|
@@ -1325,6 +1393,8 @@ function _decodeBase64(k, d) {
|
|
|
1325
1393
|
////// global
|
|
1326
1394
|
|
|
1327
1395
|
const GATEWAY_DEFAULTS = {};
|
|
1396
|
+
|
|
1397
|
+
/** @type {Window & globalThis & Object} */
|
|
1328
1398
|
let gObj = {};
|
|
1329
1399
|
let DEFAULT_URL;
|
|
1330
1400
|
if (isBrowser || isWebWorker){
|
|
@@ -1341,7 +1411,7 @@ if (isBrowser || isWebWorker){
|
|
|
1341
1411
|
DEFAULT_URL = new URL('ws://localhost');
|
|
1342
1412
|
// Enable caching of Gateways
|
|
1343
1413
|
if (typeof gObj.fjage === 'undefined') gObj.fjage = {};
|
|
1344
|
-
if (typeof gObj.fjage.gateways == 'undefined')gObj.fjage.gateways = [];
|
|
1414
|
+
if (typeof gObj.fjage.gateways == 'undefined') gObj.fjage.gateways = [];
|
|
1345
1415
|
} else if (isJsDom || isNode){
|
|
1346
1416
|
gObj = global;
|
|
1347
1417
|
Object.assign(GATEWAY_DEFAULTS, {
|
|
@@ -1357,10 +1427,28 @@ if (isBrowser || isWebWorker){
|
|
|
1357
1427
|
gObj.atob = a => Buffer.from(a, 'base64').toString('binary');
|
|
1358
1428
|
}
|
|
1359
1429
|
|
|
1430
|
+
/**
|
|
1431
|
+
* @typedef {Object} ParameterReq.Entry
|
|
1432
|
+
* @property {string} param - parameter name
|
|
1433
|
+
* @property {Object} value - parameter value
|
|
1434
|
+
* @exports ParameterReq.Entry
|
|
1435
|
+
*/
|
|
1436
|
+
|
|
1437
|
+
|
|
1438
|
+
/**
|
|
1439
|
+
* A message that requests one or more parameters of an agent.
|
|
1440
|
+
* @typedef {Message} ParameterReq
|
|
1441
|
+
* @property {string} param - parameters name to be get/set if only a single parameter is to be get/set
|
|
1442
|
+
* @property {Object} value - parameters value to be set if only a single parameter is to be set
|
|
1443
|
+
* @property {Array<ParameterReq.Entry>} requests - a list of multiple parameters to be get/set
|
|
1444
|
+
* @property {number} [index=-1] - index of parameter(s) to be set
|
|
1445
|
+
* @exports ParameterReq
|
|
1446
|
+
*/
|
|
1360
1447
|
const ParameterReq = MessageClass('org.arl.fjage.param.ParameterReq');
|
|
1361
1448
|
|
|
1362
1449
|
const DatagramReq$1 = MessageClass('org.arl.unet.DatagramReq');
|
|
1363
1450
|
const DatagramNtf$1 = MessageClass('org.arl.unet.DatagramNtf');
|
|
1451
|
+
const RxFrameNtf$1 = MessageClass('org.arl.unet.phy.RxFrameNtf', DatagramNtf$1);
|
|
1364
1452
|
const BasebandSignal = MessageClass('org.arl.unet.bb.BasebandSignal');
|
|
1365
1453
|
|
|
1366
1454
|
let UnetServices = {
|
|
@@ -1432,7 +1520,8 @@ let UnetMessages = {
|
|
|
1432
1520
|
|
|
1433
1521
|
// phy
|
|
1434
1522
|
'FecDecodeReq' : MessageClass('org.arl.unet.phy.FecDecodeReq'),
|
|
1435
|
-
'
|
|
1523
|
+
'RxSWiG1FrameNtf' : MessageClass('org.arl.unet.phy.RxSWiG1FrameNtf', RxFrameNtf$1),
|
|
1524
|
+
'RxJanusFrameNtf' : MessageClass('org.arl.unet.phy.RxJanusFrameNtf', RxFrameNtf$1),
|
|
1436
1525
|
'TxJanusFrameReq' : MessageClass('org.arl.unet.phy.TxJanusFrameReq'),
|
|
1437
1526
|
'BadFrameNtf' : MessageClass('org.arl.unet.phy.BadFrameNtf'),
|
|
1438
1527
|
'BadRangeNtf' : MessageClass('org.arl.unet.phy.BadRangeNtf'),
|