summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-05-27 18:54:15 +0200
committerFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-05-27 18:54:15 +0200
commit8f66556f5acf149fadd2fe0ac9e03f5e6225026e (patch)
tree6a4f9a72970f192e34e61ecc509dc71a65997707 /src
parent:bug: fix CDN (diff)
downloadserver-8f66556f5acf149fadd2fe0ac9e03f5e6225026e.tar.xz
:construction: WIP rewrite
Diffstat (limited to 'src')
-rw-r--r--src/Server.ts32
-rw-r--r--src/Snowflake.js145
-rw-r--r--src/Util.ts38
-rw-r--r--src/index.ts10
-rw-r--r--src/routes/attachments.ts13
-rw-r--r--src/routes/external.ts22
-rw-r--r--src/util/FileStorage.ts7
-rw-r--r--src/util/Storage.ts14
8 files changed, 51 insertions, 230 deletions
diff --git a/src/Server.ts b/src/Server.ts

index 3e8c9321..3ad794be 100644 --- a/src/Server.ts +++ b/src/Server.ts
@@ -1,42 +1,28 @@ -import { MongoDatabase, Database } from "lambert-db"; import { Server, ServerOptions } from "lambert-server"; +import { Config, db } from "@fosscord/server-util"; +import path from "path"; -const log = console.log; -console.log = (content) => { - log(`[${new Date().toTimeString().split(" ")[0]}]`, content); -}; - -declare global { - namespace Express { - interface Request { - cdn: CDNServer; - } - } -} - -export interface CDNServerOptions extends ServerOptions { - db: string; -} +export interface CDNServerOptions extends ServerOptions {} export class CDNServer extends Server { - db: Database; public options: CDNServerOptions; - constructor(options: Partial<CDNServerOptions>) { + constructor(options?: Partial<CDNServerOptions>) { super(options); - - this.db = new MongoDatabase(options?.db); } async start() { console.log("[Database] connecting ..."); - await this.db.init(); + // @ts-ignore + await (db as Promise<Connection>); + await Config.init(); console.log("[Database] connected"); + + await this.registerRoutes(path.join(__dirname, "routes")); return super.start(); } async stop() { - await this.db.destroy(); return super.stop(); } } diff --git a/src/Snowflake.js b/src/Snowflake.js deleted file mode 100644
index feb5eb41..00000000 --- a/src/Snowflake.js +++ /dev/null
@@ -1,145 +0,0 @@ -// @ts-nocheck - -// github.com/discordjs/discord.js/blob/master/src/util/Snowflake.js -"use strict"; - -// Discord epoch (2015-01-01T00:00:00.000Z) -const EPOCH = 1420070400000; -let INCREMENT = 0; - -/** - * A container for useful snowflake-related methods. - */ -class SnowflakeUtil { - constructor() { - throw new Error(`The ${this.constructor.name} class may not be instantiated.`); - } - - /** - * A Twitter snowflake, except the epoch is 2015-01-01T00:00:00.000Z - * ``` - * If we have a snowflake '266241948824764416' we can represent it as binary: - * - * 64 22 17 12 0 - * 000000111011000111100001101001000101000000 00001 00000 000000000000 - * number of ms since Discord epoch worker pid increment - * ``` - * @typedef {string} Snowflake - */ - - /** - * Transforms a snowflake from a decimal string to a bit string. - * @param {Snowflake} num Snowflake to be transformed - * @returns {string} - * @private - */ - static idToBinary(num) { - let bin = ""; - let high = parseInt(num.slice(0, -10)) || 0; - let low = parseInt(num.slice(-10)); - while (low > 0 || high > 0) { - bin = String(low & 1) + bin; - low = Math.floor(low / 2); - if (high > 0) { - low += 5000000000 * (high % 2); - high = Math.floor(high / 2); - } - } - return bin; - } - - /** - * Transforms a snowflake from a bit string to a decimal string. - * @param {string} num Bit string to be transformed - * @returns {Snowflake} - * @private - */ - static binaryToID(num) { - let dec = ""; - - while (num.length > 50) { - const high = parseInt(num.slice(0, -32), 2); - const low = parseInt((high % 10).toString(2) + num.slice(-32), 2); - - dec = (low % 10).toString() + dec; - num = - Math.floor(high / 10).toString(2) + - Math.floor(low / 10) - .toString(2) - .padStart(32, "0"); - } - - num = parseInt(num, 2); - while (num > 0) { - dec = (num % 10).toString() + dec; - num = Math.floor(num / 10); - } - - return dec; - } - - /** - * Generates a Discord snowflake. - * <info>This hardcodes the worker ID as 1 and the process ID as 0.</info> - * @param {number|Date} [timestamp=Date.now()] Timestamp or date of the snowflake to generate - * @returns {Snowflake} The generated snowflake - */ - static generate(timestamp = Date.now()) { - if (timestamp instanceof Date) timestamp = timestamp.getTime(); - if (typeof timestamp !== "number" || isNaN(timestamp)) { - throw new TypeError( - `"timestamp" argument must be a number (received ${isNaN(timestamp) ? "NaN" : typeof timestamp})` - ); - } - if (INCREMENT >= 4095) INCREMENT = 0; - const BINARY = `${(timestamp - EPOCH).toString(2).padStart(42, "0")}0000100000${(INCREMENT++) - .toString(2) - .padStart(12, "0")}`; - return SnowflakeUtil.binaryToID(BINARY); - } - - /** - * A deconstructed snowflake. - * @typedef {Object} DeconstructedSnowflake - * @property {number} timestamp Timestamp the snowflake was created - * @property {Date} date Date the snowflake was created - * @property {number} workerID Worker ID in the snowflake - * @property {number} processID Process ID in the snowflake - * @property {number} increment Increment in the snowflake - * @property {string} binary Binary representation of the snowflake - */ - - /** - * Deconstructs a Discord snowflake. - * @param {Snowflake} snowflake Snowflake to deconstruct - * @returns {DeconstructedSnowflake} Deconstructed snowflake - */ - static deconstruct(snowflake) { - const BINARY = SnowflakeUtil.idToBinary(snowflake).toString(2).padStart(64, "0"); - const res = { - timestamp: parseInt(BINARY.substring(0, 42), 2) + EPOCH, - workerID: parseInt(BINARY.substring(42, 47), 2), - processID: parseInt(BINARY.substring(47, 52), 2), - increment: parseInt(BINARY.substring(52, 64), 2), - binary: BINARY, - }; - Object.defineProperty(res, "date", { - get: function get() { - return new Date(this.timestamp); - }, - enumerable: true, - }); - return res; - } - - /** - * Discord's epoch value (2015-01-01T00:00:00.000Z). - * @type {number} - * @readonly - */ - static get EPOCH() { - return EPOCH; - } -} - -module.exports = SnowflakeUtil; diff --git a/src/Util.ts b/src/Util.ts deleted file mode 100644
index 291372c1..00000000 --- a/src/Util.ts +++ /dev/null
@@ -1,38 +0,0 @@ -import fs from "fs/promises"; -import "missing-native-js-functions"; - -export interface traverseDirectoryOptions { - dirname: string; - filter?: RegExp; - excludeDirs?: RegExp; - recursive?: boolean; -} - -const DEFAULT_EXCLUDE_DIR = /^\./; -const DEFAULT_FILTER = /^([^\.].*)\.js$/; - -export async function traverseDirectory<T>( - options: traverseDirectoryOptions, - action: (path: string) => T -): Promise<T[]> { - if (!options.filter) options.filter = DEFAULT_FILTER; - if (!options.excludeDirs) options.excludeDirs = DEFAULT_EXCLUDE_DIR; - - const routes = await fs.readdir(options.dirname); - const promises = <Promise<T | T[] | undefined>[]>routes.map(async (file) => { - const path = options.dirname + file; - const stat = await fs.lstat(path); - if (path.match(<RegExp>options.excludeDirs)) return; - - if (stat.isFile() && path.match(<RegExp>options.filter)) { - return action(path); - } else if (options.recursive && stat.isDirectory()) { - return traverseDirectory({ ...options, dirname: path + "/" }, action); - } - }); - const result = await Promise.all(promises); - - const t = <(T | undefined)[]>result.flat(); - - return <T[]>t.filter((x) => x != undefined); -} diff --git a/src/index.ts b/src/index.ts
index 64fca7e5..cdf88fd9 100644 --- a/src/index.ts +++ b/src/index.ts
@@ -1,6 +1,14 @@ import { CDNServer } from "./Server"; +import dotenv from "dotenv"; +dotenv.config(); -const server = new CDNServer({ db: "" }); +if (process.env.STORAGE_LOCATION) { + if (!process.env.STORAGE_LOCATION.startsWith("/")) { + process.env.STORAGE_LOCATION = __dirname + "/../" + process.env.STORAGE_LOCATION; + } +} else process.env.STORAGE_LOCATION = __dirname + "/../files/"; + +const server = new CDNServer(); server .start() .then(() => { diff --git a/src/routes/attachments.ts b/src/routes/attachments.ts
index 9f016174..87368e48 100644 --- a/src/routes/attachments.ts +++ b/src/routes/attachments.ts
@@ -1,6 +1,7 @@ import { Router } from "express"; import multer from "multer"; -import Snowflake from "../Snowflake"; +import { Snowflake } from "@fosscord/server-util"; +import { storage } from "../util/Storage"; const multer_ = multer(); const router = Router(); @@ -11,11 +12,11 @@ type Attachment = { id: string; type: string; }; - router.post("/:filename", multer_.single("attachment"), async (req, res) => { const { buffer, mimetype } = req.file; const { filename } = req.params; - const { db } = req.cdn; + + // storage.set(filename, ); const File: Attachment = { filename, @@ -23,14 +24,9 @@ router.post("/:filename", multer_.single("attachment"), async (req, res) => { id: Snowflake.generate(), type: mimetype, }; - - if (!(await db.data.attachments.push(File))) throw new Error("Error uploading file"); - - return res.status(201).send({ success: true, message: "attachment uploaded", id: File.id, filename }); }); router.get("/:hash/:filename", async (req, res) => { - const { db } = req.cdn; const { hash, filename } = req.params; const File: Attachment = await db.data.attachments({ id: hash, filename: filename }).get(); @@ -41,7 +37,6 @@ router.get("/:hash/:filename", async (req, res) => { router.delete("/:hash/:filename", async (req, res) => { const { hash, filename } = req.params; - const { db } = req.cdn; await db.data.attachments({ id: hash, filename: filename }).delete(); return res.send({ success: true, message: "attachment deleted" }); diff --git a/src/routes/external.ts b/src/routes/external.ts
index f75f6a66..045eb7da 100644 --- a/src/routes/external.ts +++ b/src/routes/external.ts
@@ -2,8 +2,7 @@ import bodyParser from "body-parser"; import { Router } from "express"; import fetch from "node-fetch"; import cheerio from "cheerio"; -import btoa from "btoa"; -import { URL } from "url"; +import crypto from "crypto"; const router = Router(); @@ -30,25 +29,21 @@ const DEFAULT_FETCH_OPTIONS: any = { router.post("/", bodyParser.json(), async (req, res) => { if (!req.body) throw new Error("Invalid Body (url missing) \nExample: url:https://discord.com"); - const { db } = req.cdn; const { url } = req.body; - const ID = btoa(url); - - const cache = await db.data.crawler({ id: ID }).get(); - if (cache) return res.send(cache); + const hash = crypto.createHash("md5").update(url).digest("hex"); try { const request = await fetch(url, DEFAULT_FETCH_OPTIONS); const text = await request.text(); - const ツ: any = cheerio.load(text); + const $ = cheerio.load(text); - const ogTitle = ツ('meta[property="og:title"]').attr("content"); - const ogDescription = ツ('meta[property="og:description"]').attr("content"); - const ogImage = ツ('meta[property="og:image"]').attr("content"); - const ogUrl = ツ('meta[property="og:url"]').attr("content"); - const ogType = ツ('meta[property="og:type"]').attr("content"); + const ogTitle = $('meta[property="og:title"]').attr("content"); + const ogDescription = $('meta[property="og:description"]').attr("content"); + const ogImage = $('meta[property="og:image"]').attr("content"); + const ogUrl = $('meta[property="og:url"]').attr("content"); + const ogType = $('meta[property="og:type"]').attr("content"); const filename = new URL(url).host.split(".")[0]; @@ -72,7 +67,6 @@ router.post("/", bodyParser.json(), async (req, res) => { }); router.get("/:id/:filename", async (req, res) => { - const { db } = req.cdn; const { id, filename } = req.params; const { image, type } = await db.data.externals({ id: id }).get(); const imageBuffer = Buffer.from(image, "base64"); diff --git a/src/util/FileStorage.ts b/src/util/FileStorage.ts new file mode 100644
index 00000000..01be0050 --- /dev/null +++ b/src/util/FileStorage.ts
@@ -0,0 +1,7 @@ +import { Storage } from "./Storage"; + +export class FileStorage implements Storage { + async get(path: string, prefix?: string) {} + + async set(path: string, value: any) {} +} diff --git a/src/util/Storage.ts b/src/util/Storage.ts new file mode 100644
index 00000000..ad00fbb7 --- /dev/null +++ b/src/util/Storage.ts
@@ -0,0 +1,14 @@ +import { FileStorage } from "./FileStorage"; + +export interface Storage { + set(hash: string, data: any, prefix?: string): Promise<void>; + get(hash: string, prefix?: string): Promise<any>; +} + +var storage: Storage; + +if (process.env.STORAGE_PROVIDER === "file") { + storage = new FileStorage(); +} + +export { storage };