diff --git a/src/cdn/util/basicCrdFileRouter.ts b/src/cdn/util/basicCrdFileRouter.ts
index 46fcf882..b05f3dbe 100644
--- a/src/cdn/util/basicCrdFileRouter.ts
+++ b/src/cdn/util/basicCrdFileRouter.ts
@@ -1,6 +1,6 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
+ Copyright (C) 2025 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
@@ -18,19 +18,16 @@
import { Router, Response, Request } from "express";
import { Config, Snowflake } from "@spacebar/util";
-import { storage } from "../util/Storage";
import { fileTypeFromBuffer } from "file-type";
import { HTTPError } from "lambert-server";
import crypto from "crypto";
-import { multer } from "../util/multer";
+import { storage, multer, ANIMATED_MIME_TYPES, STATIC_MIME_TYPES } from "../util";
// TODO: check premium and animated pfp are allowed in the config
// TODO: generate different sizes of icon
// TODO: generate different image types of icon
// TODO: delete old icons
-const ANIMATED_MIME_TYPES = ["image/apng", "image/gif", "image/gifv"];
-const STATIC_MIME_TYPES = ["image/png", "image/jpeg", "image/webp", "image/svg+xml", "image/svg"];
const ALLOWED_MIME_TYPES = [...ANIMATED_MIME_TYPES, ...STATIC_MIME_TYPES];
export class BasicCrdFileRouterOptions {
@@ -44,6 +41,7 @@ export class BasicCrdFileRouterOptions {
export function createBasicCrdFileRouter(opts: BasicCrdFileRouterOptions) {
const router = Router({ mergeParams: true });
+ console.log("Creating Basic CRD File Router with opts:", JSON.stringify(opts));
router.post("/:user_id", multer.single("file"), async (req: Request, res: Response) => {
if (req.headers.signature !== Config.get().security.requestSignature) throw new HTTPError("Invalid request signature");
diff --git a/src/cdn/util/cache.ts b/src/cdn/util/cache.ts
new file mode 100644
index 00000000..c48087dd
--- /dev/null
+++ b/src/cdn/util/cache.ts
@@ -0,0 +1,7 @@
+import { NextFunction, Response, Request } from "express";
+
+export function cache(req: Request, res: Response, next: NextFunction) {
+ const durationInSeconds = 21600; // 6 hours
+ res.set("Cache-Control", `public, max-age=${durationInSeconds}, s-maxage=${durationInSeconds}, immutable`);
+ next();
+}
diff --git a/src/cdn/util/FileStorage.ts b/src/cdn/util/fileStorage.ts
index 6f01b3c5..e2118228 100644
--- a/src/cdn/util/FileStorage.ts
+++ b/src/cdn/util/fileStorage.ts
@@ -16,7 +16,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Storage } from "./Storage";
+import { Storage } from ".";
import fs from "fs";
import fsp from "fs/promises";
import { join, dirname } from "path";
@@ -36,6 +36,7 @@ function getPath(path: string) {
export class FileStorage implements Storage {
async get(path: string): Promise<Buffer | null> {
+ if (process.env.CDN_LOG_IO) console.log(`[CDN][IO] read file: ${path}`);
path = getPath(path);
try {
return await fsp.readFile(path);
@@ -51,6 +52,7 @@ export class FileStorage implements Storage {
}
async clone(path: string, newPath: string) {
+ if (process.env.CDN_LOG_IO) console.log(`[CDN][IO] clone file: ${path} -> ${newPath}`);
path = getPath(path);
newPath = getPath(newPath);
@@ -61,6 +63,7 @@ export class FileStorage implements Storage {
}
async set(path: string, value: Buffer) {
+ if (process.env.CDN_LOG_IO) console.log(`[CDN][IO] write file: ${path}`);
path = getPath(path);
if (!fs.existsSync(dirname(path))) fs.mkdirSync(dirname(path), { recursive: true });
@@ -71,6 +74,7 @@ export class FileStorage implements Storage {
}
async delete(path: string) {
+ if (process.env.CDN_LOG_IO) console.log(`[CDN][IO] delete file: ${path}`);
//TODO we should delete the parent directory if empty
fs.unlinkSync(getPath(path));
}
diff --git a/src/cdn/util/index.ts b/src/cdn/util/index.ts
index ba249845..9d58117b 100644
--- a/src/cdn/util/index.ts
+++ b/src/cdn/util/index.ts
@@ -16,6 +16,9 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-export * from "./FileStorage";
+export * from "./storage";
+export * from "./fileStorage";
+export * from "./s3Storage";
export * from "./multer";
-export * from "./Storage";
+export * from "./cache";
+export * from "./mimetypes";
diff --git a/src/cdn/util/mimetypes.ts b/src/cdn/util/mimetypes.ts
new file mode 100644
index 00000000..c56bd734
--- /dev/null
+++ b/src/cdn/util/mimetypes.ts
@@ -0,0 +1,2 @@
+export const ANIMATED_MIME_TYPES = ["image/apng", "image/gif", "image/gifv"];
+export const STATIC_MIME_TYPES = ["image/png", "image/jpeg", "image/webp", "image/svg+xml", "image/svg"];
diff --git a/src/cdn/util/S3Storage.ts b/src/cdn/util/s3Storage.ts
index f657fd29..2827e974 100644
--- a/src/cdn/util/S3Storage.ts
+++ b/src/cdn/util/s3Storage.ts
@@ -17,7 +17,7 @@
*/
import { Readable } from "stream";
-import { Storage } from "./Storage";
+import { Storage } from ".";
const readableToBuffer = (readable: Readable): Promise<Buffer> =>
new Promise((resolve, reject) => {
@@ -46,6 +46,7 @@ export class S3Storage implements Storage {
}
async set(path: string, data: Buffer): Promise<void> {
+ if (process.env.CDN_LOG_IO) console.log(`[CDN][IO] write file: ${path}`);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
await this.client.putObject({
@@ -56,6 +57,7 @@ export class S3Storage implements Storage {
}
async clone(path: string, newPath: string): Promise<void> {
+ if (process.env.CDN_LOG_IO) console.log(`[CDN][IO] clone file: ${path} -> ${newPath}`);
// TODO: does this even work?
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
@@ -67,6 +69,7 @@ export class S3Storage implements Storage {
}
async get(path: string): Promise<Buffer | null> {
+ if (process.env.CDN_LOG_IO) console.log(`[CDN][IO] read file: ${path}`);
try {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
@@ -88,6 +91,7 @@ export class S3Storage implements Storage {
}
async delete(path: string): Promise<void> {
+ if (process.env.CDN_LOG_IO) console.log(`[CDN][IO] delete file: ${path}`);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
await this.client.deleteObject({
diff --git a/src/cdn/util/Storage.ts b/src/cdn/util/storage.ts
index 1184bde8..f9d9d6f9 100644
--- a/src/cdn/util/Storage.ts
+++ b/src/cdn/util/storage.ts
@@ -16,7 +16,8 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { FileStorage } from "./FileStorage";
+import { FileStorage } from "./fileStorage";
+import { S3Storage } from "./s3Storage";
import path from "path";
import fs from "fs";
import { red } from "picocolors";
@@ -39,7 +40,7 @@ if (process.env.STORAGE_PROVIDER === "file" || !process.env.STORAGE_PROVIDER) {
location = path.join(process.cwd(), "files");
}
// TODO: move this to some start func, so it doesn't run when server is imported
- //console.log(`[CDN] storage location: ${bgCyan(`${black(location)}`)}`);
+ // console.log(`[CDN] storage location: ${bgCyan(`${black(location)}`)}`);
if (!fs.existsSync(location)) fs.mkdirSync(location);
process.env.STORAGE_LOCATION = location;
|