From 6c10e25bcabe4fd2ddc6c3fcd2da7e7ed4d17064 Mon Sep 17 00:00:00 2001 From: xnacly Date: Sun, 3 Jan 2021 22:43:52 +0100 Subject: [PATCH] routes + util + snowflake --- package-lock.json | Bin 46367 -> 19838 bytes src/Snowflake.js | 145 ++++++++++++++++++ src/Util.ts | 38 +++++ .../api/v8/channel/#CHANNELID/followers.ts | 0 .../api/v8/channel/#CHANNELID/invites.ts | 0 .../api/v8/channel/#CHANNELID/messages.ts | 0 .../api/v8/channel/#CHANNELID/permissions.ts | 0 src/routes/api/v8/channel/#CHANNELID/pins.ts | 0 .../api/v8/channel/#CHANNELID/recipients.ts | 0 .../api/v8/channel/#CHANNELID/typing.ts | 0 src/routes/api/v8/guilds/templates/index.ts | 0 src/routes/api/v8/invite/index.ts | 0 src/routes/assets/index.ts | 4 + 13 files changed, 187 insertions(+) create mode 100644 src/Snowflake.js create mode 100644 src/Util.ts create mode 100644 src/routes/api/v8/channel/#CHANNELID/followers.ts create mode 100644 src/routes/api/v8/channel/#CHANNELID/invites.ts create mode 100644 src/routes/api/v8/channel/#CHANNELID/messages.ts create mode 100644 src/routes/api/v8/channel/#CHANNELID/permissions.ts create mode 100644 src/routes/api/v8/channel/#CHANNELID/pins.ts create mode 100644 src/routes/api/v8/channel/#CHANNELID/recipients.ts create mode 100644 src/routes/api/v8/channel/#CHANNELID/typing.ts create mode 100644 src/routes/api/v8/guilds/templates/index.ts create mode 100644 src/routes/api/v8/invite/index.ts diff --git a/package-lock.json b/package-lock.json index 2b13235caeeb74774056337d7af6006f0246f6e5..c05e4a3c2fa84561111b84b9bae239b16da32be5 100644 GIT binary patch delta 78 zcmbRLis|1h#t9+fhB{md3Q9$(g{7HAsl`fG3MECQsXAPf8(Aban{qyZ8R9hRYuoyfo45Y%Z}{Z6Z1w4~a;!9k$A194WRK z%gwQ~itQOZ2hV~#)wS^Kkf|aZ;*cOAJli&K!fS&SZyh`+D26{36`P20+C?*M^dUH2 z^ccLpy~s@kkjw>@5hv}Y+iYZk)Q=4<#PGso<@DE>^eC*1u)&ICX^;jD328Cm6Y zB+AFbNU~qQU^2k--Wp|--!pWoN8v-mgY@VD%}7IGW~6xaQaOwjJ*S!Qm7==jzl$m} z-p%mc?Iy666+^$VTQl`J<2{XKrTD(ul3dew`(eEugslbXE_eVWC?@80)evM;EA;`Tz;fEn|dV7hJ+m4WKWHxxU<9Rpj+3c z7`{>d>z(R#q(y-vs~FtC9BnbP-3gC0=Nmj3 zJQMN`4!ch+Mmw@cZHpl!;`Ir-6|AI@qM#{z&hT`_n z;D*%&-!xy-vs(|@t$J@Wi!ve^tcKXmU+VU?do4r^PLAb*h>EZRI}3M8EJi2IFf;>i zG%~iFAtd6|sXkL=B3SF|BU8c2IClv76LU+kAuERHK@ zNZ^2vk#=TJ39~yKhOjkax zJH={F7^*72bvaGaYg7^Zq{^blV?Mb5rRtNdy129JuUmET+v;2Df&g#q{s7~BKU}r! z(Tu!pxj}7~;||)DIuo-BsyvGEO5M0S?1DemjOq?wU5R)k$zpU7d#nY2EokEXsP;`Y z>2N2A^6;W(FZ^oH*Yqr{5Ln~=^xn5M7VEytdYtA1#m#;HB*i9qd;gU}`(|^E>nW3; z0T=3QDF*zkeh0i)-`k#bNvh#md(_ryRhb|ZbJ7dz2?hrn>b~T_)FicL7mPH_w&du7 zk%5U+Q_fpx10jJ82U&p+Pn%xb zs;k$VKT}e4jcTAbo1!(~RjHC65`st!DH5R?zGG~KHk#8!{wn>^ri+OJaDu0zImX_^mDjJ0()Ia&sL z12f*){A-i`>4-@v&POAx(jM1K%{t5X^(1xL=YchDJ*}9W`G~sU*0N! zCLFib)j5LXV3bekL_+Xqme%yM~l}+-7Idjnq)^q2qogJ+ikZCsjQriuss&JkfJz?c*xEDPi zY}LiHhu+o1H+cA-65mw&Vg2PuO{gp-6*=JJL5Vbw?6eVHT}^-3s46a!XH!mFA`{ z{34s6W}-Y%WYut`Cp%3gG-va3Jhu!ly(1utd}(PEE^g&gspN1 z^`xre<0@K7_`$%gvZRUjb8k6ZbTq?XRg(2N8L%Q1h%v=w-p0`K!9)Q8%}=N>Ip3ceR?+pK-OyjI4CkcQBN%$LAjK zdwl+Z$XtM*Jkd0<5Q(sC)OT`VqiTgSzkEG(ubf1?(Gw09LAsxCl4BJg7nb~=J$#(E z?EhjOKJZh=C3Et<`nO7UXjLvb+|MD3eOnd98KL_H>R_DC&!vNtU@tA*zSfY*>%oTY hn$g{^lP|ab-CUk3Pqqx1NKbqy&APTkvy$bK{{ek_AISg! diff --git a/src/Snowflake.js b/src/Snowflake.js new file mode 100644 index 00000000..feb5eb41 --- /dev/null +++ b/src/Snowflake.js @@ -0,0 +1,145 @@ +// @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. + * This hardcodes the worker ID as 1 and the process ID as 0. + * @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 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/routes/api/v8/channel/#CHANNELID/followers.ts b/src/routes/api/v8/channel/#CHANNELID/followers.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/routes/api/v8/channel/#CHANNELID/invites.ts b/src/routes/api/v8/channel/#CHANNELID/invites.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/routes/api/v8/channel/#CHANNELID/messages.ts b/src/routes/api/v8/channel/#CHANNELID/messages.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/routes/api/v8/channel/#CHANNELID/permissions.ts b/src/routes/api/v8/channel/#CHANNELID/permissions.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/routes/api/v8/channel/#CHANNELID/pins.ts b/src/routes/api/v8/channel/#CHANNELID/pins.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/routes/api/v8/channel/#CHANNELID/recipients.ts b/src/routes/api/v8/channel/#CHANNELID/recipients.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/routes/api/v8/channel/#CHANNELID/typing.ts b/src/routes/api/v8/channel/#CHANNELID/typing.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/routes/api/v8/guilds/templates/index.ts b/src/routes/api/v8/guilds/templates/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/routes/api/v8/invite/index.ts b/src/routes/api/v8/invite/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/routes/assets/index.ts b/src/routes/assets/index.ts index d3683f43..c2b9f2b0 100644 --- a/src/routes/assets/index.ts +++ b/src/routes/assets/index.ts @@ -1,3 +1,7 @@ +/** + * * patch to redirect requests from cloned client + * (../../client/index.html) + */ import { Router } from "express"; import fetch from "node-fetch";