From 36a65bc7f6a96179c3e5a142f807e3ab9627143f Mon Sep 17 00:00:00 2001 From: Rory& Date: Thu, 23 Oct 2025 14:15:20 +0200 Subject: [PATCH] Use EnvConfig for logging settings --- src/api/Server.ts | 238 +++++++++++++++++++++---------------------- src/bundle/Server.ts | 54 +++++----- src/cdn/Server.ts | 154 ++++++++++++++-------------- 3 files changed, 223 insertions(+), 223 deletions(-) diff --git a/src/api/Server.ts b/src/api/Server.ts index f81898e81..375beffe3 100644 --- a/src/api/Server.ts +++ b/src/api/Server.ts @@ -16,7 +16,7 @@ along with this program. If not, see . */ -import { Config, ConnectionConfig, ConnectionLoader, Email, JSONReplacer, WebAuthn, initDatabase, initEvent, registerRoutes } from "@spacebar/util"; +import { Config, ConnectionConfig, ConnectionLoader, Email, JSONReplacer, WebAuthn, initDatabase, initEvent, registerRoutes, EnvConfig } from "@spacebar/util"; import { Authentication, CORS, ImageProxy, BodyParser, ErrorHandler, initRateLimits, initTranslation } from "./middlewares"; import { Request, Response, Router } from "express"; import { Server, ServerOptions } from "lambert-server"; @@ -31,149 +31,149 @@ const PUBLIC_ASSETS_FOLDER = path.join(ASSETS_FOLDER, "public"); export type SpacebarServerOptions = ServerOptions; declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace Express { - interface Request { - server: SpacebarServer; - } - } + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Express { + interface Request { + server: SpacebarServer; + } + } } export class SpacebarServer extends Server { - declare public options: SpacebarServerOptions; + declare public options: SpacebarServerOptions; - constructor(opts?: Partial) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - super({ ...opts, errorHandler: false, jsonBody: false }); - } + constructor(opts?: Partial) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + super({ ...opts, errorHandler: false, jsonBody: false }); + } - async start() { - await initDatabase(); - await Config.init(); - await initEvent(); - await Email.init(); - await ConnectionConfig.init(); - await initInstance(); - WebAuthn.init(); + async start() { + await initDatabase(); + await Config.init(); + await initEvent(); + await Email.init(); + await ConnectionConfig.init(); + await initInstance(); + WebAuthn.init(); - const logRequests = process.env["LOG_REQUESTS"] != undefined; - if (logRequests) { - this.app.use( - morgan("combined", { - skip: (req, res) => { - let skip = !(process.env["LOG_REQUESTS"]?.includes(res.statusCode.toString()) ?? false); - if (process.env["LOG_REQUESTS"]?.charAt(0) == "-") skip = !skip; - return skip; - }, - }), - ); - } + const logRequests = EnvConfig.logging.logRequests !== ""; + if (logRequests) { + this.app.use( + morgan("combined", { + skip: (req, res) => { + let skip = !(EnvConfig.logging.logRequests.includes(res.statusCode.toString()) ?? false); + if (EnvConfig.logging.logRequests.charAt(0) == "-") skip = !skip; + return skip; + }, + }), + ); + } - this.app.set("json replacer", JSONReplacer); - this.app.disable("x-powered-by"); + this.app.set("json replacer", JSONReplacer); + this.app.disable("x-powered-by"); - const trustedProxies = Config.get().security.trustedProxies; - if (trustedProxies) this.app.set("trust proxy", trustedProxies); + const trustedProxies = Config.get().security.trustedProxies; + if (trustedProxies) this.app.set("trust proxy", trustedProxies); - this.app.use(CORS); - this.app.use(BodyParser({ inflate: true, limit: "10mb" })); + this.app.use(CORS); + this.app.use(BodyParser({ inflate: true, limit: "10mb" })); - const app = this.app; - const api = Router({ mergeParams: true }); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - this.app = api; + const app = this.app; + const api = Router({ mergeParams: true }); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this.app = api; - api.use(Authentication); - await initRateLimits(api); - await initTranslation(api); + api.use(Authentication); + await initRateLimits(api); + await initTranslation(api); - this.routes = (await registerRoutes(this, path.join(__dirname, "routes", "/"))).filter((r) => !!r); + this.routes = (await registerRoutes(this, path.join(__dirname, "routes", "/"))).filter((r) => !!r); - // 404 is not an error in express, so this should not be an error middleware - // this is a fine place to put the 404 handler because its after we register the routes - // and since its not an error middleware, our error handler below still works. - // Emma [it/its] @ Rory& - the _ is required now, as pillarjs throw an error if you don't pass a param name now - api.use("*_", (req: Request, res: Response) => { - res.status(404).json({ - message: "404 endpoint not found", - code: 0, - }); - }); + // 404 is not an error in express, so this should not be an error middleware + // this is a fine place to put the 404 handler because its after we register the routes + // and since its not an error middleware, our error handler below still works. + // Emma [it/its] @ Rory& - the _ is required now, as pillarjs throw an error if you don't pass a param name now + api.use("*_", (req: Request, res: Response) => { + res.status(404).json({ + message: "404 endpoint not found", + code: 0, + }); + }); - this.app = app; + this.app = app; - //app.use("/__development", ) - //app.use("/__internals", ) - app.use("/api/v6", api); - app.use("/api/v7", api); - app.use("/api/v8", api); - app.use("/api/v9", api); - app.use("/api", api); // allow unversioned requests + //app.use("/__development", ) + //app.use("/__internals", ) + app.use("/api/v6", api); + app.use("/api/v7", api); + app.use("/api/v8", api); + app.use("/api/v9", api); + app.use("/api", api); // allow unversioned requests - app.use("/imageproxy/:hash/:size/:url", ImageProxy); + app.use("/imageproxy/:hash/:size/:url", ImageProxy); - app.get("/", (req, res) => res.sendFile(path.join(PUBLIC_ASSETS_FOLDER, "index.html"))); + app.get("/", (req, res) => res.sendFile(path.join(PUBLIC_ASSETS_FOLDER, "index.html"))); - app.get("/verify-email", (req, res) => res.sendFile(path.join(PUBLIC_ASSETS_FOLDER, "verify.html"))); + app.get("/verify-email", (req, res) => res.sendFile(path.join(PUBLIC_ASSETS_FOLDER, "verify.html"))); - app.get("/_spacebar/api/schemas.json", (req, res) => { - res.sendFile(path.join(ASSETS_FOLDER, "schemas.json")); - }); + app.get("/_spacebar/api/schemas.json", (req, res) => { + res.sendFile(path.join(ASSETS_FOLDER, "schemas.json")); + }); - app.get("/_spacebar/api/openapi.json", (req, res) => { - res.sendFile(path.join(ASSETS_FOLDER, "openapi.json")); - }); + app.get("/_spacebar/api/openapi.json", (req, res) => { + res.sendFile(path.join(ASSETS_FOLDER, "openapi.json")); + }); - // current well-known location - app.get("/.well-known/spacebar", (req, res) => { - res.json({ - api: Config.get().api.endpointPublic, - }); - }); + // current well-known location + app.get("/.well-known/spacebar", (req, res) => { + res.json({ + api: Config.get().api.endpointPublic, + }); + }); - // new well-known location - app.get("/.well-known/spacebar/client", (req, res) => { - let erlpackSupported = false; - try { - require("@yukikaze-bot/erlpack"); - erlpackSupported = true; - } catch (e) { - // empty - } + // new well-known location + app.get("/.well-known/spacebar/client", (req, res) => { + let erlpackSupported = false; + try { + require("@yukikaze-bot/erlpack"); + erlpackSupported = true; + } catch (e) { + // empty + } - res.json({ - api: { - baseUrl: Config.get().api.endpointPublic?.split("/api")[0] || "", // TODO: migrate database values to not include /api/v9 - apiVersions: { - default: Config.get().api.defaultVersion, - active: Config.get().api.activeVersions, - }, - }, - cdn: { - baseUrl: Config.get().cdn.endpointPublic, - }, - gateway: { - baseUrl: Config.get().gateway.endpointPublic, - encoding: [...(erlpackSupported ? ["etf"] : []), "json"], - compression: ["zstd-stream", "zlib-stream", null], - }, - admin: - Config.get().admin.endpointPublic === null - ? undefined - : { - baseUrl: Config.get().admin.endpointPublic, - }, - }); - }); + res.json({ + api: { + baseUrl: Config.get().api.endpointPublic?.split("/api")[0] || "", // TODO: migrate database values to not include /api/v9 + apiVersions: { + default: Config.get().api.defaultVersion, + active: Config.get().api.activeVersions, + }, + }, + cdn: { + baseUrl: Config.get().cdn.endpointPublic, + }, + gateway: { + baseUrl: Config.get().gateway.endpointPublic, + encoding: [...(erlpackSupported ? ["etf"] : []), "json"], + compression: ["zstd-stream", "zlib-stream", null], + }, + admin: + Config.get().admin.endpointPublic === null + ? undefined + : { + baseUrl: Config.get().admin.endpointPublic, + }, + }); + }); - this.app.use(ErrorHandler); + this.app.use(ErrorHandler); - ConnectionLoader.loadConnections(); + ConnectionLoader.loadConnections(); - if (logRequests) console.log(red(`Warning: Request logging is enabled! This will spam your console!\nTo disable this, unset the 'LOG_REQUESTS' environment variable!`)); + if (logRequests) console.log(red(`Warning: Request logging is enabled! This will spam your console!\nTo disable this, unset the 'LOG_REQUESTS' environment variable!`)); - return super.start(); - } + return super.start(); + } } diff --git a/src/bundle/Server.ts b/src/bundle/Server.ts index bcc567d74..1a90f270b 100644 --- a/src/bundle/Server.ts +++ b/src/bundle/Server.ts @@ -28,7 +28,7 @@ import * as Webrtc from "@spacebar/webrtc"; import { CDNServer } from "@spacebar/cdn"; import express from "express"; import { green, bold } from "picocolors"; -import { Config, initDatabase } from "@spacebar/util"; +import { Config, EnvConfig, initDatabase } from "@spacebar/util"; const app = express(); const server = http.createServer(); @@ -41,41 +41,41 @@ const api = new Api.SpacebarServer({ server, port, production, app }); const cdn = new CDNServer({ server, port, production, app }); const gateway = new Gateway.Server({ server, port, production }); const webrtc = new Webrtc.Server({ - server: undefined, - port: wrtcWsPort, - production, + server: undefined, + port: wrtcWsPort, + production, }); process.on("SIGTERM", async () => { - console.log("Shutting down due to SIGTERM"); - await gateway.stop(); - await cdn.stop(); - await api.stop(); - await webrtc.stop(); - server.close(); + console.log("Shutting down due to SIGTERM"); + await gateway.stop(); + await cdn.stop(); + await api.stop(); + await webrtc.stop(); + server.close(); }); async function main() { - await initDatabase(); - await Config.init(); + await initDatabase(); + await Config.init(); - const logRequests = process.env["LOG_REQUESTS"] != undefined; - if (logRequests) { - app.use( - morgan("combined", { - skip: (req, res) => { - let skip = !(process.env["LOG_REQUESTS"]?.includes(res.statusCode.toString()) ?? false); - if (process.env["LOG_REQUESTS"]?.charAt(0) == "-") skip = !skip; - return skip; - }, - }), - ); - } + const logRequests = EnvConfig.logging.logRequests != ""; + if (logRequests) { + app.use( + morgan("combined", { + skip: (req, res) => { + let skip = !(EnvConfig.logging.logRequests.includes(res.statusCode.toString()) ?? false); + if (EnvConfig.logging.logRequests.charAt(0) == "-") skip = !skip; + return skip; + }, + }), + ); + } - await new Promise((resolve) => server.listen({ port }, () => resolve(undefined))); - await Promise.all([api.start(), cdn.start(), gateway.start(), webrtc.start()]); + await new Promise((resolve) => server.listen({ port }, () => resolve(undefined))); + await Promise.all([api.start(), cdn.start(), gateway.start(), webrtc.start()]); - console.log(`[Server] ${green(`Listening on port ${bold(port)}`)}`); + console.log(`[Server] ${green(`Listening on port ${bold(port)}`)}`); } main().catch(console.error); diff --git a/src/cdn/Server.ts b/src/cdn/Server.ts index 091621f06..2a64e0fad 100644 --- a/src/cdn/Server.ts +++ b/src/cdn/Server.ts @@ -17,7 +17,7 @@ */ import { Server, ServerOptions } from "lambert-server"; -import { Attachment, Config, initDatabase, registerRoutes } from "@spacebar/util"; +import { Attachment, Config, EnvConfig, initDatabase, registerRoutes } from "@spacebar/util"; import { CORS, BodyParser } from "@spacebar/api"; import path from "path"; import avatarsRoute from "./routes/avatars"; @@ -29,105 +29,105 @@ import { Like } from "typeorm"; export type CDNServerOptions = ServerOptions; export class CDNServer extends Server { - declare public options: CDNServerOptions; + declare public options: CDNServerOptions; - constructor(options?: Partial) { - super(options); - } + constructor(options?: Partial) { + super(options); + } - async start() { - await initDatabase(); - await Config.init(); - await this.cleanupSignaturesInDb(); + async start() { + await initDatabase(); + await Config.init(); + await this.cleanupSignaturesInDb(); - const logRequests = process.env["LOG_REQUESTS"] != undefined; - if (logRequests) { - this.app.use( - morgan("combined", { - skip: (req, res) => { - let skip = !(process.env["LOG_REQUESTS"]?.includes(res.statusCode.toString()) ?? false); - if (process.env["LOG_REQUESTS"]?.charAt(0) == "-") skip = !skip; - return skip; - }, - }), - ); - } + const logRequests = EnvConfig.logging.logRequests != undefined; + if (logRequests) { + this.app.use( + morgan("combined", { + skip: (req, res) => { + let skip = !(EnvConfig.logging.logRequests.includes(res.statusCode.toString()) ?? false); + if (EnvConfig.logging.logRequests.charAt(0) == "-") skip = !skip; + return skip; + }, + }), + ); + } - const trustedProxies = Config.get().security.trustedProxies; - if (trustedProxies) this.app.set("trust proxy", trustedProxies); + const trustedProxies = Config.get().security.trustedProxies; + if (trustedProxies) this.app.set("trust proxy", trustedProxies); - this.app.disable("x-powered-by"); + this.app.disable("x-powered-by"); - this.app.use(CORS); - this.app.use(BodyParser({ inflate: true, limit: "10mb" })); + this.app.use(CORS); + this.app.use(BodyParser({ inflate: true, limit: "10mb" })); - await registerRoutes(this, path.join(__dirname, "routes/")); + await registerRoutes(this, path.join(__dirname, "routes/")); - this.app.use("/icons/", avatarsRoute); - console.log("[Server] Route /icons registered"); + this.app.use("/icons/", avatarsRoute); + console.log("[Server] Route /icons registered"); - this.app.use("/role-icons/", iconsRoute); - console.log("[Server] Route /role-icons registered"); + this.app.use("/role-icons/", iconsRoute); + console.log("[Server] Route /role-icons registered"); - this.app.use("/emojis/", avatarsRoute); - console.log("[Server] Route /emojis registered"); + this.app.use("/emojis/", avatarsRoute); + console.log("[Server] Route /emojis registered"); - this.app.use("/stickers/", avatarsRoute); - console.log("[Server] Route /stickers registered"); + this.app.use("/stickers/", avatarsRoute); + console.log("[Server] Route /stickers registered"); - this.app.use("/banners/", avatarsRoute); - console.log("[Server] Route /banners registered"); + this.app.use("/banners/", avatarsRoute); + console.log("[Server] Route /banners registered"); - this.app.use("/splashes/", avatarsRoute); - console.log("[Server] Route /splashes registered"); + this.app.use("/splashes/", avatarsRoute); + console.log("[Server] Route /splashes registered"); - this.app.use("/discovery-splashes/", avatarsRoute); - console.log("[Server] Route /discovery-splashes registered"); + this.app.use("/discovery-splashes/", avatarsRoute); + console.log("[Server] Route /discovery-splashes registered"); - this.app.use("/app-icons/", avatarsRoute); - console.log("[Server] Route /app-icons registered"); + this.app.use("/app-icons/", avatarsRoute); + console.log("[Server] Route /app-icons registered"); - this.app.use("/app-assets/", avatarsRoute); - console.log("[Server] Route /app-assets registered"); + this.app.use("/app-assets/", avatarsRoute); + console.log("[Server] Route /app-assets registered"); - this.app.use("/discover-splashes/", avatarsRoute); - console.log("[Server] Route /discover-splashes registered"); + this.app.use("/discover-splashes/", avatarsRoute); + console.log("[Server] Route /discover-splashes registered"); - this.app.use("/team-icons/", avatarsRoute); - console.log("[Server] Route /team-icons registered"); + this.app.use("/team-icons/", avatarsRoute); + console.log("[Server] Route /team-icons registered"); - this.app.use("/channel-icons/", avatarsRoute); - console.log("[Server] Route /channel-icons registered"); + this.app.use("/channel-icons/", avatarsRoute); + console.log("[Server] Route /channel-icons registered"); - this.app.use("/guilds/:guild_id/users/:user_id/avatars", guildProfilesRoute); - console.log("[Server] Route /guilds/avatars registered"); + this.app.use("/guilds/:guild_id/users/:user_id/avatars", guildProfilesRoute); + console.log("[Server] Route /guilds/avatars registered"); - this.app.use("/guilds/:guild_id/users/:user_id/banners", guildProfilesRoute); - console.log("[Server] Route /guilds/banners registered"); + this.app.use("/guilds/:guild_id/users/:user_id/banners", guildProfilesRoute); + console.log("[Server] Route /guilds/banners registered"); - return super.start(); - } + return super.start(); + } - async stop() { - return super.stop(); - } + async stop() { + return super.stop(); + } - async cleanupSignaturesInDb() { - console.log("[CDN] Cleaning up signatures in database"); - const attachmentsToFix = await Attachment.find({ - where: { url: Like("%?ex=%") }, - }); - if (attachmentsToFix.length === 0) { - console.log("[CDN] No attachments to fix"); - return; - } + async cleanupSignaturesInDb() { + console.log("[CDN] Cleaning up signatures in database"); + const attachmentsToFix = await Attachment.find({ + where: { url: Like("%?ex=%") }, + }); + if (attachmentsToFix.length === 0) { + console.log("[CDN] No attachments to fix"); + return; + } - console.log("[CDN] Found", attachmentsToFix.length, " attachments to fix"); - for (const attachment of attachmentsToFix) { - attachment.url = attachment.url.split("?ex=")[0]; - attachment.proxy_url = attachment.proxy_url?.split("?ex=")[0]; - await attachment.save(); - console.log(`[CDN] Fixed attachment ${attachment.id}`); - } - } + console.log("[CDN] Found", attachmentsToFix.length, " attachments to fix"); + for (const attachment of attachmentsToFix) { + attachment.url = attachment.url.split("?ex=")[0]; + attachment.proxy_url = attachment.proxy_url?.split("?ex=")[0]; + await attachment.save(); + console.log(`[CDN] Fixed attachment ${attachment.id}`); + } + } }