From 82e63ef807cad85905df323b09b2ac0fb21bcb1a Mon Sep 17 00:00:00 2001 From: xnacly Date: Wed, 30 Dec 2020 22:49:01 +0100 Subject: [PATCH] :sparkles: added crawler to cdn --- .gitignore | 3 + package-lock.json | Bin 0 -> 59210 bytes package.json | 38 ++++++++++++ src/Server.ts | 93 +++++++++++++++++++++++++++++ src/Util.ts | 38 ++++++++++++ src/index.ts | 14 +++++ src/routes/attachments.ts.disabled | 19 ++++++ src/routes/external.ts | 83 +++++++++++++++++++++++++ tsconfig.json | 69 +++++++++++++++++++++ 9 files changed, 357 insertions(+) create mode 100644 .gitignore create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/Server.ts create mode 100644 src/Util.ts create mode 100644 src/index.ts create mode 100644 src/routes/attachments.ts.disabled create mode 100644 src/routes/external.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ab03d840 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.vscode/ +node_modules/ +dist/ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..9d7a1f511d23e32c87fbecec6194d1039168b5ae GIT binary patch literal 59210 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 literal 0 HcmV?d00001 diff --git a/package.json b/package.json new file mode 100644 index 00000000..847c688f --- /dev/null +++ b/package.json @@ -0,0 +1,38 @@ +{ + "name": "discord-cdn", + "version": "1.0.0", + "description": "cdn for discord clone", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/discord-open-source/discord-cdn.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/discord-open-source/discord-cdn/issues" + }, + "homepage": "https://github.com/discord-open-source/discord-cdn#readme", + "dependencies": { + "body-parser": "^1.19.0", + "btoa": "^1.2.1", + "cheerio": "^1.0.0-rc.5", + "express": "^4.17.1", + "express-async-errors": "^3.1.1", + "lambert-db": "^1.0.5", + "missing-native-js-functions": "^1.0.8", + "multer": "^1.4.2", + "node-fetch": "^2.6.1" + }, + "devDependencies": { + "@types/btoa": "^1.2.3", + "@types/express": "^4.17.9", + "@types/multer": "^1.4.5", + "@types/node": "^14.14.16", + "@types/node-fetch": "^2.5.7" + } +} diff --git a/src/Server.ts b/src/Server.ts new file mode 100644 index 00000000..7d93c444 --- /dev/null +++ b/src/Server.ts @@ -0,0 +1,93 @@ +import express, { Application, Router, Request, Response, NextFunction } from "express"; +import { MongoDatabase, Database } from "lambert-db"; +import { Server as HTTPServer } from "http"; +import { traverseDirectory } from "./Util"; +import bodyParser from "body-parser"; +import "express-async-errors"; + +const log = console.log; +console.log = (content) => { + log(`[${new Date().toTimeString().split(" ")[0]}]`, content); +}; + +export type ServerOptions = { + db: string; + port: number; + host: string; +}; + +declare global { + namespace Express { + interface Request { + server: Server; + } + } +} + +export class Server { + app: Application; + http: HTTPServer; + db: Database; + routes: Router[]; + options: ServerOptions; + + constructor(options: Partial = { port: 3000, host: "0.0.0.0" }) { + this.app = express(); + this.db = new MongoDatabase(options?.db); + this.options = options as ServerOptions; + } + + async init() { + await this.db.init(); + + console.log("[Database] connected..."); + await new Promise((res, rej) => { + this.http = this.app.listen(this.options.port, this.options.host, () => res(null)); + }); + this.routes = await this.registerRoutes(__dirname + "/routes/"); + } + + async registerRoutes(root: string) { + this.app.use((req, res, next) => { + req.server = this; + next(); + }); + const routes = await traverseDirectory({ dirname: root, recursive: true }, this.registerRoute.bind(this, root)); + this.app.use((err: string | Error, req: Request, res: Response, next: NextFunction) => { + res.status(400).send(err); + next(err); + }); + return routes; + } + + registerRoute(root: string, file: string): any { + if (root.endsWith("/") || root.endsWith("\\")) root = root.slice(0, -1); // removes slash at the end of the root dir + let path = file.replace(root, ""); // remove root from path and + path = path.split(".").slice(0, -1).join("."); // trancate .js/.ts file extension of path + if (path.endsWith("/index")) path = path.slice(0, -6); // delete index from path + + try { + var router = require(file); + if (router.router) router = router.router; + if (router.default) router = router.default; + if (!router || router?.prototype?.constructor?.name !== "router") + throw `File doesn't export any default router`; + this.app.use(path, router); + console.log(`[Routes] ${path} registerd`); + + return router; + } catch (error) { + console.error(new Error(`[Server] ¯\\_(ツ)_/¯ Failed to register route ${path}: ${error}`)); + } + } + + async destroy() { + await this.db.destroy(); + await new Promise((res, rej) => { + this.http.close((err) => { + if (err) return rej(err); + return res(""); + }); + }); + } +} diff --git a/src/Util.ts b/src/Util.ts new file mode 100644 index 00000000..291372c1 --- /dev/null +++ b/src/Util.ts @@ -0,0 +1,38 @@ +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( + options: traverseDirectoryOptions, + action: (path: string) => T +): Promise { + if (!options.filter) options.filter = DEFAULT_FILTER; + if (!options.excludeDirs) options.excludeDirs = DEFAULT_EXCLUDE_DIR; + + const routes = await fs.readdir(options.dirname); + const promises = []>routes.map(async (file) => { + const path = options.dirname + file; + const stat = await fs.lstat(path); + if (path.match(options.excludeDirs)) return; + + if (stat.isFile() && path.match(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.filter((x) => x != undefined); +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..d8025968 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,14 @@ +import { Server } from "./Server"; + +const server = new Server(); +server + .init() + .then(() => { + console.log("[Server] started on :" + server.options.port); + }) + .catch((e) => console.error("[Server] Error starting: ", e)); + +//// server +//// .destroy() +//// .then(() => console.log("[Server] closed.")) +//// .catch((e) => console.log("[Server] Error closing: ", e)); diff --git a/src/routes/attachments.ts.disabled b/src/routes/attachments.ts.disabled new file mode 100644 index 00000000..db1a7efc --- /dev/null +++ b/src/routes/attachments.ts.disabled @@ -0,0 +1,19 @@ +import { Router } from "express"; +import multer from "multer"; +const multer_ = multer(); + +const router = Router(); +router.post("/:file", multer_.single("attachment"), async (req, res) => { + const { buffer } = req.file; + + res.set("Content-Type", "image/png"); + res.send(buffer); +}); +router.get("/:hash/:file", async (req, res) => { + res.send(`${req.params.hash}/${req.params.file}`); +}); +router.delete("/:hash/:file", async (req, res) => { + res.send("remove"); +}); + +export default router; diff --git a/src/routes/external.ts b/src/routes/external.ts new file mode 100644 index 00000000..14980b05 --- /dev/null +++ b/src/routes/external.ts @@ -0,0 +1,83 @@ +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"; + +const router = Router(); + +type crawled = { + title: string; + type: string; + description: string; + url: string; + image_url: string; +}; + +const DEFAULT_FETCH_OPTIONS: any = { + redirect: "follow", + follow: 1, + headers: { + "user-agent": "Mozilla/5.0 (compatible; Discordbot/2.0; +https://discordapp.com)", + }, + size: 1024 * 1024 * 8, + compress: true, + method: "GET", +}; + +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.server; + const { url } = req.body; + + const ID = btoa(url); + + const cache = await db.data.crawler({ id: ID }).get(); + if (cache) return res.send(cache); + + try { + const request = await fetch(url, DEFAULT_FETCH_OPTIONS); + + const text = await request.text(); + const ツ: any = 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 filename = new URL(url).host.split(".")[0]; + + const ImageResponse = await fetch(ogImage, DEFAULT_FETCH_OPTIONS); + const ImageType = ImageResponse.headers.get("content-type"); + const ImageExtension = ImageType?.split("/")[1]; + const ImageResponseBuffer = (await ImageResponse.buffer()).toString("base64"); + const cachedImage = `/external/${ID}/${filename}.${ImageExtension}`; + + await db.data.externals.push({ image: ImageResponseBuffer, id: ID, type: ImageType }); + + const new_cache_entry = { id: ID, ogTitle, ogDescription, cachedImage, ogUrl, ogType }; + await db.data.crawler.push(new_cache_entry); + + res.send(new_cache_entry); + } catch (error) { + console.log(error); + + throw new Error("Couldn't fetch website"); + } +}); + +router.get("/:id/:filename", async (req, res) => { + const { db } = req.server; + const { id, filename } = req.params; + const { image, type } = await db.data.externals({ id: id }).get(); + const imageBuffer = Buffer.from(image, "base64"); + + res.set("Content-Type", type); + res.send(imageBuffer); +}); + +export default router; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..26be7b1b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,69 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "ES6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + "lib": ["ES2015"] /* Specify library files to be included in the compilation. */, + "allowJs": true /* Allow javascript files to be compiled. */, + "checkJs": true /* Report errors in .js files. */, + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true /* Generates corresponding '.d.ts' file. */, + "declarationMap": false /* Generates a sourcemap for each corresponding '.d.ts' file. */, + "inlineSourceMap": true /* Emit a single file with source maps instead of having a separate file. */, + // "sourceMap": true /* Generates corresponding '.map' file. */, + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist/" /* Redirect output structure to the directory. */, + "rootDir": "./src/" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + "strictPropertyInitialization": false /* Enable strict checking of property initialization in classes. */, + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */, + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + "types": ["node"] /* Type declaration files to be included in compilation. */, + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true /* Skip type checking of declaration files. */, + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +}