mirror of
https://github.com/spacebarchat/server.git
synced 2026-04-25 11:52:07 +00:00
✨ attachments
This commit is contained in:
@@ -18,7 +18,7 @@ export class CDNServer extends Server {
|
||||
await Config.init();
|
||||
console.log("[Database] connected");
|
||||
|
||||
await this.registerRoutes(path.join(__dirname, "routes"));
|
||||
await this.registerRoutes(path.join(__dirname, "routes/"));
|
||||
return super.start();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ import { Router } from "express";
|
||||
import multer from "multer";
|
||||
import { Config, Snowflake } from "@fosscord/server-util";
|
||||
import { storage } from "../util/Storage";
|
||||
import FileType from "file-type";
|
||||
import { HTTPError } from "lambert-server";
|
||||
|
||||
const multer_ = multer({
|
||||
storage: multer.memoryStorage(),
|
||||
@@ -13,42 +15,46 @@ const multer_ = multer({
|
||||
});
|
||||
const router = Router();
|
||||
|
||||
router.post("/:channel_id", multer_.single("attachment"), async (req, res) => {
|
||||
const { buffer, mimetype, stream, size, originalname, fieldname } = req.file;
|
||||
router.post("/:channel_id", multer_.single("file"), async (req, res) => {
|
||||
const { buffer, mimetype, size, originalname, fieldname } = req.file;
|
||||
const { channel_id } = req.params;
|
||||
const filename = originalname.replaceAll(" ", "_").replace(/\W+/g, "");
|
||||
|
||||
const filename = originalname.replaceAll(" ", "_").replace(/[^a-zA-Z0-9._]+/g, "");
|
||||
const id = Snowflake.generate();
|
||||
const path = `attachments/${channel_id}/${id}/${filename}`;
|
||||
|
||||
const endpoint = Config.get().cdn.endpoint || "http://localhost:3003";
|
||||
|
||||
await storage.set(originalname, buffer);
|
||||
|
||||
const id = Snowflake.generate();
|
||||
await storage.set(path, buffer);
|
||||
|
||||
const file = {
|
||||
id,
|
||||
type: mimetype,
|
||||
content_type: mimetype,
|
||||
filename: originalname,
|
||||
filename: filename,
|
||||
size,
|
||||
url: `${endpoint}/attachments/${channel_id}/${id}/`,
|
||||
url: `${endpoint}/attachments/${channel_id}/${id}/${filename}`,
|
||||
};
|
||||
|
||||
return res.json(file);
|
||||
});
|
||||
|
||||
router.get("/:hash/:filename", async (req, res) => {
|
||||
const { hash, filename } = req.params;
|
||||
router.get("/:channel_id/:id/:filename", async (req, res) => {
|
||||
const { channel_id, id, filename } = req.params;
|
||||
|
||||
const File = await db.data.attachments({ id: hash, filename: filename }).get();
|
||||
const file = await storage.get(`attachments/${channel_id}/${id}/${filename}`);
|
||||
if (!file) throw new HTTPError("File not found");
|
||||
const result = await FileType.fromBuffer(file);
|
||||
|
||||
res.set("Content-Type", File.type);
|
||||
return res.send(Buffer.from(File.file, "base64"));
|
||||
res.set("Content-Type", result?.mime);
|
||||
|
||||
return res.send(file);
|
||||
});
|
||||
|
||||
router.delete("/:hash/:filename", async (req, res) => {
|
||||
const { hash, filename } = req.params;
|
||||
router.delete("/:channel_id/:id/:filename", async (req, res) => {
|
||||
const { channel_id, id, filename } = req.params;
|
||||
const path = `attachments/${channel_id}/${id}/${filename}`;
|
||||
|
||||
storage.delete(path);
|
||||
|
||||
await db.data.attachments({ id: hash, filename: filename }).delete();
|
||||
return res.send({ success: true, message: "attachment deleted" });
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
import bodyParser from "body-parser";
|
||||
import { Router } from "express";
|
||||
import fetch from "node-fetch";
|
||||
|
||||
@@ -1,13 +1,30 @@
|
||||
import { Storage } from "./Storage";
|
||||
import fs from "fs/promises";
|
||||
import { join } from "path";
|
||||
import "missing-native-js-functions";
|
||||
|
||||
export class FileStorage implements Storage {
|
||||
async get(path: string) {
|
||||
return fs.readFile(join(process.env.STORAGE_LOCATION || "", path), { encoding: "binary" });
|
||||
async get(path: string): Promise<Buffer | null> {
|
||||
path = join(process.env.STORAGE_LOCATION || "", path);
|
||||
try {
|
||||
const file = await fs.readFile(path);
|
||||
// @ts-ignore
|
||||
return file;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async set(path: string, value: any) {
|
||||
return fs.writeFile(join(process.env.STORAGE_LOCATION || "", path), value, { encoding: "binary" });
|
||||
path = join(process.env.STORAGE_LOCATION || "", path);
|
||||
const dir = path.split("/").slice(0, -1).join("/");
|
||||
await fs.mkdir(dir, { recursive: true }).caught();
|
||||
|
||||
return fs.writeFile(path, value, { encoding: "binary" });
|
||||
}
|
||||
|
||||
async delete(path: string) {
|
||||
path = join(process.env.STORAGE_LOCATION || "", path);
|
||||
await fs.unlink(path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { FileStorage } from "./FileStorage";
|
||||
|
||||
export interface Storage {
|
||||
set(path: string, data: any): Promise<void>;
|
||||
get(path: string): Promise<any>;
|
||||
set(path: string, data: Buffer): Promise<void>;
|
||||
get(path: string): Promise<Buffer | null>;
|
||||
delete(path: string): Promise<void>;
|
||||
}
|
||||
|
||||
var storage: Storage;
|
||||
|
||||
Reference in New Issue
Block a user