UNPKG

@obelisk/client

Version:

Typescript client to interact with Obelisk on a higher level than the regular ReST API calls.

109 lines (108 loc) 4.45 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.StreamEndpoint = void 0; const event_source_polyfill_1 = require("event-source-polyfill"); const rxjs_1 = require("rxjs"); const operators_1 = require("rxjs/operators"); const util_1 = require("../util"); /** * Endpoint class represents an IoT-stack API Endpoint. * For now just get(), but will support all http methods. */ class StreamEndpoint { constructor(client, uri, apiVersion = 'v1') { this.apiVersion = 'v1'; this.client = client; this._url = util_1.InternalUtils.norm(client, uri, apiVersion); this.apiVersion = apiVersion; } /** * Absolute url to use in requests */ get url() { return this._url; } /** * Creates an Endpoint instance * @param client The client is used to add auth tokens to the request * @param uri The uri is a relative path starting after /api/<version>. Examples are: <code>/things/my_thing/metrics/my_metric/events?from=1530089953000</code> or <code>/locations/my_loc/metrics/my_metric/stats/unit</code> */ static create(client, uri, apiVersion = 'v1') { return new StreamEndpoint(client, uri, apiVersion); } /** * Connects with this endpoint as an eventsource. * @param options StreamOptions to filter the stream. * @return Observable of TPage objects. Unsubscribe to manually close the stream. */ connect(options) { let retry = !(options && options.stopOn504); if (options) { delete options.stopOn504; } util_1.Logger.debug(this._url, 'SSE'); const source = this.observablePolyEventSource(options).pipe(util_1.InternalUtils.catch40xAndRetry(this.client)); return retry ? source.pipe(util_1.InternalUtils.catch504AndRetry()) : source; } /** * Wraps the EventSourcePolyfill in an Observable. * @param options */ observablePolyEventSource(options) { const url = options ? this.addOptionsToUrl(this._url, options) : this._url; const h = { headers: { Authorization: 'Bearer ' + (this.client.tokens.rpt ? this.client.tokens.rpt.getToken() : '<no rpt present>') }, }; const subject = new rxjs_1.ReplaySubject(1); const eventsource = new event_source_polyfill_1.EventSourcePolyfill(url, h); eventsource.onmessage = function (event) { const json = JSON.parse(event.data); subject.next(json); }; eventsource.onerror = function (event) { eventsource.close(); if (eventsource.readyState === 0) { // connecting subject.complete(); } else { subject.error(event); } }; return subject.asObservable().pipe(operators_1.finalize(() => { eventsource.close(); eventsource.readyState = 2; })); } /** * Adds the StreamOptions to the url as a querystring. * @param url The url to add querystring to * @param options The StreamOptions to limit the stream */ addOptionsToUrl(url, options) { let query = ''; const { things, metrics, area } = options; if (this.apiVersion === 'v1') { if (things && things.length > 0) { query += '&things=' + ((things instanceof Array) ? things.join(',') : things); } if (metrics && metrics.length > 0) { query += '&metrics=' + ((metrics instanceof Array) ? metrics.join(',') : metrics); } } if (this.apiVersion === 'v2') { let filter = []; if (things && things.length > 0) { filter.push(`sourceId =~ ${((things instanceof Array) ? things.join('|') : things)}`); } if (metrics && metrics.length > 0) { filter.push(`metricId =~ ${((metrics instanceof Array) ? metrics.join('|') : metrics)}`); } query += `&filter=${filter.join(',')}`; } if (area && area.length > 0) { query += '&area=' + ((area instanceof Array) ? area.join(',') : area); } return query.length === 0 ? url : url + '?' + query.slice(1); } } exports.StreamEndpoint = StreamEndpoint;