aboutsummaryrefslogtreecommitdiff
path: root/src/server/DashSession.ts
blob: 9c36fa17f0d88053bc05843c88fc6c85cf61599d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import { Session } from "./Session/session";
import { Email } from "./ActionUtilities";
import { red, yellow } from "colors";
import { SolrManager } from "./ApiManagers/SearchManager";
import { execSync } from "child_process";
import { isMaster } from "cluster";
import { Utils } from "../Utils";
import { WebSocket } from "./Websocket/Websocket";
import { MessageStore } from "./Message";
import { launchServer } from ".";

const notificationRecipients = ["samuel_wilkins@brown.edu"];
const signature = "-Dash Server Session Manager";

const monitorHooks: Session.MonitorNotifierHooks = {
    key: async (key, masterLog) => {
        const content = `The key for this session (started @ ${new Date().toUTCString()}) is ${key}.\n\n${signature}`;
        const failures = await Email.dispatchAll(notificationRecipients, "Server Termination Key", content);
        if (failures) {
            failures.map(({ recipient, error: { message } }) => masterLog(red(`dispatch failure @ ${recipient} (${yellow(message)})`)));
            return false;
        }
        return true;
    },
    crash: async ({ name, message, stack }, masterLog) => {
        const body = [
            "You, as a Dash Administrator, are being notified of a server crash event. Here's what we know:",
            `name:\n${name}`,
            `message:\n${message}`,
            `stack:\n${stack}`,
            "The server is already restarting itself, but if you're concerned, use the Remote Desktop Connection to monitor progress.",
        ].join("\n\n");
        const content = `${body}\n\n${signature}`;
        const failures = await Email.dispatchAll(notificationRecipients, "Dash Web Server Crash", content);
        if (failures) {
            failures.map(({ recipient, error: { message } }) => masterLog(red(`dispatch failure @ ${recipient} (${yellow(message)})`)));
            return false;
        }
        return true;
    }
};

export class DashSessionAgent extends Session.AppliedSessionAgent {

    /**
    * If we're the monitor (master) thread, we should launch the monitor logic for the session.
    * Otherwise, we must be on a worker thread that was spawned *by* the monitor (master) thread, and thus
    * our job should be to run the server.
    */
    protected async launchImplementation() {
        if (isMaster) {
            this.sessionMonitor = await Session.initializeMonitorThread(monitorHooks);
            this.sessionMonitor.addReplCommand("pull", [], () => execSync("git pull", { stdio: ["ignore", "inherit", "inherit"] }));
            this.sessionMonitor.addReplCommand("solr", [/start|stop/g], args => SolrManager.SetRunning(args[0] === "start"));
        } else {
            this.serverWorker = await Session.initializeWorkerThread(launchServer); // server initialization delegated to worker
            this.serverWorker.addExitHandler(() => Utils.Emit(WebSocket._socket, MessageStore.ConnectionTerminated, "Manual"));
        }
    }

}