2023-11-20 10:59:32 +00:00
|
|
|
import express, { Express } from "express";
|
2023-11-20 15:42:08 +00:00
|
|
|
import { ServerMessages } from "../route/messages";
|
2023-11-20 10:59:32 +00:00
|
|
|
import { Route } from "../route/route";
|
|
|
|
|
|
|
|
type ServerConfig = {
|
|
|
|
port: number;
|
|
|
|
routes?: Route[];
|
|
|
|
};
|
|
|
|
|
|
|
|
export default class Server {
|
|
|
|
/**
|
|
|
|
* The port that this server is listening on.
|
|
|
|
*/
|
|
|
|
private port: number;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The express server.
|
|
|
|
*/
|
|
|
|
private server: Express;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The routes that this server is serving.
|
|
|
|
*/
|
|
|
|
private routes: Route[] = [];
|
|
|
|
|
|
|
|
constructor({ port, routes }: ServerConfig) {
|
|
|
|
this.port = port;
|
|
|
|
if (routes) {
|
|
|
|
this.routes.push(...routes);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the express server
|
|
|
|
this.server = express();
|
|
|
|
this.preInit();
|
|
|
|
|
2023-11-20 15:42:08 +00:00
|
|
|
// Setup route logging
|
|
|
|
this.server.use((req, res, next) => {
|
|
|
|
// TODO: make this look better?
|
|
|
|
console.log(`[${req.method}] ${req.path}`);
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
|
2023-11-20 10:59:32 +00:00
|
|
|
// Handle the routes
|
|
|
|
for (const route of this.routes) {
|
2023-11-20 11:04:24 +00:00
|
|
|
this.server.all(route.getPath(), (req, res, next) => {
|
|
|
|
if (req.method.toUpperCase() !== route.getMethod().toUpperCase()) {
|
|
|
|
return next(); // Skip this method
|
|
|
|
}
|
2023-11-20 15:42:08 +00:00
|
|
|
try {
|
|
|
|
route.handle(req, res, next);
|
|
|
|
} catch (ex) {
|
|
|
|
console.error(ex);
|
|
|
|
// Inform the user that an internal server error occurred
|
|
|
|
res.status(500).json(ServerMessages.internalServerError());
|
|
|
|
}
|
2023-11-20 11:04:24 +00:00
|
|
|
});
|
2023-11-20 10:59:32 +00:00
|
|
|
}
|
2023-11-20 14:29:10 +00:00
|
|
|
|
|
|
|
// Log the registered routes
|
2023-11-20 10:59:32 +00:00
|
|
|
console.log(`Registered ${this.routes.length} routes`);
|
2023-11-20 14:25:48 +00:00
|
|
|
for (const route of this.routes) {
|
|
|
|
console.log(` - ${route.getMethod().toUpperCase()} ${route.getPath()}`);
|
|
|
|
}
|
2023-11-20 10:59:32 +00:00
|
|
|
|
2023-11-20 11:04:24 +00:00
|
|
|
// Handle unknown routes
|
|
|
|
this.server.all("*", (req, res) => {
|
|
|
|
res.status(404).send("404 Not Found");
|
|
|
|
});
|
|
|
|
|
2023-11-20 10:59:32 +00:00
|
|
|
// Start listening on the specified port
|
|
|
|
this.server.listen(this.port, () => {
|
2023-11-20 14:29:10 +00:00
|
|
|
console.log(`Server listening on http://localhost:${this.port}`);
|
2023-11-20 10:59:32 +00:00
|
|
|
this.postInit();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the port that this server is listening on.
|
|
|
|
*
|
|
|
|
* @returns {number} the port
|
|
|
|
*/
|
|
|
|
public getPort() {
|
|
|
|
return this.port;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Registers a list of routes.
|
|
|
|
*
|
|
|
|
* @param route the routes to register
|
|
|
|
*/
|
|
|
|
public registerRoute(...routes: Route[]) {
|
|
|
|
this.routes.push(...routes);
|
|
|
|
}
|
|
|
|
|
|
|
|
public getRoute(path: string): Route | undefined {
|
|
|
|
return this.routes.find((route) => route.getPath() === path);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets called before the server starts listening.
|
|
|
|
*/
|
|
|
|
public preInit(): void {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets called after the server starts listening.
|
|
|
|
*/
|
|
|
|
public postInit(): void {}
|
|
|
|
}
|