"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "PrinterSocketStore", {
    enumerable: true,
    get: function() {
        return PrinterSocketStore;
    }
});
const _node = require("@sentry/node");
const _errorutils = require("../utils/error.utils");
const _eventconstants = require("../constants/event.constants");
const _printerapiinterface = require("../services/printer-api.interface");
class PrinterSocketStore {
    socketIoGateway;
    socketFactory;
    eventEmitter2;
    printerCache;
    printerSocketAdaptersById = {};
    logger;
    configService;
    settingsStore;
    constructor({ socketFactory, socketIoGateway, settingsStore, eventEmitter2, printerCache, loggerFactory, configService }){
        this.printerCache = printerCache;
        this.socketIoGateway = socketIoGateway;
        this.socketFactory = socketFactory;
        this.eventEmitter2 = eventEmitter2;
        this.settingsStore = settingsStore;
        this.logger = loggerFactory(PrinterSocketStore.name);
        this.configService = configService;
        this.subscribeToEvents();
    }
    getSocketStatesById() {
        const socketStatesById = {};
        Object.values(this.printerSocketAdaptersById).forEach((s)=>{
            socketStatesById[s.printerId] = {
                printerId: s.printerId,
                printerType: s.printerType,
                socket: s.socketState,
                api: s.apiState
            };
        });
        return socketStatesById;
    }
    async loadPrinterSockets() {
        await this.printerCache.loadCache();
        const printerDocs = await this.printerCache.listCachedPrinters(false);
        this.printerSocketAdaptersById = {};
        for (const doc of printerDocs){
            try {
                await this.handlePrinterCreated({
                    printer: doc
                });
            } catch (e) {
                (0, _node.captureException)(e);
                this.logger.error("PrinterSocketStore failed to construct new OctoPrint socket.", (0, _errorutils.errorSummary)(e));
            }
        }
        this.logger.log(`Loaded ${Object.keys(this.printerSocketAdaptersById).length} printer OctoPrint sockets`);
    }
    listPrinterSockets() {
        return Object.values(this.printerSocketAdaptersById);
    }
    reconnectOctoPrint(id) {
        const socket = this.getPrinterSocket(id);
        if (!socket) return;
        socket.close();
        socket.resetSocketState();
    }
    getPrinterSocket(id) {
        return this.printerSocketAdaptersById[id];
    }
    async reconnectPrinterSockets() {
        let reauthRequested = 0;
        let socketSetupRequested = 0;
        const socketStates = {};
        const apiStates = {};
        const promisesReauth = [];
        const failedSocketsReauth = [];
        for (const socket of Object.values(this.printerSocketAdaptersById)){
            try {
                if (socket.printerType === _printerapiinterface.OctoprintType && socket.needsReauth()) {
                    reauthRequested++;
                    const promise = socket.reauthSession().catch((_)=>{
                        failedSocketsReauth.push(socket.printerId);
                    });
                    promisesReauth.push(promise);
                }
            } catch (e) {
                if (this.settingsStore.getDebugSettingsSensitive()?.debugSocketSetup) {
                    this.logger.log("Failed to reauth printer socket", (0, _errorutils.errorSummary)(e));
                }
                (0, _node.captureException)(e);
            }
        }
        await Promise.all(promisesReauth);
        const promisesOpenSocket = [];
        const failedSocketReopened = [];
        for (const socket of Object.values(this.printerSocketAdaptersById)){
            try {
                if (socket.needsSetup() || socket.needsReopen()) {
                    if (this.settingsStore.getDebugSettingsSensitive()?.debugSocketSetup) {
                        this.logger.log(`Reopening socket for printerId '${socket.printerId}' (setup: ${socket.needsSetup()}, reopen: ${socket.needsReopen()})`);
                    }
                    socketSetupRequested++;
                    const promise = socket.setupSocketSession().then(()=>{
                        socket.open();
                    }).catch((_)=>{
                        failedSocketReopened.push(socket.printerId);
                    });
                    promisesOpenSocket.push(promise);
                }
            } catch (e) {
                if (this.settingsStore.getDebugSettingsSensitive()?.debugSocketSetup) {
                    this.logger.log(`Failed to setup printer socket ${(0, _errorutils.errorSummary)(e)}`);
                }
                (0, _node.captureException)(e);
            }
            const keySocket = socket.socketState;
            const valSocket = socketStates[keySocket];
            socketStates[keySocket] = valSocket ? valSocket + 1 : 1;
            const keyApi = socket.apiState;
            const valApi = apiStates[keyApi];
            apiStates[keyApi] = valApi ? valApi + 1 : 1;
        }
        await Promise.all(promisesOpenSocket);
        return {
            reauth: reauthRequested,
            failedSocketReopened,
            failedSocketsReauth,
            socketSetup: socketSetupRequested,
            socket: socketStates,
            api: apiStates
        };
    }
    createOrUpdateSocket(printer) {
        const { enabled, id } = printer;
        let foundAdapter = this.printerSocketAdaptersById[id.toString()];
        if (!enabled) {
            this.logger.log(`Printer is disabled. Deleting socket`);
            this.deleteSocket(id);
            return;
        }
        if (!foundAdapter) {
            foundAdapter = this.socketFactory.createInstance(printer.printerType);
            this.printerSocketAdaptersById[id] = foundAdapter;
        } else {
            foundAdapter.close();
            this.logger.log(`Closing printer socket for update`);
        }
        foundAdapter.registerCredentials({
            printerId: printer.id.toString(),
            loginDto: {
                apiKey: printer.apiKey,
                printerURL: printer.printerURL,
                printerType: printer.printerType
            },
            protocol: "ws"
        });
        foundAdapter.resetSocketState();
    }
    handleBatchPrinterCreated({ printers }) {
        for (const p of printers){
            this.handlePrinterCreated({
                printer: p
            });
        }
    }
    handlePrinterCreated({ printer }) {
        this.createOrUpdateSocket(printer);
    }
    handlePrinterUpdated({ printer }) {
        this.logger.log(`Printer updated. Updating socket`);
        this.createOrUpdateSocket(printer);
    }
    handlePrintersDeleted({ printerIds }) {
        printerIds.forEach((id)=>{
            this.deleteSocket(id);
        });
    }
    subscribeToEvents() {
        this.eventEmitter2.on(_eventconstants.printerEvents.printerCreated, this.handlePrinterCreated.bind(this));
        this.eventEmitter2.on(_eventconstants.printerEvents.printersDeleted, this.handlePrintersDeleted.bind(this));
        this.eventEmitter2.on(_eventconstants.printerEvents.printerUpdated, this.handlePrinterUpdated.bind(this));
        this.eventEmitter2.on(_eventconstants.printerEvents.batchPrinterCreated, this.handleBatchPrinterCreated.bind(this));
    }
    deleteSocket(printerId) {
        const socket = this.printerSocketAdaptersById[printerId];
        if (!!socket) {
            socket.close();
        }
        delete this.printerSocketAdaptersById[printerId];
    }
}

//# sourceMappingURL=printer-socket.store.js.map