"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.localSocketBroadcast = exports.localSocket = exports.cloud = void 0;
const node_http_1 = __importDefault(require("node:http"));
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const ws_1 = require("ws");
const is_reachable_1 = __importDefault(require("is-reachable"));
const TOML = __importStar(require("@ltd/j-toml"));
const deep_extend_1 = __importDefault(require("deep-extend"));
const logging_1 = require("./logging");
const cloudapi_1 = require("./modules/ocs2/cloudapi");
const pl2_1 = require("./modules/pl2");
const wsConnectionHandler_1 = require("./ws/wsConnectionHandler");
const systemStateContainer_1 = require("./state/systemStateContainer");
logging_1.log.info("Starting Sineware ProLinuxD... 🚀");
const localSocketBroadcast = (msg) => {
    exports.localSocket.clients.forEach((client) => {
        if (client.readyState === ws_1.WebSocket.OPEN) {
            client.send(JSON.stringify(msg));
        }
    });
};
exports.localSocketBroadcast = localSocketBroadcast;
let cleanupFunctions = [];
async function main() {
    // Read configuration file
    logging_1.log.info("Loading base system configuration...");
    try {
        const tomlConfig = TOML.parse(node_fs_1.default.readFileSync(process.env.CONFIG_FILE ?? node_path_1.default.join(__dirname, "prolinux.toml"), "utf-8"));
        systemStateContainer_1.state.config = (0, deep_extend_1.default)(systemStateContainer_1.state.config, tomlConfig);
        logging_1.log.info("Configuration file loaded!");
        logging_1.log.info(JSON.stringify(systemStateContainer_1.state.config, null, 4));
    }
    catch (e) {
        console.log(e);
        logging_1.log.error("Could not load configuration file, resetting to default... " + e?.message);
        let tomlConfig = TOML.stringify(systemStateContainer_1.state.config, {
            newline: "\n"
        });
        node_fs_1.default.writeFileSync(process.env.CONFIG_FILE ?? node_path_1.default.join(__dirname, "prolinux.toml"), Buffer.from(tomlConfig), "utf-8");
    }
    // Read extra-config json file
    logging_1.log.info("Loading extra configuration...");
    try {
        const extraConfig = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(node_path_1.default.dirname(process.env.CONFIG_FILE ?? node_path_1.default.join(__dirname, "prolinux.toml")), "extra-config.json"), "utf-8"));
        systemStateContainer_1.state.extraConfig = (0, deep_extend_1.default)(systemStateContainer_1.state.extraConfig, extraConfig);
        logging_1.log.info("Extra configuration file loaded!");
        logging_1.log.info(JSON.stringify(systemStateContainer_1.state.extraConfig, null, 4));
    }
    catch (e) {
        console.log(e);
        logging_1.log.error("Could not load extra configuration file, resetting to default... " + e?.message);
        let extraConfig = JSON.stringify(systemStateContainer_1.state.extraConfig, null, 4);
        node_fs_1.default.writeFileSync(node_path_1.default.join(node_path_1.default.dirname(process.env.CONFIG_FILE ?? node_path_1.default.join(__dirname, "prolinux.toml")), "extra-config.json"), Buffer.from(extraConfig), "utf-8");
    }
    try {
        node_fs_1.default.unlinkSync("/tmp/prolinuxd.sock");
    }
    catch (err) { }
    // Local websocket server (/tmp/prolinuxd.sock)
    const server = node_http_1.default.createServer();
    const wss = new ws_1.WebSocket.Server({ server });
    exports.localSocket = wss;
    wss.on("connection", (socket) => {
        (0, wsConnectionHandler_1.wsConnectionHandler)(socket, systemStateContainer_1.state.config, exports.cloud, exports.localSocketBroadcast);
    });
    wss.on("error", (err) => {
        logging_1.log.error("WS Server error: " + err.message);
        console.log(err);
    });
    server.listen("/tmp/prolinuxd.sock");
    server.on("listening", async () => {
        node_fs_1.default.chmodSync("/tmp/prolinuxd.sock", 666);
        logging_1.log.info("ProLinuxD is listening on /tmp/prolinuxd.sock!");
        if (systemStateContainer_1.state.config.prolinuxd.modules.includes("ocs2") && systemStateContainer_1.state.config.ocs2?.access_token !== "") {
            logging_1.log.info("Connecting to Sineware Cloud...");
            let attempts = 0;
            let attemptCloudConnection = () => {
                (0, is_reachable_1.default)("update.sineware.ca").then((reachable) => {
                    if (reachable) {
                        exports.cloud = new cloudapi_1.OCS2Connection();
                    }
                    else {
                        if (attempts >= 100) {
                            logging_1.log.error("Could not connect to Sineware Cloud Services, giving up.");
                        }
                        else {
                            logging_1.log.info("Could not connect to Sineware Cloud Services, retrying in 5 seconds...");
                            setTimeout(attemptCloudConnection, 5000);
                        }
                        attempts++;
                    }
                });
            };
            attemptCloudConnection();
        }
        if (systemStateContainer_1.state.config.prolinuxd.modules.includes("pl2")) {
            logging_1.log.info("Starting ProLinux 2 Module...");
            let cleanup = await (0, pl2_1.loadPL2Module)();
            cleanupFunctions.push(cleanup);
        }
        if (systemStateContainer_1.state.config.pl2.remote_api) {
            // create a new wss server on port 25567 using wsConnectionHandler
            const remoteServer = node_http_1.default.createServer();
            const remoteWss = new ws_1.WebSocket.Server({ server: remoteServer });
            remoteWss.on("connection", (socket) => {
                // todo check for auth
                (0, wsConnectionHandler_1.wsConnectionHandler)(socket, systemStateContainer_1.state.config, exports.cloud, exports.localSocketBroadcast);
            });
            remoteWss.on("error", (err) => {
                logging_1.log.error("Remote WS Server error: " + err.message);
                console.log(err);
            });
            remoteServer.listen(25567);
            remoteServer.on("listening", async () => {
                logging_1.log.info("Remote API is listening on port 25567!");
            });
        }
    });
}
try {
    // setup cleanup on exit
    process.on("exit", () => {
        logging_1.log.info("Shutting down ProLinuxD...");
        cleanupFunctions.forEach((cleanup) => {
            cleanup();
        });
    });
    main();
}
catch (err) {
    logging_1.log.error("Fatal error: " + err);
    console.log(err);
}
//# sourceMappingURL=index.js.map