UNPKG

box-node-sdk

Version:

Official SDK for Box Platform APIs

168 lines 6.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EventStream = void 0; const errors_1 = require("./errors"); const utilsNode_1 = require("../internal/utilsNode"); var RealtimeServerEventValue; (function (RealtimeServerEventValue) { RealtimeServerEventValue["NEW_CHANGE"] = "new_change"; RealtimeServerEventValue["RECONNECT"] = "reconnect"; })(RealtimeServerEventValue || (RealtimeServerEventValue = {})); /** * EventStream is a readable stream that fetches events from the Box API. * It uses long polling to receive real-time updates. * This class is designed to be used with Node.js streams. * * @param {EventsManager} options.eventsManager - The EventsManager instance which provides relevant methods to fetch events. * @param {GetEventsQueryParams} options.queryParams - The query parameters to use for fetching events. * @param {GetEventsHeadersInput} options.headersInput - The headers to include in the request. */ class EventStream extends utilsNode_1.ByteStream { _eventsManager; _queryParams; _headersInput; _streamPosition; _longPollingInfo; _longPollingRetries = 0; _started = false; _abortController; _deduplicationFilterSize = 1000; _dedupHash = new Map(); constructor(options) { super({ objectMode: true, }); this._eventsManager = options.eventsManager; this._streamPosition = options.queryParams.streamPosition || 'now'; this._queryParams = options.queryParams; this._headersInput = options.headersInput; this._abortController = new AbortController(); this._dedupHash = new Map(); } _read(size) { if (this.destroyed) { return; } if (!this._started) { this._started = true; this.fetchEvents(); } } _destroy(error, callback) { this._abortController?.abort('Stream destroyed'); if (!error) { this.push(null); } callback(error); } async getLongPollInfo() { if (this.destroyed) { return; } try { const info = await this._eventsManager.getEventsWithLongPolling(undefined, this._abortController?.signal); const server = info.entries?.find((entry) => entry.type === 'realtime_server') || undefined; if (!server) { throw new errors_1.BoxSdkError({ message: 'No realtime server found in the response.', }); } this._longPollingInfo = server; this._longPollingRetries = 0; return this.doLongPoll(); } catch (error) { if (error.name !== 'AbortError') { this.emit('error', error); return this.getLongPollInfo(); } } } async doLongPoll() { if (this.destroyed) { return; } try { if (!this._longPollingInfo || this._longPollingRetries > parseInt(this._longPollingInfo?.maxRetries || '10', 10)) { return this.getLongPollInfo(); } this._longPollingRetries++; const longPollUrl = this._longPollingInfo?.url; const longPollWithStreamPosition = `${longPollUrl}${longPollUrl.includes('?') ? '&' : '?'}stream_position=${this._streamPosition}`; const response = await this._eventsManager.networkSession.networkClient.fetch({ url: longPollWithStreamPosition, method: 'GET', headers: { 'Content-Type': 'application/json', }, responseFormat: 'json', auth: this._eventsManager.auth, networkSession: this._eventsManager.networkSession, cancellationToken: this._abortController?.signal, }); if (this.destroyed) { return; } if (response.data) { const message = response.data; if (message.message === RealtimeServerEventValue.NEW_CHANGE) { return this.fetchEvents(); } else if (message.message === RealtimeServerEventValue.RECONNECT) { return this.getLongPollInfo(); } return this.doLongPoll(); } } catch (error) { if (error.name !== 'AbortError') { this.emit('error', error); this.doLongPoll(); } } } async fetchEvents() { if (this.destroyed) { return; } try { const events = await this._eventsManager.getEvents({ ...this._queryParams, ...{ streamPosition: this._streamPosition, }, }, this._headersInput, this._abortController?.signal); this._streamPosition = events.nextStreamPosition?.toString() || 'now'; if (events.entries) { for (const entry of events.entries) { if (entry.eventId) { if (this._dedupHash.has(entry.eventId)) { continue; } this._dedupHash.set(entry.eventId, true); } this.push(entry); } if (this._dedupHash.size >= this._deduplicationFilterSize) { for (const [key] of this._dedupHash) { if (!events.entries.some((entry) => entry.eventId === key)) { this._dedupHash.delete(key); } } } } return this.doLongPoll(); } catch (error) { if (error.name !== 'AbortError') { this.emit('error', error); this.fetchEvents(); } } } } exports.EventStream = EventStream; //# sourceMappingURL=eventStream.js.map