Browse Source

refactor: Export instantiated classes

Owen Diffey 1 year ago
parent
commit
b71a0cf769

+ 2 - 14
backend/src/BaseModule.ts

@@ -1,5 +1,4 @@
 import JobContext from "@/JobContext";
-import JobQueue from "@/JobQueue";
 import LogBook, { Log } from "@/LogBook";
 import ModuleManager from "@/ModuleManager";
 import { Modules } from "@/types/Modules";
@@ -15,12 +14,6 @@ export enum ModuleStatus {
 }
 
 export default abstract class BaseModule {
-	protected _moduleManager: ModuleManager;
-
-	protected _logBook: LogBook;
-
-	protected _jobQueue: JobQueue;
-
 	protected _name: string;
 
 	protected _status: ModuleStatus;
@@ -54,9 +47,6 @@ export default abstract class BaseModule {
 	 * @param name - Module name
 	 */
 	public constructor(name: string) {
-		this._moduleManager = ModuleManager.getPrimaryInstance();
-		this._logBook = LogBook.getPrimaryInstance();
-		this._jobQueue = JobQueue.getPrimaryInstance();
 		this._name = name;
 		this._status = ModuleStatus.LOADED;
 		this._dependentModules = [];
@@ -207,9 +197,7 @@ export default abstract class BaseModule {
 			(canRunJobs: boolean, moduleName: keyof Modules): boolean => {
 				if (canRunJobs === false) return false;
 
-				return !!this._moduleManager
-					.getModule(moduleName)
-					?.canRunJobs();
+				return !!ModuleManager.getModule(moduleName)?.canRunJobs();
 			},
 			this.getStatus() === ModuleStatus.STARTED
 		);
@@ -261,7 +249,7 @@ export default abstract class BaseModule {
 		} = {
 			...(typeof log === "string" ? { message: log } : log)
 		};
-		this._logBook.log({
+		LogBook.log({
 			message,
 			type,
 			category: `modules.${this.getName()}`,

+ 7 - 18
backend/src/Job.ts

@@ -1,4 +1,3 @@
-import BaseModule from "@/BaseModule";
 import JobContext from "@/JobContext";
 import JobStatistics from "@/JobStatistics";
 import LogBook, { Log } from "@/LogBook";
@@ -45,10 +44,6 @@ export default class Job {
 
 	private _completedAt?: number;
 
-	private _logBook: LogBook;
-
-	private _jobStatistics: JobStatistics;
-
 	/**
 	 * Job
 	 *
@@ -66,7 +61,7 @@ export default class Job {
 		this._name = name;
 		this._priority = 1;
 
-		const module = ModuleManager.getPrimaryInstance().getModule(moduleName);
+		const module = ModuleManager.getModule(moduleName);
 		if (!module) throw new Error("Module not found.");
 		this._module = module;
 
@@ -74,10 +69,7 @@ export default class Job {
 
 		this._payload = payload;
 
-		this._logBook = LogBook.getPrimaryInstance();
-
-		this._jobStatistics = JobStatistics.getPrimaryInstance();
-		this._jobStatistics.updateStats(this.getName(), "added");
+		JobStatistics.updateStats(this.getName(), "added");
 
 		let contextOptions;
 
@@ -187,10 +179,7 @@ export default class Job {
 						message: "Job completed successfully",
 						type: "success"
 					});
-					this._jobStatistics.updateStats(
-						this.getName(),
-						"successful"
-					);
+					JobStatistics.updateStats(this.getName(), "successful");
 					return response;
 				})
 				.catch((err: any) => {
@@ -199,14 +188,14 @@ export default class Job {
 						type: "error",
 						data: { error: err }
 					});
-					this._jobStatistics.updateStats(this.getName(), "failed");
+					JobStatistics.updateStats(this.getName(), "failed");
 					throw err;
 				})
 				.finally(() => {
 					this._completedAt = performance.now();
-					this._jobStatistics.updateStats(this.getName(), "total");
+					JobStatistics.updateStats(this.getName(), "total");
 					if (this._startedAt)
-						this._jobStatistics.updateStats(
+						JobStatistics.updateStats(
 							this.getName(),
 							"duration",
 							this._completedAt - this._startedAt
@@ -229,7 +218,7 @@ export default class Job {
 		} = {
 			...(typeof log === "string" ? { message: log } : log)
 		};
-		this._logBook.log({
+		LogBook.log({
 			message,
 			type,
 			category: this.getName(),

+ 0 - 4
backend/src/JobContext.ts

@@ -2,7 +2,6 @@ import { Types } from "mongoose";
 import { SessionSchema } from "@/models/schemas/sessions/schema";
 import BaseModule from "@/BaseModule";
 import Job from "@/Job";
-import JobQueue from "@/JobQueue";
 import { Log } from "@/LogBook";
 import { JobOptions } from "@/types/JobOptions";
 import { Jobs, Modules } from "@/types/Modules";
@@ -11,8 +10,6 @@ import { Models } from "@/types/Models";
 export default class JobContext {
 	public readonly job: Job;
 
-	public readonly jobQueue: JobQueue;
-
 	private _session?: SessionSchema;
 
 	private readonly _socketId?: string;
@@ -22,7 +19,6 @@ export default class JobContext {
 		options?: { session?: SessionSchema; socketId?: string }
 	) {
 		this.job = job;
-		this.jobQueue = JobQueue.getPrimaryInstance();
 		this._session = options?.session;
 		this._socketId = options?.socketId;
 	}

+ 3 - 11
backend/src/JobQueue.ts

@@ -3,9 +3,7 @@ import Job, { JobStatus } from "@/Job";
 import { JobOptions } from "@/types/JobOptions";
 import { Jobs, Modules } from "@/types/Modules";
 
-export default class JobQueue {
-	static primaryInstance = new this();
-
+export class JobQueue {
 	private _concurrency: number;
 
 	private _isPaused: boolean;
@@ -237,12 +235,6 @@ export default class JobQueue {
 	public getJobs() {
 		return this._jobs;
 	}
-
-	static getPrimaryInstance(): JobQueue {
-		return this.primaryInstance;
-	}
-
-	static setPrimaryInstance(instance: JobQueue) {
-		this.primaryInstance = instance;
-	}
 }
+
+export default new JobQueue();

+ 3 - 11
backend/src/JobStatistics.ts

@@ -1,6 +1,4 @@
-export default class JobStatistics {
-	static primaryInstance = new this();
-
+export class JobStatistics {
 	private _stats: Record<
 		string,
 		{
@@ -79,12 +77,6 @@ export default class JobStatistics {
 				this._stats[jobName].totalTime / this._stats[jobName].total;
 		} else this._stats[jobName][type] += 1;
 	}
-
-	static getPrimaryInstance(): JobStatistics {
-		return this.primaryInstance;
-	}
-
-	static setPrimaryInstance(instance: JobStatistics) {
-		this.primaryInstance = instance;
-	}
 }
+
+export default new JobStatistics();

+ 3 - 11
backend/src/LogBook.ts

@@ -31,9 +31,7 @@ const COLOR_YELLOW = "\x1b[33m";
 const COLOR_CYAN = "\x1b[36m";
 const COLOR_RESET = "\x1b[0m";
 
-export default class LogBook {
-	static primaryInstance = new this();
-
+export class LogBook {
 	// A list of log objects stored in memory, if enabled generally
 	private _logs: Log[];
 
@@ -308,12 +306,6 @@ export default class LogBook {
 			}
 		}
 	}
-
-	static getPrimaryInstance(): LogBook {
-		return this.primaryInstance;
-	}
-
-	static setPrimaryInstance(instance: LogBook) {
-		this.primaryInstance = instance;
-	}
 }
+
+export default new LogBook();

+ 9 - 16
backend/src/ModuleManager.ts

@@ -1,10 +1,8 @@
 import { ModuleStatus } from "@/BaseModule";
 import JobQueue from "@/JobQueue";
-import { Modules, ModuleClass } from "@/types/Modules";
-
-export default class ModuleManager {
-	static primaryInstance = new this();
+import { Modules } from "@/types/Modules";
 
+export class ModuleManager {
 	private _modules?: Modules;
 
 	/**
@@ -42,9 +40,10 @@ export default class ModuleManager {
 			stations: "StationsModule",
 			websocket: "WebSocketModule"
 		};
-		const { default: Module }: { default: ModuleClass<Modules[T]> } =
-			await import(`./modules/${mapper[moduleName]}`);
-		return new Module();
+		const { default: Module }: { default: Modules[T] } = await import(
+			`./modules/${mapper[moduleName]}`
+		);
+		return Module;
 	}
 
 	/**
@@ -123,7 +122,7 @@ export default class ModuleManager {
 				await this._startModule(module);
 			}
 
-			JobQueue.getPrimaryInstance().resume();
+			JobQueue.resume();
 		} catch (err) {
 			await this.shutdown();
 			throw err;
@@ -168,12 +167,6 @@ export default class ModuleManager {
 			}
 		}
 	}
-
-	static getPrimaryInstance(): ModuleManager {
-		return this.primaryInstance;
-	}
-
-	static setPrimaryInstance(instance: ModuleManager) {
-		this.primaryInstance = instance;
-	}
 }
+
+export default new ModuleManager();

+ 1 - 3
backend/src/WebSocket.ts

@@ -2,8 +2,6 @@ import { WebSocket as WSWebSocket } from "ws";
 import LogBook, { Log } from "@/LogBook";
 
 export default class WebSocket extends WSWebSocket {
-	private _logBook: LogBook = LogBook.getPrimaryInstance();
-
 	private _socketId?: string;
 
 	private _sessionId?: string;
@@ -25,7 +23,7 @@ export default class WebSocket extends WSWebSocket {
 		} = {
 			...(typeof log === "string" ? { message: log } : log)
 		};
-		this._logBook.log({
+		LogBook.log({
 			message,
 			type,
 			category: "modules.websocket.socket",

+ 22 - 34
backend/src/main.ts

@@ -1,37 +1,25 @@
 import * as readline from "node:readline";
+import mongoose from "mongoose";
 import ModuleManager from "@/ModuleManager";
 import LogBook from "@/LogBook";
 import JobQueue from "@/JobQueue";
 import JobStatistics from "@/JobStatistics";
 
-const logBook = LogBook.getPrimaryInstance();
 
 process.removeAllListeners("uncaughtException");
 process.on("uncaughtException", err => {
 	if (err.name === "ECONNREFUSED" || err.name === "UNCERTAIN_STATE") return;
 
-	logBook.log({
+	LogBook.log({
 		message: err.message,
 		type: "error",
 		category: "uncaught-exceptions",
-		data: {
-			error: err.message
-				? {
-						cause: err.cause,
-						name: err.name,
-						stack: err.stack
-				  }
-				: err
-		}
+		data: { error: err }
 	});
 });
 
-const moduleManager = ModuleManager.getPrimaryInstance();
-const jobQueue = JobQueue.getPrimaryInstance();
-
-moduleManager.startup().then(async () => {
-
-	const Model = await jobQueue.runJob("data", "getModel", { name: "news" });
+ModuleManager.startup().then(async () => {
+	const Model = await JobQueue.runJob("data", "getModel", { name: "news" });
 	// console.log("Model", Model);
 	const abcs = await Model.findOne({}).newest();
 	console.log("Abcs", abcs);
@@ -68,11 +56,11 @@ moduleManager.startup().then(async () => {
 
 	// Events schedule (was notifications)
 	const now = Date.now();
-	await jobQueue.runJob("events", "schedule", {
+	await JobQueue.runJob("events", "schedule", {
 		channel: "test",
 		time: 30000
 	});
-	await jobQueue.runJob("events", "subscribe", {
+	await JobQueue.runJob("events", "subscribe", {
 		channel: "test",
 		type: "schedule",
 		callback: async () => {
@@ -81,13 +69,13 @@ moduleManager.startup().then(async () => {
 	});
 
 	// Events (was cache pub/sub)
-	await jobQueue.runJob("events", "subscribe", {
+	await JobQueue.runJob("events", "subscribe", {
 		channel: "test",
 		callback: async value => {
 			console.log(`PUBLISHED: ${value}`);
 		}
 	});
-	await jobQueue.runJob("events", "publish", {
+	await JobQueue.runJob("events", "publish", {
 		channel: "test",
 		value: "a value!"
 	});
@@ -96,10 +84,10 @@ moduleManager.startup().then(async () => {
 // TOOD remove, or put behind debug option
 // eslint-disable-next-line
 // @ts-ignore
-global.moduleManager = moduleManager;
+global.ModuleManager = ModuleManager;
 // eslint-disable-next-line
 // @ts-ignore
-global.jobQueue = jobQueue;
+global.JobQueue = JobQueue;
 // eslint-disable-next-line
 // @ts-ignore
 global.rs = () => {
@@ -110,11 +98,11 @@ global.rs = () => {
 //	const start = Date.now();
 //	const x = [];
 //	while (x.length < 1) {
-//		x.push(jobQueue.runJob("stations", "addC", {}).catch(() => {}));
+//		x.push(JobQueue.runJob("stations", "addC", {}).catch(() => {}));
 //	}
 //	const y = await Promise.all(x);
 //	console.log(y);
-//	// const a = await jobQueue.runJob("stations", "addC", {}).catch(() => {});
+//	// const a = await JobQueue.runJob("stations", "addC", {}).catch(() => {});
 //	// console.log(555, a);
 //	const difference = Date.now() - start;
 //	console.log({ difference });
@@ -143,7 +131,7 @@ const shutdown = async () => {
 		rl.removeAllListeners();
 		rl.close();
 	}
-	await moduleManager.shutdown().catch(() => process.exit(1));
+	await ModuleManager.shutdown().catch(() => process.exit(1));
 	process.exit(0);
 };
 process.on("SIGINT", shutdown);
@@ -167,18 +155,18 @@ const runCommand = (line: string) => {
 		}
 		case "status": {
 			console.log("Module Manager Status:");
-			console.table(moduleManager.getStatus());
+			console.table(ModuleManager.getStatus());
 			console.log("Job Queue Status:");
-			console.table(jobQueue.getStatus());
+			console.table(JobQueue.getStatus());
 			break;
 		}
 		case "stats": {
 			console.log("Job Queue Stats:");
-			console.table(JobStatistics.getPrimaryInstance().getStats());
+			console.table(JobStatistics.getStats());
 			break;
 		}
 		case "queue": {
-			const queueStatus = jobQueue.getQueueStatus().queue;
+			const queueStatus = JobQueue.getQueueStatus().queue;
 			if (queueStatus.length === 0)
 				console.log("There are no jobs in the queue.");
 			else
@@ -189,7 +177,7 @@ const runCommand = (line: string) => {
 			break;
 		}
 		case "active": {
-			const activeStatus = jobQueue.getQueueStatus().active;
+			const activeStatus = JobQueue.getQueueStatus().active;
 			if (activeStatus.length === 0)
 				console.log("There are no active jobs.");
 			else console.log(`There are ${activeStatus.length} active jobs.`);
@@ -200,7 +188,7 @@ const runCommand = (line: string) => {
 			if (args.length === 0) console.log("Please specify a jobId");
 			else {
 				const jobId = args[0];
-				const job = jobQueue.getJob(jobId);
+				const job = JobQueue.getJob(jobId);
 
 				if (!job) console.log(`Job "${jobId}" not found`);
 				else {
@@ -239,7 +227,7 @@ const runCommand = (line: string) => {
 				value = values.map(_filter => JSON.parse(_filter));
 				if (value.length === 1) [value] = value;
 			}
-			logBook
+			LogBook
 				// eslint-disable-next-line
 				// @ts-ignore
 				.updateOutput(output, key, action, value)
@@ -250,7 +238,7 @@ const runCommand = (line: string) => {
 			break;
 		}
 		case "getjobs": {
-			console.log(moduleManager.getJobs());
+			console.log(ModuleManager.getJobs());
 			break;
 		}
 		default: {

+ 9 - 5
backend/src/modules/APIModule.ts

@@ -9,8 +9,10 @@ import WebSocket from "@/WebSocket";
 import permissions from "@/permissions";
 import Job from "@/Job";
 import { Models } from "@/types/Models";
+import ModuleManager from "@/ModuleManager";
+import JobQueue from "@/JobQueue";
 
-export default class APIModule extends BaseModule {
+export class APIModule extends BaseModule {
 	private _subscriptions: Record<string, Set<string>>;
 
 	/**
@@ -19,7 +21,7 @@ export default class APIModule extends BaseModule {
 	public constructor() {
 		super("api");
 
-		this._dependentModules = ["cache", "data", "events", "websocket"];
+		this._dependentModules = ["data", "events", "websocket"];
 
 		this._subscriptions = {};
 
@@ -147,7 +149,7 @@ export default class APIModule extends BaseModule {
 
 		socket.on("close", async () => {
 			if (socketId)
-				await this._jobQueue.runJob(
+				await JobQueue.runJob(
 					"api",
 					"unsubscribeAll",
 					{},
@@ -225,7 +227,7 @@ export default class APIModule extends BaseModule {
 		if (modelId && !model) throw new Error("Model not found");
 
 		const jobs = await Promise.all(
-			Object.keys(this._moduleManager.getModule("data")?.getJobs() ?? {})
+			Object.keys(ModuleManager.getModule("data")?.getJobs() ?? {})
 				.filter(
 					jobName =>
 						jobName.startsWith(modelName.toString()) &&
@@ -280,7 +282,7 @@ export default class APIModule extends BaseModule {
 		const promises = [];
 		for await (const socketId of this._subscriptions[channel].values()) {
 			promises.push(
-				this._jobQueue.runJob("websocket", "dispatch", {
+				JobQueue.runJob("websocket", "dispatch", {
 					socketId,
 					channel,
 					value
@@ -435,3 +437,5 @@ export type APIModuleJobs = {
 		returns: Awaited<ReturnType<UniqueMethods<APIModule>[Property]>>;
 	};
 };
+
+export default new APIModule();

+ 5 - 2
backend/src/modules/DataModule.ts

@@ -20,6 +20,7 @@ import BaseModule, { ModuleStatus } from "@/BaseModule";
 import { UniqueMethods } from "@/types/Modules";
 import { AnyModel, Models } from "@/types/Models";
 import { Schemas } from "@/types/Schemas";
+import JobQueue from "@/JobQueue";
 
 /**
  * Experimental: function to get all nested keys from a MongoDB query object
@@ -109,7 +110,7 @@ function getAllKeys(obj: object) {
 	return keys;
 }
 
-export default class DataModule extends BaseModule {
+export class DataModule extends BaseModule {
 	private _models?: Models;
 
 	private _mongoConnection?: Connection;
@@ -335,7 +336,7 @@ export default class DataModule extends BaseModule {
 
 					if (action !== "created") channel += `.${modelId}`;
 
-					await this._jobQueue.runJob("events", "publish", {
+					await JobQueue.runJob("events", "publish", {
 						channel,
 						value: { doc, oldDoc }
 					});
@@ -688,3 +689,5 @@ export type DataModuleJobs = {
 		returns: Awaited<ReturnType<UniqueMethods<DataModule>[Property]>>;
 	};
 };
+
+export default new DataModule();

+ 3 - 1
backend/src/modules/EventsModule.ts

@@ -5,7 +5,7 @@ import BaseModule, { ModuleStatus } from "@/BaseModule";
 import { UniqueMethods } from "@/types/Modules";
 import JobContext from "@/JobContext";
 
-export default class EventsModule extends BaseModule {
+export class EventsModule extends BaseModule {
 	private _pubClient?: RedisClientType;
 
 	private _subClient?: RedisClientType;
@@ -351,3 +351,5 @@ export type EventsModuleJobs = {
 		returns: Awaited<ReturnType<UniqueMethods<EventsModule>[Property]>>;
 	};
 };
+
+export default new EventsModule();

+ 7 - 4
backend/src/modules/StationsModule.ts

@@ -1,8 +1,9 @@
 import JobContext from "@/JobContext";
 import { UniqueMethods } from "@/types/Modules";
 import BaseModule from "@/BaseModule";
+import JobQueue from "@/JobQueue";
 
-export default class StationsModule extends BaseModule {
+export class StationsModule extends BaseModule {
 	/**
 	 * Station Module
 	 */
@@ -47,16 +48,16 @@ export default class StationsModule extends BaseModule {
 
 	public async addA(context: JobContext) {
 		context.log("ADDA");
-		await context.jobQueue.runJob("stations", "addB", {}, { priority: 5 });
+		await JobQueue.runJob("stations", "addB", {}, { priority: 5 });
 		return { number: 123 };
 	}
 
 	public async addB(context: JobContext) {
 		context.log("ADDB");
-		await context.jobQueue.runJob("stations", "addToQueue", {
+		await JobQueue.runJob("stations", "addToQueue", {
 			songId: "test"
 		});
-		await context.jobQueue.runJob("stations", "addC", {});
+		await JobQueue.runJob("stations", "addC", {});
 	}
 
 	public async addC(context: JobContext) {
@@ -71,3 +72,5 @@ export type StationsModuleJobs = {
 		returns: Awaited<ReturnType<UniqueMethods<StationsModule>[Property]>>;
 	};
 };
+
+export default new StationsModule();

+ 9 - 5
backend/src/modules/WebSocketModule.ts

@@ -8,8 +8,10 @@ import { UniqueMethods } from "@/types/Modules";
 import WebSocket from "@/WebSocket";
 import JobContext from "@/JobContext";
 import Job from "@/Job";
+import ModuleManager from "@/ModuleManager";
+import JobQueue from "@/JobQueue";
 
-export default class WebSocketModule extends BaseModule {
+export class WebSocketModule extends BaseModule {
 	private _httpServer?: Server;
 
 	private _wsServer?: WebSocketServer;
@@ -87,7 +89,7 @@ export default class WebSocketModule extends BaseModule {
 		socket: WebSocket,
 		request: IncomingMessage
 	) {
-		if (this._jobQueue.getStatus().isPaused) {
+		if (JobQueue.getStatus().isPaused) {
 			socket.close();
 			return;
 		}
@@ -126,7 +128,7 @@ export default class WebSocketModule extends BaseModule {
 	 * handleMessage - Handle websocket message
 	 */
 	private async _handleMessage(socket: WebSocket, message: RawData) {
-		if (this._jobQueue.getStatus().isPaused) {
+		if (JobQueue.getStatus().isPaused) {
 			socket.close();
 			return;
 		}
@@ -150,13 +152,13 @@ export default class WebSocketModule extends BaseModule {
 					`No callback reference provided for job ${moduleJob}`
 				);
 
-			const module = this._moduleManager.getModule(moduleName);
+			const module = ModuleManager.getModule(moduleName);
 			if (!module) throw new Error(`Module "${moduleName}" not found`);
 
 			const job = module.getJob(jobName);
 			if (!job.api) throw new Error(`Job "${jobName}" not found.`);
 
-			const res = await this._jobQueue.runJob("api", "runJob", {
+			const res = await JobQueue.runJob("api", "runJob", {
 				moduleName,
 				jobName,
 				payload,
@@ -255,3 +257,5 @@ export type WebSocketModuleJobs = {
 		returns: Awaited<ReturnType<UniqueMethods<WebSocketModule>[Property]>>;
 	};
 };
+
+export default new WebSocketModule();

+ 6 - 5
backend/src/types/Modules.ts

@@ -1,8 +1,9 @@
-import APIModule, { APIModuleJobs } from "@/modules/APIModule";
-import DataModule, { DataModuleJobs } from "@/modules/DataModule";
-import EventsModule, { EventsModuleJobs } from "@/modules/EventsModule";
-import StationsModule, { StationsModuleJobs } from "@/modules/StationsModule";
-import WebSocketModule, {
+import { APIModule, APIModuleJobs } from "@/modules/APIModule";
+import { DataModule, DataModuleJobs } from "@/modules/DataModule";
+import { EventsModule, EventsModuleJobs } from "@/modules/EventsModule";
+import { StationsModule, StationsModuleJobs } from "@/modules/StationsModule";
+import {
+	WebSocketModule,
 	WebSocketModuleJobs
 } from "@/modules/WebSocketModule";
 import BaseModule from "@/BaseModule";