diff options
Diffstat (limited to 'src/server/DashSession/Session')
8 files changed, 202 insertions, 206 deletions
diff --git a/src/server/DashSession/Session/agents/applied_session_agent.ts b/src/server/DashSession/Session/agents/applied_session_agent.ts index 2037e93e5..c42ba95cc 100644 --- a/src/server/DashSession/Session/agents/applied_session_agent.ts +++ b/src/server/DashSession/Session/agents/applied_session_agent.ts @@ -1,13 +1,13 @@ -import * as _cluster from "cluster"; -import { Monitor } from "./monitor"; -import { ServerWorker } from "./server_worker"; +import * as _cluster from 'cluster'; +import { Monitor } from './monitor'; +import { ServerWorker } from './server_worker'; +  const cluster = _cluster as any;  const isMaster = cluster.isPrimary;  export type ExitHandler = (reason: Error | boolean) => void | Promise<void>;  export abstract class AppliedSessionAgent { -      // the following two methods allow the developer to create a custom      // session and use the built in customization options for each thread      protected abstract initializeMonitor(monitor: Monitor): Promise<string>; @@ -18,15 +18,15 @@ export abstract class AppliedSessionAgent {      public killSession = (reason: string, graceful = true, errorCode = 0) => {          const target = cluster.default.isPrimary ? this.sessionMonitor : this.serverWorker;          target.killSession(reason, graceful, errorCode); -    } +    };      private sessionMonitorRef: Monitor | undefined;      public get sessionMonitor(): Monitor {          if (!cluster.default.isPrimary) { -            this.serverWorker.emit("kill", { +            this.serverWorker.emit('kill', {                  graceful: false, -                reason: "Cannot access the session monitor directly from the server worker thread.", -                errorCode: 1 +                reason: 'Cannot access the session monitor directly from the server worker thread.', +                errorCode: 1,              });              throw new Error();          } @@ -36,7 +36,7 @@ export abstract class AppliedSessionAgent {      private serverWorkerRef: ServerWorker | undefined;      public get serverWorker(): ServerWorker {          if (isMaster) { -            throw new Error("Cannot access the server worker directly from the session monitor thread"); +            throw new Error('Cannot access the server worker directly from the session monitor thread');          }          return this.serverWorkerRef!;      } @@ -52,8 +52,7 @@ export abstract class AppliedSessionAgent {                  this.serverWorkerRef = await this.initializeServerWorker();              }          } else { -            throw new Error("Cannot launch a session thread more than once per process."); +            throw new Error('Cannot launch a session thread more than once per process.');          }      } - -}
\ No newline at end of file +} diff --git a/src/server/DashSession/Session/agents/monitor.ts b/src/server/DashSession/Session/agents/monitor.ts index a6fde4356..6cdad46c2 100644 --- a/src/server/DashSession/Session/agents/monitor.ts +++ b/src/server/DashSession/Session/agents/monitor.ts @@ -1,21 +1,19 @@ -import { ExitHandler } from './applied_session_agent'; -import { Configuration, configurationSchema, defaultConfig, Identifiers, colorMapping } from '../utilities/session_config'; -import Repl, { ReplAction } from '../utilities/repl'; +import { ExecOptions, exec } from 'child_process';  import * as _cluster from 'cluster';  import { Worker } from 'cluster'; -import { manage, MessageHandler, ErrorLike } from './promisified_ipc_manager'; -import { red, cyan, white, yellow, blue } from 'colors'; -import { exec, ExecOptions } from 'child_process'; -import { validate, ValidationError } from 'jsonschema'; -import { Utilities } from '../utilities/utilities'; +import { blue, cyan, red, white, yellow } from 'colors';  import { readFileSync } from 'fs'; +import { ValidationError, validate } from 'jsonschema'; +import Repl, { ReplAction } from '../utilities/repl'; +import { Configuration, Identifiers, colorMapping, configurationSchema, defaultConfig } from '../utilities/session_config'; +import { Utilities } from '../utilities/utilities'; +import { ExitHandler } from './applied_session_agent';  import IPCMessageReceiver from './process_message_router'; +import { ErrorLike, MessageHandler, manage } from './promisified_ipc_manager';  import { ServerWorker } from './server_worker'; +  const cluster = _cluster as any; -const isWorker = cluster.isWorker; -const setupMaster = cluster.setupPrimary; -const on = cluster.on; -const fork = cluster.fork; +const { isWorker, setupMaster, on, fork } = cluster;  /**   * Validates and reads the configuration file, accordingly builds a child process factory @@ -41,9 +39,8 @@ export class Monitor extends IPCMessageReceiver {          } else if (++Monitor.count > 1) {              console.error(red('cannot create more than one monitor.'));              process.exit(1); -        } else { -            return new Monitor();          } +        return new Monitor();      }      private constructor() { @@ -128,25 +125,25 @@ export class Monitor extends IPCMessageReceiver {          this.repl.registerCommand(basename, argPatterns, action);      }; -    public exec = (command: string, options?: ExecOptions) => { -        return new Promise<void>(resolve => { +    public exec = (command: string, options?: ExecOptions) => +        new Promise<void>(resolve => {              exec(command, { ...options, encoding: 'utf8' }, (error, stdout, stderr) => {                  if (error) {                      this.execLog(red(`unable to execute ${white(command)}`));                      error.message.split('\n').forEach(line => line.length && this.execLog(red(`(error) ${line}`)));                  } else { -                    let outLines: string[], errorLines: string[]; -                    if ((outLines = stdout.split('\n').filter(line => line.length)).length) { +                    const outLines = stdout.split('\n').filter(line => line.length); +                    if (outLines.length) {                          outLines.forEach(line => line.length && this.execLog(cyan(`(stdout) ${line}`)));                      } -                    if ((errorLines = stderr.split('\n').filter(line => line.length)).length) { +                    const errorLines = stderr.split('\n').filter(line => line.length); +                    if (errorLines.length) {                          errorLines.forEach(line => line.length && this.execLog(yellow(`(stderr) ${line}`)));                      }                  }                  resolve();              });          }); -    };      /**       * Generates a blue UTC string associated with the time @@ -226,12 +223,10 @@ export class Monitor extends IPCMessageReceiver {              const newPollingIntervalSeconds = Math.floor(Number(args[1]));              if (newPollingIntervalSeconds < 0) {                  this.mainLog(red('the polling interval must be a non-negative integer')); -            } else { -                if (newPollingIntervalSeconds !== this.config.polling.intervalSeconds) { -                    this.config.polling.intervalSeconds = newPollingIntervalSeconds; -                    if (args[2] === 'true') { -                        Monitor.IPCManager.emit('updatePollingInterval', { newPollingIntervalSeconds }); -                    } +            } else if (newPollingIntervalSeconds !== this.config.polling.intervalSeconds) { +                this.config.polling.intervalSeconds = newPollingIntervalSeconds; +                if (args[2] === 'true') { +                    Monitor.IPCManager.emit('updatePollingInterval', { newPollingIntervalSeconds });                  }              }          }); @@ -297,6 +292,7 @@ export class Monitor extends IPCMessageReceiver {      };  } +// eslint-disable-next-line no-redeclare  export namespace Monitor {      export enum IntrinsicEvents {          KeyGenerated = 'key_generated', diff --git a/src/server/DashSession/Session/agents/process_message_router.ts b/src/server/DashSession/Session/agents/process_message_router.ts index 0745ea455..3e2b7d8d0 100644 --- a/src/server/DashSession/Session/agents/process_message_router.ts +++ b/src/server/DashSession/Session/agents/process_message_router.ts @@ -1,7 +1,6 @@ -import { MessageHandler, PromisifiedIPCManager, HandlerMap } from "./promisified_ipc_manager"; +import { MessageHandler, PromisifiedIPCManager, HandlerMap } from './promisified_ipc_manager';  export default abstract class IPCMessageReceiver { -      protected static IPCManager: PromisifiedIPCManager;      protected handlers: HandlerMap = {}; @@ -18,7 +17,7 @@ export default abstract class IPCMessageReceiver {          } else {              handlers.push(handler);          } -    } +    };      /**       * Unregister a given listener at this message. @@ -31,11 +30,10 @@ export default abstract class IPCMessageReceiver {                  handlers.splice(index, 1);              }          } -    } +    }; -    /**  +    /**       * Unregister all listeners at this message.       */      public clearMessageListeners = (...names: string[]) => names.map(name => delete this.handlers[name]); - -}
\ No newline at end of file +} diff --git a/src/server/DashSession/Session/agents/promisified_ipc_manager.ts b/src/server/DashSession/Session/agents/promisified_ipc_manager.ts index 76e218977..fc870d003 100644 --- a/src/server/DashSession/Session/agents/promisified_ipc_manager.ts +++ b/src/server/DashSession/Session/agents/promisified_ipc_manager.ts @@ -1,13 +1,14 @@ -import { Utilities } from '../utilities/utilities';  import { ChildProcess } from 'child_process'; +import { Utilities } from '../utilities/utilities';  /** - * Convenience constructor - * @param target the process / worker to which to attach the specialized listeners + * Specifies a general message format for this API   */ -export function manage(target: IPCTarget, handlers?: HandlerMap) { -    return new PromisifiedIPCManager(target, handlers); -} +export type Message<T = any> = { +    name: string; +    args?: T; +}; +export type MessageHandler<T = any> = (args: T) => any | Promise<any>;  /**   * Captures the logic to execute upon receiving a message @@ -22,15 +23,10 @@ export type HandlerMap = { [name: string]: MessageHandler[] };   */  export type IPCTarget = NodeJS.Process | ChildProcess; -/** - * Specifies a general message format for this API - */ -export type Message<T = any> = { -    name: string; -    args?: T; -}; -export type MessageHandler<T = any> = (args: T) => any | Promise<any>; - +interface Metadata { +    isResponse: boolean; +    id: string; +}  /**   * When a message is emitted, it is embedded with private metadata   * to facilitate the resolution of promises, etc. @@ -38,10 +34,6 @@ export type MessageHandler<T = any> = (args: T) => any | Promise<any>;  interface InternalMessage extends Message {      metadata: Metadata;  } -interface Metadata { -    isResponse: boolean; -    id: string; -}  /**   * Allows for the transmission of the error's key features over IPC. @@ -95,11 +87,11 @@ export class PromisifiedIPCManager {          }          return new Promise<Response<T>>(resolve => {              const messageId = Utilities.guid(); -            type InternalMessageHandler = (message: any /* MessageListener*/) => any | Promise<any>; -            const responseHandler: InternalMessageHandler = ({ metadata: { id, isResponse }, args }) => { +            type InternalMessageHandler = (message: any /* MessageListener */) => any | Promise<any>; +            const responseHandler: InternalMessageHandler = ({ metadata: { id, isResponse }, args: hargs }) => {                  if (isResponse && id === messageId) {                      this.target.removeListener('message', responseHandler); -                    resolve(args); +                    resolve(hargs);                  }              };              this.target.addListener('message', responseHandler); @@ -118,8 +110,9 @@ export class PromisifiedIPCManager {       * completion response for each of the pending messages, allowing their       * promises in the caller to resolve.       */ -    public destroy = () => { -        return new Promise<void>(async resolve => { +    public destroy = () => +        // eslint-disable-next-line no-async-promise-executor +        new Promise<void>(async resolve => {              if (this.callerIsTarget) {                  this.destroyHelper();              } else { @@ -127,7 +120,6 @@ export class PromisifiedIPCManager {              }              resolve();          }); -    };      /**       * Dispatches the dummy responses and sets the isDestroyed flag to true. @@ -168,12 +160,20 @@ export class PromisifiedIPCManager {                      error = e;                  }                  if (!this.isDestroyed && this.target.send) { -                    const metadata = { id, isResponse: true }; +                    const metadataRes = { id, isResponse: true };                      const response: Response = { results, error }; -                    const message = { name, args: response, metadata }; +                    const messageRes = { name, args: response, metadata: metadataRes };                      delete this.pendingMessages[id]; -                    this.target.send(message); +                    this.target.send(messageRes);                  }              }          };  } + +/** + * Convenience constructor + * @param target the process / worker to which to attach the specialized listeners + */ +export function manage(target: IPCTarget, handlers?: HandlerMap) { +    return new PromisifiedIPCManager(target, handlers); +} diff --git a/src/server/DashSession/Session/agents/server_worker.ts b/src/server/DashSession/Session/agents/server_worker.ts index d8b3ee80b..85e1b31d6 100644 --- a/src/server/DashSession/Session/agents/server_worker.ts +++ b/src/server/DashSession/Session/agents/server_worker.ts @@ -1,10 +1,10 @@ -import cluster from "cluster"; -import { green, red, white, yellow } from "colors"; -import { get } from "request-promise"; -import { ExitHandler } from "./applied_session_agent"; -import { Monitor } from "./monitor"; -import IPCMessageReceiver from "./process_message_router"; -import { ErrorLike, manage } from "./promisified_ipc_manager"; +import cluster from 'cluster'; +import { green, red, white, yellow } from 'colors'; +import { get } from 'request-promise'; +import { ExitHandler } from './applied_session_agent'; +import { Monitor } from './monitor'; +import IPCMessageReceiver from './process_message_router'; +import { ErrorLike, manage } from './promisified_ipc_manager';  /**   * Effectively, each worker repairs the connection to the server by reintroducing a consistent state @@ -23,18 +23,17 @@ export class ServerWorker extends IPCMessageReceiver {      private isInitialized = false;      public static Create(work: Function) {          if (cluster.isPrimary) { -            console.error(red("cannot create a worker on the monitor process.")); +            console.error(red('cannot create a worker on the monitor process.'));              process.exit(1);          } else if (++ServerWorker.count > 1) { -            ServerWorker.IPCManager.emit("kill", { -                reason: "cannot create more than one worker on a given worker process.", +            ServerWorker.IPCManager.emit('kill', { +                reason: 'cannot create more than one worker on a given worker process.',                  graceful: false, -                errorCode: 1 +                errorCode: 1,              });              process.exit(1); -        } else { -            return new ServerWorker(work);          } +        return new ServerWorker(work);      }      /** @@ -48,7 +47,7 @@ export class ServerWorker extends IPCMessageReceiver {       * server worker (child process). This will also kill       * this process (child process).       */ -    public killSession = (reason: string, graceful = true, errorCode = 0) => this.emit<never>("kill", { reason, graceful, errorCode }); +    public killSession = (reason: string, graceful = true, errorCode = 0) => this.emit<never>('kill', { reason, graceful, errorCode });      /**       * A convenience wrapper to tell the session monitor (parent process) @@ -60,7 +59,7 @@ export class ServerWorker extends IPCMessageReceiver {          super();          this.configureInternalHandlers();          ServerWorker.IPCManager = manage(process, this.handlers); -        this.lifecycleNotification(green(`initializing process... ${white(`[${process.execPath} ${process.execArgv.join(" ")}]`)}`)); +        this.lifecycleNotification(green(`initializing process... ${white(`[${process.execPath} ${process.execArgv.join(' ')}]`)}`));          const { pollingRoute, serverPort, pollingIntervalSeconds, pollingFailureTolerance } = process.env;          this.serverPort = Number(serverPort); @@ -78,8 +77,10 @@ export class ServerWorker extends IPCMessageReceiver {       */      protected configureInternalHandlers = () => {          // updates the local values of variables to the those sent from master -        this.on("updatePollingInterval", ({ newPollingIntervalSeconds }) => this.pollingIntervalSeconds = newPollingIntervalSeconds); -        this.on("manualExit", async ({ isSessionEnd }) => { +        this.on('updatePollingInterval', ({ newPollingIntervalSeconds }) => { +            this.pollingIntervalSeconds = newPollingIntervalSeconds; +        }); +        this.on('manualExit', async ({ isSessionEnd }) => {              await ServerWorker.IPCManager.destroy();              await this.executeExitHandlers(isSessionEnd);              process.exit(0); @@ -91,7 +92,7 @@ export class ServerWorker extends IPCMessageReceiver {              const appropriateError = reason instanceof Error ? reason : new Error(`unhandled rejection: ${reason}`);              this.proactiveUnplannedExit(appropriateError);          }); -    } +    };      /**       * Execute the list of functions registered to be called @@ -102,7 +103,7 @@ export class ServerWorker extends IPCMessageReceiver {      /**       * Notify master thread (which will log update in the console) of initialization via IPC.       */ -    public lifecycleNotification = (event: string) => this.emit("lifecycle", { event }); +    public lifecycleNotification = (event: string) => this.emit('lifecycle', { event });      /**       * Called whenever the process has a reason to terminate, either through an uncaught exception @@ -120,11 +121,11 @@ export class ServerWorker extends IPCMessageReceiver {          this.lifecycleNotification(red(error.message));          await ServerWorker.IPCManager.destroy();          process.exit(1); -    } +    };      /**       * This monitors the health of the server by submitting a get request to whatever port / route specified -     * by the configuration every n seconds, where n is also given by the configuration.  +     * by the configuration every n seconds, where n is also given by the configuration.       */      private pollServer = async (): Promise<void> => {          await new Promise<void>(resolve => { @@ -156,6 +157,5 @@ export class ServerWorker extends IPCMessageReceiver {          });          // controlled, asynchronous infinite recursion achieves a persistent poll that does not submit a new request until the previous has completed          this.pollServer(); -    } - +    };  } diff --git a/src/server/DashSession/Session/utilities/repl.ts b/src/server/DashSession/Session/utilities/repl.ts index 643141286..5d9f15e4c 100644 --- a/src/server/DashSession/Session/utilities/repl.ts +++ b/src/server/DashSession/Session/utilities/repl.ts @@ -1,5 +1,5 @@ -import { createInterface, Interface } from "readline"; -import { red, green, white } from "colors"; +import { createInterface, Interface } from 'readline'; +import { red, green, white } from 'colors';  export interface Configuration {      identifier: () => string | string; @@ -32,76 +32,82 @@ export default class Repl {          this.interface = createInterface(process.stdin, process.stdout).on('line', this.considerInput);      } -    private resolvedIdentifier = () => typeof this.identifier === "string" ? this.identifier : this.identifier(); +    private resolvedIdentifier = () => (typeof this.identifier === 'string' ? this.identifier : this.identifier());      private usage = (command: string, validCommand: boolean) => {          if (validCommand) {              const formatted = white(command); -            const patterns = green(this.commandMap.get(command)!.map(({ argPatterns }) => `${formatted}  ${argPatterns.join("  ")}`).join('\n')); +            const patterns = green( +                this.commandMap +                    .get(command)! +                    .map(({ argPatterns }) => `${formatted}  ${argPatterns.join('  ')}`) +                    .join('\n') +            );              return `${this.resolvedIdentifier()}\nthe given arguments do not match any registered patterns for ${formatted}\nthe list of valid argument patterns is given by:\n${patterns}`; -        } else { -            const resolved = this.keys; -            if (resolved) { -                return resolved; -            } -            const members: string[] = []; -            const keys = this.commandMap.keys(); -            let next: IteratorResult<string>; -            while (!(next = keys.next()).done) { -                members.push(next.value); -            } -            return `${this.resolvedIdentifier()} commands: { ${members.sort().join(", ")} }`;          } -    } +        const resolved = this.keys; +        if (resolved) { +            return resolved; +        } +        const members: string[] = []; +        const keys = this.commandMap.keys(); +        let next: IteratorResult<string>; +        // eslint-disable-next-line no-cond-assign +        while (!(next = keys.next()).done) { +            members.push(next.value); +        } +        return `${this.resolvedIdentifier()} commands: { ${members.sort().join(', ')} }`; +    };      private success = (command: string) => `${this.resolvedIdentifier()} completed local execution of ${white(command)}`;      public registerCommand = (basename: string, argPatterns: (RegExp | string)[], action: ReplAction) => {          const existing = this.commandMap.get(basename); -        const converted = argPatterns.map(input => input instanceof RegExp ? input : new RegExp(input)); +        const converted = argPatterns.map(input => (input instanceof RegExp ? input : new RegExp(input)));          const registration = { argPatterns: converted, action };          if (existing) {              existing.push(registration);          } else {              this.commandMap.set(basename, [registration]);          } -    } +    };      private invalid = (command: string, validCommand: boolean) => { -        console.log(red(typeof this.onInvalid === "string" ? this.onInvalid : this.onInvalid(command, validCommand))); +        console.log(red(typeof this.onInvalid === 'string' ? this.onInvalid : this.onInvalid(command, validCommand)));          this.busy = false; -    } +    };      private valid = (command: string) => { -        console.log(green(typeof this.onValid === "string" ? this.onValid : this.onValid(command))); +        console.log(green(typeof this.onValid === 'string' ? this.onValid : this.onValid(command)));          this.busy = false; -    } +    }; -    private considerInput = async (line: string) => { +    private considerInput = async (lineIn: string) => {          if (this.busy) { -            console.log(red("Busy")); +            console.log(red('Busy'));              return;          }          this.busy = true; -        line = line.trim(); +        let line = lineIn.trim();          if (this.isCaseSensitive) {              line = line.toLowerCase();          }          const [command, ...args] = line.split(/\s+/g);          if (!command) { -            return this.invalid(command, false); +            this.invalid(command, false); +            return;          }          const registered = this.commandMap.get(command);          if (registered) {              const { length } = args;              const candidates = registered.filter(({ argPatterns: { length: count } }) => count === length); -            for (const { argPatterns, action } of candidates) { +            candidates.forEach(({ argPatterns, action }: { argPatterns: any; action: any }) => {                  const parsed: string[] = [];                  let matched = true;                  if (length) {                      for (let i = 0; i < length; i++) { -                        let matches: RegExpExecArray | null; -                        if ((matches = argPatterns[i].exec(args[i])) === null) { +                        const matches = argPatterns[i].exec(args[i]); +                        if (matches === null) {                              matched = false;                              break;                          } @@ -110,19 +116,17 @@ export default class Repl {                  }                  if (!length || matched) {                      const result = action(parsed); -                    const resolve = () => this.valid(`${command} ${parsed.join(" ")}`); +                    const resolve = () => this.valid(`${command} ${parsed.join(' ')}`);                      if (result instanceof Promise) {                          result.then(resolve);                      } else {                          resolve();                      } -                    return;                  } -            } +            });              this.invalid(command, true);          } else {              this.invalid(command, false);          } -    } - -}
\ No newline at end of file +    }; +} diff --git a/src/server/DashSession/Session/utilities/session_config.ts b/src/server/DashSession/Session/utilities/session_config.ts index 266759929..b42c1a3c7 100644 --- a/src/server/DashSession/Session/utilities/session_config.ts +++ b/src/server/DashSession/Session/utilities/session_config.ts @@ -1,85 +1,85 @@ -import { Schema } from "jsonschema"; -import { yellow, red, cyan, green, blue, magenta, Color, grey, gray, white, black } from "colors"; +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", +    type: 'object',      properties: {          text: { -            type: "string", -            minLength: 1 +            type: 'string', +            minLength: 1,          },          color: { -            type: "string", -            pattern: colorPattern -        } -    } +            type: 'string', +            pattern: colorPattern, +        }, +    },  };  const portProperties: Schema = { -    type: "number", +    type: 'number',      minimum: 443, -    maximum: 65535 +    maximum: 65535,  };  export const configurationSchema: Schema = { -    id: "/configuration", -    type: "object", +    id: '/configuration', +    type: 'object',      properties: { -        showServerOutput: { type: "boolean" }, +        showServerOutput: { type: 'boolean' },          ports: { -            type: "object", +            type: 'object',              properties: {                  server: portProperties, -                socket: portProperties +                socket: portProperties,              }, -            required: ["server"], -            additionalProperties: true +            required: ['server'], +            additionalProperties: true,          },          identifiers: { -            type: "object", +            type: 'object',              properties: {                  master: identifierProperties,                  worker: identifierProperties, -                exec: identifierProperties -            } +                exec: identifierProperties, +            },          },          polling: { -            type: "object", +            type: 'object',              additionalProperties: false,              properties: {                  intervalSeconds: { -                    type: "number", +                    type: 'number',                      minimum: 1, -                    maximum: 86400 +                    maximum: 86400,                  },                  route: { -                    type: "string", -                    pattern: /\/[a-zA-Z]*/g +                    type: 'string', +                    pattern: /\/[a-zA-Z]*/g,                  },                  failureTolerance: { -                    type: "number", +                    type: 'number',                      minimum: 0, -                } -            } +                }, +            },          }, -    } +    },  }; -type ColorLabel = "yellow" | "red" | "cyan" | "green" | "blue" | "magenta" | "grey" | "gray" | "white" | "black"; +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] +    ['yellow', yellow], +    ['red', red], +    ['cyan', cyan], +    ['green', green], +    ['blue', blue], +    ['magenta', magenta], +    ['grey', grey], +    ['gray', gray], +    ['white', white], +    ['black', black],  ]);  interface Identifier { @@ -108,22 +108,22 @@ export const defaultConfig: Configuration = {      showServerOutput: false,      identifiers: {          master: { -            text: "__monitor__", -            color: "yellow" +            text: '__monitor__', +            color: 'yellow',          },          worker: { -            text: "__server__", -            color: "magenta" +            text: '__server__', +            color: 'magenta',          },          exec: { -            text: "__exec__", -            color: "green" -        } +            text: '__exec__', +            color: 'green', +        },      },      ports: { server: 1050 },      polling: { -        route: "/", +        route: '/',          intervalSeconds: 30, -        failureTolerance: 0 -    } -};
\ No newline at end of file +        failureTolerance: 0, +    }, +}; diff --git a/src/server/DashSession/Session/utilities/utilities.ts b/src/server/DashSession/Session/utilities/utilities.ts index eb8de9d7e..a2ba29c67 100644 --- a/src/server/DashSession/Session/utilities/utilities.ts +++ b/src/server/DashSession/Session/utilities/utilities.ts @@ -1,31 +1,16 @@ -import { v4 } from "uuid"; +import { v4 } from 'uuid';  export namespace Utilities { -      export function guid() {          return v4();      } -    /** -         * 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") { +        Array.from(new Set([...Object.keys(target), ...Object.keys(source)])).forEach(property => { +            const targetValue = target[property]; +            const sourceValue = source[property]; +            if (sourceValue) { +                if (typeof sourceValue === 'object' && typeof targetValue === 'object') {                      preciseAssignHelper(targetValue, sourceValue);                  } else {                      target[property] = sourceValue; @@ -34,4 +19,18 @@ export namespace Utilities {          });      } -}
\ No newline at end of file +    /** +     * 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 { +        sources.forEach(source => { +            preciseAssignHelper(target, source); +        }); +        return target; +    } +}  | 
