@openremote/core 1.0.3 → 1.2.0-snapshot.20240512154942

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/event.js DELETED
@@ -1,567 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import manager from "./index";
11
- import { arrayRemove, Deferred } from "./util";
12
- export var EventProviderStatus;
13
- (function (EventProviderStatus) {
14
- EventProviderStatus["DISCONNECTED"] = "DISCONNECTED";
15
- EventProviderStatus["CONNECTED"] = "CONNECTED";
16
- EventProviderStatus["CONNECTING"] = "CONNECTING";
17
- })(EventProviderStatus || (EventProviderStatus = {}));
18
- const SUBSCRIBE_MESSAGE_PREFIX = "SUBSCRIBE:";
19
- const SUBSCRIBED_MESSAGE_PREFIX = "SUBSCRIBED:";
20
- const UNSUBSCRIBE_MESSAGE_PREFIX = "UNSUBSCRIBE:";
21
- const UNAUTHORIZED_MESSAGE_PREFIX = "UNAUTHORIZED:";
22
- const TRIGGERED_MESSAGE_PREFIX = "TRIGGERED:";
23
- const EVENT_MESSAGE_PREFIX = "EVENT:";
24
- const EVENT_REQUEST_RESPONSE_MESSAGE_PREFIX = "REQUESTRESPONSE:";
25
- class EventProviderImpl {
26
- constructor() {
27
- this._disconnectRequested = false;
28
- this._reconnectDelayMillis = WebSocketEventProvider.MIN_RECONNECT_DELAY;
29
- this._reconnectTimer = null;
30
- this._status = EventProviderStatus.DISCONNECTED;
31
- this._connectingDeferred = null;
32
- this._statusCallbacks = [];
33
- this._pendingSubscription = null;
34
- this._queuedSubscriptions = [];
35
- this._subscriptionMap = {};
36
- this._assetSubscriptionMap = new Map();
37
- }
38
- get status() {
39
- return this._status;
40
- }
41
- subscribeStatusChange(callback) {
42
- this._statusCallbacks.push(callback);
43
- }
44
- unsubscribeStatusChange(callback) {
45
- arrayRemove(this._statusCallbacks, callback);
46
- }
47
- connect() {
48
- if (this._status === EventProviderStatus.CONNECTED) {
49
- return Promise.resolve(true);
50
- }
51
- this._disconnectRequested = false;
52
- if (this._connectingDeferred) {
53
- return this._connectingDeferred.promise;
54
- }
55
- this._onStatusChanged(EventProviderStatus.CONNECTING);
56
- this._connectingDeferred = new Deferred();
57
- this._doConnect().then((connected) => {
58
- if (this._connectingDeferred) {
59
- const deferred = this._connectingDeferred;
60
- this._connectingDeferred = null;
61
- if (this._reconnectTimer) {
62
- window.clearTimeout(this._reconnectTimer);
63
- this._reconnectTimer = null;
64
- }
65
- if (connected) {
66
- console.debug("Connected to event service: " + this.endpointUrl);
67
- this._reconnectDelayMillis = WebSocketEventProvider.MIN_RECONNECT_DELAY;
68
- this._onStatusChanged(EventProviderStatus.CONNECTED);
69
- window.setTimeout(() => {
70
- this._onConnect();
71
- }, 0);
72
- }
73
- else {
74
- console.debug("Failed to connect to event service: " + this.endpointUrl);
75
- this._onStatusChanged(EventProviderStatus.DISCONNECTED);
76
- }
77
- deferred.resolve(connected);
78
- }
79
- });
80
- return this._connectingDeferred.promise;
81
- }
82
- disconnect() {
83
- if (this._disconnectRequested) {
84
- return;
85
- }
86
- this._disconnectRequested = true;
87
- if (this._reconnectTimer) {
88
- window.clearTimeout(this._reconnectTimer);
89
- this._reconnectTimer = null;
90
- }
91
- if (this.status === EventProviderStatus.DISCONNECTED) {
92
- return;
93
- }
94
- this._doDisconnect();
95
- }
96
- subscribe(eventSubscription, callback) {
97
- const subscriptionInfo = {
98
- eventSubscription: eventSubscription,
99
- callback: callback,
100
- deferred: new Deferred()
101
- };
102
- if (this._pendingSubscription != null || this._status !== EventProviderStatus.CONNECTED) {
103
- this._queuedSubscriptions.push(subscriptionInfo);
104
- return subscriptionInfo.deferred.promise;
105
- }
106
- this._pendingSubscription = subscriptionInfo;
107
- this._doSubscribe(eventSubscription).then(subscriptionId => {
108
- if (this._pendingSubscription) {
109
- const subscription = this._pendingSubscription;
110
- this._pendingSubscription = null;
111
- // Store subscriptionId and callback
112
- this._subscriptionMap[subscriptionId] = subscription;
113
- this._processNextSubscription();
114
- const deferred = subscription.deferred;
115
- subscription.deferred = null;
116
- if (deferred) {
117
- deferred.resolve(subscriptionId);
118
- }
119
- }
120
- }, (reason) => {
121
- if (this._pendingSubscription) {
122
- const subscription = this._pendingSubscription;
123
- this._pendingSubscription = null;
124
- this._processNextSubscription();
125
- const deferred = subscription.deferred;
126
- subscription.deferred = null;
127
- if (deferred) {
128
- deferred.reject(reason);
129
- }
130
- }
131
- });
132
- return this._pendingSubscription.deferred.promise;
133
- }
134
- unsubscribe(subscriptionId) {
135
- const callback = this._subscriptionMap[subscriptionId];
136
- if (callback) {
137
- delete this._subscriptionMap[subscriptionId];
138
- this._doUnsubscribe(subscriptionId);
139
- }
140
- else {
141
- const removeSubscriptions = [];
142
- this._assetSubscriptionMap.forEach((info, key) => {
143
- const callbackMap = info.callbacks;
144
- callbackMap.delete(subscriptionId);
145
- if (callbackMap.size === 0) {
146
- removeSubscriptions.push(key);
147
- }
148
- });
149
- removeSubscriptions.forEach((subscriptionIdToRemove) => {
150
- this._assetSubscriptionMap.delete(subscriptionIdToRemove);
151
- this.unsubscribe(subscriptionIdToRemove);
152
- });
153
- }
154
- }
155
- sendEvent(event) {
156
- if (this._status === EventProviderStatus.CONNECTED) {
157
- this._doSend(event);
158
- }
159
- }
160
- sendEventWithReply(event) {
161
- if (this._status !== EventProviderStatus.CONNECTED) {
162
- return Promise.reject("Not connected");
163
- }
164
- return this._doSendWithReply(event);
165
- }
166
- subscribeAssetEvents(ids, requestCurrentValues, callback) {
167
- return __awaiter(this, void 0, void 0, function* () {
168
- const subscription = {
169
- eventType: "asset"
170
- };
171
- const isAttributeRef = ids && typeof ids[0] !== "string";
172
- const assetIds = isAttributeRef ? ids.map((id) => id.entityId) : ids;
173
- if (assetIds && assetIds.length > 0) {
174
- subscription.filter = {
175
- filterType: "asset",
176
- assetIds: ids
177
- };
178
- }
179
- let subscriptionId = null;
180
- try {
181
- subscriptionId = yield this.subscribe(subscription, callback);
182
- // Get the current state of the assets
183
- if (assetIds && requestCurrentValues) {
184
- const readRequest = {
185
- messageId: "read-assets:" + assetIds.join(",") + ":" + subscriptionId,
186
- event: {
187
- eventType: "read-assets",
188
- assetQuery: {
189
- ids: assetIds
190
- }
191
- }
192
- };
193
- const response = yield this.sendEventWithReply(readRequest);
194
- if (response.assets) {
195
- response.assets.forEach((asset) => {
196
- const assetEvent = {
197
- eventType: "asset",
198
- asset: asset,
199
- cause: "READ" /* READ */
200
- };
201
- callback(assetEvent);
202
- });
203
- }
204
- }
205
- }
206
- catch (e) {
207
- console.error("Failed to subscribe to asset events for assets: " + ids);
208
- if (subscriptionId) {
209
- this.unsubscribe(subscriptionId);
210
- }
211
- throw e;
212
- }
213
- return subscriptionId;
214
- });
215
- }
216
- /**
217
- * Subscribe for updates to a particular attribute; internally this creates subscriptions for all attributes of an
218
- * asset and manages delivery of the update attributes to the subscribers
219
- */
220
- subscribeAttributeEvents(ids, requestCurrentValues, callback) {
221
- return __awaiter(this, void 0, void 0, function* () {
222
- if (!ids || ids.length === 0) {
223
- throw new Error("At least one ID must be provided");
224
- }
225
- const isAttributeRef = typeof ids[0] !== "string";
226
- const assetIds = isAttributeRef ? [...new Set(ids.map((id) => id.entityId))] : [...new Set(ids)];
227
- const attributes = isAttributeRef ? ids : undefined;
228
- const subscriptionId = "AttributeEvent" + EventProviderImpl._subscriptionCounter++;
229
- // Check if we have an existing subscription for each asset, otherwise create one
230
- const assetSubscriptions = assetIds.map((assetId) => {
231
- const assetAttributes = attributes ? attributes.filter((attributeRef) => attributeRef.entityId === assetId) : undefined;
232
- let info = this._assetSubscriptionMap.get(assetId);
233
- let promise = Promise.resolve(assetId);
234
- if (!info) {
235
- info = {
236
- callbacks: new Map()
237
- };
238
- this._assetSubscriptionMap.set(assetId, info);
239
- const subscription = {
240
- subscriptionId: assetId,
241
- eventType: "attribute",
242
- filter: {
243
- filterType: "asset",
244
- assetIds: [assetId]
245
- }
246
- };
247
- promise = this.subscribe(subscription, (evt) => {
248
- const assetSubscription = this._assetSubscriptionMap.get(assetId);
249
- if (!assetSubscription) {
250
- return;
251
- }
252
- // Keep cached asset in sync
253
- if (assetSubscription.asset) {
254
- if (evt.attributeState.deleted) {
255
- delete assetSubscription.asset.attributes[evt.attributeState.attributeRef.attributeName];
256
- }
257
- else {
258
- const attr = assetSubscription.asset.attributes[evt.attributeState.attributeRef.attributeName];
259
- attr.value = evt.attributeState.value;
260
- attr.valueTimestamp = evt.timestamp;
261
- }
262
- }
263
- assetSubscription.callbacks.forEach((cb, key) => {
264
- cb(evt);
265
- });
266
- }).then((sId) => {
267
- // Get and store the asset so we can quickly provide the current value of attributes
268
- const readEvent = {
269
- event: {
270
- eventType: "read-assets",
271
- assetQuery: {
272
- ids: [assetId],
273
- select: {
274
- excludeParentInfo: true,
275
- excludePath: true
276
- }
277
- }
278
- }
279
- };
280
- return this.sendEventWithReply(readEvent);
281
- }).then((response) => {
282
- const assetsEvent = response;
283
- if (assetsEvent.assets && assetsEvent.assets.length === 1) {
284
- info.asset = assetsEvent.assets[0];
285
- }
286
- info.promise = undefined;
287
- });
288
- info.promise = promise;
289
- }
290
- else if (info.promise) {
291
- promise = info.promise;
292
- }
293
- info.callbacks.set(subscriptionId, (evt) => {
294
- if (assetAttributes) {
295
- if (assetAttributes.find((attributeRef) => evt.attributeState.attributeRef.attributeName === attributeRef.attributeName)) {
296
- callback(evt);
297
- }
298
- }
299
- else {
300
- callback(evt);
301
- }
302
- });
303
- return promise;
304
- });
305
- yield Promise.all(assetSubscriptions);
306
- if (requestCurrentValues) {
307
- assetIds.forEach((assetId) => {
308
- const info = this._assetSubscriptionMap.get(assetId);
309
- if (info && info.asset) {
310
- Object.entries(info.asset.attributes).forEach(([attributeName, v]) => {
311
- const attr = v;
312
- if (!attributes || attributes.find((attributeRef) => attributeRef.entityId === info.asset.id && attributeRef.attributeName === attributeName)) {
313
- callback({
314
- eventType: "attribute",
315
- timestamp: attr.valueTimestamp,
316
- attributeState: {
317
- value: attr.value,
318
- attributeRef: {
319
- entityId: assetId,
320
- attributeName: attributeName
321
- }
322
- }
323
- });
324
- }
325
- });
326
- }
327
- });
328
- }
329
- return subscriptionId;
330
- });
331
- }
332
- _processNextSubscription() {
333
- if (this._status !== EventProviderStatus.CONNECTED || this._queuedSubscriptions.length === 0) {
334
- return;
335
- }
336
- setTimeout(() => {
337
- const subscriptionInfo = this._queuedSubscriptions.shift();
338
- if (subscriptionInfo) {
339
- this.subscribe(subscriptionInfo.eventSubscription, subscriptionInfo.callback)
340
- .then((id) => {
341
- const deferred = subscriptionInfo.deferred;
342
- subscriptionInfo.deferred = null;
343
- if (deferred) {
344
- deferred.resolve(id);
345
- }
346
- }, reason => {
347
- const deferred = subscriptionInfo.deferred;
348
- subscriptionInfo.deferred = null;
349
- if (deferred) {
350
- deferred.reject(reason);
351
- }
352
- });
353
- }
354
- }, 0);
355
- }
356
- _onStatusChanged(status) {
357
- if (status === this._status) {
358
- return;
359
- }
360
- console.debug("Event provider status changed: " + status);
361
- this._status = status;
362
- window.setTimeout(() => {
363
- this._statusCallbacks.forEach((cb) => cb(status));
364
- }, 0);
365
- }
366
- _onMessageReceived(subscriptionId, event) {
367
- const subscriptionInfo = this._subscriptionMap[subscriptionId];
368
- if (subscriptionInfo) {
369
- subscriptionInfo.callback(event);
370
- }
371
- }
372
- _onConnect() {
373
- console.debug("Event provider connected: " + this.constructor.name);
374
- if (Object.keys(this._subscriptionMap).length > 0) {
375
- for (const subscriptionId in this._subscriptionMap) {
376
- if (this._subscriptionMap.hasOwnProperty(subscriptionId)) {
377
- this._queuedSubscriptions.unshift(this._subscriptionMap[subscriptionId]);
378
- }
379
- }
380
- this._subscriptionMap = {};
381
- }
382
- this._processNextSubscription();
383
- }
384
- _onDisconnect() {
385
- console.debug("Event provider disconnected");
386
- this._onStatusChanged(EventProviderStatus.DISCONNECTED);
387
- if (this._pendingSubscription) {
388
- this._queuedSubscriptions.unshift(this._pendingSubscription);
389
- this._pendingSubscription = null;
390
- }
391
- this._scheduleReconnect();
392
- }
393
- _scheduleReconnect() {
394
- if (this._reconnectTimer) {
395
- return;
396
- }
397
- if (this._disconnectRequested) {
398
- return;
399
- }
400
- console.debug("Event provider scheduling reconnect in " + this._reconnectDelayMillis + "ms");
401
- this._reconnectTimer = window.setTimeout(() => {
402
- if (this._disconnectRequested) {
403
- return;
404
- }
405
- this.connect().then(connected => {
406
- if (!connected) {
407
- this._scheduleReconnect();
408
- }
409
- }).catch(error => {
410
- this._scheduleReconnect();
411
- });
412
- }, this._reconnectDelayMillis);
413
- if (this._reconnectDelayMillis < WebSocketEventProvider.MAX_RECONNECT_DELAY) {
414
- this._reconnectDelayMillis = Math.min(WebSocketEventProvider.MAX_RECONNECT_DELAY, this._reconnectDelayMillis + 3000);
415
- }
416
- }
417
- }
418
- EventProviderImpl.MIN_RECONNECT_DELAY = 0;
419
- EventProviderImpl.MAX_RECONNECT_DELAY = 30000;
420
- EventProviderImpl._subscriptionCounter = 0;
421
- export class WebSocketEventProvider extends EventProviderImpl {
422
- constructor(managerUrl) {
423
- super();
424
- this._webSocket = undefined;
425
- this._connectDeferred = null;
426
- this._subscribeDeferred = null;
427
- this._repliesDeferred = new Map();
428
- this._endpointUrl = (managerUrl.startsWith("https:") ? "wss" : "ws") + "://" + managerUrl.substr(managerUrl.indexOf("://") + 3) + "/websocket/events";
429
- // Close socket on unload/refresh of page
430
- window.addEventListener("beforeunload", () => {
431
- this.disconnect();
432
- });
433
- }
434
- get endpointUrl() {
435
- return this._endpointUrl;
436
- }
437
- _doConnect() {
438
- let authorisedUrl = this._endpointUrl + "?Auth-Realm=" + manager.config.realm;
439
- if (manager.authenticated) {
440
- authorisedUrl += "&Authorization=" + manager.getAuthorizationHeader();
441
- }
442
- this._webSocket = new WebSocket(authorisedUrl);
443
- this._connectDeferred = new Deferred();
444
- this._webSocket.onopen = () => {
445
- if (this._connectDeferred) {
446
- const deferred = this._connectDeferred;
447
- this._connectDeferred = null;
448
- deferred.resolve(true);
449
- }
450
- };
451
- this._webSocket.onerror = () => {
452
- if (this._connectDeferred) {
453
- const deferred = this._connectDeferred;
454
- this._connectDeferred = null;
455
- deferred.resolve(false);
456
- }
457
- else {
458
- console.debug("Event provider error");
459
- // Could have inconsistent state so disconnect and let consumers decide what to do and when to reconnect
460
- this._beforeDisconnect();
461
- }
462
- };
463
- this._webSocket.onclose = () => {
464
- this._webSocket = undefined;
465
- if (this._connectDeferred) {
466
- const deferred = this._connectDeferred;
467
- this._connectDeferred = null;
468
- deferred.resolve(false);
469
- }
470
- else {
471
- this._beforeDisconnect();
472
- }
473
- };
474
- this._webSocket.onmessage = (e) => {
475
- const msg = e.data;
476
- if (msg && msg.startsWith(SUBSCRIBED_MESSAGE_PREFIX)) {
477
- const jsonStr = msg.substring(SUBSCRIBED_MESSAGE_PREFIX.length);
478
- const subscription = JSON.parse(jsonStr);
479
- const deferred = this._subscribeDeferred;
480
- this._subscribeDeferred = null;
481
- if (deferred) {
482
- deferred.resolve(subscription.subscriptionId);
483
- }
484
- }
485
- else if (msg.startsWith(UNAUTHORIZED_MESSAGE_PREFIX)) {
486
- const jsonStr = msg.substring(UNAUTHORIZED_MESSAGE_PREFIX.length);
487
- const subscription = JSON.parse(jsonStr);
488
- const deferred = this._subscribeDeferred;
489
- this._subscribeDeferred = null;
490
- if (deferred) {
491
- console.warn("Unauthorized event subscription: " + subscription);
492
- deferred.reject("Unauthorized");
493
- }
494
- }
495
- else if (msg.startsWith(TRIGGERED_MESSAGE_PREFIX)) {
496
- const str = msg.substring(TRIGGERED_MESSAGE_PREFIX.length);
497
- const triggered = JSON.parse(str);
498
- if (triggered.events) {
499
- triggered.events.forEach((event) => {
500
- this._onMessageReceived(triggered.subscriptionId, event);
501
- });
502
- }
503
- }
504
- else if (msg.startsWith(EVENT_REQUEST_RESPONSE_MESSAGE_PREFIX)) {
505
- const str = msg.substring(EVENT_REQUEST_RESPONSE_MESSAGE_PREFIX.length);
506
- const event = JSON.parse(str);
507
- if (event.messageId && event.event) {
508
- const deferred = this._repliesDeferred.get(event.messageId);
509
- this._repliesDeferred.delete(event.messageId);
510
- if (deferred) {
511
- deferred.resolve(event.event);
512
- }
513
- }
514
- }
515
- };
516
- return this._connectDeferred.promise;
517
- }
518
- _beforeDisconnect() {
519
- this._onDisconnect();
520
- }
521
- _doDisconnect() {
522
- this._webSocket.close();
523
- this._subscribeDeferred = null;
524
- this._repliesDeferred.clear();
525
- }
526
- _doSubscribe(subscription) {
527
- if (!this._webSocket) {
528
- return Promise.reject("Not connected");
529
- }
530
- if (this._subscribeDeferred) {
531
- return Promise.reject("There's already a pending subscription");
532
- }
533
- this._subscribeDeferred = new Deferred();
534
- if (!subscription.subscriptionId) {
535
- subscription.subscriptionId = WebSocketEventProvider._subscriptionCounter++ + "";
536
- }
537
- this._webSocket.send(SUBSCRIBE_MESSAGE_PREFIX + JSON.stringify(subscription));
538
- return this._subscribeDeferred.promise;
539
- }
540
- _doUnsubscribe(subscriptionId) {
541
- if (!this._webSocket) {
542
- return;
543
- }
544
- const cancelSubscription = {
545
- subscriptionId: subscriptionId
546
- };
547
- this._webSocket.send(UNSUBSCRIBE_MESSAGE_PREFIX + JSON.stringify(cancelSubscription));
548
- }
549
- _doSend(event) {
550
- const message = EVENT_MESSAGE_PREFIX + JSON.stringify(event);
551
- this._webSocket.send(message);
552
- }
553
- _doSendWithReply(event) {
554
- if (!event.messageId) {
555
- event.messageId = (new Date().getTime() + (Math.random() * 10)).toString(10);
556
- }
557
- if (this._repliesDeferred.has(event.messageId)) {
558
- return Promise.reject("There's already a pending send and reply with this ID");
559
- }
560
- const deferred = new Deferred();
561
- this._repliesDeferred.set(event.messageId, deferred);
562
- this._webSocket.send(EVENT_REQUEST_RESPONSE_MESSAGE_PREFIX + JSON.stringify(event));
563
- return deferred.promise;
564
- }
565
- }
566
- WebSocketEventProvider._subscriptionCounter = 1;
567
- //# sourceMappingURL=event.js.map