UNPKG

diffusion

Version:

Diffusion JavaScript client

270 lines (269 loc) 10.4 kB
"use strict"; /** * @module Routing */ var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TopicCache = void 0; var topic_cache_datatype_entry_1 = require("./../routing/topic-cache-datatype-entry"); var topic_cache_no_value_entry_1 = require("./../routing/topic-cache-no-value-entry"); var topic_cache_time_series_entry_1 = require("./../routing/topic-cache-time-series-entry"); var errors_1 = require("../../errors/errors"); var topic_type_1 = require("../../topics/topic-type"); var topics_1 = require("../../topics/topics"); /** * The topic cache used by the internal session to cache all topic values that * the session subscribes to. */ var TopicCache = /** @class */ (function () { /** * Create a new TopicCache instance * * @param datatypes the data types */ function TopicCache(datatypes) { /** * All the topic cache entries by their topic path */ this.byPath = {}; /** * All the topic cache entries by their ID */ this.byId = {}; this.datatypes = datatypes; } /** * Handle a subscription to a new topic * * This is called by the internal session when the client subscribes to a * new topic. A new entry {@link TopicCacheEntry} is created and all streams * in the stream registry that select the subscribed path will be added to * that entry. * * The entry will then be notified of the initial subscription. * * @param info the information about the new topic * @param registry the stream registry */ TopicCache.prototype.handleSubscription = function (info, registry) { var path = info.path; var streams = registry.streamsFor(path, info.specification); var entry; switch (info.specification.type) { case topic_type_1.TopicType.JSON: case topic_type_1.TopicType.BINARY: case topic_type_1.TopicType.STRING: case topic_type_1.TopicType.DOUBLE: case topic_type_1.TopicType.INT64: case topic_type_1.TopicType.RECORD_V2: var datatype = this.datatypes.get(info.specification.type); /* istanbul ignore next */ if (datatype === null) { throw new errors_1.InternalError('Invalid topic type'); } entry = new topic_cache_datatype_entry_1.DatatypeCacheEntry(streams, path, info.specification, datatype); break; case topic_type_1.TopicType.TIME_SERIES: var eventType = this.datatypes.get(info.specification.properties.TIME_SERIES_EVENT_VALUE_TYPE); /* istanbul ignore next */ if (eventType === null) { throw new errors_1.InternalError('Invalid timeseries event type'); } entry = new topic_cache_time_series_entry_1.TimeSeriesCacheEntry(streams, path, info.specification, eventType); break; default: entry = new topic_cache_no_value_entry_1.NoValueEntry(streams, path, info.specification); } var oldByPath = this.byPath[path]; this.byPath[path] = entry; if (oldByPath) { throw new errors_1.InternalError("Existing cache entry for " + path); } var oldById = this.byId[info.id]; this.byId[info.id] = entry; if (oldById) { throw new errors_1.InternalError("Existing cache entry for " + info.id); } entry.notifyInitialSubscription(registry); }; /** * Clear the topic cache and notify all entries of an unsubscription * * @param registry the stream registry */ TopicCache.prototype.notifyUnsubscriptionOfAllTopics = function (registry) { // eslint-disable-next-line guard-for-in for (var id in this.byId) { this.byId[id].notifyUnsubscription(topics_1.UnsubscribeReasonEnum.SUBSCRIPTION_REFRESH, registry); } this.byPath = {}; this.byId = {}; }; /** * Handle a value on a given topic ID * * @param id the topic ID * @param content the new content * @param registry the stream registry * @param handler an error handler that will be called with a {@link SessionError} * if no cache entry could be found or an {@link InvalidDataError} if the delta * could not be applied */ TopicCache.prototype.handleValue = function (id, content, registry, handler) { var errorHandler = handler.getErrorHandler(); var entry = this.byId[id]; if (entry) { entry.handleValue(content, registry, errorHandler); } else { errorHandler(new errors_1.SessionError("Data loss on topic with ID: " + id + " - possibly due to reconnection")); } }; /** * Handle a delta on a given topic ID * * @param id the topic ID * @param delta the delta content * @param registry the stream registry * @param handler an error handler that will be called with a {@link SessionError} * if no cache entry could be found or an {@link InvalidDataError} if the delta * could not be applied */ TopicCache.prototype.handleDelta = function (id, delta, registry, handler) { var errorHandler = handler.getErrorHandler(); var entry = this.byId[id]; if (entry) { entry.handleDelta(delta, registry, errorHandler); } else { errorHandler(new errors_1.SessionError("Data loss on topic with ID: " + id + " - possibly due to reconnection")); } }; /** * Handle an unsubscription event on a given topic ID * * @param id the topic ID * @param reason reason for unsubscribing * @param registry the stream registry */ TopicCache.prototype.handleUnsubscription = function (id, reason, registry) { var entry = this.byId[id]; delete this.byId[id]; if (entry) { var path = entry.getTopicPath(); delete this.byPath[path]; entry.notifyUnsubscription(reason, registry); } }; /** * Add a new stream to the cache * * The stream will be added to all current entries that the stream selects. * * @param selector the topic selector of the topics that the stream should * receive events for * @param stream the stream adapter to add * @param registry the stream registry * @throws an {@link InvalidDataError} if any value received is incompatible with the data type * of the stream or does not represent a valid value. */ TopicCache.prototype.newStream = function (selector, stream, registry) { var e_1, _a; try { for (var _b = __values(Object.entries(this.byPath)), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = __read(_c.value, 2), path = _d[0], entry = _d[1]; var specification = entry.getTopicSpecification(); if (selector.selects(path) && stream.selects(specification)) { entry.addStream(stream.adapter ? stream.adapter(specification) : stream, registry); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } }; /** * Remove a stream from the cache * * Removes the stream from all entries that contain it. * * @param stream the stream adapter to remove * @param registry the stream registry */ TopicCache.prototype.removeStream = function (stream, registry) { var e_2, _a; try { for (var _b = __values(Object.values(this.byPath)), _c = _b.next(); !_c.done; _c = _b.next()) { var entry = _c.value; entry.removeStream(stream, registry); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_2) throw e_2.error; } } }; /** * Remove all streams from the cache * * Removes all streams from all entries without removing the entries themselves */ TopicCache.prototype.removeAllStreams = function () { var e_3, _a; try { for (var _b = __values(Object.getOwnPropertyNames(this.byPath)), _c = _b.next(); !_c.done; _c = _b.next()) { var path = _c.value; this.byPath[path].removeAllStreams(); } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_3) throw e_3.error; } } }; /** * Removes all topic cache entries */ TopicCache.prototype.clear = function () { this.byPath = {}; this.byId = {}; }; return TopicCache; }()); exports.TopicCache = TopicCache;