aboutsummaryrefslogtreecommitdiff
path: root/src/server/session/utilities
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/session/utilities')
-rw-r--r--src/server/session/utilities/ipc.ts52
-rw-r--r--src/server/session/utilities/session_config.ts129
-rw-r--r--src/server/session/utilities/utilities.ts31
3 files changed, 212 insertions, 0 deletions
diff --git a/src/server/session/utilities/ipc.ts b/src/server/session/utilities/ipc.ts
new file mode 100644
index 000000000..b20f3d337
--- /dev/null
+++ b/src/server/session/utilities/ipc.ts
@@ -0,0 +1,52 @@
+import { isMaster } from "cluster";
+import { Utils } from "../../../Utils";
+
+export namespace IPC {
+
+ export const suffix = isMaster ? Utils.GenerateGuid() : process.env.ipc_suffix;
+ const ipc_id = `ipc_id_${suffix}`;
+ const response_expected = `response_expected_${suffix}`;
+ const is_response = `is_response_${suffix}`;
+
+ export async function dispatchMessage(target: NodeJS.EventEmitter & { send?: Function }, message: any, expectResponse = false): Promise<Error | undefined> {
+ if (!target.send) {
+ return new Error("Cannot dispatch when send is undefined.");
+ }
+ message[response_expected] = expectResponse;
+ if (expectResponse) {
+ return new Promise(resolve => {
+ const messageId = Utils.GenerateGuid();
+ message[ipc_id] = messageId;
+ const responseHandler: (args: any) => void = response => {
+ const { error } = response;
+ if (response[is_response] && response[ipc_id] === messageId) {
+ target.removeListener("message", responseHandler);
+ resolve(error);
+ }
+ };
+ target.addListener("message", responseHandler);
+ target.send!(message);
+ });
+ } else {
+ target.send(message);
+ }
+ }
+
+ export function addMessagesHandler(target: NodeJS.EventEmitter & { send?: Function }, handler: (message: any) => void | Promise<void>): void {
+ target.addListener("message", async incoming => {
+ let error: Error | undefined;
+ try {
+ await handler(incoming);
+ } catch (e) {
+ error = e;
+ }
+ if (incoming[response_expected] && target.send) {
+ const response: any = { error };
+ response[ipc_id] = incoming[ipc_id];
+ response[is_response] = true;
+ target.send(response);
+ }
+ });
+ }
+
+} \ No newline at end of file
diff --git a/src/server/session/utilities/session_config.ts b/src/server/session/utilities/session_config.ts
new file mode 100644
index 000000000..b0e65dde4
--- /dev/null
+++ b/src/server/session/utilities/session_config.ts
@@ -0,0 +1,129 @@
+import { Schema } from "jsonschema";
+import { yellow, red, cyan, green, blue, magenta, Color, grey, gray, white, black } from "colors";
+
+const colorPattern = /black|red|green|yellow|blue|magenta|cyan|white|gray|grey/;
+
+const identifierProperties: Schema = {
+ type: "object",
+ properties: {
+ text: {
+ type: "string",
+ minLength: 1
+ },
+ color: {
+ type: "string",
+ pattern: colorPattern
+ }
+ }
+};
+
+const portProperties: Schema = {
+ type: "number",
+ minimum: 1024,
+ maximum: 65535
+};
+
+export const configurationSchema: Schema = {
+ id: "/configuration",
+ type: "object",
+ properties: {
+ showServerOutput: { type: "boolean" },
+ ports: {
+ type: "object",
+ properties: {
+ server: portProperties,
+ socket: portProperties
+ },
+ required: ["server"],
+ additionalProperties: true
+ },
+ identifiers: {
+ type: "object",
+ properties: {
+ master: identifierProperties,
+ worker: identifierProperties,
+ exec: identifierProperties
+ }
+ },
+ polling: {
+ type: "object",
+ additionalProperties: false,
+ properties: {
+ intervalSeconds: {
+ type: "number",
+ minimum: 1,
+ maximum: 86400
+ },
+ route: {
+ type: "string",
+ pattern: /\/[a-zA-Z]*/g
+ },
+ failureTolerance: {
+ type: "number",
+ minimum: 0,
+ }
+ }
+ },
+ }
+};
+
+type ColorLabel = "yellow" | "red" | "cyan" | "green" | "blue" | "magenta" | "grey" | "gray" | "white" | "black";
+
+export const colorMapping: Map<ColorLabel, Color> = new Map([
+ ["yellow", yellow],
+ ["red", red],
+ ["cyan", cyan],
+ ["green", green],
+ ["blue", blue],
+ ["magenta", magenta],
+ ["grey", grey],
+ ["gray", gray],
+ ["white", white],
+ ["black", black]
+]);
+
+interface Identifier {
+ text: string;
+ color: ColorLabel;
+}
+
+export interface Identifiers {
+ master: Identifier;
+ worker: Identifier;
+ exec: Identifier;
+}
+
+export interface Configuration {
+ showServerOutput: boolean;
+ identifiers: Identifiers;
+ ports: { [description: string]: number };
+ polling: {
+ route: string;
+ intervalSeconds: number;
+ failureTolerance: number;
+ };
+}
+
+export const defaultConfig: Configuration = {
+ showServerOutput: false,
+ identifiers: {
+ master: {
+ text: "__monitor__",
+ color: "yellow"
+ },
+ worker: {
+ text: "__server__",
+ color: "magenta"
+ },
+ exec: {
+ text: "__exec__",
+ color: "green"
+ }
+ },
+ ports: { server: 3000 },
+ polling: {
+ route: "/",
+ intervalSeconds: 30,
+ failureTolerance: 0
+ }
+}; \ No newline at end of file
diff --git a/src/server/session/utilities/utilities.ts b/src/server/session/utilities/utilities.ts
new file mode 100644
index 000000000..ac8a6590a
--- /dev/null
+++ b/src/server/session/utilities/utilities.ts
@@ -0,0 +1,31 @@
+export namespace Utilities {
+
+ /**
+ * At any arbitrary layer of nesting within the configuration objects, any single value that
+ * is not specified by the configuration is given the default counterpart. If, within an object,
+ * one peer is given by configuration and two are not, the one is preserved while the two are given
+ * the default value.
+ * @returns the composition of all of the assigned objects, much like Object.assign(), but with more
+ * granularity in the overwriting of nested objects
+ */
+ export function preciseAssign(target: any, ...sources: any[]): any {
+ for (const source of sources) {
+ preciseAssignHelper(target, source);
+ }
+ return target;
+ }
+
+ export function preciseAssignHelper(target: any, source: any) {
+ Array.from(new Set([...Object.keys(target), ...Object.keys(source)])).map(property => {
+ let targetValue: any, sourceValue: any;
+ if (sourceValue = source[property]) {
+ if (typeof sourceValue === "object" && typeof (targetValue = target[property]) === "object") {
+ preciseAssignHelper(targetValue, sourceValue);
+ } else {
+ target[property] = sourceValue;
+ }
+ }
+ });
+ }
+
+} \ No newline at end of file