"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StreamingTransport = void 0;
const util_1 = require("../../util");
const subscription_1 = require("./subscription");
const metrics_1 = require("../../metrics");
const logger = (0, util_1.makeLogger)('StreamingTransport');
/**
 * Abstract Transport that will take incoming requests and add them to a subscription set as part
 * of the registration. It also defines an abstract stream handler method, that will be called by the
 * background execute and provided with calculated subscription deltas.
 *
 * @typeParam T - all types related to the [[Transport]]
 */
class StreamingTransport extends subscription_1.SubscriptionTransport {
    constructor() {
        super(...arguments);
        // The double sets serve to create a simple polling mechanism instead of needing a subscription
        // This one would not; this is always local state
        this.localSubscriptions = [];
        // This only tracks when the connection was established, not when the subscription was requested
        this.providerDataStreamEstablished = 0;
        this.retryCount = 0;
        this.retryTime = 0;
    }
    async backgroundHandler(context, desiredSubs) {
        if (this.retryTime > Date.now()) {
            return;
        }
        logger.debug('Generating delta (subscribes & unsubscribes)');
        const desiredSubsSet = new Set(desiredSubs.map((s) => JSON.stringify(s)));
        const localSubscriptionsSet = new Set(this.localSubscriptions.map((s) => JSON.stringify(s)));
        const subscriptions = {
            desired: desiredSubs,
            new: desiredSubs.filter((s) => !localSubscriptionsSet.has(JSON.stringify(s))),
            stale: this.localSubscriptions.filter((s) => !desiredSubsSet.has(JSON.stringify(s))),
        };
        logger.debug(`${subscriptions.new.length} new subscriptions; ${subscriptions.stale.length} to unsubscribe`);
        if (subscriptions.new.length) {
            (0, util_1.censorLogs)(() => logger.trace(`Will subscribe to: ${JSON.stringify(subscriptions.new)}`));
        }
        if (subscriptions.stale.length) {
            (0, util_1.censorLogs)(() => logger.trace(`Will unsubscribe to: ${JSON.stringify(subscriptions.stale)}`));
        }
        try {
            await this.streamHandler(context, subscriptions);
            this.retryCount = 0;
        }
        catch (error) {
            (0, util_1.censorLogs)(() => logger.error(error, error.stack));
            metrics_1.metrics
                .get('streamHandlerErrors')
                .labels({ adapter_endpoint: context.endpointName, transport: this.name })
                .inc();
            const timeout = Math.min(context.adapterSettings.STREAM_HANDLER_RETRY_MIN_MS *
                context.adapterSettings.STREAM_HANDLER_RETRY_EXP_FACTOR ** this.retryCount, context.adapterSettings.STREAM_HANDLER_RETRY_MAX_MS);
            this.retryTime = Date.now() + timeout;
            this.retryCount += 1;
            logger.info(`Waiting ${timeout}ms before backgroundHandler retry #${this.retryCount}`);
            return;
        }
        logger.debug('Setting local state to subscription set value');
        this.localSubscriptions = desiredSubs;
        return;
    }
}
exports.StreamingTransport = StreamingTransport;
//# sourceMappingURL=streaming.js.map