jsgar 3.0.0 → 3.1.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/gar.umd.js +128 -8
- package/package.json +1 -1
package/dist/gar.umd.js
CHANGED
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
this.user = user;
|
|
51
51
|
this.working_namespace = working_namespace;
|
|
52
52
|
this.heartbeatTimeoutInterval = heartbeatTimeoutInterval;
|
|
53
|
-
this.version =
|
|
53
|
+
this.version = 650706;
|
|
54
54
|
|
|
55
55
|
if (typeof window !== 'undefined' && window.location) {
|
|
56
56
|
this.application = window.location.href;
|
|
@@ -64,25 +64,23 @@
|
|
|
64
64
|
this.serverTopicNameToId = new Map();
|
|
65
65
|
this.serverKeyIdToName = new Map();
|
|
66
66
|
this.serverKeyNameToId = new Map();
|
|
67
|
-
this.localTopicCounter = 1;
|
|
68
|
-
this.localKeyCounter = 1;
|
|
69
67
|
this.localTopicMap = new Map();
|
|
70
68
|
this.localKeyMap = new Map();
|
|
69
|
+
this.recordMap = new Map();
|
|
71
70
|
|
|
72
71
|
this.running = false;
|
|
73
72
|
this.heartbeatIntervalId = null;
|
|
74
73
|
this.messageHandlers = new Map();
|
|
75
74
|
this.lastHeartbeatTime = Date.now() / 1000;
|
|
76
75
|
this.heartbeatTimeout = 3; // Seconds
|
|
77
|
-
this._initialGracePeriod = false;
|
|
78
|
-
this._initialGraceDeadline = 0;
|
|
79
76
|
|
|
80
77
|
this.heartbeatTimeoutCallback = null;
|
|
81
78
|
this.stoppedCallback = null;
|
|
82
|
-
this.recordMap = new Map();
|
|
83
79
|
this.allowSelfSignedCertificate = allowSelfSignedCertificate;
|
|
84
80
|
this.exitCode = 0;
|
|
85
81
|
|
|
82
|
+
this.clearConnectionState();
|
|
83
|
+
|
|
86
84
|
// Initialize log levels and set logLevel
|
|
87
85
|
this.logLevels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'];
|
|
88
86
|
this.logLevel = logLevel.toUpperCase();
|
|
@@ -91,8 +89,6 @@
|
|
|
91
89
|
this.logLevel = 'INFO';
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
this.activeSubscriptionGroup = 0;
|
|
95
|
-
|
|
96
92
|
this.registerDefaultHandlers();
|
|
97
93
|
}
|
|
98
94
|
|
|
@@ -114,10 +110,43 @@
|
|
|
114
110
|
}
|
|
115
111
|
}
|
|
116
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Reset all connection-related state:
|
|
115
|
+
* server/client topic/key mappings, counters, grace flags, and records.
|
|
116
|
+
*/
|
|
117
|
+
clearConnectionState() {
|
|
118
|
+
// Server assigned topic/key <-> name mappings
|
|
119
|
+
this.serverTopicIdToName.clear();
|
|
120
|
+
this.serverTopicNameToId.clear();
|
|
121
|
+
this.serverKeyIdToName.clear();
|
|
122
|
+
this.serverKeyNameToId.clear();
|
|
123
|
+
|
|
124
|
+
// Client assigned topic/key counters and name <-> ID maps
|
|
125
|
+
this.localTopicCounter = 1;
|
|
126
|
+
this.localKeyCounter = 1;
|
|
127
|
+
this.localTopicMap.clear();
|
|
128
|
+
this.localKeyMap.clear();
|
|
129
|
+
|
|
130
|
+
// Heartbeat grace period flags
|
|
131
|
+
this._initialGracePeriod = false;
|
|
132
|
+
this._initialGraceDeadline = 0;
|
|
133
|
+
|
|
134
|
+
// Cached records
|
|
135
|
+
this.recordMap.clear();
|
|
136
|
+
|
|
137
|
+
this.activeSubscriptionGroup = 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Establish WebSocket connection with reconnection logic.
|
|
142
|
+
*/
|
|
117
143
|
/**
|
|
118
144
|
* Establish WebSocket connection with reconnection logic.
|
|
119
145
|
*/
|
|
120
146
|
async connect() {
|
|
147
|
+
// Before attempting a new connection, clear any previous state
|
|
148
|
+
this.clearConnectionState();
|
|
149
|
+
|
|
121
150
|
while (this.running && !this.connected) {
|
|
122
151
|
try {
|
|
123
152
|
if (this.allowSelfSignedCertificate) {
|
|
@@ -343,6 +372,19 @@
|
|
|
343
372
|
}, subscriptionGroup);
|
|
344
373
|
}
|
|
345
374
|
|
|
375
|
+
/**
|
|
376
|
+
* Register handler for BatchUpdate message.
|
|
377
|
+
* If a batch handler is registered it is expected to process all the updates in the batch.
|
|
378
|
+
* If no batch handler is registered, individual key introductions and record updates will be fanned out to their respective handlers.
|
|
379
|
+
* @param {Function} handler - Callback with (batchData, subscriptionGroup)
|
|
380
|
+
* @param {number} [subscriptionGroup=0] - The subscription group for callback
|
|
381
|
+
*/
|
|
382
|
+
registerBatchUpdateHandler(handler, subscriptionGroup = 0) {
|
|
383
|
+
this.registerHandler('BatchUpdate', (msg) => {
|
|
384
|
+
handler(msg.value, subscriptionGroup);
|
|
385
|
+
}, subscriptionGroup);
|
|
386
|
+
}
|
|
387
|
+
|
|
346
388
|
/**
|
|
347
389
|
* Register a callback to handle heartbeat timeout events.
|
|
348
390
|
* @param {Function} handler - Callback with no arguments
|
|
@@ -569,6 +611,84 @@
|
|
|
569
611
|
subscriptionGroup = this.activeSubscriptionGroup;
|
|
570
612
|
const {key_id: keyId, topic_id: topicId} = message.value;
|
|
571
613
|
this.recordMap.delete(`${keyId}:${topicId}`);
|
|
614
|
+
} else if (msgType === 'BatchUpdate') {
|
|
615
|
+
subscriptionGroup = this.activeSubscriptionGroup;
|
|
616
|
+
const value = message.value;
|
|
617
|
+
const defaultClass = value.default_class;
|
|
618
|
+
|
|
619
|
+
// Check if there's a specific batch update handler
|
|
620
|
+
const batchHandlerKey = subscriptionGroup ? `BatchUpdate ${subscriptionGroup}` : 'BatchUpdate';
|
|
621
|
+
const hasBatchHandler = this.messageHandlers.has(batchHandlerKey);
|
|
622
|
+
|
|
623
|
+
// Pre-check for individual handlers if no batch handler
|
|
624
|
+
let keyHandler = null;
|
|
625
|
+
let recordHandler = null;
|
|
626
|
+
if (!hasBatchHandler) {
|
|
627
|
+
const keyHandlerKey = subscriptionGroup ? `KeyIntroduction ${subscriptionGroup}` : 'KeyIntroduction';
|
|
628
|
+
keyHandler = this.messageHandlers.get(keyHandlerKey);
|
|
629
|
+
|
|
630
|
+
const recordHandlerKey = subscriptionGroup ? `JSONRecordUpdate ${subscriptionGroup}` : 'JSONRecordUpdate';
|
|
631
|
+
recordHandler = this.messageHandlers.get(recordHandlerKey);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
for (const keyUpdate of value.keys || []) {
|
|
635
|
+
const keyId = keyUpdate.key_id;
|
|
636
|
+
const keyName = keyUpdate.name;
|
|
637
|
+
|
|
638
|
+
// Handle key introduction if name is provided and key is new
|
|
639
|
+
if (keyName && !this.serverKeyIdToName.has(keyId)) {
|
|
640
|
+
this.serverKeyIdToName.set(keyId, keyName);
|
|
641
|
+
this.serverKeyNameToId.set(keyName, keyId);
|
|
642
|
+
|
|
643
|
+
// If no batch handler but key handler exists, call KeyIntroduction handler
|
|
644
|
+
if (!hasBatchHandler && keyHandler) {
|
|
645
|
+
// Determine class_list: use key's classes, or default_class, or null
|
|
646
|
+
let keyClasses = keyUpdate.classes;
|
|
647
|
+
if (!keyClasses && keyUpdate.class) {
|
|
648
|
+
keyClasses = [keyUpdate.class];
|
|
649
|
+
} else if (!keyClasses && defaultClass) {
|
|
650
|
+
keyClasses = [defaultClass];
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
const keyIntroMsg = {
|
|
654
|
+
message_type: 'KeyIntroduction',
|
|
655
|
+
value: {
|
|
656
|
+
key_id: keyId,
|
|
657
|
+
name: keyName,
|
|
658
|
+
...(keyClasses ? { class_list: keyClasses } : {})
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
keyHandler(keyIntroMsg);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// Process topics for this key - topic IDs are object keys
|
|
666
|
+
const topicsDict = keyUpdate.topics || {};
|
|
667
|
+
for (const [topicIdStr, recordValue] of Object.entries(topicsDict)) {
|
|
668
|
+
const topicId = parseInt(topicIdStr, 10);
|
|
669
|
+
this.recordMap.set(`${keyId}:${topicId}`, recordValue);
|
|
670
|
+
|
|
671
|
+
// If no batch handler but record handler exists, call JSONRecordUpdate handler
|
|
672
|
+
if (!hasBatchHandler && recordHandler) {
|
|
673
|
+
const recordUpdateMsg = {
|
|
674
|
+
message_type: 'JSONRecordUpdate',
|
|
675
|
+
value: {
|
|
676
|
+
record_id: { key_id: keyId, topic_id: topicId },
|
|
677
|
+
value: recordValue
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
recordHandler(recordUpdateMsg);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// If there is a batch handler, call it
|
|
686
|
+
if (hasBatchHandler) {
|
|
687
|
+
const batchHandler = this.messageHandlers.get(batchHandlerKey);
|
|
688
|
+
if (batchHandler) {
|
|
689
|
+
batchHandler(message);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
572
692
|
} else if (msgType === "ActiveSubscription") {
|
|
573
693
|
this.activeSubscriptionGroup = message["value"]["subscription_group"];
|
|
574
694
|
} else if (msgType === 'Logoff') {
|