"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DashboardServer = void 0;
const express_1 = __importDefault(require("express"));
const path_1 = __importDefault(require("path"));
const get_port_1 = __importDefault(require("get-port"));
const open_1 = __importDefault(require("open"));
const uuid_1 = require("uuid");
const config_1 = __importDefault(require("@truffle/config"));
const dashboard_message_bus_common_1 = require("@truffle/dashboard-message-bus-common");
const dashboard_message_bus_1 = require("@truffle/dashboard-message-bus");
const dashboard_message_bus_client_1 = require("@truffle/dashboard-message-bus-client");
const cors_1 = __importDefault(require("cors"));
const debug_1 = __importDefault(require("debug"));
class DashboardServer {
    constructor(options) {
        var _a, _b, _c, _d;
        this.host = (_a = options.host) !== null && _a !== void 0 ? _a : "localhost";
        this.port = options.port;
        this.configPublishPort = options.publishPort;
        this.configSubscribePort = options.subscribePort;
        this.rpc = (_b = options.rpc) !== null && _b !== void 0 ? _b : true;
        this.verbose = (_c = options.verbose) !== null && _c !== void 0 ? _c : false;
        this.autoOpen = (_d = options.autoOpen) !== null && _d !== void 0 ? _d : true;
        this.frontendPath = path_1.default.join(__dirname, "dashboard-frontend");
        this.boundTerminateListener = () => this.stop();
    }
    get subscribePort() {
        var _a;
        return (_a = this.messageBus) === null || _a === void 0 ? void 0 : _a.subscribePort;
    }
    get publishPort() {
        var _a;
        return (_a = this.messageBus) === null || _a === void 0 ? void 0 : _a.subscribePort;
    }
    start() {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            if ((_a = this.httpServer) === null || _a === void 0 ? void 0 : _a.listening) {
                return;
            }
            this.messageBus = yield this.startMessageBus();
            this.expressApp = (0, express_1.default)();
            this.expressApp.use((0, cors_1.default)());
            this.expressApp.use(express_1.default.json());
            this.expressApp.get("/ports", this.getPorts.bind(this));
            if (this.rpc) {
                yield this.connectToMessageBus();
                this.expressApp.post("/rpc", this.postRpc.bind(this));
            }
            this.expressApp.get("/analytics", (_req, res) => {
                const userConfig = config_1.default.getUserConfig();
                res.json({
                    enableAnalytics: userConfig.get("enableAnalytics"),
                    analyticsSet: userConfig.get("analyticsSet"),
                    analyticsMessageDateTime: userConfig.get("analyticsMessageDateTime")
                });
            });
            this.expressApp.put("/analytics", (req, _res) => {
                const { value } = req.body;
                const userConfig = config_1.default.getUserConfig();
                const uid = userConfig.get("uniqueId");
                if (!uid)
                    userConfig.set("uniqueId", (0, uuid_1.v4)());
                userConfig.set({
                    enableAnalytics: !!value,
                    analyticsSet: true,
                    analyticsMessageDateTime: Date.now()
                });
            });
            this.expressApp.use(express_1.default.static(this.frontendPath));
            this.expressApp.get("*", (_req, res) => {
                res.sendFile("index.html", { root: this.frontendPath });
            });
            yield new Promise(resolve => {
                this.httpServer = this.expressApp.listen(this.port, this.host, () => {
                    if (this.autoOpen) {
                        const host = this.host === "0.0.0.0" ? "localhost" : this.host;
                        (0, open_1.default)(`http://${host}:${this.port}`);
                    }
                    resolve();
                });
            });
        });
    }
    stop() {
        var _a, _b, _c;
        return __awaiter(this, void 0, void 0, function* () {
            (_a = this.messageBus) === null || _a === void 0 ? void 0 : _a.off("terminate", this.boundTerminateListener);
            yield Promise.all([
                (_b = this.client) === null || _b === void 0 ? void 0 : _b.close(),
                (_c = this.messageBus) === null || _c === void 0 ? void 0 : _c.terminate(),
                new Promise(resolve => {
                    var _a;
                    (_a = this.httpServer) === null || _a === void 0 ? void 0 : _a.close(() => resolve());
                })
            ]);
            delete this.client;
        });
    }
    getPorts(req, res) {
        if (!this.messageBus) {
            throw new Error("Message bus has not been started yet");
        }
        res.json({
            dashboardPort: this.port,
            subscribePort: this.messageBus.subscribePort,
            publishPort: this.messageBus.publishPort
        });
    }
    postRpc(req, res, next) {
        if (!this.client) {
            throw new Error("Not connected to message bus");
        }
        this.client
            .publish({ type: dashboard_message_bus_common_1.dashboardProviderMessageType, payload: req.body })
            .then(lifecycle => lifecycle.response)
            .then(response => res.json(response === null || response === void 0 ? void 0 : response.payload))
            .catch(next);
    }
    startMessageBus() {
        var _a, _b;
        return __awaiter(this, void 0, void 0, function* () {
            const subscribePort = (_a = this.configSubscribePort) !== null && _a !== void 0 ? _a : (yield (0, get_port_1.default)({ host: this.host }));
            const publishPort = (_b = this.configPublishPort) !== null && _b !== void 0 ? _b : (yield (0, get_port_1.default)({ host: this.host }));
            const messageBus = new dashboard_message_bus_1.DashboardMessageBus(publishPort, subscribePort, this.host);
            yield messageBus.start();
            messageBus.on("terminate", this.boundTerminateListener);
            return messageBus;
        });
    }
    connectToMessageBus() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.messageBus) {
                throw new Error("Message bus has not been started yet");
            }
            if (this.client) {
                return;
            }
            this.client = new dashboard_message_bus_client_1.DashboardMessageBusClient({
                host: this.host,
                subscribePort: this.messageBus.subscribePort,
                publishPort: this.messageBus.publishPort
            });
            yield this.client.ready();
            // the promise returned by `setupVerboseLogging` never resolves, so don't
            // bother awaiting it.
            this.setupVerboseLogging();
        });
    }
    setupVerboseLogging() {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.verbose && this.client) {
                this.client
                    .subscribe({ type: dashboard_message_bus_common_1.logMessageType })
                    .on("message", lifecycle => {
                    if (lifecycle && lifecycle.message.type === "log") {
                        const logMessage = lifecycle.message;
                        const debug = (0, debug_1.default)(logMessage.payload.namespace);
                        debug.enabled = true;
                        debug(logMessage.payload.message);
                    }
                });
            }
        });
    }
}
exports.DashboardServer = DashboardServer;
//# sourceMappingURL=DashboardServer.js.map