"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.OCS2Connection = void 0;
const node_child_process_1 = require("node:child_process");
const node_fs_1 = __importDefault(require("node:fs"));
const uuid_1 = require("uuid");
const ws_1 = __importDefault(require("ws"));
const logging_1 = require("../../logging");
const index_1 = require("../../index");
const systemStateContainer_1 = require("../../state/systemStateContainer");
const config = systemStateContainer_1.state.config;
async function spawnChild(command) {
    const child = (0, node_child_process_1.spawn)('/bin/sh', ["-c", command]);
    let data = "";
    for await (const chunk of child.stdout) {
        console.log('stdout chunk: ' + chunk);
        data += chunk;
    }
    for await (const chunk of child.stderr) {
        console.error('stderr chunk: ' + chunk);
        data += chunk;
    }
    const exitCode = await new Promise((resolve, reject) => {
        child.on('close', resolve);
    });
    return { data, exitCode };
}
class OCS2Connection {
    ready = false;
    connected = false;
    ws;
    uuid;
    constructor() {
        this.startCloudConnection();
    }
    startCloudConnection() {
        this.ws = new ws_1.default(config.ocs2.gateway_url);
        this.ws.on('open', () => {
            logging_1.log.info("Connected to the Sineware Cloud Gateway!");
            this.connected = true;
        });
        this.ws.on('message', async (data) => {
            try {
                let msg = JSON.parse(data.toString());
                if (msg.payload?.forAction !== "ping" && msg.action !== "device-stream-terminal") {
                    console.log(msg);
                }
                if (msg.action === "hello" && msg.payload.status) {
                    let machineID = node_fs_1.default.readFileSync("/etc/machine-id", "utf-8").trim();
                    let hostname = node_fs_1.default.readFileSync("/etc/hostname", "utf-8").trim();
                    this.uuid = machineID;
                    let org = await this.callWS("device-hello", {
                        clientType: config.ocs2.client_type,
                        accessToken: config.ocs2.access_token,
                        uuid: machineID,
                        name: hostname
                    });
                    logging_1.log.info(JSON.stringify(org));
                    setInterval(() => {
                        this.callWS("ping", { text: "" }, false);
                    }, 10000);
                    this.ready = true;
                }
                else if (msg.action === "device-stream-terminal") {
                    if (!msg.payload.fromDevice) {
                        index_1.localSocket.clients.forEach((client) => {
                            //console.log("Sending message to client: " + msg.payload.text)
                            client.send(JSON.stringify({
                                action: "device-stream-terminal",
                                payload: {
                                    data: msg.payload.text
                                }
                            }));
                        });
                    }
                }
                else if (msg.action === "device-exec") {
                    let payload = msg.payload;
                    if (!payload.fromDevice) {
                        let { data, exitCode } = await spawnChild(payload.command);
                        this.callWS("device-exec", {
                            deviceUUID: payload.deviceUUID,
                            fromDevice: true,
                            fromUUID: payload.fromUUID,
                            idWrapper: payload.idWrapper,
                            command: payload.command,
                            data,
                            exitCode: exitCode.toString()
                        }, false);
                    }
                }
            }
            catch (e) {
                logging_1.log.error("Error while parsing message from Sineware Cloud Gateway: " + e);
            }
        });
        this.ws.on('error', (err) => {
            logging_1.log.info("Error while connecting to Sineware Cloud Gateway: " + err.message);
            console.error(err);
            // try to reconnect
            console.log("Reconnecting... " + err.message);
            this.startCloudConnection();
        });
        this.ws.on('close', (code, reason) => {
            console.error("Connection closed: " + code + " " + reason);
            // try to reconnect
            console.log("Reconnecting..." + reason);
            this.startCloudConnection();
        });
    }
    ;
    callWS(action, payload, promise = true) {
        if (!this.connected) {
            return new Promise((resolve, reject) => {
                resolve({});
            });
        }
        return new Promise((resolve, reject) => {
            let id = (0, uuid_1.v4)();
            let msg = { action, payload, id };
            //console.log("[Call] Sending message: " + JSON.stringify(msg));
            if (promise) {
                const listener = (e) => {
                    let msg = JSON.parse(e.data);
                    if (msg.id === id) {
                        if (msg.payload.status) {
                            resolve(msg.payload.data);
                        }
                        else {
                            reject(new Error(msg.payload.data.msg));
                        }
                        this.ws?.removeEventListener("message", listener);
                    }
                };
                this.ws?.addEventListener("message", listener);
            }
            this.ws?.send(JSON.stringify(msg));
            if (!promise)
                resolve({});
        });
    }
}
exports.OCS2Connection = OCS2Connection;
//# sourceMappingURL=cloudapi.js.map