aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/ActionUtilities.ts10
-rw-r--r--src/server/ApiManagers/DiagnosticManager.ts30
-rw-r--r--src/server/ApiManagers/SearchManager.ts36
-rw-r--r--src/server/ApiManagers/UtilManager.ts10
-rw-r--r--src/server/Initialization.ts8
-rw-r--r--src/server/Message.ts1
-rw-r--r--src/server/Websocket/Websocket.ts13
-rw-r--r--src/server/database.ts4
-rw-r--r--src/server/index.ts26
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';