From 4ed6fd76752d60c617d9a396193ab6d8195dac1c Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 10 Dec 2019 21:08:39 -0500 Subject: persistence daemon improvement, relaxed dummy gmail account security to allow messages --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'package.json') diff --git a/package.json b/package.json index dc2b1f5d0..1689194db 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "start-release": "cross-env RELEASE=true NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", - "start": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", + "start": "cross-env LOCATION=http://localhost NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", "debug": "cross-env NODE_OPTIONS=--max_old_space_size=8192 ts-node-dev --inspect -- src/server/index.ts", "build": "cross-env NODE_OPTIONS=--max_old_space_size=8192 webpack --env production", "test": "mocha -r ts-node/register test/**/*.ts", @@ -230,4 +230,4 @@ "xoauth2": "^1.2.0", "youtube": "^0.1.0" } -} +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 6665483b80ff6874cf9cc7c9cb3f7e58fcec20ca Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 10 Dec 2019 23:40:42 -0500 Subject: persistance daemon improvements --- ...npx ts-node-20965-Wed, 11 Dec 2019 03:38:32 GMT | 0 package.json | 3 +- src/server/ActionUtilities.ts | 13 ++- src/server/ProcessManager.ts | 45 +++++++++++ src/server/daemon/persistence_daemon.ts | 92 ++++++++++++++++++++++ src/server/index.ts | 13 ++- src/server/persistence_daemon.ts | 82 ------------------- 7 files changed, 163 insertions(+), 85 deletions(-) create mode 100644 logs/npx ts-node-20965-Wed, 11 Dec 2019 03:38:32 GMT create mode 100644 src/server/ProcessManager.ts create mode 100644 src/server/daemon/persistence_daemon.ts delete mode 100644 src/server/persistence_daemon.ts (limited to 'package.json') diff --git a/logs/npx ts-node-20965-Wed, 11 Dec 2019 03:38:32 GMT b/logs/npx ts-node-20965-Wed, 11 Dec 2019 03:38:32 GMT new file mode 100644 index 000000000..e69de29bb diff --git a/package.json b/package.json index 1689194db..97563e137 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "start-release": "cross-env RELEASE=true NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", - "start": "cross-env LOCATION=http://localhost NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", + "start-spawn": "cross-env SPAWNED=true NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", + "start": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", "debug": "cross-env NODE_OPTIONS=--max_old_space_size=8192 ts-node-dev --inspect -- src/server/index.ts", "build": "cross-env NODE_OPTIONS=--max_old_space_size=8192 webpack --env production", "test": "mocha -r ts-node/register test/**/*.ts", diff --git a/src/server/ActionUtilities.ts b/src/server/ActionUtilities.ts index bc978c982..2173f4369 100644 --- a/src/server/ActionUtilities.ts +++ b/src/server/ActionUtilities.ts @@ -1,12 +1,16 @@ import * as fs from 'fs'; import { ExecOptions } from 'shelljs'; -import { exec } from 'child_process'; +import { exec, spawn } from 'child_process'; import * as path from 'path'; import * as rimraf from "rimraf"; import { yellow, Color } from 'colors'; const projectRoot = path.resolve(__dirname, "../../"); +export function pathFromRoot(relative: string) { + return path.resolve(projectRoot, relative); +} + export const command_line = (command: string, fromDirectory?: string) => { return new Promise((resolve, reject) => { const options: ExecOptions = {}; @@ -17,6 +21,13 @@ export const command_line = (command: string, fromDirectory?: string) => { }); }; +export async function spawn_detached_process(command: string, args?: readonly string[]) { + const out = path.resolve(projectRoot, `./logs/${command}-${process.pid}-${new Date().toUTCString()}`); + const child_out = fs.openSync(out, 'a'); + const child_error = fs.openSync(out, 'a'); + spawn(command, args, { detached: true, stdio: ["ignore", child_out, child_error] }).unref(); +} + export const read_text_file = (relativePath: string) => { const target = path.resolve(__dirname, relativePath); return new Promise((resolve, reject) => { diff --git a/src/server/ProcessManager.ts b/src/server/ProcessManager.ts new file mode 100644 index 000000000..2237f9e1b --- /dev/null +++ b/src/server/ProcessManager.ts @@ -0,0 +1,45 @@ +import { writeFileSync, unlinkSync, existsSync, mkdirSync } from "fs"; +import { pathFromRoot, log_execution, spawn_detached_process } from './ActionUtilities'; +import { resolve } from "path"; +import { red, yellow } from "colors"; + +const daemonPath = pathFromRoot("./src/server/daemon/persistence_daemon.ts"); + +export namespace ProcessManager { + + export async function initialize() { + const logPath = pathFromRoot("./logs"); + const filePath = resolve(logPath, "./server_pids.txt"); + const exists = existsSync(logPath); + if (exists) { + unlinkSync(filePath); + } else { + mkdirSync(logPath); + } + const { pid } = process; + if (process.env.SPAWNED === "true") { + writeFileSync(filePath, `${pid} created at ${new Date().toUTCString()}\n`); + } + } + + let daemonInitialized = false; + export async function trySpawnDaemon() { + if (!daemonInitialized) { + daemonInitialized = true; + 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")); + process.exit(0); + } + return "persistence daemon process closed"; + }, + action: () => spawn_detached_process("npx ts-node", [daemonPath]), + color: yellow + }); + } + } + +} \ No newline at end of file diff --git a/src/server/daemon/persistence_daemon.ts b/src/server/daemon/persistence_daemon.ts new file mode 100644 index 000000000..3eb17a9b4 --- /dev/null +++ b/src/server/daemon/persistence_daemon.ts @@ -0,0 +1,92 @@ +import * as request from "request-promise"; +import { log_execution, spawn_detached_process } from "../ActionUtilities"; +import { red, yellow, cyan, green } from "colors"; +import * as nodemailer from "nodemailer"; +import { MailOptions } from "nodemailer/lib/json-transport"; +import { writeFileSync } from "fs"; +import { resolve } from 'path'; + +const LOCATION = "http://localhost"; +const recipient = "samuel_wilkins@brown.edu"; +let restarting = false; + +writeFileSync(resolve(__dirname, "./current_pid.txt"), process.pid); + +function timestamp() { + return `@ ${new Date().toISOString()}`; +} + +async function listen() { + if (!LOCATION) { + console.log(red("No location specified for persistence daemon. Please include as a command line environment variable or in a .env file.")); + process.exit(0); + } + const heartbeat = `${LOCATION}:1050/serverHeartbeat`; + // if this is on our remote server, the server must be run in release mode + // const suffix = LOCATION.includes("localhost") ? "" : "-release"; + setInterval(async () => { + let error: any; + try { + await request.get(heartbeat); + } catch (e) { + error = e; + } finally { + if (error) { + if (!restarting) { + restarting = true; + console.log(yellow("Detected a server crash!")); + await log_execution({ + startMessage: "Sending crash notification email", + endMessage: ({ error, result }) => { + const success = error === null && result === true; + return (success ? `Notification successfully sent to ` : `Failed to notify `) + recipient; + }, + action: async () => notify(error || "Hmm, no error to report..."), + color: cyan + }); + console.log(await log_execution({ + startMessage: "Initiating server restart", + endMessage: "Server successfully restarted", + action: () => spawn_detached_process(`npm run start-spawn`), + color: green + })); + restarting = false; + } else { + console.log(yellow(`Callback ignored because restarting already initiated ${timestamp()}`)); + } + } else { + console.log(green(`No issues detected ${timestamp()}`)); + } + } + }, 1000 * 10); +} + +function emailText(error: any) { + return [ + `Hey ${recipient.split("@")[0]},`, + "You, as a Dash Administrator, are being notified of a server crash event. Here's what we know:", + `Location: ${LOCATION}\nError: ${error}`, + "The server should already be restarting itself, but if you're concerned, use the Remote Desktop Connection to monitor progress." + ].join("\n\n"); +} + +async function notify(error: any) { + const smtpTransport = nodemailer.createTransport({ + service: 'Gmail', + auth: { + user: 'brownptcdash@gmail.com', + pass: 'browngfx1' + } + }); + const mailOptions = { + to: recipient, + from: 'brownptcdash@gmail.com', + subject: 'Dash Server Crash', + text: emailText(error) + } as MailOptions; + return new Promise(resolve => { + smtpTransport.sendMail(mailOptions, (dispatchError: Error | null) => { console.log(dispatchError); resolve(dispatchError === null); }); + }); +} + +listen(); \ No newline at end of file diff --git a/src/server/index.ts b/src/server/index.ts index 7671936a2..795418b31 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -18,11 +18,12 @@ import { GoogleCredentialsLoader } from './credentials/CredentialsLoader'; import DeleteManager from "./ApiManagers/DeleteManager"; import PDFManager from "./ApiManagers/PDFManager"; import UploadManager from "./ApiManagers/UploadManager"; -import { log_execution, command_line } from "./ActionUtilities"; +import { log_execution } from "./ActionUtilities"; import GeneralGoogleManager from "./ApiManagers/GeneralGoogleManager"; import GooglePhotosManager from "./ApiManagers/GooglePhotosManager"; import { yellow, red } from "colors"; import { disconnect } from "../server/Initialization"; +import { ProcessManager } from "./ProcessManager"; export const publicDirectory = path.resolve(__dirname, "public"); export const filesDirectory = path.resolve(publicDirectory, "files"); @@ -35,6 +36,7 @@ export const ExitHandlers = new Array<() => void>(); * before clients can access the server should be run or awaited here. */ async function preliminaryFunctions() { + await ProcessManager.initialize(); await GoogleCredentialsLoader.loadCredentials(); GoogleApiServerUtils.processProjectCredentials(); await DashUploadUtils.buildFileDirectories(); @@ -119,6 +121,15 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }: } }); + addSupervisedRoute({ + method: Method.GET, + subscription: "/persist", + onValidation: ({ res }) => { + ProcessManager.trySpawnDaemon(); + res.redirect("/home"); + } + }); + logRegistrationOutcome(); // initialize the web socket (bidirectional communication: if a user changes diff --git a/src/server/persistence_daemon.ts b/src/server/persistence_daemon.ts deleted file mode 100644 index 2cb17456c..000000000 --- a/src/server/persistence_daemon.ts +++ /dev/null @@ -1,82 +0,0 @@ -import * as request from "request-promise"; -import { command_line, log_execution } from "./ActionUtilities"; -import { red, yellow, cyan, green } from "colors"; -import * as nodemailer from "nodemailer"; -import { MailOptions } from "nodemailer/lib/json-transport"; -import { Database } from "./database"; - -const LOCATION = "http://localhost"; -const recipient = "samuel_wilkins@brown.edu"; -let restarting = false; - -async function listen() { - if (!LOCATION) { - console.log(red("No location specified for persistence daemon. Please include as a command line environment variable or in a .env file.")); - process.exit(0); - } - const heartbeat = `${LOCATION}:1050/serverHeartbeat`; - // if this is on our remote server, the server must be run in release mode - const suffix = LOCATION.includes("localhost") ? "" : "-release"; - setInterval(async () => { - let response: any; - let error: any; - try { - response = await request.get(heartbeat); - } catch (e) { - error = e; - } finally { - if (!response && !restarting) { - restarting = true; - console.log(yellow("Detected a server crash!")); - await log_execution({ - startMessage: "Sending crash notification email", - endMessage: ({ error, result }) => { - const success = error === null && result === true; - return (success ? `Notification successfully sent to ` : `Failed to notify `) + recipient; - }, - action: async () => notify(error || "Hmm, no error to report..."), - color: cyan - }); - console.log(await log_execution({ - startMessage: "Initiating server restart", - endMessage: "Server successfully restarted", - action: () => command_line(`npm run start${suffix}`), - color: green - })); - restarting = false; - } else { - console.log(green(`No issues detected as of ${new Date().toISOString()}`)); - } - } - }, 1000 * 10); -} - -function emailText(error: any) { - return [ - `Hey ${recipient.split("@")[0]},`, - "You, as a Dash Administrator, are being notified of a server crash event. Here's what we know:", - `Location: ${LOCATION}\nError: ${error}`, - "The server should already be restarting itself, but if you're concerned, use the Remote Desktop Connection to monitor progress." - ].join("\n\n"); -} - -async function notify(error: any) { - const smtpTransport = nodemailer.createTransport({ - service: 'Gmail', - auth: { - user: 'brownptcdash@gmail.com', - pass: 'browngfx1' - } - }); - const mailOptions = { - to: recipient, - from: 'brownptcdash@gmail.com', - subject: 'Dash Server Crash', - text: emailText(error) - } as MailOptions; - return new Promise(resolve => { - smtpTransport.sendMail(mailOptions, (dispatchError: Error | null) => { console.log(dispatchError); resolve(dispatchError === null); }); - }); -} - -listen(); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From e01499153fdd335493973dc79d80ccc4ae8df95c Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 11 Dec 2019 19:43:37 -0500 Subject: first steps toward restructure of session daemon --- package.json | 2 +- .../daemon/persistence_daemon.ts | 137 --------------------- src/server/ChildProcessUtilities/daemon/session.ts | 137 +++++++++++++++++++++ src/server/index.ts | 14 --- 4 files changed, 138 insertions(+), 152 deletions(-) delete mode 100644 src/server/ChildProcessUtilities/daemon/persistence_daemon.ts create mode 100644 src/server/ChildProcessUtilities/daemon/session.ts (limited to 'package.json') diff --git a/package.json b/package.json index 97563e137..77a521e27 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "start-release": "cross-env RELEASE=true NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", - "start-spawn": "cross-env SPAWNED=true NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", + "session": "npx ts-node ./src/server/ChildProcessUtilities/daemon/session.ts", "start": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", "debug": "cross-env NODE_OPTIONS=--max_old_space_size=8192 ts-node-dev --inspect -- src/server/index.ts", "build": "cross-env NODE_OPTIONS=--max_old_space_size=8192 webpack --env production", diff --git a/src/server/ChildProcessUtilities/daemon/persistence_daemon.ts b/src/server/ChildProcessUtilities/daemon/persistence_daemon.ts deleted file mode 100644 index 888cf38b8..000000000 --- a/src/server/ChildProcessUtilities/daemon/persistence_daemon.ts +++ /dev/null @@ -1,137 +0,0 @@ -import * as request from "request-promise"; -import { log_execution } from "../../ActionUtilities"; -import { red, yellow, cyan, green, Color } from "colors"; -import * as nodemailer from "nodemailer"; -import { MailOptions } from "nodemailer/lib/json-transport"; -import { writeFileSync, appendFileSync, existsSync, mkdirSync } from "fs"; -import { resolve } from 'path'; -import { ChildProcess } from "child_process"; -import { ProcessFactory } from "../ProcessFactory"; - -const identifier = yellow("__daemon__:"); - -process.on('SIGINT', () => current_backup?.kill("SIGTERM")); - -const logPath = resolve(__dirname, "./logs"); -const crashPath = resolve(logPath, "./crashes"); -if (!existsSync(logPath)) { - mkdirSync(logPath); -} -if (!existsSync(crashPath)) { - mkdirSync(crashPath); -} - -const crashLogPath = resolve(crashPath, `./session_crashes_${timestamp()}.log`); -function addLogEntry(message: string, color: Color) { - const formatted = color(`${message} ${timestamp()}.`); - identifiedLog(formatted); - appendFileSync(crashLogPath, `${formatted}\n`); -} - -function identifiedLog(message?: any, ...optionalParams: any[]) { - console.log(identifier, message, ...optionalParams); -} - -const LOCATION = "http://localhost"; -const recipient = "samuel_wilkins@brown.edu"; -const frequency = 10; -const { pid } = process; -let restarting = false; - -identifiedLog("Initializing daemon..."); - -writeLocalPidLog("daemon", pid); - -function writeLocalPidLog(filename: string, contents: any) { - const path = `./logs/current_${filename}_pid.log`; - identifiedLog(cyan(`${contents} written to ${path}`)); - writeFileSync(resolve(__dirname, path), `${contents}\n`); -} - -function timestamp() { - return `@ ${new Date().toISOString()}`; -} - -let current_backup: ChildProcess | undefined = undefined; - -async function listen() { - identifiedLog(yellow(`Beginning to poll server heartbeat every ${frequency} seconds...\n`)); - if (!LOCATION) { - identifiedLog(red("No location specified for persistence daemon. Please include as a command line environment variable or in a .env file.")); - process.exit(0); - } - const heartbeat = `${LOCATION}:1050/serverHeartbeat`; - // if this is on our remote server, the server must be run in release mode - // const suffix = LOCATION.includes("localhost") ? "" : "-release"; - setInterval(async () => { - let error: any; - try { - await request.get(heartbeat); - if (restarting) { - addLogEntry("Backup server successfully restarted", green); - } - restarting = false; - } catch (e) { - error = e; - } finally { - if (error) { - if (!restarting) { - restarting = true; - addLogEntry("Detected a server crash", red); - current_backup?.kill(); - await log_execution({ - startMessage: identifier + " Sending crash notification email", - endMessage: ({ error, result }) => { - const success = error === null && result === true; - return identifier + ` ${(success ? `Notification successfully sent to` : `Failed to notify`)} ${recipient} ${timestamp()}`; - }, - action: async () => notify(error || "Hmm, no error to report..."), - color: cyan - }); - current_backup = await log_execution({ - startMessage: identifier + " Initiating server restart", - endMessage: ({ result, error }) => { - const success = error === null && result !== undefined; - return identifier + success ? " Child process spawned..." : ` An error occurred while attempting to restart the server:\n${error}`; - }, - action: () => ProcessFactory.createWorker('npm', ['run', 'start-spawn'], "inherit"), - color: green - }); - writeLocalPidLog("server", `${(current_backup?.pid ?? -2) + 1} created ${timestamp()}`); - } else { - identifiedLog(yellow(`Callback ignored because restarting already initiated ${timestamp()}`)); - } - } - } - }, 1000 * 10); -} - -function emailText(error: any) { - return [ - `Hey ${recipient.split("@")[0]},`, - "You, as a Dash Administrator, are being notified of a server crash event. Here's what we know:", - `Location: ${LOCATION}\nError: ${error}`, - "The server should already be restarting itself, but if you're concerned, use the Remote Desktop Connection to monitor progress." - ].join("\n\n"); -} - -async function notify(error: any) { - const smtpTransport = nodemailer.createTransport({ - service: 'Gmail', - auth: { - user: 'brownptcdash@gmail.com', - pass: 'browngfx1' - } - }); - const mailOptions = { - to: recipient, - from: 'brownptcdash@gmail.com', - subject: 'Dash Server Crash', - text: emailText(error) - } as MailOptions; - return new Promise(resolve => { - smtpTransport.sendMail(mailOptions, (dispatchError: Error | null) => resolve(dispatchError === null)); - }); -} - -listen(); \ No newline at end of file diff --git a/src/server/ChildProcessUtilities/daemon/session.ts b/src/server/ChildProcessUtilities/daemon/session.ts new file mode 100644 index 000000000..c41657cc9 --- /dev/null +++ b/src/server/ChildProcessUtilities/daemon/session.ts @@ -0,0 +1,137 @@ +import * as request from "request-promise"; +import { log_execution } from "../../ActionUtilities"; +import { red, yellow, cyan, green, Color } from "colors"; +import * as nodemailer from "nodemailer"; +import { MailOptions } from "nodemailer/lib/json-transport"; +import { writeFileSync, appendFileSync, existsSync, mkdirSync } from "fs"; +import { resolve } from 'path'; +import { ChildProcess } from "child_process"; +import { ProcessFactory } from "../ProcessFactory"; + +const identifier = yellow("__daemon__:"); + +process.on('SIGINT', () => current_backup?.kill("SIGTERM")); + +const logPath = resolve(__dirname, "./logs"); +const crashPath = resolve(logPath, "./crashes"); +if (!existsSync(logPath)) { + mkdirSync(logPath); +} +if (!existsSync(crashPath)) { + mkdirSync(crashPath); +} + +const crashLogPath = resolve(crashPath, `./session_crashes_${timestamp()}.log`); +function addLogEntry(message: string, color: Color) { + const formatted = color(`${message} ${timestamp()}.`); + identifiedLog(formatted); + appendFileSync(crashLogPath, `${formatted}\n`); +} + +function identifiedLog(message?: any, ...optionalParams: any[]) { + console.log(identifier, message, ...optionalParams); +} + +const LOCATION = "http://localhost"; +const recipient = "samuel_wilkins@brown.edu"; +const frequency = 10; +const { pid } = process; +let restarting = false; + +identifiedLog("Initializing daemon..."); + +writeLocalPidLog("daemon", pid); + +function writeLocalPidLog(filename: string, contents: any) { + const path = `./logs/current_${filename}_pid.log`; + identifiedLog(cyan(`${contents} written to ${path}`)); + writeFileSync(resolve(__dirname, path), `${contents}\n`); +} + +function timestamp() { + return `@ ${new Date().toISOString()}`; +} + +let current_backup: ChildProcess | undefined = undefined; + +async function listen() { + identifiedLog(yellow(`Beginning to poll server heartbeat every ${frequency} seconds...\n`)); + if (!LOCATION) { + identifiedLog(red("No location specified for persistence daemon. Please include as a command line environment variable or in a .env file.")); + process.exit(0); + } + const heartbeat = `${LOCATION}:1050/serverHeartbeat`; + // if this is on our remote server, the server must be run in release mode + // const suffix = LOCATION.includes("localhost") ? "" : "-release"; + setInterval(async () => { + let error: any; + try { + await request.get(heartbeat); + if (restarting) { + addLogEntry("Backup server successfully restarted", green); + } + restarting = false; + } catch (e) { + error = e; + } finally { + if (error) { + if (!restarting) { + restarting = true; + addLogEntry("Detected a server crash", red); + current_backup?.kill(); + await log_execution({ + startMessage: identifier + " Sending crash notification email", + endMessage: ({ error, result }) => { + const success = error === null && result === true; + return identifier + ` ${(success ? `Notification successfully sent to` : `Failed to notify`)} ${recipient} ${timestamp()}`; + }, + action: async () => notify(error || "Hmm, no error to report..."), + color: cyan + }); + current_backup = await log_execution({ + startMessage: identifier + " Initiating server restart", + endMessage: ({ result, error }) => { + const success = error === null && result !== undefined; + return identifier + success ? " Child process spawned..." : ` An error occurred while attempting to restart the server:\n${error}`; + }, + action: () => ProcessFactory.createWorker('npm', ['run', 'start'], "inherit"), + color: green + }); + writeLocalPidLog("server", `${(current_backup?.pid ?? -2) + 1} created ${timestamp()}`); + } else { + identifiedLog(yellow(`Callback ignored because restarting already initiated ${timestamp()}`)); + } + } + } + }, 1000 * 10); +} + +function emailText(error: any) { + return [ + `Hey ${recipient.split("@")[0]},`, + "You, as a Dash Administrator, are being notified of a server crash event. Here's what we know:", + `Location: ${LOCATION}\nError: ${error}`, + "The server should already be restarting itself, but if you're concerned, use the Remote Desktop Connection to monitor progress." + ].join("\n\n"); +} + +async function notify(error: any) { + const smtpTransport = nodemailer.createTransport({ + service: 'Gmail', + auth: { + user: 'brownptcdash@gmail.com', + pass: 'browngfx1' + } + }); + const mailOptions = { + to: recipient, + from: 'brownptcdash@gmail.com', + subject: 'Dash Server Crash', + text: emailText(error) + } as MailOptions; + return new Promise(resolve => { + smtpTransport.sendMail(mailOptions, (dispatchError: Error | null) => resolve(dispatchError === null)); + }); +} + +listen(); \ No newline at end of file diff --git a/src/server/index.ts b/src/server/index.ts index bebb9b365..bc481e579 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -121,20 +121,6 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }: } }); - let daemonInitialized = false; - const { SPAWNED, RELEASE } = process.env; - addSupervisedRoute({ - method: Method.GET, - subscription: "/persist", - onValidation: ({ res }) => { - if (RELEASE && !SPAWNED && !daemonInitialized) { - daemonInitialized = true; - ProcessFactory.NamedAgents.persistenceDaemon(); - } - res.redirect("/home"); - } - }); - logRegistrationOutcome(); // initialize the web socket (bidirectional communication: if a user changes -- cgit v1.2.3-70-g09d2 From 85e7ca251beefa0b5417c8e6e6d28f9aaa5d886c Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 12 Dec 2019 11:05:36 -0500 Subject: killport --- package.json | 3 ++- src/server/ChildProcessUtilities/daemon/session.ts | 25 ++++------------------ src/typings/index.d.ts | 1 + 3 files changed, 7 insertions(+), 22 deletions(-) (limited to 'package.json') diff --git a/package.json b/package.json index 77a521e27..c58f542fc 100644 --- a/package.json +++ b/package.json @@ -161,6 +161,7 @@ "js-datepicker": "^4.6.6", "jsonwebtoken": "^8.5.0", "jsx-to-string": "^1.4.0", + "kill-port": "^1.6.0", "lodash": "^4.17.15", "mobile-detect": "^1.4.3", "mobx": "^5.15.0", @@ -231,4 +232,4 @@ "xoauth2": "^1.2.0", "youtube": "^0.1.0" } -} \ No newline at end of file +} diff --git a/src/server/ChildProcessUtilities/daemon/session.ts b/src/server/ChildProcessUtilities/daemon/session.ts index 9e082e665..41eb6976e 100644 --- a/src/server/ChildProcessUtilities/daemon/session.ts +++ b/src/server/ChildProcessUtilities/daemon/session.ts @@ -6,7 +6,7 @@ import { MailOptions } from "nodemailer/lib/json-transport"; import { writeFileSync, appendFileSync, existsSync, mkdirSync } from "fs"; import { resolve } from 'path'; import { ChildProcess, exec } from "child_process"; -import { ProcessFactory } from "../ProcessFactory"; +import * as killport from "kill-port"; const identifier = yellow("__daemon__:"); @@ -79,6 +79,7 @@ async function listen() { restarting = true; addLogEntry("Detected a server crash", red); current_backup?.kill(); + await killport(1050, 'tcp'); await log_execution({ startMessage: identifier + " Sending crash notification email", endMessage: ({ error, result }) => { @@ -88,26 +89,8 @@ async function listen() { action: async () => notify(error || "Hmm, no error to report..."), color: cyan }); - await log_execution({ - startMessage: identifier + " Initiating server restart", - endMessage: ({ result, error }) => { - const success = error === null && result !== undefined; - return identifier + success ? " Child process spawned..." : ` An error occurred while attempting to restart the server:\n${error}`; - }, - action: async () => { - return new Promise(resolve => { - exec('"C:\\Program Files\\Git\\git-bash.exe" -c "npm run start-release"', err => { - if (err) { - identifiedLog(err.message); - return; - } - resolve(); - }); - - }); - }, - color: green - }); + identifiedLog(green("Initiating server restart...")); + current_backup = exec('"C:\\Program Files\\Git\\git-bash.exe" -c "npm run start-release"', err => identifiedLog(err?.message || "Previous server process exited.")); writeLocalPidLog("server", `${(current_backup?.pid ?? -2) + 1} created ${timestamp()}`); } else { identifiedLog(yellow(`Callback ignored because restarting already initiated ${timestamp()}`)); diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts index 9e8ace962..674278126 100644 --- a/src/typings/index.d.ts +++ b/src/typings/index.d.ts @@ -2,6 +2,7 @@ declare module 'googlephotos'; declare module 'react-image-lightbox-with-rotate'; +declare module 'kill-port'; declare module '@react-pdf/renderer' { import * as React from 'react'; -- cgit v1.2.3-70-g09d2