Rearrange code (self-review)

This commit is contained in:
Cadence Ember 2024-03-04 17:02:38 +13:00
parent c5d6c5e4c7
commit 47ac49a855
16 changed files with 275 additions and 74 deletions

View file

@ -0,0 +1,36 @@
// @ts-check
const assert = require("assert")
const fetch = require("node-fetch").default
const utils = require("../converters/utils")
const {sync} = require("../../passthrough")
/** @type {import("../converters/emoji-sheet")} */
const emojiSheetConverter = sync.require("../converters/emoji-sheet")
/**
* Downloads the emoji from the web and converts to uncompressed PNG data.
* @param {string} mxc a single mxc:// URL
* @returns {Promise<Buffer | undefined>} uncompressed PNG data, or undefined if the downloaded emoji is not valid
*/
async function getAndConvertEmoji(mxc) {
const abortController = new AbortController()
const url = utils.getPublicUrlForMxc(mxc)
assert(url)
/** @type {import("node-fetch").Response} */
// If it turns out to be a GIF, we want to abandon the connection without downloading the whole thing.
// If we were using connection pooling, we would be forced to download the entire GIF.
// So we set no agent to ensure we are not connection pooling.
// @ts-ignore the signal is slightly different from the type it wants (still works fine)
const res = await fetch(url, {agent: false, signal: abortController.signal})
return emojiSheetConverter.convertImageStream(res.body, () => {
abortController.abort()
res.body.pause()
res.body.emit("end")
})
}
module.exports.getAndConvertEmoji = getAndConvertEmoji

View file

@ -17,8 +17,8 @@ const eventToMessage = sync.require("../converters/event-to-message")
const api = sync.require("../../matrix/api")
/** @type {import("../../d2m/actions/register-user")} */
const registerUser = sync.require("../../d2m/actions/register-user")
/** @type {import("../converters/emoji-sheet")} */
const emojiSheet = sync.require("../converters/emoji-sheet")
/** @type {import("../actions/emoji-sheet")} */
const emojiSheet = sync.require("../actions/emoji-sheet")
/**
* @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

View file

@ -1,13 +1,10 @@
// @ts-check
const assert = require("assert").strict
const fs = require("fs")
const {pipeline} = require("stream").promises
const sharp = require("sharp")
const {GIFrame} = require("giframe")
const {PNG} = require("pngjs")
const utils = require("./utils")
const fetch = require("node-fetch").default
const streamMimeType = require("stream-mime-type")
const SIZE = 48
@ -50,49 +47,6 @@ async function compositeMatrixEmojis(mxcs, mxcDownloader) {
return output.data
}
/**
* Downloads the emoji from the web and converts to uncompressed PNG data.
* @param {string} mxc a single mxc:// URL
* @returns {Promise<Buffer | undefined>} uncompressed PNG data, or undefined if the downloaded emoji is not valid
*/
async function getAndConvertEmoji(mxc) {
const abortController = new AbortController()
const url = utils.getPublicUrlForMxc(mxc)
assert(url)
/** @type {import("node-fetch").Response} */
// If it turns out to be a GIF, we want to abandon the connection without downloading the whole thing.
// If we were using connection pooling, we would be forced to download the entire GIF.
// So we set no agent to ensure we are not connection pooling.
// @ts-ignore the signal is slightly different from the type it wants (still works fine)
const res = await fetch(url, {agent: false, signal: abortController.signal})
return convertImageStream(res.body, () => {
abortController.abort()
res.body.pause()
res.body.emit("end")
})
}
/**
* MOCK: Gets the emoji from the filesystem and converts to uncompressed PNG data.
* @param {string} mxc a single mxc:// URL
* @returns {Promise<Buffer | undefined>} uncompressed PNG data, or undefined if the downloaded emoji is not valid
*/
async function _mockGetAndConvertEmoji(mxc) {
const id = mxc.match(/\/([^./]*)$/)?.[1]
let s
if (fs.existsSync(`test/res/${id}.png`)) {
s = fs.createReadStream(`test/res/${id}.png`)
} else {
s = fs.createReadStream(`test/res/${id}.gif`)
}
return convertImageStream(s, () => {
s.pause()
s.emit("end")
})
}
/**
* @param {import("node-fetch").Response["body"]} streamIn
* @param {() => any} stopStream
@ -156,6 +110,4 @@ async function convertImageStream(streamIn, stopStream) {
}
module.exports.compositeMatrixEmojis = compositeMatrixEmojis
module.exports.getAndConvertEmoji = getAndConvertEmoji
module.exports._mockGetAndConvertEmoji = _mockGetAndConvertEmoji
module.exports._convertImageStream = convertImageStream
module.exports.convertImageStream = convertImageStream

View file

@ -1,6 +1,5 @@
const assert = require("assert").strict
const {test} = require("supertape")
const {_convertImageStream} = require("./emoji-sheet")
const {convertImageStream} = require("./emoji-sheet")
const fs = require("fs")
const {Transform} = require("stream").Transform
@ -33,7 +32,7 @@ async function runSingleTest(t, path, totalSize, sizeCheck) {
const file = fs.createReadStream(path)
const meter = new Meter()
const p = file.pipe(meter)
const result = await _convertImageStream(p, () => {
const result = await convertImageStream(p, () => {
file.pause()
file.emit("end")
})

View file

@ -1,10 +1,11 @@
const assert = require("assert").strict
const fs = require("fs")
const {test} = require("supertape")
const {eventToMessage} = require("./event-to-message")
const {_mockGetAndConvertEmoji} = require("./emoji-sheet")
const {convertImageStream} = require("./emoji-sheet")
const data = require("../../test/data")
const {MatrixServerError} = require("../../matrix/mreq")
const {db, select, discord} = require("../../passthrough")
const {select, discord} = require("../../passthrough")
/* c8 ignore next 7 */
function slow() {
@ -47,6 +48,25 @@ function sameFirstContentAndWhitespace(t, a, b) {
t.equal(a2, b2)
}
/**
* MOCK: Gets the emoji from the filesystem and converts to uncompressed PNG data.
* @param {string} mxc a single mxc:// URL
* @returns {Promise<Buffer | undefined>} uncompressed PNG data, or undefined if the downloaded emoji is not valid
*/
async function mockGetAndConvertEmoji(mxc) {
const id = mxc.match(/\/([^./]*)$/)?.[1]
let s
if (fs.existsSync(`test/res/${id}.png`)) {
s = fs.createReadStream(`test/res/${id}.png`)
} else {
s = fs.createReadStream(`test/res/${id}.gif`)
}
return convertImageStream(s, () => {
s.pause()
s.emit("end")
})
}
test("event2message: body is used when there is no formatted_body", async t => {
t.deepEqual(
await eventToMessage({
@ -3535,7 +3555,7 @@ slow()("event2message: unknown emoji at the end is reuploaded as a sprite sheet"
},
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
}, {}, {mxcDownloader: _mockGetAndConvertEmoji})
}, {}, {mxcDownloader: mockGetAndConvertEmoji})
const testResult = {
content: messages.messagesToSend[0].content,
fileName: messages.messagesToSend[0].pendingFiles[0].name,
@ -3560,7 +3580,7 @@ slow()("event2message: known emoji from an unreachable server at the end is reup
},
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
}, {}, {mxcDownloader: _mockGetAndConvertEmoji})
}, {}, {mxcDownloader: mockGetAndConvertEmoji})
const testResult = {
content: messages.messagesToSend[0].content,
fileName: messages.messagesToSend[0].pendingFiles[0].name,
@ -3585,7 +3605,7 @@ slow()("event2message: known and unknown emojis in the end are reuploaded as a s
},
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
}, {}, {mxcDownloader: _mockGetAndConvertEmoji})
}, {}, {mxcDownloader: mockGetAndConvertEmoji})
const testResult = {
content: messages.messagesToSend[0].content,
fileName: messages.messagesToSend[0].pendingFiles[0].name,
@ -3610,7 +3630,7 @@ slow()("event2message: all unknown chess emojis are reuploaded as a sprite sheet
},
event_id: "$Me6iE8C8CZyrDEOYYrXKSYRuuh_25Jj9kZaNrf7LKr4",
room_id: "!maggESguZBqGBZtSnr:cadence.moe"
}, {}, {mxcDownloader: _mockGetAndConvertEmoji})
}, {}, {mxcDownloader: mockGetAndConvertEmoji})
const testResult = {
content: messages.messagesToSend[0].content,
fileName: messages.messagesToSend[0].pendingFiles[0].name,