Merge pull request #2688 from bluewave-labs/feat/server-refactor

feat: server refactor
This commit is contained in:
Alexander Holliday authored and GitHub committed 2025-07-28 09:01:39 -07:00
commit 41f917ddf6
127 files changed
+657 -666

No files matched your search

+1 -1
View File
@@ -10,4 +10,4 @@ COPY ./server/ ./
EXPOSE 52345
CMD ["node", "index.js"]
CMD ["node", "src/index.js"]
+1 -1
View File
@@ -22,4 +22,4 @@ RUN chmod +x ./scripts/inject-vars.sh
EXPOSE 52345
CMD ./scripts/inject-vars.sh && node ./index.js
CMD ./scripts/inject-vars.sh && node ./src/index.js
+1 -1
View File
@@ -22,4 +22,4 @@ RUN chmod +x ./scripts/inject-vars.sh
EXPOSE 52345
CMD ./scripts/inject-vars.sh && node ./index.js
CMD ./scripts/inject-vars.sh && node ./src/index.js
+2 -2
View File
@@ -12,10 +12,10 @@ declare -A services=(
)
for service in "${!services[@]}"; do
docker buildx build \
--platform linux/amd64,linux/arm64 \
docker build \
-f "${services[$service]}" \
-t "$service" \
.
if [ $? -ne 0 ]; then
echo "Error building $service image. Exiting..."
+1 -1
View File
@@ -10,4 +10,4 @@ COPY ./server/ ./
EXPOSE 52345
CMD ["node", "index.js"]
CMD ["node", "src/index.js"]
+1 -1
View File
@@ -12,4 +12,4 @@ COPY ./server ./
EXPOSE 52345
CMD ["node", "index.js"]
CMD ["node", "src/index.js"]
+1 -1
View File
@@ -12,4 +12,4 @@ COPY ./server ./
EXPOSE 52345
CMD ["node", "index.js"]
CMD ["node", "src/index.js"]
Executable → Regular
+24 -427
View File
@@ -1,450 +1,47 @@
import { initializeServices } from "./src/config/services.js";
import { initializeControllers } from "./src/config/controllers.js";
import { createApp } from "./src/app.js";
import { initShutdownListener } from "./shutdown.js";
import logger from "./utils/logger.js";
import { fileURLToPath } from "url";
import path from "path";
import fs from "fs";
import swaggerUi from "swagger-ui-express";
import jwt from "jsonwebtoken";
import papaparse from "papaparse";
import express from "express";
import helmet from "helmet";
import cors from "cors";
import compression from "compression";
import { Logger } from "./utils/logger.js";
import logger from "./utils/logger.js";
import { verifyJWT } from "./middleware/verifyJWT.js";
import { handleErrors } from "./middleware/handleErrors.js";
import { responseHandler } from "./middleware/responseHandler.js";
import { fileURLToPath } from "url";
import { createCommonDependencies } from "./controllers/baseController.js";
import AuthRoutes from "./routes/authRoute.js";
import AuthController from "./controllers/authController.js";
import InviteRoutes from "./routes/inviteRoute.js";
import InviteController from "./controllers/inviteController.js";
import MonitorRoutes from "./routes/monitorRoute.js";
import MonitorController from "./controllers/monitorController.js";
import CheckRoutes from "./routes/checkRoute.js";
import CheckController from "./controllers/checkController.js";
import MaintenanceWindowRoutes from "./routes/maintenanceWindowRoute.js";
import MaintenanceWindowController from "./controllers/maintenanceWindowController.js";
import SettingsRoutes from "./routes/settingsRoute.js";
import SettingsController from "./controllers/settingsController.js";
import StatusPageRoutes from "./routes/statusPageRoute.js";
import StatusPageController from "./controllers/statusPageController.js";
import QueueRoutes from "./routes/queueRoute.js";
import QueueController from "./controllers/queueController.js";
import LogRoutes from "./routes/logRoutes.js";
import LogController from "./controllers/logController.js";
import NotificationRoutes from "./routes/notificationRoute.js";
import NotificationController from "./controllers/notificationController.js";
import DiagnosticRoutes from "./routes/diagnosticRoute.js";
import DiagnosticController from "./controllers/diagnosticController.js";
//JobQueue service and dependencies
import JobQueue from "./service/infrastructure/JobQueue/JobQueue.js";
import JobQueueHelper from "./service/infrastructure/JobQueue/JobQueueHelper.js";
import { Queue, Worker } from "bullmq";
import PulseQueue from "./service/infrastructure/PulseQueue/PulseQueue.js";
import PulseQueueHelper from "./service/infrastructure/PulseQueue/PulseQueueHelper.js";
import SuperSimpleQueue from "./service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js";
import SuperSimpleQueueHelper from "./service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js";
import ErrorService from "./service/infrastructure/errorService.js";
// Business services
import UserService from "./service/business/userService.js";
import CheckService from "./service/business/checkService.js";
import DiagnosticService from "./service/business/diagnosticService.js";
import InviteService from "./service/business/inviteService.js";
import MaintenanceWindowService from "./service/business/maintenanceWindowService.js";
import MonitorService from "./service/business/monitorService.js";
//Network service and dependencies
import NetworkService from "./service/infrastructure/networkService.js";
import axios from "axios";
import ping from "ping";
import http from "http";
import Docker from "dockerode";
import net from "net";
// Email service and dependencies
import EmailService from "./service/infrastructure/emailService.js";
import nodemailer from "nodemailer";
import pkg from "handlebars";
const { compile } = pkg;
import mjml2html from "mjml";
// Settings Service and dependencies
import SettingsService from "./service/system/settingsService.js";
import AppSettings from "./db/models/AppSettings.js";
// Status Service and dependencies
import StatusService from "./service/infrastructure/statusService.js";
// Notification Service and dependencies
import NotificationService from "./service/infrastructure/notificationService.js";
import NotificationUtils from "./service/infrastructure/notificationUtils.js";
// Buffer Service and dependencies
import BufferService from "./service/infrastructure/bufferService.js";
// Service Registry
import ServiceRegistry from "./service/system/serviceRegistry.js";
import MongoDB from "./db/mongo/MongoDB.js";
// Redis Service and dependencies
import IORedis from "ioredis";
import RedisService from "./service/data/redisService.js";
import TranslationService from "./service/system/translationService.js";
import languageMiddleware from "./middleware/languageMiddleware.js";
import StringService from "./service/system/stringService.js";
import SettingsService from "./src/service/system/settingsService.js";
import AppSettings from "./src/db/models/AppSettings.js";
const SERVICE_NAME = "Server";
const SHUTDOWN_TIMEOUT = 1000;
let isShuttingDown = false;
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const openApiSpec = JSON.parse(fs.readFileSync(path.join(__dirname, "openapi.json"), "utf8"));
const frontendPath = path.join(__dirname, "public");
let server;
const shutdown = async () => {
if (isShuttingDown) {
return;
}
isShuttingDown = true;
logger.info({ message: "Attempting graceful shutdown" });
setTimeout(async () => {
logger.error({
message: "Could not shut down in time, forcing shutdown",
service: SERVICE_NAME,
method: "shutdown",
});
await ServiceRegistry.get(RedisService.SERVICE_NAME).flushRedis();
process.exit(1);
}, SHUTDOWN_TIMEOUT);
try {
server.close();
await ServiceRegistry.get(JobQueue.SERVICE_NAME).shutdown();
await ServiceRegistry.get(MongoDB.SERVICE_NAME).disconnect();
logger.info({ message: "Graceful shutdown complete" });
process.exit(0);
} catch (error) {
logger.error({
message: error.message,
service: SERVICE_NAME,
method: "shutdown",
stack: error.stack,
});
}
};
// Need to wrap server setup in a function to handle async nature of JobQueue
const startApp = async () => {
const app = express();
// Create and Register Primary services
const translationService = new TranslationService(logger);
const stringService = new StringService(translationService);
ServiceRegistry.register(StringService.SERVICE_NAME, stringService);
// FE path
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const openApiSpec = JSON.parse(fs.readFileSync(path.join(__dirname, "openapi.json"), "utf8"));
const frontendPath = path.join(__dirname, "public");
// Create services
const settingsService = new SettingsService(AppSettings);
const appSettings = settingsService.loadSettings();
// Create DB
const db = new MongoDB({ appSettings });
await db.connect();
// Initialize services
const services = await initializeServices(appSettings, settingsService);
// Set allowed origin
const allowedOrigin = appSettings.clientHost;
// Initialize controllers
const controllers = initializeControllers(services);
const networkService = new NetworkService(axios, ping, logger, http, Docker, net, stringService, settingsService);
const emailService = new EmailService(settingsService, fs, path, compile, mjml2html, nodemailer, logger);
const bufferService = new BufferService({ db, logger });
const statusService = new StatusService({ db, logger, buffer: bufferService });
const notificationUtils = new NotificationUtils({
stringService,
emailService,
});
const notificationService = new NotificationService({
emailService,
db,
logger,
networkService,
stringService,
notificationUtils,
});
const redisService = new RedisService({ Redis: IORedis, logger });
const errorService = new ErrorService();
// const jobQueueHelper = new JobQueueHelper({
// redisService,
// Queue,
// Worker,
// logger,
// db,
// networkService,
// statusService,
// notificationService,
// });
// const jobQueue = await JobQueue.create({
// db,
// jobQueueHelper,
// logger,
// stringService,
// });
// const pulseQueueHelper = new PulseQueueHelper({
// db,
// logger,
// networkService,
// statusService,
// notificationService,
// });
// const pulseQueue = await PulseQueue.create({
// appSettings,
// db,
// pulseQueueHelper,
// logger,
// });
const superSimpleQueueHelper = new SuperSimpleQueueHelper({
db,
logger,
networkService,
statusService,
notificationService,
});
const superSimpleQueue = await SuperSimpleQueue.create({
const app = createApp({
services,
controllers,
appSettings,
db,
logger,
helper: superSimpleQueueHelper,
frontendPath,
openApiSpec,
});
// Business services
const userService = new UserService({
db,
emailService,
settingsService,
logger,
stringService,
jwt,
errorService,
});
const checkService = new CheckService({
db,
settingsService,
stringService,
errorService,
});
const diagnosticService = new DiagnosticService();
const inviteService = new InviteService({
db,
settingsService,
emailService,
stringService,
errorService,
});
const maintenanceWindowService = new MaintenanceWindowService({
db,
settingsService,
stringService,
errorService,
});
const monitorService = new MonitorService({
db,
settingsService,
jobQueue: superSimpleQueue,
stringService,
emailService,
papaparse,
logger,
errorService,
});
// Register services
// ServiceRegistry.register(JobQueue.SERVICE_NAME, jobQueue);
// ServiceRegistry.register(JobQueue.SERVICE_NAME, pulseQueue);
ServiceRegistry.register(Logger.SERVICE_NAME, logger);
ServiceRegistry.register(JobQueue.SERVICE_NAME, superSimpleQueue);
ServiceRegistry.register(ErrorService.SERVICE_NAME, errorService);
ServiceRegistry.register(MongoDB.SERVICE_NAME, db);
ServiceRegistry.register(SettingsService.SERVICE_NAME, settingsService);
ServiceRegistry.register(EmailService.SERVICE_NAME, emailService);
ServiceRegistry.register(NetworkService.SERVICE_NAME, networkService);
ServiceRegistry.register(BufferService.SERVICE_NAME, bufferService);
ServiceRegistry.register(StatusService.SERVICE_NAME, statusService);
ServiceRegistry.register(NotificationService.SERVICE_NAME, notificationService);
ServiceRegistry.register(TranslationService.SERVICE_NAME, translationService);
ServiceRegistry.register(RedisService.SERVICE_NAME, redisService);
ServiceRegistry.register(UserService.SERVICE_NAME, userService);
ServiceRegistry.register(CheckService.SERVICE_NAME, checkService);
ServiceRegistry.register(InviteService.SERVICE_NAME, inviteService);
ServiceRegistry.register(MaintenanceWindowService.SERVICE_NAME, maintenanceWindowService);
ServiceRegistry.register(MonitorService.SERVICE_NAME, monitorService);
ServiceRegistry.register(DiagnosticService.SERVICE_NAME, diagnosticService);
await translationService.initialize();
const port = appSettings.port || 52345;
server = app.listen(port, () => {
const server = app.listen(port, () => {
logger.info({ message: `Server started on port:${port}` });
});
process.on("SIGUSR2", shutdown);
process.on("SIGINT", shutdown);
process.on("SIGTERM", shutdown);
//Create controllers
const commonDependencies = createCommonDependencies(
ServiceRegistry,
MongoDB.SERVICE_NAME,
Logger.SERVICE_NAME,
ErrorService.SERVICE_NAME,
StringService.SERVICE_NAME
);
const authController = new AuthController(commonDependencies, {
settingsService: ServiceRegistry.get(SettingsService.SERVICE_NAME),
emailService: ServiceRegistry.get(EmailService.SERVICE_NAME),
jobQueue: ServiceRegistry.get(JobQueue.SERVICE_NAME),
userService: ServiceRegistry.get(UserService.SERVICE_NAME),
});
const monitorController = new MonitorController(commonDependencies, {
settingsService: ServiceRegistry.get(SettingsService.SERVICE_NAME),
jobQueue: ServiceRegistry.get(JobQueue.SERVICE_NAME),
emailService: ServiceRegistry.get(EmailService.SERVICE_NAME),
monitorService: ServiceRegistry.get(MonitorService.SERVICE_NAME),
});
const settingsController = new SettingsController(commonDependencies, {
settingsService: ServiceRegistry.get(SettingsService.SERVICE_NAME),
emailService: ServiceRegistry.get(EmailService.SERVICE_NAME),
});
const checkController = new CheckController(commonDependencies, {
settingsService: ServiceRegistry.get(SettingsService.SERVICE_NAME),
checkService: ServiceRegistry.get(CheckService.SERVICE_NAME),
});
const inviteController = new InviteController(commonDependencies, {
inviteService: ServiceRegistry.get(InviteService.SERVICE_NAME),
});
const maintenanceWindowController = new MaintenanceWindowController(commonDependencies, {
settingsService: ServiceRegistry.get(SettingsService.SERVICE_NAME),
maintenanceWindowService: ServiceRegistry.get(MaintenanceWindowService.SERVICE_NAME),
});
const queueController = new QueueController(commonDependencies, {
jobQueue: ServiceRegistry.get(JobQueue.SERVICE_NAME),
});
const logController = new LogController(commonDependencies);
const statusPageController = new StatusPageController(commonDependencies);
const notificationController = new NotificationController(commonDependencies, {
notificationService: ServiceRegistry.get(NotificationService.SERVICE_NAME),
statusService: ServiceRegistry.get(StatusService.SERVICE_NAME),
});
const diagnosticController = new DiagnosticController(commonDependencies, {
diagnosticService: ServiceRegistry.get(DiagnosticService.SERVICE_NAME),
});
//Create routes
const authRoutes = new AuthRoutes(authController);
const monitorRoutes = new MonitorRoutes(monitorController);
const settingsRoutes = new SettingsRoutes(settingsController);
const checkRoutes = new CheckRoutes(checkController);
const inviteRoutes = new InviteRoutes(inviteController);
const maintenanceWindowRoutes = new MaintenanceWindowRoutes(maintenanceWindowController);
const queueRoutes = new QueueRoutes(queueController);
const logRoutes = new LogRoutes(logController);
const statusPageRoutes = new StatusPageRoutes(statusPageController);
const notificationRoutes = new NotificationRoutes(notificationController);
const diagnosticRoutes = new DiagnosticRoutes(diagnosticController);
// Middleware
app.use(express.static(frontendPath));
app.use(responseHandler);
app.use(
cors({
origin: allowedOrigin,
methods: "GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS",
allowedHeaders: "*",
credentials: true,
})
);
app.use(express.json());
app.use(
helmet({
hsts: false,
contentSecurityPolicy: {
useDefaults: true,
directives: {
upgradeInsecureRequests: null,
},
},
})
);
app.use(
compression({
level: 6,
threshold: 1024,
filter: (req, res) => {
if (req.headers["x-no-compression"]) {
return false;
}
return compression.filter(req, res);
},
})
);
app.use(languageMiddleware(stringService, translationService, settingsService));
// Swagger UI
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(openApiSpec));
//routes
app.use("/api/v1/auth", authRoutes.getRouter());
app.use("/api/v1/monitors", verifyJWT, monitorRoutes.getRouter());
app.use("/api/v1/settings", verifyJWT, settingsRoutes.getRouter());
app.use("/api/v1/checks", verifyJWT, checkRoutes.getRouter());
app.use("/api/v1/invite", inviteRoutes.getRouter());
app.use("/api/v1/maintenance-window", verifyJWT, maintenanceWindowRoutes.getRouter());
app.use("/api/v1/queue", verifyJWT, queueRoutes.getRouter());
app.use("/api/v1/logs", verifyJWT, logRoutes.getRouter());
app.use("/api/v1/status-page", statusPageRoutes.getRouter());
app.use("/api/v1/notifications", verifyJWT, notificationRoutes.getRouter());
app.use("/api/v1/diagnostic", verifyJWT, diagnosticRoutes.getRouter());
app.use("/api/v1/health", (req, res) => {
res.json({
status: "OK",
});
});
// FE routes
app.get("*", (req, res) => {
res.sendFile(path.join(frontendPath, "index.html"));
});
app.use(handleErrors);
initShutdownListener(server, services);
};
startApp().catch((error) => {
+2 -2
View File
@@ -1,5 +1,5 @@
{
"ignore": ["locales/*", "*.log", "node_modules/*"],
"watch": ["*.js", "*.json"],
"ignore": ["src/locales/*", "*.log", "node_modules/*"],
"watch": ["src/**/*.js", "*.json"],
"ext": "js,json"
}
+1 -1
View File
@@ -6,7 +6,7 @@
"type": "module",
"scripts": {
"test": "c8 mocha",
"dev": "nodemon index.js",
"dev": "nodemon src/index.js",
"lint": "eslint .",
"lint-fix": "eslint --fix .",
"format": "prettier --write .",
-208
View File
@@ -1,208 +0,0 @@
const SERVICE_NAME = "userService";
import { createAuthError, createError } from "../utils/errorUtils.js";
class UserService {
static SERVICE_NAME = SERVICE_NAME;
constructor({ db, emailService, settingsService, logger, stringService, jwt }) {
this.db = db;
this.emailService = emailService;
this.settingsService = settingsService;
this.logger = logger;
this.stringService = stringService;
this.jwt = jwt;
}
issueToken = (payload, appSettings) => {
const tokenTTL = appSettings?.jwtTTL ?? "2h";
const tokenSecret = appSettings?.jwtSecret;
const payloadData = payload;
return this.jwt.sign(payloadData, tokenSecret, { expiresIn: tokenTTL });
};
registerUser = async (user, file) => {
// Create a new user
// If superAdmin exists, a token should be attached to all further register requests
const superAdminExists = await this.db.checkSuperadmin();
if (superAdminExists) {
const invitedUser = await this.db.getInviteTokenAndDelete(user.inviteToken);
user.role = invitedUser.role;
user.teamId = invitedUser.teamId;
} else {
// This is the first account, create JWT secret to use if one is not supplied by env
const jwtSecret = crypto.randomBytes(64).toString("hex");
await this.db.updateAppSettings({ jwtSecret });
}
const newUser = await this.db.insertUser({ ...user }, file);
this.logger.debug({
message: "New user created",
service: SERVICE_NAME,
method: "registerUser",
details: newUser._id,
});
const userForToken = { ...newUser._doc };
delete userForToken.profileImage;
delete userForToken.avatarImage;
const appSettings = await this.settingsService.getSettings();
const token = this.issueToken(userForToken, appSettings);
try {
const html = await this.emailService.buildEmail("welcomeEmailTemplate", {
name: newUser.firstName,
});
this.emailService.sendEmail(newUser.email, "Welcome to Uptime Monitor", html).catch((error) => {
this.logger.warn({
message: error.message,
service: SERVICE_NAME,
method: "registerUser",
stack: error.stack,
});
});
} catch (error) {
this.logger.warn({
message: error.message,
service: SERVICE_NAME,
method: "registerUser",
stack: error.stack,
});
}
return { user: newUser, token };
};
loginUser = async (email, password) => {
// Check if user exists
const user = await this.db.getUserByEmail(email);
// Compare password
const match = await user.comparePassword(password);
if (match !== true) {
throw createAuthError(this.stringService.authIncorrectPassword);
}
// Remove password from user object. Should this be abstracted to DB layer?
const userWithoutPassword = { ...user._doc };
delete userWithoutPassword.password;
delete userWithoutPassword.avatarImage;
// Happy path, return token
const appSettings = await this.settingsService.getSettings();
const token = this.issueToken(userWithoutPassword, appSettings);
// reset avatar image
userWithoutPassword.avatarImage = user.avatarImage;
return { user: userWithoutPassword, token };
};
editUser = async (updates, file, currentUser) => {
// Change Password check
if (updates?.password && updates?.newPassword) {
// Get user's email
// Add user email to body for DB operation
updates.email = currentUser.email;
// Get user
const user = await this.db.getUserByEmail(currentUser.email);
// Compare passwords
const match = await user.comparePassword(updates?.password);
// If not a match, throw a 403
// 403 instead of 401 to avoid triggering axios interceptor
if (!match) {
throw createError(this.stringService.authIncorrectPassword, 403);
}
// If a match, update the password
updates.password = updates.newPassword;
}
const updatedUser = await this.db.updateUser({ userId: currentUser?._id, user: updates, file: file });
return updatedUser;
};
checkSuperadminExists = async () => {
const superAdminExists = await this.db.checkSuperadmin();
return superAdminExists;
};
requestRecovery = async (email) => {
const user = await this.db.getUserByEmail(email);
const recoveryToken = await this.db.requestRecoveryToken(email);
const name = user.firstName;
const { clientHost } = this.settingsService.getSettings();
const url = `${clientHost}/set-new-password/${recoveryToken.token}`;
const html = await this.emailService.buildEmail("passwordResetTemplate", {
name,
email,
url,
});
const msgId = await this.emailService.sendEmail(email, "Checkmate Password Reset", html);
return msgId;
};
validateRecovery = async (recoveryToken) => {
await this.db.validateRecoveryToken(recoveryToken);
};
resetPassword = async (password, recoveryToken) => {
const user = await this.db.resetPassword(password, recoveryToken);
const appSettings = await this.settingsService.getSettings();
const token = this.issueToken(user._doc, appSettings);
return { user, token };
};
deleteUser = async (user) => {
const email = user?.email;
if (!email) {
throw new Error("No email in request");
}
const teamId = user?.teamId;
const userId = user?._id;
if (!teamId) {
throw new Error("No team ID in request");
}
if (!userId) {
throw new Error("No user ID in request");
}
const roles = user?.role;
if (roles.includes("demo")) {
throw new Error("Demo user cannot be deleted");
}
// 1. Find all the monitors associated with the team ID if superadmin
const result = await this.db.getMonitorsByTeamId({
teamId: teamId,
});
if (roles.includes("superadmin")) {
// 2. Remove all jobs, delete checks and alerts
result?.monitors.length > 0 &&
(await Promise.all(
result.monitors.map(async (monitor) => {
await this.jobQueue.deleteJob(monitor);
})
));
}
// 6. Delete the user by id
await this.db.deleteUser(userId);
};
getAllUsers = async () => {
const users = await this.db.getAllUsers();
return users;
};
getUserById = async (roles, userId) => {
const user = await this.db.getUserById(roles, userId);
return user;
};
editUserById = async (userId, user) => {
await this.db.editUserById(userId, user);
};
}
export default UserService;
+73
View File
@@ -0,0 +1,73 @@
import express from "express";
import path from "path";
import { responseHandler } from "./middleware/responseHandler.js";
import cors from "cors";
import helmet from "helmet";
import compression from "compression";
import languageMiddleware from "./middleware/languageMiddleware.js";
import swaggerUi from "swagger-ui-express";
import { handleErrors } from "./middleware/handleErrors.js";
import { setupRoutes } from "./config/routes.js";
export const createApp = ({ services, controllers, appSettings, frontendPath, openApiSpec }) => {
const allowedOrigin = appSettings.clientHost;
const app = express();
// Static files
app.use(express.static(frontendPath));
// Response handler
app.use(responseHandler);
app.use(
cors({
origin: allowedOrigin,
methods: "GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS",
allowedHeaders: "*",
credentials: true,
})
);
app.use(express.json());
app.use(
helmet({
hsts: false,
contentSecurityPolicy: {
useDefaults: true,
directives: {
upgradeInsecureRequests: null,
},
},
})
);
app.use(
compression({
level: 6,
threshold: 1024,
filter: (req, res) => {
if (req.headers["x-no-compression"]) {
return false;
}
return compression.filter(req, res);
},
})
);
app.use(languageMiddleware(services.stringService, services.translationService, services.settingsService));
// Swagger UI
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(openApiSpec));
app.use("/api/v1/health", (req, res) => {
res.json({
status: "OK",
});
});
// Main app routes
setupRoutes(app, controllers);
// FE routes
app.get("*", (req, res) => {
res.sendFile(path.join(frontendPath, "index.html"));
});
app.use(handleErrors);
return app;
};
+66
View File
@@ -0,0 +1,66 @@
import { createCommonDependencies } from "../controllers/baseController.js";
// Services
// Controllers
import MonitorController from "../controllers/monitorController.js";
import AuthController from "../controllers/authController.js";
import SettingsController from "../controllers/settingsController.js";
import CheckController from "../controllers/checkController.js";
import InviteController from "../controllers/inviteController.js";
import MaintenanceWindowController from "../controllers/maintenanceWindowController.js";
import QueueController from "../controllers/queueController.js";
import LogController from "../controllers/logController.js";
import StatusPageController from "../controllers/statusPageController.js";
import NotificationController from "../controllers/notificationController.js";
import DiagnosticController from "../controllers/diagnosticController.js";
export const initializeControllers = (services) => {
const controllers = {};
const commonDependencies = createCommonDependencies(services.db, services.errorService, services.logger, services.stringService);
controllers.authController = new AuthController(commonDependencies, {
settingsService: services.settingsService,
emailService: services.emailService,
jobQueue: services.jobQueue,
userService: services.userService,
});
controllers.monitorController = new MonitorController(commonDependencies, {
settingsService: services.settingsService,
jobQueue: services.jobQueue,
emailService: services.emailService,
monitorService: services.monitorService,
});
controllers.settingsController = new SettingsController(commonDependencies, {
settingsService: services.settingsService,
emailService: services.emailService,
});
controllers.checkController = new CheckController(commonDependencies, {
settingsService: services.settingsService,
checkService: services.checkService,
});
controllers.inviteController = new InviteController(commonDependencies, {
inviteService: services.inviteService,
});
controllers.maintenanceWindowController = new MaintenanceWindowController(commonDependencies, {
settingsService: services.settingsService,
maintenanceWindowService: services.maintenanceWindowService,
});
controllers.queueController = new QueueController(commonDependencies, {
jobQueue: services.jobQueue,
});
controllers.logController = new LogController(commonDependencies);
controllers.statusPageController = new StatusPageController(commonDependencies);
controllers.notificationController = new NotificationController(commonDependencies, {
notificationService: services.notificationService,
statusService: services.statusService,
});
controllers.diagnosticController = new DiagnosticController(commonDependencies, {
diagnosticService: services.diagnosticService,
});
return controllers;
};
View File
Whitespace-only changes.
+39
View File
@@ -0,0 +1,39 @@
import { verifyJWT } from "../middleware/verifyJWT.js";
import AuthRoutes from "../routes/authRoute.js";
import InviteRoutes from "../routes/inviteRoute.js";
import MonitorRoutes from "../routes/monitorRoute.js";
import CheckRoutes from "../routes/checkRoute.js";
import SettingsRoutes from "../routes/settingsRoute.js";
import MaintenanceWindowRoutes from "../routes/maintenanceWindowRoute.js";
import StatusPageRoutes from "../routes/statusPageRoute.js";
import QueueRoutes from "../routes/queueRoute.js";
import LogRoutes from "../routes/logRoutes.js";
import DiagnosticRoutes from "../routes/diagnosticRoute.js";
import NotificationRoutes from "../routes/notificationRoute.js";
export const setupRoutes = (app, controllers) => {
const authRoutes = new AuthRoutes(controllers.authController);
const monitorRoutes = new MonitorRoutes(controllers.monitorController);
const settingsRoutes = new SettingsRoutes(controllers.settingsController);
const checkRoutes = new CheckRoutes(controllers.checkController);
const inviteRoutes = new InviteRoutes(controllers.inviteController);
const maintenanceWindowRoutes = new MaintenanceWindowRoutes(controllers.maintenanceWindowController);
const queueRoutes = new QueueRoutes(controllers.queueController);
const logRoutes = new LogRoutes(controllers.logController);
const statusPageRoutes = new StatusPageRoutes(controllers.statusPageController);
const notificationRoutes = new NotificationRoutes(controllers.notificationController);
const diagnosticRoutes = new DiagnosticRoutes(controllers.diagnosticController);
app.use("/api/v1/auth", authRoutes.getRouter());
app.use("/api/v1/monitors", verifyJWT, monitorRoutes.getRouter());
app.use("/api/v1/settings", verifyJWT, settingsRoutes.getRouter());
app.use("/api/v1/checks", verifyJWT, checkRoutes.getRouter());
app.use("/api/v1/invite", inviteRoutes.getRouter());
app.use("/api/v1/maintenance-window", verifyJWT, maintenanceWindowRoutes.getRouter());
app.use("/api/v1/queue", verifyJWT, queueRoutes.getRouter());
app.use("/api/v1/logs", verifyJWT, logRoutes.getRouter());
app.use("/api/v1/status-page", statusPageRoutes.getRouter());
app.use("/api/v1/notifications", verifyJWT, notificationRoutes.getRouter());
app.use("/api/v1/diagnostic", verifyJWT, diagnosticRoutes.getRouter());
};
+155
View File
@@ -0,0 +1,155 @@
import ServiceRegistry from "../service/system/serviceRegistry.js";
import logger from "../utils/logger.js";
import TranslationService from "../service/system/translationService.js";
import StringService from "../service/system/stringService.js";
import MongoDB from "../db/mongo/MongoDB.js";
import NetworkService from "../service/infrastructure/networkService.js";
import EmailService from "../service/infrastructure/emailService.js";
import BufferService from "../service/infrastructure/bufferService.js";
import StatusService from "../service/infrastructure/statusService.js";
import NotificationUtils from "../service/infrastructure/notificationUtils.js";
import NotificationService from "../service/infrastructure/notificationService.js";
import RedisService from "../service/data/redisService.js";
import ErrorService from "../service/infrastructure/errorService.js";
import SuperSimpleQueueHelper from "../service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js";
import SuperSimpleQueue from "../service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js";
import UserService from "../service/business/userService.js";
import CheckService from "../service/business/checkService.js";
import DiagnosticService from "../service/business/diagnosticService.js";
import InviteService from "../service/business/inviteService.js";
import MaintenanceWindowService from "../service/business/maintenanceWindowService.js";
import MonitorService from "../service/business/monitorService.js";
import IORedis from "ioredis";
import papaparse from "papaparse";
import axios from "axios";
import ping from "ping";
import http from "http";
import Docker from "dockerode";
import net from "net";
import fs from "fs";
import path from "path";
import nodemailer from "nodemailer";
import pkg from "handlebars";
const { compile } = pkg;
import mjml2html from "mjml";
import jwt from "jsonwebtoken";
import crypto from "crypto";
export const initializeServices = async (appSettings, settingsService) => {
const translationService = new TranslationService(logger);
await translationService.initialize();
const stringService = new StringService(translationService);
// Create DB
const db = new MongoDB({ appSettings });
await db.connect();
const networkService = new NetworkService(axios, ping, logger, http, Docker, net, stringService, settingsService);
const emailService = new EmailService(settingsService, fs, path, compile, mjml2html, nodemailer, logger);
const bufferService = new BufferService({ db, logger });
const statusService = new StatusService({ db, logger, buffer: bufferService });
const notificationUtils = new NotificationUtils({
stringService,
emailService,
});
const notificationService = new NotificationService({
emailService,
db,
logger,
networkService,
stringService,
notificationUtils,
});
const redisService = new RedisService({ Redis: IORedis, logger });
const errorService = new ErrorService();
const superSimpleQueueHelper = new SuperSimpleQueueHelper({
db,
logger,
networkService,
statusService,
notificationService,
});
const superSimpleQueue = await SuperSimpleQueue.create({
appSettings,
db,
logger,
helper: superSimpleQueueHelper,
});
// Business services
const userService = new UserService({
crypto,
db,
emailService,
settingsService,
logger,
stringService,
jwt,
errorService,
jobQueue: superSimpleQueue,
});
const checkService = new CheckService({
db,
settingsService,
stringService,
errorService,
});
const diagnosticService = new DiagnosticService();
const inviteService = new InviteService({
db,
settingsService,
emailService,
stringService,
errorService,
});
const maintenanceWindowService = new MaintenanceWindowService({
db,
settingsService,
stringService,
errorService,
});
const monitorService = new MonitorService({
db,
settingsService,
jobQueue: superSimpleQueue,
stringService,
emailService,
papaparse,
logger,
errorService,
});
const services = {
settingsService,
translationService,
stringService,
db,
networkService,
emailService,
bufferService,
statusService,
notificationService,
redisService,
jobQueue: superSimpleQueue,
userService,
checkService,
diagnosticService,
inviteService,
maintenanceWindowService,
monitorService,
errorService,
logger,
};
Object.values(services).forEach((service) => {
ServiceRegistry.register(service.serviceName, service);
});
return services;
};
@@ -1,4 +1,5 @@
import { createAnnouncementValidation } from "../validation/joi.js";
import BaseController from "./baseController.js";
const SERVICE_NAME = "announcementController";
@@ -10,12 +11,17 @@ const SERVICE_NAME = "announcementController";
*/
class AnnouncementController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
constructor(commonDependencies) {
super(commonDependencies);
this.createAnnouncement = this.createAnnouncement.bind(this);
this.getAnnouncement = this.getAnnouncement.bind(this);
}
get serviceName() {
return AnnouncementController.SERVICE_NAME;
}
/**
* Handles the creation of a new announcement.
*
@@ -24,6 +24,7 @@ const SERVICE_NAME = "authController";
* @description Manages user authentication and authorization operations
*/
class AuthController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
/**
* Creates an instance of AuthController.
*
@@ -42,6 +43,10 @@ class AuthController extends BaseController {
this.userService = userService;
}
get serviceName() {
return AuthController.SERVICE_NAME;
}
/**
* Registers a new user in the system.
*
@@ -1,11 +1,11 @@
import { AppError } from "../service/infrastructure/errorService.js";
export const createCommonDependencies = (serviceRegistry, dbServiceName, loggerServiceName, errorServiceName, stringServiceName) => {
export const createCommonDependencies = (db, errorService, logger, stringService) => {
return {
db: serviceRegistry.get(dbServiceName),
errorService: serviceRegistry.get(errorServiceName),
logger: serviceRegistry.get(loggerServiceName),
stringService: serviceRegistry.get(stringServiceName),
db,
errorService,
logger,
stringService,
};
};
@@ -23,6 +23,7 @@ const SERVICE_NAME = "checkController";
* @description Manages check operations and monitoring data
*/
class CheckController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
/**
* Creates an instance of CheckController.
*
@@ -37,6 +38,10 @@ class CheckController extends BaseController {
this.checkService = checkService;
}
get serviceName() {
return CheckController.SERVICE_NAME;
}
/**
* Retrieves checks for a specific monitor with filtering and pagination.
*
@@ -10,6 +10,7 @@ import BaseController from "./baseController.js";
* @description Manages system diagnostics and performance monitoring
*/
class DiagnosticController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
/**
* Creates an instance of DiagnosticController.
* @param {Object} commonDependencies - Common dependencies injected into the controller
@@ -21,6 +22,9 @@ class DiagnosticController extends BaseController {
this.diagnosticService = diagnosticService;
}
get serviceName() {
return DiagnosticController.SERVICE_NAME;
}
/**
* Retrieves comprehensive system statistics and performance metrics.
*
@@ -7,6 +7,7 @@ const SERVICE_NAME = "inviteController";
* Manages invite token generation, email sending, and token verification
*/
class InviteController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
/**
* Creates a new InviteController instance
* @param {Object} commonDependencies - Common dependencies injected into the controller
@@ -17,6 +18,10 @@ class InviteController extends BaseController {
this.inviteService = inviteService;
}
get serviceName() {
return InviteController.SERVICE_NAME;
}
/**
* Generates an invite token for a user invitation
* @param {Object} req - Express request object
@@ -2,10 +2,15 @@ import BaseController from "./baseController.js";
const SERVICE_NAME = "LogController";
class LogController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
constructor(commonDependencies) {
super(commonDependencies);
}
get serviceName() {
return LogController.SERVICE_NAME;
}
getLogs = this.asyncHandler(
async (req, res) => {
const logs = await this.logger.getLogs();
@@ -12,12 +12,17 @@ import BaseController from "./baseController.js";
const SERVICE_NAME = "maintenanceWindowController";
class MaintenanceWindowController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
constructor(commonDependencies, { settingsService, maintenanceWindowService }) {
super(commonDependencies);
this.settingsService = settingsService;
this.maintenanceWindowService = maintenanceWindowService;
}
get serviceName() {
return MaintenanceWindowController.SERVICE_NAME;
}
createMaintenanceWindows = this.asyncHandler(
async (req, res) => {
await createMaintenanceWindowBodyValidation.validateAsync(req.body);
@@ -18,6 +18,7 @@ import BaseController from "./baseController.js";
const SERVICE_NAME = "monitorController";
class MonitorController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
constructor(commonDependencies, { settingsService, jobQueue, emailService, monitorService }) {
super(commonDependencies);
this.settingsService = settingsService;
@@ -26,6 +27,10 @@ class MonitorController extends BaseController {
this.monitorService = monitorService;
}
get serviceName() {
return MonitorController.SERVICE_NAME;
}
async verifyTeamAccess(teamId, monitorId) {
const monitor = await this.db.getMonitorById(monitorId);
if (!monitor.teamId.equals(teamId)) {
@@ -4,12 +4,17 @@ import BaseController from "./baseController.js";
const SERVICE_NAME = "NotificationController";
class NotificationController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
constructor(commonDependencies, { notificationService, statusService }) {
super(commonDependencies);
this.notificationService = notificationService;
this.statusService = statusService;
}
get serviceName() {
return NotificationController.SERVICE_NAME;
}
testNotification = this.asyncHandler(
async (req, res) => {
const notification = req.body;
@@ -2,11 +2,16 @@ import BaseController from "./baseController.js";
const SERVICE_NAME = "JobQueueController";
class JobQueueController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
constructor(commonDependencies, { jobQueue }) {
super(commonDependencies);
this.jobQueue = jobQueue;
}
get serviceName() {
return JobQueueController.SERVICE_NAME;
}
getMetrics = this.asyncHandler(
async (req, res) => {
const metrics = await this.jobQueue.getMetrics();
@@ -5,12 +5,17 @@ import BaseController from "./baseController.js";
const SERVICE_NAME = "SettingsController";
class SettingsController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
constructor(commonDependencies, { settingsService, emailService }) {
super(commonDependencies);
this.settingsService = settingsService;
this.emailService = emailService;
}
get serviceName() {
return SettingsController.SERVICE_NAME;
}
buildAppSettings = (dbSettings) => {
const sanitizedSettings = { ...dbSettings };
delete sanitizedSettings.version;
@@ -4,10 +4,15 @@ import BaseController from "./baseController.js";
const SERVICE_NAME = "statusPageController";
class StatusPageController extends BaseController {
static SERVICE_NAME = SERVICE_NAME;
constructor(commonDependencies) {
super(commonDependencies);
}
get serviceName() {
return StatusPageController.SERVICE_NAME;
}
createStatusPage = this.asyncHandler(
async (req, res) => {
await createStatusPageBodyValidation.validateAsync(req.body);
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,7 +1,5 @@
import mongoose from "mongoose";
import { BaseCheckSchema } from "./Check.js";
import logger from "../../utils/logger.js";
import { time } from "console";
const AuditSchema = mongoose.Schema({
id: { type: String, required: true },
title: { type: String, required: true },
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,5 +1,4 @@
import mongoose from "mongoose";
import UserModel from "../models/User.js";
import AppSettings from "../models/AppSettings.js";
import logger from "../../utils/logger.js";
@@ -87,6 +86,10 @@ class MongoDB {
Object.assign(this, diagnosticModule);
}
get serviceName() {
return MongoDB.SERVICE_NAME;
}
connect = async () => {
try {
const connectionString = this.appSettings.dbConnectionString || "mongodb://localhost:27017/uptime_db";
File renamed without changes.
+55
View File
@@ -0,0 +1,55 @@
import { initializeServices } from "./config/services.js";
import { initializeControllers } from "./config/controllers.js";
import { createApp } from "./app.js";
import { initShutdownListener } from "./shutdown.js";
import logger from "./utils/logger.js";
import { fileURLToPath } from "url";
import path from "path";
import fs from "fs";
import SettingsService from "./service/system/settingsService.js";
import AppSettings from "./db/models/AppSettings.js";
const SERVICE_NAME = "Server";
const startApp = async () => {
// FE path
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const openApiSpec = JSON.parse(fs.readFileSync(path.join(__dirname, "../openapi.json"), "utf8"));
const frontendPath = path.join(__dirname, "public");
// Create services
const settingsService = new SettingsService(AppSettings);
const appSettings = settingsService.loadSettings();
// Initialize services
const services = await initializeServices(appSettings, settingsService);
// Initialize controllers
const controllers = initializeControllers(services);
const app = createApp({
services,
controllers,
appSettings,
frontendPath,
openApiSpec,
});
const port = appSettings.port || 52345;
const server = app.listen(port, () => {
logger.info({ message: `Server started on port:${port}` });
});
initShutdownListener(server, services);
};
startApp().catch((error) => {
logger.error({
message: error.message,
service: SERVICE_NAME,
method: "startApp",
stack: error.stack,
});
process.exit(1);
});
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -10,6 +10,10 @@ class CheckService {
this.errorService = errorService;
}
get serviceName() {
return CheckService.SERVICE_NAME;
}
getChecksByMonitor = async ({ monitorId, query, teamId }) => {
if (!monitorId) {
throw this.errorService.createBadRequestError("No monitor ID in request");
@@ -5,6 +5,7 @@ const SERVICE_NAME = "diagnosticService";
class DiagnosticService {
static SERVICE_NAME = SERVICE_NAME;
constructor() {
/**
* Performance Observer for monitoring system performance metrics.
@@ -18,6 +19,10 @@ class DiagnosticService {
obs.observe({ entryTypes: ["measure"] });
}
get serviceName() {
return DiagnosticService.SERVICE_NAME;
}
getCPUUsage = async () => {
const startUsage = process.cpuUsage();
const timingPeriod = 1000; // measured in ms
@@ -11,6 +11,10 @@ class InviteService {
this.errorService = errorService;
}
get serviceName() {
return InviteService.SERVICE_NAME;
}
getInviteToken = async ({ invite, teamId }) => {
invite.teamId = teamId;
const inviteToken = await this.db.requestInviteToken(invite);
@@ -2,6 +2,7 @@ const SERVICE_NAME = "maintenanceWindowService";
class MaintenanceWindowService {
static SERVICE_NAME = SERVICE_NAME;
constructor({ db, settingsService, stringService, errorService }) {
this.db = db;
this.settingsService = settingsService;
@@ -9,6 +10,10 @@ class MaintenanceWindowService {
this.errorService = errorService;
}
get serviceName() {
return MaintenanceWindowService.SERVICE_NAME;
}
createMaintenanceWindow = async ({ teamId, body }) => {
const monitorIds = body.monitors;
const monitors = await this.db.getMonitorsByIds(monitorIds);
@@ -2,7 +2,7 @@ import { createMonitorsBodyValidation } from "../../validation/joi.js";
const SERVICE_NAME = "MonitorService";
class MonitorService {
SERVICE_NAME = SERVICE_NAME;
static SERVICE_NAME = SERVICE_NAME;
constructor({ db, settingsService, jobQueue, stringService, emailService, papaparse, logger, errorService }) {
this.db = db;
@@ -15,6 +15,10 @@ class MonitorService {
this.errorService = errorService;
}
get serviceName() {
return MonitorService.SERVICE_NAME;
}
verifyTeamAccess = async ({ teamId, monitorId }) => {
const monitor = await this.db.getMonitorById(monitorId);
if (!monitor?.teamId?.equals(teamId)) {
@@ -2,7 +2,8 @@ const SERVICE_NAME = "userService";
class UserService {
static SERVICE_NAME = SERVICE_NAME;
constructor({ db, emailService, settingsService, logger, stringService, jwt, errorService }) {
constructor({ crypto, db, emailService, settingsService, logger, stringService, jwt, errorService, jobQueue }) {
this.db = db;
this.emailService = emailService;
this.settingsService = settingsService;
@@ -10,6 +11,12 @@ class UserService {
this.stringService = stringService;
this.jwt = jwt;
this.errorService = errorService;
this.jobQueue = jobQueue;
this.crypto = crypto;
}
get serviceName() {
return UserService.SERVICE_NAME;
}
issueToken = (payload, appSettings) => {
@@ -2,12 +2,17 @@ const SERVICE_NAME = "RedisService";
class RedisService {
static SERVICE_NAME = SERVICE_NAME;
constructor({ Redis, logger }) {
this.Redis = Redis;
this.connections = new Set();
this.logger = logger;
}
get serviceName() {
return RedisService.SERVICE_NAME;
}
getNewConnection(options = {}) {
const connection = new this.Redis(process.env.REDIS_URL, {
retryStrategy: (times) => {
@@ -23,6 +23,10 @@ class JobQueue {
this.workers = [];
}
get serviceName() {
return JobQueue.SERVICE_NAME;
}
static async create({ db, jobQueueHelper, logger, stringService }) {
const instance = new JobQueue({ db, jobQueueHelper, logger, stringService });
await instance.init();
@@ -1,6 +1,8 @@
const SERVICE_NAME = "JobQueueHelper";
class JobQueueHelper {
static SERVICE_NAME = SERVICE_NAME;
constructor({ redisService, Queue, Worker, logger, db, networkService, statusService, notificationService }) {
this.db = db;
this.redisService = redisService;
@@ -12,6 +14,10 @@ class JobQueueHelper {
this.notificationService = notificationService;
}
get serviceName() {
return JobQueueHelper.SERVICE_NAME;
}
createQueue(queueName) {
const connection = this.redisService.getNewConnection();
const q = new this.Queue(queueName, {
@@ -1,6 +1,6 @@
import { Pulse } from "@pulsecron/pulse";
const SERVICE_NAME = "PulseQueue";
const SERVICE_NAME = "JobQueue";
class PulseQueue {
static SERVICE_NAME = SERVICE_NAME;
@@ -11,6 +11,10 @@ class PulseQueue {
this.logger = logger;
}
get serviceName() {
return PulseQueue.SERVICE_NAME;
}
static async create({ appSettings, db, pulseQueueHelper, logger }) {
const instance = new PulseQueue({ appSettings, db, pulseQueueHelper, logger });
await instance.init();
@@ -1,6 +1,8 @@
const SERVICE_NAME = "PulseQueueHelper";
class PulseQueueHelper {
static SERVICE_NAME = SERVICE_NAME;
constructor({ db, logger, networkService, statusService, notificationService }) {
this.db = db;
this.logger = logger;
@@ -9,6 +11,10 @@ class PulseQueueHelper {
this.notificationService = notificationService;
}
get serviceName() {
return PulseQueueHelper.SERVICE_NAME;
}
getMonitorJob = () => {
return async (job) => {
try {
@@ -1,5 +1,5 @@
import Scheduler from "super-simple-scheduler";
const SERVICE_NAME = "SuperSimpleQueue";
const SERVICE_NAME = "JobQueue";
class SuperSimpleQueue {
static SERVICE_NAME = SERVICE_NAME;
@@ -11,6 +11,10 @@ class SuperSimpleQueue {
this.helper = helper;
}
get serviceName() {
return SuperSimpleQueue.SERVICE_NAME;
}
static async create({ appSettings, db, logger, helper }) {
const instance = new SuperSimpleQueue({ appSettings, db, logger, helper });
await instance.init();
@@ -1,6 +1,7 @@
const SERVICE_NAME = "SuperSimpleQueueHelper";
const SERVICE_NAME = "JobQueueHelper";
class SuperSimpleQueueHelper {
static SERVICE_NAME = SERVICE_NAME;
constructor({ db, logger, networkService, statusService, notificationService }) {
this.db = db;
this.logger = logger;
@@ -9,6 +10,10 @@ class SuperSimpleQueueHelper {
this.notificationService = notificationService;
}
get serviceName() {
return SuperSimpleQueueHelper.SERVICE_NAME;
}
getMonitorJob = () => {
return async (monitor) => {
try {
@@ -10,6 +10,7 @@ const TYPE_MAP = {
};
class BufferService {
static SERVICE_NAME = SERVICE_NAME;
constructor({ db, logger }) {
this.db = db;
this.logger = logger;
@@ -32,7 +33,10 @@ class BufferService {
method: "constructor",
});
}
static SERVICE_NAME = SERVICE_NAME;
get serviceName() {
return BufferService.SERVICE_NAME;
}
addToBuffer({ check, type }) {
try {
@@ -33,6 +33,10 @@ class EmailService {
this.init();
}
get serviceName() {
return EmailService.SERVICE_NAME;
}
init = async () => {
/**
* Loads an email template from the filesystem.
@@ -42,7 +46,7 @@ class EmailService {
*/
this.loadTemplate = (templateName) => {
try {
const templatePath = this.path.join(__dirname, `../templates/${templateName}.mjml`);
const templatePath = this.path.join(__dirname, `../../templates/${templateName}.mjml`);
const templateContent = this.fs.readFileSync(templatePath, "utf8");
return this.compile(templateContent);
} catch (error) {
Loaded 100 of 127 files, more files were not shown because too many files have changed in this diff. Show more