Upload files to Discord as streams for speed

This commit is contained in:
Cadence Ember 2023-10-15 00:26:52 +13:00
parent fff8f0d94c
commit 9c3f1abd3a
3 changed files with 25 additions and 25 deletions

View File

@ -2,6 +2,7 @@
const assert = require("assert").strict const assert = require("assert").strict
const DiscordTypes = require("discord-api-types/v10") const DiscordTypes = require("discord-api-types/v10")
const {Readable} = require("stream")
const passthrough = require("../../passthrough") const passthrough = require("../../passthrough")
const {discord, db, select} = passthrough const {discord, db, select} = passthrough
@ -51,7 +52,7 @@ async function withWebhook(channelID, callback) {
/** /**
* @param {string} channelID * @param {string} channelID
* @param {DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer}[]}} data * @param {DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer | Readable}[]}} data
* @param {string} [threadID] * @param {string} [threadID]
*/ */
async function sendMessageWithWebhook(channelID, data, threadID) { async function sendMessageWithWebhook(channelID, data, threadID) {
@ -64,7 +65,7 @@ async function sendMessageWithWebhook(channelID, data, threadID) {
/** /**
* @param {string} channelID * @param {string} channelID
* @param {string} messageID * @param {string} messageID
* @param {DiscordTypes.RESTPatchAPIWebhookWithTokenMessageJSONBody & {files?: {name: string, file: Buffer}[]}} data * @param {DiscordTypes.RESTPatchAPIWebhookWithTokenMessageJSONBody & {files?: {name: string, file: Buffer | Readable}[]}} data
* @param {string} [threadID] * @param {string} [threadID]
*/ */
async function editMessageWithWebhook(channelID, messageID, data, threadID) { async function editMessageWithWebhook(channelID, messageID, data, threadID) {

View File

@ -1,11 +1,11 @@
// @ts-check // @ts-check
const assert = require("assert").strict
const crypto = require("crypto")
const {pipeline} = require("stream")
const {promisify} = require("util")
const Ty = require("../../types") const Ty = require("../../types")
const DiscordTypes = require("discord-api-types/v10") const DiscordTypes = require("discord-api-types/v10")
const {Readable} = require("stream")
const assert = require("assert").strict
const crypto = require("crypto")
const fetch = require("node-fetch").default
const passthrough = require("../../passthrough") const passthrough = require("../../passthrough")
const {sync, discord, db, select} = passthrough const {sync, discord, db, select} = passthrough
@ -17,13 +17,12 @@ const eventToMessage = sync.require("../converters/event-to-message")
const api = sync.require("../../matrix/api") const api = sync.require("../../matrix/api")
/** /**
* @param {DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer}[], pendingFiles?: ({name: string, url: string} | {name: string, url: string, key: string, iv: string} | {name: string, buffer: Buffer})[]}} message * @param {DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer | Readable}[], pendingFiles?: ({name: string, url: string} | {name: string, url: string, key: string, iv: string} | {name: string, buffer: Buffer | Readable})[]}} message
* @returns {Promise<DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer}[]}>} * @returns {Promise<DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer | Readable}[]}>}
*/ */
async function resolvePendingFiles(message) { async function resolvePendingFiles(message) {
if (!message.pendingFiles) return message if (!message.pendingFiles) return message
const files = await Promise.all(message.pendingFiles.map(async p => { const files = await Promise.all(message.pendingFiles.map(async p => {
let fileBuffer
if ("buffer" in p) { if ("buffer" in p) {
return { return {
name: p.name, name: p.name,
@ -31,21 +30,22 @@ async function resolvePendingFiles(message) {
} }
} }
if ("key" in p) { if ("key" in p) {
// Encrypted // Encrypted file
const d = crypto.createDecipheriv("aes-256-ctr", Buffer.from(p.key, "base64url"), Buffer.from(p.iv, "base64url")) const d = crypto.createDecipheriv("aes-256-ctr", Buffer.from(p.key, "base64url"), Buffer.from(p.iv, "base64url"))
fileBuffer = await fetch(p.url).then(res => res.arrayBuffer()).then(x => { // @ts-ignore
return Buffer.concat([ fetch(p.url).then(res => res.body.pipe(d))
d.update(Buffer.from(x)), return {
d.final() name: p.name,
]) file: d
}) }
} else { } else {
// Unencrypted // Unencrypted file
fileBuffer = await fetch(p.url).then(res => res.arrayBuffer()).then(x => Buffer.from(x)) /** @type {Readable} */ // @ts-ignore
} const body = await fetch(p.url).then(res => res.body)
return { return {
name: p.name, name: p.name,
file: fileBuffer // TODO: Once SnowTransfer supports ReadableStreams for attachment uploads, pass in those instead of Buffers file: body
}
} }
})) }))
const newMessage = { const newMessage = {

View File

@ -2,6 +2,7 @@
const Ty = require("../../types") const Ty = require("../../types")
const DiscordTypes = require("discord-api-types/v10") const DiscordTypes = require("discord-api-types/v10")
const {Readable} = require("stream")
const chunk = require("chunk-text") const chunk = require("chunk-text")
const TurndownService = require("turndown") const TurndownService = require("turndown")
const assert = require("assert").strict const assert = require("assert").strict
@ -9,8 +10,6 @@ const entities = require("entities")
const passthrough = require("../../passthrough") const passthrough = require("../../passthrough")
const {sync, db, discord, select, from} = passthrough const {sync, db, discord, select, from} = passthrough
/** @type {import("../../matrix/file")} */
const file = sync.require("../../matrix/file")
/** @type {import("../converters/utils")} */ /** @type {import("../converters/utils")} */
const utils = sync.require("../converters/utils") const utils = sync.require("../converters/utils")
/** @type {import("./emoji-sheet")} */ /** @type {import("./emoji-sheet")} */
@ -245,7 +244,7 @@ async function uploadEndOfMessageSpriteSheet(content, attachments, pendingFiles)
* @param {{api: import("../../matrix/api")}} di simple-as-nails dependency injection for the matrix API * @param {{api: import("../../matrix/api")}} di simple-as-nails dependency injection for the matrix API
*/ */
async function eventToMessage(event, guild, di) { async function eventToMessage(event, guild, di) {
/** @type {(DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer}[]})[]} */ /** @type {(DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer | Readable}[]})[]} */
let messages = [] let messages = []
let displayName = event.sender let displayName = event.sender