"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TrackerConnector = void 0;
const utils_1 = require("@streamr/utils");
const PeerInfo_1 = require("../connection/PeerInfo");
const NameDirectory_1 = require("../NameDirectory");
const logger = new utils_1.Logger(module);
var ConnectionState;
(function (ConnectionState) {
    ConnectionState[ConnectionState["SUCCESS"] = 0] = "SUCCESS";
    ConnectionState[ConnectionState["ERROR"] = 1] = "ERROR";
})(ConnectionState || (ConnectionState = {}));
class TrackerConnector {
    constructor(getStreamParts, connectToTracker, disconnectFromTracker, trackerRegistry, maintenanceInterval) {
        this.getStreamParts = getStreamParts;
        this.connectToTracker = connectToTracker;
        this.disconnectFromTracker = disconnectFromTracker;
        this.trackerRegistry = trackerRegistry;
        this.maintenanceInterval = maintenanceInterval;
        this.connectionStates = new Map();
        this.signallingOnlyTrackers = new Set();
    }
    onNewStreamPart(streamPartId) {
        const trackerInfo = this.trackerRegistry.getTracker(streamPartId);
        this.connectTo(trackerInfo);
    }
    async createSignallingOnlyTrackerConnection(trackerId, trackerAddress) {
        this.signallingOnlyTrackers.add(trackerId);
        await this.connectToTracker(trackerAddress, PeerInfo_1.PeerInfo.newTracker(trackerId));
        logger.info('Connected to tracker %s for signalling only', NameDirectory_1.NameDirectory.getName(trackerId));
    }
    removeSignallingOnlyTrackerConnection(trackerId) {
        this.signallingOnlyTrackers.delete(trackerId);
    }
    start() {
        this.maintainConnections();
        this.maintenanceTimer = setInterval(this.maintainConnections.bind(this), this.maintenanceInterval);
    }
    stop() {
        if (this.maintenanceTimer) {
            clearInterval(this.maintenanceTimer);
            this.maintenanceTimer = null;
        }
    }
    maintainConnections() {
        this.trackerRegistry.getAllTrackers().forEach((trackerInfo) => {
            if (this.isActiveTracker(trackerInfo.id)) {
                this.connectTo(trackerInfo);
            }
            else {
                this.disconnectFromTracker(trackerInfo.id);
            }
        });
    }
    connectTo({ id, ws }) {
        this.connectToTracker(ws, PeerInfo_1.PeerInfo.newTracker(id))
            .then(() => {
            if (this.connectionStates.get(id) !== ConnectionState.SUCCESS) {
                logger.info('Connected to tracker %s', NameDirectory_1.NameDirectory.getName(id));
                this.connectionStates.set(id, ConnectionState.SUCCESS);
            }
            return;
        })
            .catch((err) => {
            if (this.connectionStates.get(id) !== ConnectionState.ERROR) {
                // TODO we could also store the previous error and check that the current error is the same?
                // -> now it doesn't log anything if the connection error reason changes
                this.connectionStates.set(id, ConnectionState.ERROR);
                logger.warn('Could not connect to tracker %s, reason: %s', NameDirectory_1.NameDirectory.getName(id), err.message);
            }
        });
    }
    isActiveTracker(trackerId) {
        if (this.signallingOnlyTrackers.has(trackerId)) {
            return true;
        }
        for (const streamPartId of this.getStreamParts()) {
            if (this.trackerRegistry.getTracker(streamPartId).id === trackerId) {
                return true;
            }
        }
        return false;
    }
}
exports.TrackerConnector = TrackerConnector;
//# sourceMappingURL=TrackerConnector.js.map