aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json41
-rw-r--r--src/client/views/SearchDocBox.tsx34
-rw-r--r--src/client/views/search/CheckBox.tsx146
-rw-r--r--src/client/views/search/SearchBox.tsx47
-rw-r--r--src/server/ApiManagers/SessionManager.ts20
-rw-r--r--src/server/DashSession/DashSessionAgent.ts446
-rw-r--r--src/server/index.ts4
7 files changed, 384 insertions, 354 deletions
diff --git a/package-lock.json b/package-lock.json
index f6b1e80da..e60950308 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5600,8 +5600,7 @@
},
"ansi-regex": {
"version": "2.1.1",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"aproba": {
"version": "1.2.0",
@@ -5619,13 +5618,11 @@
},
"balanced-match": {
"version": "1.0.0",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
- "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -5638,18 +5635,15 @@
},
"code-point-at": {
"version": "1.1.0",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"concat-map": {
"version": "0.0.1",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"console-control-strings": {
"version": "1.1.0",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"core-util-is": {
"version": "1.0.2",
@@ -5752,8 +5746,7 @@
},
"inherits": {
"version": "2.0.4",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"ini": {
"version": "1.3.5",
@@ -5763,7 +5756,6 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
- "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -5776,20 +5768,17 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
- "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
- "optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -5806,7 +5795,6 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
- "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -5887,8 +5875,7 @@
},
"number-is-nan": {
"version": "1.0.1",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"object-assign": {
"version": "4.1.1",
@@ -5898,7 +5885,6 @@
"once": {
"version": "1.4.0",
"bundled": true,
- "optional": true,
"requires": {
"wrappy": "1"
}
@@ -5974,8 +5960,7 @@
},
"safe-buffer": {
"version": "5.1.2",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -6005,7 +5990,6 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
- "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -6023,7 +6007,6 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
- "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -6062,13 +6045,11 @@
},
"wrappy": {
"version": "1.0.2",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"yallist": {
"version": "3.1.1",
- "bundled": true,
- "optional": true
+ "bundled": true
}
}
},
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index 5f308ff71..5a76a882f 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -39,6 +39,8 @@ export const keyPlaceholder = "Query";
@observer
export class SearchDocBox extends React.Component<FieldViewProps> {
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchDocBox, fieldKey); }
+
// @observable private _display: boolean = false;
@observable private _pageX: number = 0;
@observable private _pageY: number = 0;
@@ -72,7 +74,7 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
console.log("didit"
);
this.query = StrCast(this.props.Document.searchText);
- this.content = (Docs.Create.TreeDocument(DocListCast(Doc.GetProto(this.props.Document).data), { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query}));
+ this.content = (Docs.Create.TreeDocument(DocListCast(Doc.GetProto(this.props.Document).data), { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query }));
});
if (this.inputRef.current) {
@@ -89,16 +91,16 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
@action
updateKey = async (newKey: string) => {
this.query = newKey;
- if (newKey.length >1){
- let newdocs= await this.getAllResults(this.query)
+ if (newKey.length > 1) {
+ let newdocs = await this.getAllResults(this.query);
let things = newdocs.docs
console.log(things);
console.log(this.content);
runInAction(() => {
- this.content= Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query });
- });
- console.log(this.content);
- }
+ this.content = Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query });
+ });
+ console.log(this.content);
+ }
//this.keyRef.current && this.keyRef.current.setIsFocused(false);
@@ -161,11 +163,11 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
enter = async (e: React.KeyboardEvent) => {
console.log(e.key);
if (e.key === "Enter") {
- let newdocs= await this.getAllResults(this.query)
+ let newdocs = await this.getAllResults(this.query)
let things = newdocs.docs
console.log(things);
- this.content=Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` });
-
+ this.content = Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` });
+
}
}
@@ -407,9 +409,9 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
return (
<div style={{ pointerEvents: "all" }}>
<ContentFittingDocumentView {...this.props}
- Document={this.content}
- getTransform={this.props.ScreenToLocalTransform}>
- s</ContentFittingDocumentView>
+ Document={this.content}
+ getTransform={this.props.ScreenToLocalTransform}>
+ s</ContentFittingDocumentView>
<div
style={{
position: "absolute",
@@ -421,12 +423,12 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
opacity: 1,
transition: "0.4s opacity ease",
zIndex: 99,
- top:0,
+ top: 0,
}}
title={"Add Metadata"}
- onClick={action(() => {this.editingMetadata = !this.editingMetadata })}
+ onClick={action(() => { this.editingMetadata = !this.editingMetadata })}
/>
- <div className="editableclass" onKeyPress={this.enter} style={{ opacity: isEditing ? 1 : 0, pointerEvents: isEditing ? "auto" : "none", transition: "0.4s opacity ease",position:"absolute",top:0,left:0, height:20, width:"-webkit-fill-available" }}>
+ <div className="editableclass" onKeyPress={this.enter} style={{ opacity: isEditing ? 1 : 0, pointerEvents: isEditing ? "auto" : "none", transition: "0.4s opacity ease", position: "absolute", top: 0, left: 0, height: 20, width: "-webkit-fill-available" }}>
<EditableView
contents={this.query}
SetValue={this.updateKey}
diff --git a/src/client/views/search/CheckBox.tsx b/src/client/views/search/CheckBox.tsx
index a9d48219a..8c97d5dbc 100644
--- a/src/client/views/search/CheckBox.tsx
+++ b/src/client/views/search/CheckBox.tsx
@@ -17,8 +17,8 @@ interface CheckBoxProps {
export class CheckBox extends React.Component<CheckBoxProps>{
// true = checked, false = unchecked
@observable private _status: boolean;
- @observable private uncheckTimeline: anime.AnimeTimelineInstance;
- @observable private checkTimeline: anime.AnimeTimelineInstance;
+ // @observable private uncheckTimeline: anime.AnimeTimelineInstance;
+ // @observable private checkTimeline: anime.AnimeTimelineInstance;
@observable private checkRef: any;
@observable private _resetReaction?: IReactionDisposer;
@@ -28,87 +28,87 @@ export class CheckBox extends React.Component<CheckBoxProps>{
this._status = this.props.originalStatus;
this.checkRef = React.createRef();
- this.checkTimeline = anime.timeline({
- loop: false,
- autoplay: false,
- direction: "normal",
- }); this.uncheckTimeline = anime.timeline({
- loop: false,
- autoplay: false,
- direction: "normal",
- });
+ // this.checkTimeline = anime.timeline({
+ // loop: false,
+ // autoplay: false,
+ // direction: "normal",
+ // }); this.uncheckTimeline = anime.timeline({
+ // loop: false,
+ // autoplay: false,
+ // direction: "normal",
+ // });
}
- componentDidMount = () => {
- this.uncheckTimeline.add({
- targets: this.checkRef.current,
- easing: "easeInOutQuad",
- duration: 500,
- opacity: 0,
- });
- this.checkTimeline.add({
- targets: this.checkRef.current,
- easing: "easeInOutQuad",
- duration: 500,
- strokeDashoffset: [anime.setDashoffset, 0],
- opacity: 1
- });
+ // componentDidMount = () => {
+ // this.uncheckTimeline.add({
+ // targets: this.checkRef.current,
+ // easing: "easeInOutQuad",
+ // duration: 500,
+ // opacity: 0,
+ // });
+ // this.checkTimeline.add({
+ // targets: this.checkRef.current,
+ // easing: "easeInOutQuad",
+ // duration: 500,
+ // strokeDashoffset: [anime.setDashoffset, 0],
+ // opacity: 1
+ // });
- if (this.props.originalStatus) {
- this.checkTimeline.play();
- this.checkTimeline.restart();
- }
+ // if (this.props.originalStatus) {
+ // this.checkTimeline.play();
+ // this.checkTimeline.restart();
+ // }
- this._resetReaction = reaction(
- () => this.props.parent._resetBoolean,
- () => {
- if (this.props.parent._resetBoolean) {
- runInAction(() => {
- this.reset();
- this.props.parent._resetCounter++;
- if (this.props.parent._resetCounter === this.props.numCount) {
- this.props.parent._resetCounter = 0;
- this.props.parent._resetBoolean = false;
- }
- });
- }
- },
- );
- }
+ // this._resetReaction = reaction(
+ // () => this.props.parent._resetBoolean,
+ // () => {
+ // if (this.props.parent._resetBoolean) {
+ // runInAction(() => {
+ // this.reset();
+ // this.props.parent._resetCounter++;
+ // if (this.props.parent._resetCounter === this.props.numCount) {
+ // this.props.parent._resetCounter = 0;
+ // this.props.parent._resetBoolean = false;
+ // }
+ // });
+ // }
+ // },
+ // );
+ // }
- @action.bound
- reset() {
- if (this.props.default) {
- if (!this._status) {
- this._status = true;
- this.checkTimeline.play();
- this.checkTimeline.restart();
- }
- }
- else {
- if (this._status) {
- this._status = false;
- this.uncheckTimeline.play();
- this.uncheckTimeline.restart();
- }
- }
+ // @action.bound
+ // reset() {
+ // if (this.props.default) {
+ // if (!this._status) {
+ // this._status = true;
+ // this.checkTimeline.play();
+ // this.checkTimeline.restart();
+ // }
+ // }
+ // else {
+ // if (this._status) {
+ // this._status = false;
+ // this.uncheckTimeline.play();
+ // this.uncheckTimeline.restart();
+ // }
+ // }
- this.props.updateStatus(this.props.default);
- }
+ // this.props.updateStatus(this.props.default);
+ // }
@action.bound
onClick = () => {
- if (this._status) {
- this.uncheckTimeline.play();
- this.uncheckTimeline.restart();
- }
- else {
- this.checkTimeline.play();
- this.checkTimeline.restart();
+ // if (this._status) {
+ // this.uncheckTimeline.play();
+ // this.uncheckTimeline.restart();
+ // }
+ // else {
+ // this.checkTimeline.play();
+ // this.checkTimeline.restart();
- }
- this._status = !this._status;
- this.props.updateStatus(this._status);
+ // }
+ // this._status = !this._status;
+ // this.props.updateStatus(this._status);
}
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 9af8829fa..02b41bc70 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -17,6 +17,7 @@ import "./FilterBox.scss";
import "./SearchBox.scss";
import { SearchItem } from './SearchItem';
import { IconBar } from './IconBar';
+import { FieldFilters } from './FieldFilters';
library.add(faTimes);
@@ -338,6 +339,9 @@ export class SearchBox extends React.Component {
@computed
get resultHeight() { return this._numTotalResults * 70; }
+ @observable private _filterOpen: boolean = false;
+
+
render() {
return (
<div className="searchBox-container" onPointerDown={e => { e.stopPropagation(); e.preventDefault(); }}>
@@ -353,6 +357,49 @@ export class SearchBox extends React.Component {
<div className="searchBox-quickFilter" onPointerDown={this.openSearch}>
<div className="filter-panel"><IconBar /></div>
</div>
+ <div>
+ <div style={{ display: "flex", flexDirection: "row-reverse" }}>
+ <SearchBox />
+ {/* {this.getActiveFilters()} */}
+ </div>
+ <div className="filter-form" onPointerDown={this.stopProp} id="filter-form" style={this._filterOpen ? { display: "flex" } : { display: "none" }}>
+ <div className="top-filter-header" style={{ display: "flex", width: "100%" }}>
+ <div id="header">Filter Search Results</div>
+ <div style={{ marginLeft: "auto" }}></div>
+ <div className="close-icon" >
+ <span className="line line-1"></span>
+ <span className="line line-2"></span></div>
+ </div>
+ <div className="filter-options">
+ <div className="filter-div">
+ <div className="filter-header">
+ <div className='filter-title words'>Required words</div>
+ </div>
+ <div className="filter-panel" >
+ <button className="all-filter">Include All Keywords</button>
+ </div>
+ </div>
+ <div className="filter-div">
+ <div className="filter-header">
+ <div className="filter-title icon">Filter by type of node</div>
+ </div>
+ <div className="filter-panel"><IconBar /></div>
+ </div>
+ <div className="filter-div">
+ <div className="filter-header">
+ <div className="filter-title field">Filter by Basic Keys</div>
+ </div>
+ <div className="filter-panel"><FieldFilters
+ titleFieldStatus={this._titleFieldStatus} dataFieldStatus={this._deletedDocsStatus} authorFieldStatus={this._authorFieldStatus}
+ updateAuthorStatus={this.updateAuthorStatus} updateDataStatus={this.updateDataStatus} updateTitleStatus={this.updateTitleStatus} /> </div>
+ </div>
+ </div>
+ <div className="filter-buttons" style={{ display: "flex", justifyContent: "space-around" }}>
+ <button className="save-filter" >Save Filters</button>
+ <button className="reset-filter" >Reset Filters</button>
+ </div>
+ </div>
+ </div>
<div className="searchBox-results" onScroll={this.resultsScrolled} style={{
display: this._resultsOpen ? "flex" : "none",
height: this.resFull ? "auto" : this.resultHeight,
diff --git a/src/server/ApiManagers/SessionManager.ts b/src/server/ApiManagers/SessionManager.ts
index f1629b8f0..8ebd684bb 100644
--- a/src/server/ApiManagers/SessionManager.ts
+++ b/src/server/ApiManagers/SessionManager.ts
@@ -2,7 +2,7 @@ import ApiManager, { Registration } from "./ApiManager";
import { Method, _permission_denied, AuthorizedCore, SecureHandler } from "../RouteManager";
import RouteSubscriber from "../RouteSubscriber";
import { sessionAgent } from "..";
-import { DashSessionAgent } from "../DashSession/DashSessionAgent";
+// import { DashSessionAgent } from "../DashSession/DashSessionAgent";
const permissionError = "You are not authorized!";
@@ -25,15 +25,15 @@ export default class SessionManager extends ApiManager {
protected initialize(register: Registration): void {
- register({
- method: Method.GET,
- subscription: this.secureSubscriber("debug", "to?"),
- secureHandler: this.authorizedAction(async ({ req: { params }, res }) => {
- const to = params.to || DashSessionAgent.notificationRecipient;
- const { error } = await sessionAgent.serverWorker.emit("debug", { to });
- res.send(error ? error.message : `Your request was successful: the server captured and compressed (but did not save) a new back up. It was sent to ${to}.`);
- })
- });
+ // register({
+ // method: Method.GET,
+ // subscription: this.secureSubscriber("debug", "to?"),
+ // secureHandler: this.authorizedAction(async ({ req: { params }, res }) => {
+ // const to = params.to || DashSessionAgent.notificationRecipient;
+ // const { error } = await sessionAgent.serverWorker.emit("debug", { to });
+ // res.send(error ? error.message : `Your request was successful: the server captured and compressed (but did not save) a new back up. It was sent to ${to}.`);
+ // })
+ // });
register({
method: Method.GET,
diff --git a/src/server/DashSession/DashSessionAgent.ts b/src/server/DashSession/DashSessionAgent.ts
index c55e01243..f22d1cbbc 100644
--- a/src/server/DashSession/DashSessionAgent.ts
+++ b/src/server/DashSession/DashSessionAgent.ts
@@ -1,223 +1,223 @@
-import { Email, pathFromRoot } from "../ActionUtilities";
-import { red, yellow, green, cyan } from "colors";
-import { get } from "request-promise";
-import { Utils } from "../../Utils";
-import { WebSocket } from "../Websocket/Websocket";
-import { MessageStore } from "../Message";
-import { launchServer, onWindows } from "..";
-import { readdirSync, statSync, createWriteStream, readFileSync, unlinkSync } from "fs";
-import * as Archiver from "archiver";
-import { resolve } from "path";
-import { AppliedSessionAgent, MessageHandler, ExitHandler, Monitor, ServerWorker } from "resilient-server-session";
-import rimraf = require("rimraf");
-
-/**
- * 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.
- */
-export class DashSessionAgent extends AppliedSessionAgent {
-
- private readonly signature = "-Dash Server Session Manager";
- private readonly releaseDesktop = pathFromRoot("../../Desktop");
-
- /**
- * The core method invoked when the single master thread is initialized.
- * Installs event hooks, repl commands and additional IPC listeners.
- */
- protected async initializeMonitor(monitor: Monitor, sessionKey: string): Promise<void> {
- await this.dispatchSessionPassword(sessionKey);
- monitor.addReplCommand("pull", [], () => monitor.exec("git pull"));
- monitor.addReplCommand("solr", [/start|stop|index/], this.executeSolrCommand);
- monitor.addReplCommand("backup", [], this.backup);
- monitor.addReplCommand("debug", [/\S+\@\S+/], async ([to]) => this.dispatchZippedDebugBackup(to));
- monitor.on("backup", this.backup);
- monitor.on("debug", async ({ to }) => this.dispatchZippedDebugBackup(to));
- monitor.coreHooks.onCrashDetected(this.dispatchCrashReport);
- }
-
- /**
- * The core method invoked when a server worker thread is initialized.
- * Installs logic to be executed when the server worker dies.
- */
- protected async initializeServerWorker(): Promise<ServerWorker> {
- const worker = ServerWorker.Create(launchServer); // server initialization delegated to worker
- worker.addExitHandler(this.notifyClient);
- return worker;
- }
-
- /**
- * Prepares the body of the email with instructions on restoring the transmitted remote database backup locally.
- */
- private _remoteDebugInstructions: string | undefined;
- private generateDebugInstructions = (zipName: string, target: string): string => {
- if (!this._remoteDebugInstructions) {
- this._remoteDebugInstructions = readFileSync(resolve(__dirname, "./templates/remote_debug_instructions.txt"), { encoding: "utf8" });
- }
- return this._remoteDebugInstructions
- .replace(/__zipname__/, zipName)
- .replace(/__target__/, target)
- .replace(/__signature__/, this.signature);
- }
-
- /**
- * Prepares the body of the email with information regarding a crash event.
- */
- private _crashInstructions: string | undefined;
- private generateCrashInstructions({ name, message, stack }: Error): string {
- if (!this._crashInstructions) {
- this._crashInstructions = readFileSync(resolve(__dirname, "./templates/crash_instructions.txt"), { encoding: "utf8" });
- }
- return this._crashInstructions
- .replace(/__name__/, name || "[no error name found]")
- .replace(/__message__/, message || "[no error message found]")
- .replace(/__stack__/, stack || "[no error stack found]")
- .replace(/__signature__/, this.signature);
- }
-
- /**
- * This sends a pseudorandomly generated guid to the configuration's recipients, allowing them alone
- * to kill the server via the /kill/:key route.
- */
- private dispatchSessionPassword = async (sessionKey: string): Promise<void> => {
- const { mainLog } = this.sessionMonitor;
- const { notificationRecipient } = DashSessionAgent;
- mainLog(green("dispatching session key..."));
- const error = await Email.dispatch({
- to: notificationRecipient,
- subject: "Dash Release Session Admin Authentication Key",
- content: [
- `Here's the key for this session (started @ ${new Date().toUTCString()}):`,
- sessionKey,
- this.signature
- ].join("\n\n")
- });
- if (error) {
- this.sessionMonitor.mainLog(red(`dispatch failure @ ${notificationRecipient} (${yellow(error.message)})`));
- mainLog(red("distribution of session key experienced errors"));
- } else {
- mainLog(green("successfully distributed session key to recipients"));
- }
- }
-
- /**
- * This sends an email with the generated crash report.
- */
- private dispatchCrashReport: MessageHandler<{ error: Error }> = async ({ error: crashCause }) => {
- const { mainLog } = this.sessionMonitor;
- const { notificationRecipient } = DashSessionAgent;
- const error = await Email.dispatch({
- to: notificationRecipient,
- subject: "Dash Web Server Crash",
- content: this.generateCrashInstructions(crashCause)
- });
- if (error) {
- this.sessionMonitor.mainLog(red(`dispatch failure @ ${notificationRecipient} ${yellow(`(${error.message})`)}`));
- mainLog(red("distribution of crash notification experienced errors"));
- } else {
- mainLog(green("successfully distributed crash notification to recipients"));
- }
- }
-
- /**
- * Logic for interfacing with Solr. Either starts it,
- * stops it, or rebuilds its indicies.
- */
- private executeSolrCommand = async (args: string[]): Promise<void> => {
- const { exec, mainLog } = this.sessionMonitor;
- const action = args[0];
- if (action === "index") {
- exec("npx ts-node ./updateSearch.ts", { cwd: pathFromRoot("./src/server") });
- } else {
- const command = `${onWindows ? "solr.cmd" : "solr"} ${args[0] === "start" ? "start" : "stop -p 8983"}`;
- await exec(command, { cwd: "./solr-8.3.1/bin" });
- try {
- await get("http://localhost:8983");
- mainLog(green("successfully connected to 8983 after running solr initialization"));
- } catch {
- mainLog(red("unable to connect at 8983 after running solr initialization"));
- }
- }
- }
-
- /**
- * Broadcast to all clients that their connection
- * is no longer valid, and explain why / what to expect.
- */
- private notifyClient: ExitHandler = reason => {
- const { _socket } = WebSocket;
- if (_socket) {
- const message = typeof reason === "boolean" ? (reason ? "exit" : "temporary") : "crash";
- Utils.Emit(_socket, MessageStore.ConnectionTerminated, message);
- }
- }
-
- /**
- * Performs a backup of the database, saved to the desktop subdirectory.
- * This should work as is only on our specific release server.
- */
- private backup = async (): Promise<void> => this.sessionMonitor.exec("backup.bat", { cwd: this.releaseDesktop });
-
- /**
- * Compress either a brand new backup or the most recent backup and send it
- * as an attachment to an email, dispatched to the requested recipient.
- * @param mode specifies whether or not to make a new backup before exporting
- * @param to the recipient of the email
- */
- private async dispatchZippedDebugBackup(to: string): Promise<void> {
- const { mainLog } = this.sessionMonitor;
- try {
- // if desired, complete an immediate backup to send
- await this.backup();
- mainLog("backup complete");
-
- const backupsDirectory = `${this.releaseDesktop}/backups`;
-
- // sort all backups by their modified time, and choose the most recent one
- const target = readdirSync(backupsDirectory).map(filename => ({
- modifiedTime: statSync(`${backupsDirectory}/${filename}`).mtimeMs,
- filename
- })).sort((a, b) => b.modifiedTime - a.modifiedTime)[0].filename;
- mainLog(`targeting ${target}...`);
-
- // create a zip file and to it, write the contents of the backup directory
- const zipName = `${target}.zip`;
- const zipPath = `${this.releaseDesktop}/${zipName}`;
- const targetPath = `${backupsDirectory}/${target}`;
- const output = createWriteStream(zipPath);
- const zip = Archiver('zip');
- zip.pipe(output);
- zip.directory(`${targetPath}/Dash`, false);
- await zip.finalize();
- mainLog(`zip finalized with size ${statSync(zipPath).size} bytes, saved to ${zipPath}`);
-
- // dispatch the email to the recipient, containing the finalized zip file
- const error = await Email.dispatch({
- to,
- subject: `Remote debug: compressed backup of ${target}...`,
- content: this.generateDebugInstructions(zipName, target),
- attachments: [{ filename: zipName, path: zipPath }]
- });
-
- // since this is intended to be a zero-footprint operation, clean up
- // by unlinking both the backup generated earlier in the function and the compressed zip file.
- // to generate a persistent backup, just run backup.
- unlinkSync(zipPath);
- rimraf.sync(targetPath);
-
- // indicate success or failure
- mainLog(`${error === null ? green("successfully dispatched") : red("failed to dispatch")} ${zipName} to ${cyan(to)}`);
- error && mainLog(red(error.message));
- } catch (error) {
- mainLog(red("unable to dispatch zipped backup..."));
- mainLog(red(error.message));
- }
- }
-
-}
-
-export namespace DashSessionAgent {
-
- export const notificationRecipient = "brownptcdash@gmail.com";
-
-} \ No newline at end of file
+// import { Email, pathFromRoot } from "../ActionUtilities";
+// import { red, yellow, green, cyan } from "colors";
+// import { get } from "request-promise";
+// import { Utils } from "../../Utils";
+// import { WebSocket } from "../Websocket/Websocket";
+// import { MessageStore } from "../Message";
+// import { launchServer, onWindows } from "..";
+// import { readdirSync, statSync, createWriteStream, readFileSync, unlinkSync } from "fs";
+// import * as Archiver from "archiver";
+// import { resolve } from "path";
+// import { AppliedSessionAgent, MessageHandler, ExitHandler, Monitor, ServerWorker } from "resilient-server-session";
+// import rimraf = require("rimraf");
+
+// /**
+// * 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.
+// */
+// export class DashSessionAgent extends AppliedSessionAgent {
+
+// private readonly signature = "-Dash Server Session Manager";
+// private readonly releaseDesktop = pathFromRoot("../../Desktop");
+
+// /**
+// * The core method invoked when the single master thread is initialized.
+// * Installs event hooks, repl commands and additional IPC listeners.
+// */
+// protected async initializeMonitor(monitor: Monitor, sessionKey: string): Promise<void> {
+// await this.dispatchSessionPassword(sessionKey);
+// monitor.addReplCommand("pull", [], () => monitor.exec("git pull"));
+// monitor.addReplCommand("solr", [/start|stop|index/], this.executeSolrCommand);
+// monitor.addReplCommand("backup", [], this.backup);
+// monitor.addReplCommand("debug", [/\S+\@\S+/], async ([to]) => this.dispatchZippedDebugBackup(to));
+// monitor.on("backup", this.backup);
+// monitor.on("debug", async ({ to }) => this.dispatchZippedDebugBackup(to));
+// monitor.coreHooks.onCrashDetected(this.dispatchCrashReport);
+// }
+
+// /**
+// * The core method invoked when a server worker thread is initialized.
+// * Installs logic to be executed when the server worker dies.
+// */
+// protected async initializeServerWorker(): Promise<ServerWorker> {
+// const worker = ServerWorker.Create(launchServer); // server initialization delegated to worker
+// worker.addExitHandler(this.notifyClient);
+// return worker;
+// }
+
+// /**
+// * Prepares the body of the email with instructions on restoring the transmitted remote database backup locally.
+// */
+// private _remoteDebugInstructions: string | undefined;
+// private generateDebugInstructions = (zipName: string, target: string): string => {
+// if (!this._remoteDebugInstructions) {
+// this._remoteDebugInstructions = readFileSync(resolve(__dirname, "./templates/remote_debug_instructions.txt"), { encoding: "utf8" });
+// }
+// return this._remoteDebugInstructions
+// .replace(/__zipname__/, zipName)
+// .replace(/__target__/, target)
+// .replace(/__signature__/, this.signature);
+// }
+
+// /**
+// * Prepares the body of the email with information regarding a crash event.
+// */
+// private _crashInstructions: string | undefined;
+// private generateCrashInstructions({ name, message, stack }: Error): string {
+// if (!this._crashInstructions) {
+// this._crashInstructions = readFileSync(resolve(__dirname, "./templates/crash_instructions.txt"), { encoding: "utf8" });
+// }
+// return this._crashInstructions
+// .replace(/__name__/, name || "[no error name found]")
+// .replace(/__message__/, message || "[no error message found]")
+// .replace(/__stack__/, stack || "[no error stack found]")
+// .replace(/__signature__/, this.signature);
+// }
+
+// /**
+// * This sends a pseudorandomly generated guid to the configuration's recipients, allowing them alone
+// * to kill the server via the /kill/:key route.
+// */
+// private dispatchSessionPassword = async (sessionKey: string): Promise<void> => {
+// const { mainLog } = this.sessionMonitor;
+// const { notificationRecipient } = DashSessionAgent;
+// mainLog(green("dispatching session key..."));
+// const error = await Email.dispatch({
+// to: notificationRecipient,
+// subject: "Dash Release Session Admin Authentication Key",
+// content: [
+// `Here's the key for this session (started @ ${new Date().toUTCString()}):`,
+// sessionKey,
+// this.signature
+// ].join("\n\n")
+// });
+// if (error) {
+// this.sessionMonitor.mainLog(red(`dispatch failure @ ${notificationRecipient} (${yellow(error.message)})`));
+// mainLog(red("distribution of session key experienced errors"));
+// } else {
+// mainLog(green("successfully distributed session key to recipients"));
+// }
+// }
+
+// /**
+// * This sends an email with the generated crash report.
+// */
+// private dispatchCrashReport: MessageHandler<{ error: Error }> = async ({ error: crashCause }) => {
+// const { mainLog } = this.sessionMonitor;
+// const { notificationRecipient } = DashSessionAgent;
+// const error = await Email.dispatch({
+// to: notificationRecipient,
+// subject: "Dash Web Server Crash",
+// content: this.generateCrashInstructions(crashCause)
+// });
+// if (error) {
+// this.sessionMonitor.mainLog(red(`dispatch failure @ ${notificationRecipient} ${yellow(`(${error.message})`)}`));
+// mainLog(red("distribution of crash notification experienced errors"));
+// } else {
+// mainLog(green("successfully distributed crash notification to recipients"));
+// }
+// }
+
+// /**
+// * Logic for interfacing with Solr. Either starts it,
+// * stops it, or rebuilds its indicies.
+// */
+// private executeSolrCommand = async (args: string[]): Promise<void> => {
+// const { exec, mainLog } = this.sessionMonitor;
+// const action = args[0];
+// if (action === "index") {
+// exec("npx ts-node ./updateSearch.ts", { cwd: pathFromRoot("./src/server") });
+// } else {
+// const command = `${onWindows ? "solr.cmd" : "solr"} ${args[0] === "start" ? "start" : "stop -p 8983"}`;
+// await exec(command, { cwd: "./solr-8.3.1/bin" });
+// try {
+// await get("http://localhost:8983");
+// mainLog(green("successfully connected to 8983 after running solr initialization"));
+// } catch {
+// mainLog(red("unable to connect at 8983 after running solr initialization"));
+// }
+// }
+// }
+
+// /**
+// * Broadcast to all clients that their connection
+// * is no longer valid, and explain why / what to expect.
+// */
+// private notifyClient: ExitHandler = reason => {
+// const { _socket } = WebSocket;
+// if (_socket) {
+// const message = typeof reason === "boolean" ? (reason ? "exit" : "temporary") : "crash";
+// Utils.Emit(_socket, MessageStore.ConnectionTerminated, message);
+// }
+// }
+
+// /**
+// * Performs a backup of the database, saved to the desktop subdirectory.
+// * This should work as is only on our specific release server.
+// */
+// private backup = async (): Promise<void> => this.sessionMonitor.exec("backup.bat", { cwd: this.releaseDesktop });
+
+// /**
+// * Compress either a brand new backup or the most recent backup and send it
+// * as an attachment to an email, dispatched to the requested recipient.
+// * @param mode specifies whether or not to make a new backup before exporting
+// * @param to the recipient of the email
+// */
+// private async dispatchZippedDebugBackup(to: string): Promise<void> {
+// const { mainLog } = this.sessionMonitor;
+// try {
+// // if desired, complete an immediate backup to send
+// await this.backup();
+// mainLog("backup complete");
+
+// const backupsDirectory = `${this.releaseDesktop}/backups`;
+
+// // sort all backups by their modified time, and choose the most recent one
+// const target = readdirSync(backupsDirectory).map(filename => ({
+// modifiedTime: statSync(`${backupsDirectory}/${filename}`).mtimeMs,
+// filename
+// })).sort((a, b) => b.modifiedTime - a.modifiedTime)[0].filename;
+// mainLog(`targeting ${target}...`);
+
+// // create a zip file and to it, write the contents of the backup directory
+// const zipName = `${target}.zip`;
+// const zipPath = `${this.releaseDesktop}/${zipName}`;
+// const targetPath = `${backupsDirectory}/${target}`;
+// const output = createWriteStream(zipPath);
+// const zip = Archiver('zip');
+// zip.pipe(output);
+// zip.directory(`${targetPath}/Dash`, false);
+// await zip.finalize();
+// mainLog(`zip finalized with size ${statSync(zipPath).size} bytes, saved to ${zipPath}`);
+
+// // dispatch the email to the recipient, containing the finalized zip file
+// const error = await Email.dispatch({
+// to,
+// subject: `Remote debug: compressed backup of ${target}...`,
+// content: this.generateDebugInstructions(zipName, target),
+// attachments: [{ filename: zipName, path: zipPath }]
+// });
+
+// // since this is intended to be a zero-footprint operation, clean up
+// // by unlinking both the backup generated earlier in the function and the compressed zip file.
+// // to generate a persistent backup, just run backup.
+// unlinkSync(zipPath);
+// rimraf.sync(targetPath);
+
+// // indicate success or failure
+// mainLog(`${error === null ? green("successfully dispatched") : red("failed to dispatch")} ${zipName} to ${cyan(to)}`);
+// error && mainLog(red(error.message));
+// } catch (error) {
+// mainLog(red("unable to dispatch zipped backup..."));
+// mainLog(red(error.message));
+// }
+// }
+
+// }
+
+// export namespace DashSessionAgent {
+
+// export const notificationRecipient = "brownptcdash@gmail.com";
+
+// } \ No newline at end of file
diff --git a/src/server/index.ts b/src/server/index.ts
index 313a2f0e2..454d99305 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -22,7 +22,7 @@ import GeneralGoogleManager from "./ApiManagers/GeneralGoogleManager";
import GooglePhotosManager from "./ApiManagers/GooglePhotosManager";
import { Logger } from "./ProcessFactory";
import { yellow } from "colors";
-import { DashSessionAgent } from "./DashSession/DashSessionAgent";
+// import { DashSessionAgent } from "./DashSession/DashSessionAgent";
import SessionManager from "./ApiManagers/SessionManager";
import { AppliedSessionAgent } from "resilient-server-session";
@@ -141,7 +141,7 @@ export async function launchServer() {
* So, the 'else' clause is exactly what we've always run when executing npm start.
*/
if (process.env.RELEASE) {
- (sessionAgent = new DashSessionAgent()).launch();
+ // (sessionAgent = new DashSessionAgent()).launch();
} else {
launchServer();
}