"use strict";
/*
 * server component for the TimeLimit App
 * Copyright (C) 2019 - 2026 Jonas Lochmann
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.createWebsocketHandler = void 0;
const events_1 = require("events");
const socket_io_1 = require("socket.io");
const connected_devices_1 = require("../connected-devices");
const rooms_1 = require("./rooms");
const createWebsocketHandler = ({ connectedDevicesManager, database }) => {
    const events = new events_1.EventEmitter();
    // this disables warnings for many listeners
    // this is required because every single socket causes listeners
    events.setMaxListeners(0);
    const eventTriggerImportantSyncForAll = 'triggerimportantsyncforall';
    let socketCounter = 0;
    const server = new socket_io_1.Server({
        allowEIO3: true
    });
    server.on('connection', (socket) => {
        socketCounter++;
        socket.on('disconnect', () => socketCounter--);
        socket.on('devicelogin', (deviceAuthToken, ack) => {
            socket.rooms.forEach((room) => socket.leave(room));
            if (typeof deviceAuthToken !== 'string') {
                return;
            }
            socket.join((0, rooms_1.deviceByAuthTokenRoom)(deviceAuthToken));
            const importantSyncForAllListener = () => {
                setTimeout(() => {
                    if (socket.connected)
                        socket.emit('should sync', { isImportant: true });
                }, Math.random() * 1000 * 60 /* wait up to one minute */);
            };
            events.on(eventTriggerImportantSyncForAll, importantSyncForAllListener);
            socket.on('disconnect', () => events.removeListener(eventTriggerImportantSyncForAll, importantSyncForAllListener));
            (async () => {
                const deviceEntryUnsafe = await database.device.findOne({
                    where: {
                        deviceAuthToken
                    },
                    attributes: ['familyId', 'deviceId']
                });
                if (deviceEntryUnsafe && socket.connected) {
                    const deviceEntry = {
                        familyId: deviceEntryUnsafe.familyId,
                        deviceId: deviceEntryUnsafe.deviceId
                    };
                    const key = connected_devices_1.ConnectedDevicesManager.buildKey({
                        familyId: deviceEntry.familyId,
                        deviceId: deviceEntry.deviceId
                    });
                    connectedDevicesManager.connectedDevicesManager.reportDeviceConnected({ key });
                    const { shutdown } = connectedDevicesManager.observeConnectedDevicesOfFamily({
                        familyId: deviceEntry.familyId,
                        listener: (connectedDevices) => {
                            socket.emit('connected devices', connectedDevices);
                        }
                    });
                    socket.on('disconnect', () => {
                        connectedDevicesManager.connectedDevicesManager.reportDeviceDisconnected({ key });
                        shutdown();
                    });
                }
            })().catch(() => { });
            if (typeof ack === 'function') {
                ack();
            }
        });
    });
    const websocketApi = {
        triggerSyncByDeviceAuthToken: ({ deviceAuthToken, isImportant }) => {
            server
                .to((0, rooms_1.deviceByAuthTokenRoom)(deviceAuthToken))
                .emit('should sync', { isImportant });
        },
        triggerLogoutByDeviceAuthToken: ({ deviceAuthToken }) => {
            server
                .to((0, rooms_1.deviceByAuthTokenRoom)(deviceAuthToken))
                .emit('sign out');
        },
        triggerImportantSyncAtAllDevicesInBackground: () => {
            events.emit(eventTriggerImportantSyncForAll);
        },
        countConnections: () => socketCounter
    };
    return {
        websocketServer: server,
        websocketApi
    };
};
exports.createWebsocketHandler = createWebsocketHandler;
//# sourceMappingURL=index.js.map