diff options
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/ActionUtilities.ts | 10 | ||||
| -rw-r--r-- | src/server/ApiManagers/DiagnosticManager.ts | 30 | ||||
| -rw-r--r-- | src/server/ApiManagers/SearchManager.ts | 36 | ||||
| -rw-r--r-- | src/server/ApiManagers/UtilManager.ts | 10 | ||||
| -rw-r--r-- | src/server/Initialization.ts | 8 | ||||
| -rw-r--r-- | src/server/Message.ts | 1 | ||||
| -rw-r--r-- | src/server/Websocket/Websocket.ts | 13 | ||||
| -rw-r--r-- | src/server/database.ts | 4 | ||||
| -rw-r--r-- | src/server/index.ts | 26 |
9 files changed, 88 insertions, 50 deletions
diff --git a/src/server/ActionUtilities.ts b/src/server/ActionUtilities.ts index 4fe7374d1..94008e171 100644 --- a/src/server/ActionUtilities.ts +++ b/src/server/ActionUtilities.ts @@ -9,21 +9,21 @@ export const command_line = (command: string, fromDirectory?: string) => { return new Promise<string>((resolve, reject) => { const options: ExecOptions = {}; if (fromDirectory) { - options.cwd = path.join(__dirname, fromDirectory); + options.cwd = path.resolve(__dirname, fromDirectory); } exec(command, options, (err, stdout) => err ? reject(err) : resolve(stdout)); }); }; export const read_text_file = (relativePath: string) => { - const target = path.join(__dirname, relativePath); + const target = path.resolve(__dirname, relativePath); return new Promise<string>((resolve, reject) => { fs.readFile(target, (err, data) => err ? reject(err) : resolve(data.toString())); }); }; export const write_text_file = (relativePath: string, contents: any) => { - const target = path.join(__dirname, relativePath); + const target = path.resolve(__dirname, relativePath); return new Promise<void>((resolve, reject) => { fs.writeFile(target, contents, (err) => err ? reject(err) : resolve()); }); @@ -73,7 +73,3 @@ export async function Prune(rootDirectory: string): Promise<boolean> { } export const Destroy = (mediaPath: string) => new Promise<boolean>(resolve => fs.unlink(mediaPath, error => resolve(error === null))); - -export function addBeforeExitHandler(handler: NodeJS.BeforeExitListener) { - process.on("beforeExit", handler); -} diff --git a/src/server/ApiManagers/DiagnosticManager.ts b/src/server/ApiManagers/DiagnosticManager.ts deleted file mode 100644 index 104985481..000000000 --- a/src/server/ApiManagers/DiagnosticManager.ts +++ /dev/null @@ -1,30 +0,0 @@ -import ApiManager, { Registration } from "./ApiManager"; -import { Method } from "../RouteManager"; -import request = require('request-promise'); - -export default class DiagnosticManager extends ApiManager { - - protected initialize(register: Registration): void { - - register({ - method: Method.GET, - subscription: "/serverHeartbeat", - onValidation: ({ res }) => res.send(true) - }); - - register({ - method: Method.GET, - subscription: "/solrHeartbeat", - onValidation: async ({ res }) => { - try { - await request("http://localhost:8983"); - res.send({ running: true }); - } catch (e) { - res.send({ running: false }); - } - } - }); - - } - -}
\ No newline at end of file diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts index 7afecbb18..ccd0896bd 100644 --- a/src/server/ApiManagers/SearchManager.ts +++ b/src/server/ApiManagers/SearchManager.ts @@ -4,13 +4,31 @@ import { Search } from "../Search"; const findInFiles = require('find-in-files'); import * as path from 'path'; import { pathToDirectory, Directory } from "./UploadManager"; +import { command_line } from "../ActionUtilities"; +import request = require('request-promise'); +import { red } from "colors"; +import RouteSubscriber from "../RouteSubscriber"; -export default class SearchManager extends ApiManager { +export class SearchManager extends ApiManager { protected initialize(register: Registration): void { register({ method: Method.GET, + subscription: new RouteSubscriber("solr").add("action"), + onValidation: async ({ req, res }) => { + const { action } = req.params; + if (["start", "stop"].includes(action)) { + const status = req.params.action === "start"; + const success = await SolrManager.SetRunning(status); + console.log(success ? `Successfully ${status ? "started" : "stopped"} Solr!` : `Uh oh! Check the console for the error that occurred while ${status ? "starting" : "stopping"} Solr`); + } + res.redirect("/home"); + } + }); + + register({ + method: Method.GET, subscription: "/textsearch", onValidation: async ({ req, res }) => { const q = req.query.q; @@ -46,4 +64,20 @@ export default class SearchManager extends ApiManager { } +} + +export namespace SolrManager { + + export async function SetRunning(status: boolean): Promise<boolean> { + const args = status ? "start" : "stop -p 8983"; + try { + console.log(`Solr management: trying to ${args}`); + console.log(await command_line(`solr.cmd ${args}`, "../../solr-8.1.1/bin")); + return true; + } catch (e) { + console.log(red(`Solr management error: unable to ${args}`)); + return false; + } + } + }
\ No newline at end of file diff --git a/src/server/ApiManagers/UtilManager.ts b/src/server/ApiManagers/UtilManager.ts index 601a7d0d0..e959645e0 100644 --- a/src/server/ApiManagers/UtilManager.ts +++ b/src/server/ApiManagers/UtilManager.ts @@ -3,6 +3,7 @@ import { Method } from "../RouteManager"; import { exec } from 'child_process'; import { command_line } from "../ActionUtilities"; import RouteSubscriber from "../RouteSubscriber"; +import { red } from "colors"; export default class UtilManager extends ApiManager { @@ -11,7 +12,14 @@ export default class UtilManager extends ApiManager { register({ method: Method.GET, subscription: new RouteSubscriber("environment").add("key"), - onValidation: ({ req, res }) => res.send(process.env[req.params.key]) + onValidation: ({ req, res }) => { + const { key } = req.params; + const value = process.env[key]; + if (!value) { + console.log(red(`process.env.${key} is not defined.`)); + } + return res.send(value); + } }); register({ diff --git a/src/server/Initialization.ts b/src/server/Initialization.ts index ff2b64317..b58bc3e70 100644 --- a/src/server/Initialization.ts +++ b/src/server/Initialization.ts @@ -18,8 +18,8 @@ import * as whm from 'webpack-hot-middleware'; import * as fs from 'fs'; import * as request from 'request'; import RouteSubscriber from './RouteSubscriber'; -import { publicDirectory } from '.'; -import { logPort, addBeforeExitHandler } from './ActionUtilities'; +import { publicDirectory, ExitHandlers } from '.'; +import { logPort, } from './ActionUtilities'; import { timeMap } from './ApiManagers/UserManager'; import { blue, yellow } from 'colors'; @@ -31,6 +31,8 @@ export interface InitializationOptions { routeSetter: RouteSetter; } +export let disconnect: Function; + export default async function InitializeServer(options: InitializationOptions) { const { serverPort, routeSetter } = options; const app = buildWithMiddleware(express()); @@ -65,7 +67,7 @@ export default async function InitializeServer(options: InitializationOptions) { logPort("server", serverPort); console.log(); }); - addBeforeExitHandler(async () => { await new Promise<Error>(resolve => server.close(resolve)); }); + disconnect = async () => new Promise<Error>(resolve => server.close(resolve)); return isRelease; } diff --git a/src/server/Message.ts b/src/server/Message.ts index aaee143e8..621abfd1e 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -50,6 +50,7 @@ export namespace MessageStore { export const GetFields = new Message<string[]>("Get Fields"); // send string[] of 'id' get Transferable[] back export const GetDocument = new Message<string>("Get Document"); export const DeleteAll = new Message<any>("Delete All"); + export const ConnectionTerminated = new Message<string>("Connection Terminated"); export const GetRefField = new Message<string>("Get Ref Field"); export const GetRefFields = new Message<string[]>("Get Ref Fields"); diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts index 60c34aa44..5c0bb508b 100644 --- a/src/server/Websocket/Websocket.ts +++ b/src/server/Websocket/Websocket.ts @@ -7,14 +7,16 @@ import { Search } from "../Search"; import * as io from 'socket.io'; import YoutubeApi from "../apis/youtube/youtubeApiSample"; import { GoogleCredentialsLoader } from "../credentials/CredentialsLoader"; -import { logPort, addBeforeExitHandler } from "../ActionUtilities"; +import { logPort } from "../ActionUtilities"; import { timeMap } from "../ApiManagers/UserManager"; import { green } from "colors"; +import { SolrManager } from "../ApiManagers/SearchManager"; export namespace WebSocket { const clients: { [key: string]: Client } = {}; export const socketMap = new Map<SocketIO.Socket, string>(); + export let disconnect: Function; export async function start(serverPort: number, isRelease: boolean) { await preliminaryFunctions(); @@ -52,8 +54,13 @@ export namespace WebSocket { Utils.AddServerHandler(socket, MessageStore.DeleteFields, ids => DeleteFields(socket, ids)); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); + + disconnect = () => { + socket.broadcast.emit("connection_terminated", Date.now()); + socket.disconnect(true); + }; }); - addBeforeExitHandler(async () => { await new Promise<void>(resolve => endpoint.close(resolve)); }); + endpoint.listen(socketPort); logPort("websocket", socketPort); } @@ -171,7 +178,7 @@ export namespace WebSocket { function UpdateField(socket: Socket, diff: Diff) { Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false, "newDocuments"); - const docfield = diff.diff.$set; + const docfield = diff.diff.$set || diff.diff.$unset; if (!docfield) { return; } diff --git a/src/server/database.ts b/src/server/database.ts index 5bdf1fc45..6e0771c11 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -6,10 +6,10 @@ import { DashUploadUtils } from './DashUploadUtils'; import { Credentials } from 'google-auth-library'; import { GoogleApiServerUtils } from './apis/google/GoogleApiServerUtils'; import * as mongoose from 'mongoose'; -import { addBeforeExitHandler } from './ActionUtilities'; export namespace Database { + export let disconnect: Function; const schema = 'Dash'; const port = 27017; export const url = `mongodb://localhost:${port}/${schema}`; @@ -25,7 +25,7 @@ export namespace Database { export async function tryInitializeConnection() { try { const { connection } = mongoose; - addBeforeExitHandler(async () => { await new Promise<any>(resolve => connection.close(resolve)); }); + disconnect = async () => new Promise<any>(resolve => connection.close(resolve)); if (connection.readyState === ConnectionStates.disconnected) { await new Promise<void>((resolve, reject) => { connection.on('error', reject); diff --git a/src/server/index.ts b/src/server/index.ts index 551ce3898..6099af83c 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -10,7 +10,7 @@ import initializeServer from './Initialization'; import RouteManager, { Method, _success, _permission_denied, _error, _invalid, OnUnauthenticated } from './RouteManager'; import * as qs from 'query-string'; import UtilManager from './ApiManagers/UtilManager'; -import SearchManager from './ApiManagers/SearchManager'; +import { SearchManager, SolrManager } from './ApiManagers/SearchManager'; import UserManager from './ApiManagers/UserManager'; import { WebSocket } from './Websocket/Websocket'; import DownloadManager from './ApiManagers/DownloadManager'; @@ -21,12 +21,14 @@ import UploadManager from "./ApiManagers/UploadManager"; import { log_execution } from "./ActionUtilities"; import GeneralGoogleManager from "./ApiManagers/GeneralGoogleManager"; import GooglePhotosManager from "./ApiManagers/GooglePhotosManager"; -import DiagnosticManager from "./ApiManagers/DiagnosticManager"; import { yellow } from "colors"; +import { disconnect } from "../server/Initialization"; export const publicDirectory = path.resolve(__dirname, "public"); export const filesDirectory = path.resolve(publicDirectory, "files"); +export const ExitHandlers = new Array<() => void>(); + /** * These are the functions run before the server starts * listening. Anything that must be complete @@ -57,7 +59,6 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }: new UserManager(), new UploadManager(), new DownloadManager(), - new DiagnosticManager(), new SearchManager(), new PDFManager(), new DeleteManager(), @@ -79,6 +80,25 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }: onValidation: ({ res }) => res.redirect("/home") }); + addSupervisedRoute({ + method: Method.GET, + subscription: "/serverHeartbeat", + onValidation: ({ res }) => res.send(true) + }); + + addSupervisedRoute({ + method: Method.GET, + subscription: "/shutdown", + onValidation: async ({ res }) => { + WebSocket.disconnect(); + await disconnect(); + await Database.disconnect(); + SolrManager.SetRunning(false); + res.send("Server successfully shut down."); + process.exit(0); + } + }); + const serve: OnUnauthenticated = ({ req, res }) => { const detector = new mobileDetect(req.headers['user-agent'] || ""); const filename = detector.mobile() !== null ? 'mobile/image.html' : 'index.html'; |
