@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
JavaScript
;
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;