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