diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/ProcessFactory.ts (renamed from src/server/ChildProcessUtilities/ProcessFactory.ts) | 25 | ||||
-rw-r--r-- | src/server/index.ts | 2 | ||||
-rw-r--r-- | src/server/session_manager/config.ts | 32 | ||||
-rw-r--r-- | src/server/session_manager/input_manager.ts | 101 | ||||
-rw-r--r-- | src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log | 1 | ||||
-rw-r--r-- | src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log | 1 | ||||
-rw-r--r-- | src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log | 1 | ||||
-rw-r--r-- | src/server/session_manager/logs/current_daemon_pid.log | 1 | ||||
-rw-r--r-- | src/server/session_manager/logs/current_server_pid.log | 1 | ||||
-rw-r--r-- | src/server/session_manager/logs/current_session_manager_pid.log | 1 | ||||
-rw-r--r-- | src/server/session_manager/session_manager.ts (renamed from src/server/ChildProcessUtilities/daemon/session.ts) | 48 |
11 files changed, 158 insertions, 56 deletions
diff --git a/src/server/ChildProcessUtilities/ProcessFactory.ts b/src/server/ProcessFactory.ts index 745b1479a..acb8b3a99 100644 --- a/src/server/ChildProcessUtilities/ProcessFactory.ts +++ b/src/server/ProcessFactory.ts @@ -1,10 +1,8 @@ import { existsSync, mkdirSync } from "fs"; -import { pathFromRoot, log_execution, fileDescriptorFromStream } from '../ActionUtilities'; -import { red, green } from "colors"; +import { pathFromRoot, fileDescriptorFromStream } from './ActionUtilities'; import rimraf = require("rimraf"); import { ChildProcess, spawn, StdioOptions } from "child_process"; import { Stream } from "stream"; -import { resolve } from "path"; export namespace ProcessFactory { @@ -20,27 +18,6 @@ export namespace ProcessFactory { return child; } - export namespace NamedAgents { - - export async function persistenceDaemon() { - await log_execution({ - startMessage: "\ninitializing persistence daemon", - endMessage: ({ result, error }) => { - const success = error === null && result !== undefined; - if (!success) { - console.log(red("failed to initialize the persistance daemon")); - console.log(error); - process.exit(0); - } - return "failsafe daemon process successfully spawned"; - }, - action: () => createWorker('npx', ['ts-node', resolve(__dirname, "./daemon/persistence_daemon.ts")], ["ignore", "inherit", "inherit"]), - color: green - }); - console.log(); - } - } - } export namespace Logger { diff --git a/src/server/index.ts b/src/server/index.ts index bc481e579..2cc35ccec 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -23,7 +23,7 @@ import GeneralGoogleManager from "./ApiManagers/GeneralGoogleManager"; import GooglePhotosManager from "./ApiManagers/GooglePhotosManager"; import { yellow, red } from "colors"; import { disconnect } from "../server/Initialization"; -import { ProcessFactory, Logger } from "./ChildProcessUtilities/ProcessFactory"; +import { ProcessFactory, Logger } from "./ProcessFactory"; export const publicDirectory = path.resolve(__dirname, "public"); export const filesDirectory = path.resolve(publicDirectory, "files"); diff --git a/src/server/session_manager/config.ts b/src/server/session_manager/config.ts new file mode 100644 index 000000000..47d3375e0 --- /dev/null +++ b/src/server/session_manager/config.ts @@ -0,0 +1,32 @@ +import { resolve } from 'path'; +import { yellow } from "colors"; + +export const latency = 10; +export const ports = [1050, 4321]; +export const onWindows = process.platform === "win32"; +export const LOCATION = "http://localhost"; +export const heartbeat = `${LOCATION}:1050/serverHeartbeat`; +export const recipient = "samuel_wilkins@brown.edu"; +export const { pid, platform } = process; + +/** + * Logging + */ +export const identifier = yellow("__session_manager__:"); + +/** + * Paths + */ +export const logPath = resolve(__dirname, "./logs"); +export const crashPath = resolve(logPath, "./crashes"); + +/** + * State + */ +export enum SessionState { + INITIALIZING, + LISTENING, + AUTOMATIC_RESTART, + MANUAL_RESTART, + EXITING +}
\ No newline at end of file diff --git a/src/server/session_manager/input_manager.ts b/src/server/session_manager/input_manager.ts new file mode 100644 index 000000000..a95e6baae --- /dev/null +++ b/src/server/session_manager/input_manager.ts @@ -0,0 +1,101 @@ +import { createInterface, Interface } from "readline"; +import { red } from "colors"; + +export interface Configuration { + identifier: string; + onInvalid?: (culprit?: string) => string | string; + isCaseSensitive?: boolean; +} + +export interface Registration { + argPattern: RegExp[]; + action: (parsedArgs: IterableIterator<string>) => any | Promise<any>; +} + +export default class InputManager { + private identifier: string; + private onInvalid: ((culprit?: string) => string) | string; + private isCaseSensitive: boolean; + private commandMap = new Map<string, Registration[]>(); + public interface: Interface; + private busy = false; + private keys: string | undefined; + + constructor({ identifier: prompt, onInvalid, isCaseSensitive }: Configuration) { + this.identifier = prompt; + this.onInvalid = onInvalid || this.usage; + this.isCaseSensitive = isCaseSensitive ?? true; + this.interface = createInterface(process.stdin, process.stdout).on('line', this.considerInput); + } + + private usage = () => { + const resolved = this.keys; + if (resolved) { + return resolved; + } + const members: string[] = []; + const keys = this.commandMap.keys(); + let next: IteratorResult<string>; + while (!(next = keys.next()).done) { + members.push(next.value); + } + return `${this.identifier} commands: { ${members.sort().join(", ")} }`; + } + + public registerCommand = (basename: string, argPattern: RegExp[], action: any | Promise<any>) => { + const existing = this.commandMap.get(basename); + const registration = { argPattern, action }; + if (existing) { + existing.push(registration); + } else { + this.commandMap.set(basename, [registration]); + } + } + + private invalid = (culprit?: string) => { + console.log(red(typeof this.onInvalid === "string" ? this.onInvalid : this.onInvalid(culprit))); + this.busy = false; + } + + private considerInput = async (line: string) => { + if (this.busy) { + console.log(red("Busy")); + return; + } + this.busy = true; + line = line.trim(); + if (this.isCaseSensitive) { + line = line.toLowerCase(); + } + const [command, ...args] = line.split(/\s+/g); + if (!command) { + return this.invalid(); + } + const registered = this.commandMap.get(command); + if (registered) { + const { length } = args; + const candidates = registered.filter(({ argPattern: { length: count } }) => count === length); + for (const { argPattern, action } of candidates) { + const parsed: string[] = []; + let matched = false; + if (length) { + for (let i = 0; i < length; i++) { + let matches: RegExpExecArray | null; + if ((matches = argPattern[i].exec(args[i])) === null) { + break; + } + parsed.push(matches[0]); + } + matched = true; + } + if (!length || matched) { + await action(parsed[Symbol.iterator]()); + this.busy = false; + return; + } + } + } + this.invalid(command); + } + +}
\ No newline at end of file diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log new file mode 100644 index 000000000..4cab8a6a3 --- /dev/null +++ b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log @@ -0,0 +1 @@ +[31mDetected a server crash @ 2019-12-11T18:52:20.416Z.[39m diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log new file mode 100644 index 000000000..3c226445d --- /dev/null +++ b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log @@ -0,0 +1 @@ +[31mDetected a server crash @ 2019-12-12T00:38:54.828Z.[39m diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log new file mode 100644 index 000000000..59f14f288 --- /dev/null +++ b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log @@ -0,0 +1 @@ +[31mDetected a server crash @ 2019-12-12T00:42:21.970Z.[39m diff --git a/src/server/session_manager/logs/current_daemon_pid.log b/src/server/session_manager/logs/current_daemon_pid.log new file mode 100644 index 000000000..557e3d7c3 --- /dev/null +++ b/src/server/session_manager/logs/current_daemon_pid.log @@ -0,0 +1 @@ +26860 diff --git a/src/server/session_manager/logs/current_server_pid.log b/src/server/session_manager/logs/current_server_pid.log new file mode 100644 index 000000000..6a2f267b3 --- /dev/null +++ b/src/server/session_manager/logs/current_server_pid.log @@ -0,0 +1 @@ +50888 created @ 2019-12-14T06:59:59.767Z diff --git a/src/server/session_manager/logs/current_session_manager_pid.log b/src/server/session_manager/logs/current_session_manager_pid.log new file mode 100644 index 000000000..ab19403b4 --- /dev/null +++ b/src/server/session_manager/logs/current_session_manager_pid.log @@ -0,0 +1 @@ +50846 diff --git a/src/server/ChildProcessUtilities/daemon/session.ts b/src/server/session_manager/session_manager.ts index fb2b3551e..6e9b03c79 100644 --- a/src/server/ChildProcessUtilities/daemon/session.ts +++ b/src/server/session_manager/session_manager.ts @@ -1,40 +1,33 @@ import * as request from "request-promise"; -import { log_execution, pathFromRoot } from "../../ActionUtilities"; +import { log_execution, pathFromRoot } from "../ActionUtilities"; import { red, yellow, cyan, green, Color } from "colors"; import * as nodemailer from "nodemailer"; import { MailOptions } from "nodemailer/lib/json-transport"; import { writeFileSync, existsSync, mkdirSync } from "fs"; import { resolve } from 'path'; import { ChildProcess, exec, execSync } from "child_process"; -import { createInterface } from "readline"; +import InputManager from "./input_manager"; +import { identifier, logPath, crashPath, onWindows, pid, ports, heartbeat, recipient, LOCATION, latency } from "./config"; const killport = require("kill-port"); process.on('SIGINT', endPrevious); -const identifier = yellow("__session_manager__:"); + +const { registerCommand } = new InputManager({ identifier }); let manualRestartActive = false; -createInterface(process.stdin, process.stdout).on('line', async line => { - const prompt = line.trim().toLowerCase(); - switch (prompt) { - case "restart": - manualRestartActive = true; - identifiedLog(cyan("Initializing manual restart...")); - await endPrevious(); - break; - case "exit": - identifiedLog(cyan("Initializing session end")); - await endPrevious(); - identifiedLog("Cleanup complete. Exiting session...\n"); - execSync(killAllCommand()); - break; - default: - identifiedLog(red("commands: { exit, restart }")); - return; - } +registerCommand("restart", [], async () => { + manualRestartActive = true; + identifiedLog(cyan("Initializing manual restart...")); + await endPrevious(); +}); + +registerCommand("exit", [], async () => { + identifiedLog(cyan("Initializing session end")); + await endPrevious(); + identifiedLog("Cleanup complete. Exiting session...\n"); + execSync(killAllCommand()); }); -const logPath = resolve(__dirname, "./logs"); -const crashPath = resolve(logPath, "./crashes"); if (!existsSync(logPath)) { mkdirSync(logPath); } @@ -58,13 +51,6 @@ if (!["win32", "darwin"].includes(process.platform)) { process.exit(1); } -const latency = 10; -const ports = [1050, 4321]; -const onWindows = process.platform === "win32"; -const LOCATION = "http://localhost"; -const heartbeat = `${LOCATION}:1050/serverHeartbeat`; -const recipient = "samuel_wilkins@brown.edu"; -const { pid } = process; let restarting = false; let count = 0; @@ -98,7 +84,7 @@ function timestamp() { async function endPrevious() { identifiedLog(yellow("Cleaning up previous connections...")); - current_backup?.kill("SIGTERM"); + current_backup?.kill("SIGKILL"); await Promise.all(ports.map(port => { const task = killport(port, 'tcp'); return task.catch((error: any) => identifiedLog(red(error))); |