diff --git a/config.json b/config.json index 6122a78..a1c051e 100644 --- a/config.json +++ b/config.json @@ -1,8 +1,8 @@ { - "maxDiscordFiles": 50, + "maxDiscordFiles": 500, "maxDiscordFileSize": 10485760, "targetGuild": "906767804575928390", - "targetChannel": "1160783463696302182", + "targetChannel": "1024080525993971913", "requestTimeout": 120000, "maxUploadIdLength": 30, "accounts": { diff --git a/package-lock.json b/package-lock.json index 394b168..6b017a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "axios": "^0.27.2", "body-parser": "^1.20.0", "bytes": "^3.1.2", + "commander": "^11.1.0", "cookie-parser": "^1.4.6", "dotenv": "^16.0.2", "express": "^4.18.1", @@ -757,6 +758,14 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "engines": { + "node": ">=16" + } + }, "node_modules/concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", @@ -2420,6 +2429,11 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==" + }, "concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", diff --git a/package.json b/package.json index 714b036..84071a7 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "axios": "^0.27.2", "body-parser": "^1.20.0", "bytes": "^3.1.2", + "commander": "^11.1.0", "cookie-parser": "^1.4.6", "dotenv": "^16.0.2", "express": "^4.18.1", diff --git a/src/server/cli.ts b/src/server/cli.ts new file mode 100644 index 0000000..54b1d49 --- /dev/null +++ b/src/server/cli.ts @@ -0,0 +1,123 @@ +import fs from "fs" +import { stat } from "fs/promises" +import Files from "./lib/files" +import { program } from "commander" +import { basename } from "path" +import { Writable } from "node:stream" +const pkg = require(`${process.cwd()}/package.json`) +let config = require(`${process.cwd()}/config.json`) + +// init data + +if (!fs.existsSync(__dirname + "/../../.data/")) + fs.mkdirSync(__dirname + "/../../.data/") + +// discord +let files = new Files(config) + +program + .name("monocli") + .description("Quickly run monofile to execute a query or so") + .version(pkg.version) + +program.command("list") + .alias("ls") + .description("List files in the database") + .action(() => { + Object.keys(files.files).forEach(e => console.log(e)) + }) + + +program.command("download") + .alias("dl") + .description("Download a file from the database") + .argument("", "ID of the file you'd like to download") + .option("-o, --output ", 'Folder or filename to output to') + .action(async (id, options) => { + + await (new Promise(resolve => setTimeout(() => resolve(), 1000))) + + let fp = files.files[id] + + if (!fp) + throw `file ${id} not found` + + let out = options.output as string || `./` + + if (fs.existsSync(out) && (await stat(out)).isDirectory()) + out = `${out.replace(/\/+$/, "")}/${fp.filename}` + + ;(await files.readFileStream(id)).pipe( + fs.createWriteStream(out) + ) + }) + + +program.command("upload") + .alias("up") + .description("Upload a file to the instance") + .argument("", "Path to the file you'd like to upload") + .option("-id, --fileid ", 'Custom file ID to use') + .action(async (file, options) => { + + await (new Promise(resolve => setTimeout(() => resolve(), 1000))) + + if (!(fs.existsSync(file) && (await stat(file)).isFile())) + throw `${file} is not a file` + + let writable = files.writeFileStream({ + filename: basename(file), + mime: "application/octet-stream", + size: (await stat(file)).size, + uploadId: options.fileid + }) + + if (!(writable instanceof Writable)) + throw JSON.stringify(writable, null, 3) + + ;(await fs.createReadStream(file)).pipe( + writable + ) + + console.log(`started: ${file}`) + + writable.on("drain", () => { + console.log("Drain") + }) + + writable.on("finish", () => { + console.log("Finished!") + }) + + writable.on("error", (e) => { + console.error(e) + }) + + }) + + +program.command("memup") + .description("Upload a file to the instance (no stream)") + .argument("", "Path to the file you'd like to upload") + .option("-id, --fileid ", 'Custom file ID to use') + .action(async (file, options) => { + + await (new Promise(resolve => setTimeout(() => resolve(), 1000))) + + if (!(fs.existsSync(file) && (await stat(file)).isFile())) + throw `${file} is not a file` + + let buf = fs.readFileSync(file) + + let id = files.uploadFile({ + filename: basename(file), + mime: "application/octet-stream", + uploadId: options.fileid + }, buf) + + console.log(`uploaded: ${await id}`) + + }) + + +program.parse() \ No newline at end of file diff --git a/src/server/lib/DiscordAPI/DiscordRequests.ts b/src/server/lib/DiscordAPI/DiscordRequests.ts index 365395a..89b244f 100644 --- a/src/server/lib/DiscordAPI/DiscordRequests.ts +++ b/src/server/lib/DiscordAPI/DiscordRequests.ts @@ -1,4 +1,19 @@ -import fetch, { type RequestInit, type Response, Headers } from "node-fetch" +import { type RequestInfo, type RequestInit, type Response, Headers } from "node-fetch" + +// I jerk off to skibidi toilet. His smile is so fucking hot, oh my god, oh. +// The voices are getting louder, help me. Oh god, i want to put it inside that toilet and make him beg. +// Whenever i see skibidi toilet cum comes out like a waterfall. +// Whenever my classmates say anything about toilets the entire school gets flooded with cum everywhere. +// Dafuqboom is truly the best artist of all time. + +let ftch_dft: (url: URL | RequestInfo, init?:RequestInit) => Promise +const fetch = async (url: URL | RequestInfo, init?:RequestInit) => { + if (ftch_dft) return ftch_dft(url, init) + else { + ftch_dft = (await import("node-fetch")).default; + return ftch_dft(url, init) + } +} const base = "https://discord.com/api/v10" const buckets = new Map() @@ -64,14 +79,14 @@ class DiscordAPIBucket { let rd = extractRatelimitData(base) this.parent = rest - this.name = rd.bucket_name + this.name = rd.bucket_name || Math.random().toString() this.limit = rd.limit this.remaining = rd.remaining this.expires = rd.expires this.expirationHold = setTimeout( - this.destroy, + this.destroy.bind(this), parseFloat(base.get("x-ratelimit-reset-after")!) ) @@ -81,7 +96,6 @@ class DiscordAPIBucket { * @description Renders this bucket invalid */ destroy() { - buckets.delete(this.name) this.dead = true this.linked_routes.forEach((v) => routeConnections.delete(v)) diff --git a/src/server/lib/DiscordAPI/index.ts b/src/server/lib/DiscordAPI/index.ts index ceee7bf..5de1403 100644 --- a/src/server/lib/DiscordAPI/index.ts +++ b/src/server/lib/DiscordAPI/index.ts @@ -79,9 +79,12 @@ export class Client { let returned = await this.rest.fetch(`/channels/${this.targetChannel}/messages`, { method: "POST", - body: fd + body: fd, + headers: fd.getHeaders() }) - return (await returned.json() as APIMessage) + let response = (await returned.json() as APIMessage) + console.log(JSON.stringify(response, null, 4)) + return response } } \ No newline at end of file diff --git a/src/server/lib/files.ts b/src/server/lib/files.ts index 72a3fbf..8b2fa32 100644 --- a/src/server/lib/files.ts +++ b/src/server/lib/files.ts @@ -114,9 +114,11 @@ namespace StreamHelpers { private newmessage_debounce : boolean = true api: API + files: Files - constructor( api: API, targetSize: number ) { - this.api = api + constructor( files: Files, targetSize: number ) { + this.files = files + this.api = files.api this.targetSize = targetSize } @@ -152,7 +154,11 @@ namespace StreamHelpers { if (this.buffer[0]) return this.buffer[0] else { // startmessage.... idk - await this.startMessage(0); + await this.startMessage( + this.messages.length < Math.ceil(this.targetSize/this.files.config.maxDiscordFileSize/10) + ? 10 + : Math.ceil(this.targetSize/this.files.config.maxDiscordFileSize) - this.messages.length*10 + ); return this.buffer[0] } } @@ -165,12 +171,13 @@ export default class Files { config: Configuration api: API files: { [key: string]: FilePointer } = {} + data_directory: string = `${process.cwd()}/.data` constructor(config: Configuration) { this.config = config this.api = new API(process.env.TOKEN!, config.targetChannel) - readFile(process.cwd() + "/.data/files.json") + readFile(this.data_directory+ "/files.json") .then((buf) => { this.files = JSON.parse(buf.toString() || "{}") }) @@ -215,7 +222,7 @@ export default class Files { ) if (validation) return validation - let buf = new StreamHelpers.StreamBuffer(this.api, metadata.size) + let buf = new StreamHelpers.StreamBuffer(this, metadata.size) let fs_obj = this let wt = new Writable({ @@ -398,7 +405,7 @@ export default class Files { */ async write(): Promise { await writeFile( - process.cwd() + "/.data/files.json", + this.data_directory + "/files.json", JSON.stringify( this.files, null,