WIP: feature: threads'n'forums #74

Draft
Guzio wants to merge 109 commits from Guzio/out-of-your-element:mergable-fr-fr into main
2 changed files with 43 additions and 76 deletions
Showing only changes of commit 7eeff2faf3 - Show all commits

View file

@ -231,10 +231,8 @@ async event => {
const messageResponses = await sendEvent.sendEvent(event)
if (!messageResponses.length) return
/** @type {string|undefined} */
let executedCommand
if (event.type === "m.room.message" && event.content.msgtype === "m.text" && processCommands) {
executedCommand = await matrixCommandHandler.parseAndExecute(
await matrixCommandHandler.parseAndExecute(
// @ts-ignore - TypeScript doesn't know that the event.content.msgtype === "m.text" check ensures that event isn't of type Ty.Event.Outer_M_Room_Message_File (which, indeed, wouldn't fit here)
event
)

View file

@ -97,33 +97,6 @@ function replyctx(execute) {
}
}
/**
* @param {Error & {code?: string|number}} e
* @returns {e}
*/
function unmarshallDiscordError(e) {
if (e.name === "DiscordAPIError"){
try{
const unmarshaled = JSON.parse(e.message)
return {
...e,
...unmarshaled
}
} catch (err) {
return {
...err,
code: "JSON_PARSE_FAILED",
message: JSON.stringify({
original_error_where_message_failed_to_parse: e,
json_parser_error_message: err.message,
json_parser_error_code: err.code,
})
}
}
}
return e;
}
/** @type {Command[]} */
const commands = [{
aliases: ["emoji"],
@ -312,20 +285,20 @@ const commands = [{
}
try {
if (branchedFromDiscordMessage) await discord.snow.channel.createThreadWithMessage(channelID, branchedFromDiscordMessage, {name: words.slice(1).join(" ")})
else throw {code: "NO_BRANCH_SOURCE", was_supposed_to_be: branchedFromMxEvent};
}
catch (e){
switch (unmarshallDiscordError(e).code) {
case "NO_BRANCH_SOURCE": return api.sendEvent(event.room_id, "m.room.message", {
if (branchedFromDiscordMessage) return await discord.snow.channel.createThreadWithMessage(channelID, branchedFromDiscordMessage, {name: words.slice(1).join(" ")}) //can't just return the promise directly like in 99% of other cases here in commands, otherwise the error-handling below will not work
else {return api.sendEvent(event.room_id, "m.room.message", {
...ctx,
msgtype: "m.text",
body: "⚠️ Couldn't find a Discord representation of the message from which you're trying to branch this thread (event ID `"+e.was_supposed_to_be+"` on Matrix), so it wasn't created. Either you ran this command on an unbridged message (one sent by this bot or one that failed to bridge due to a previous error), or this is an error on our side and should be reported.",
body: "⚠️ Couldn't find a Discord representation of the message from which you're trying to branch this thread (event ID `"+branchedFromMxEvent+"` on Matrix), so it wasn't created. Either you ran this command on an unbridged message (one sent by this bot or one that failed to bridge due to a previous error), or this is an error on our side and should be reported.",
format: "org.matrix.custom.html",
formatted_body: "⚠️ Couldn't find a Discord representation of the message from which you're trying to branch this thread (event ID <code>"+e.was_supposed_to_be+"</code> on Matrix), so it wasn't created. Either you ran this command on an unbridged message (one sent by this bot or one that failed to bridge due to a previous error), or this is an error on our side and should be reported."
})
formatted_body: "⚠️ Couldn't find a Discord representation of the message from which you're trying to branch this thread (event ID <code>"+branchedFromMxEvent+"</code> on Matrix), so it wasn't created. Either you ran this command on an unbridged message (one sent by this bot or one that failed to bridge due to a previous error), or this is an error on our side and should be reported."
})};
}
catch (e){
/**@type {string|undefined} */
let err = e.message // see: https://docs.discord.com/developers/topics/opcodes-and-status-codes
case (160004): // see: https://docs.discord.com/developers/topics/opcodes-and-status-codes
if (err?.includes("160004")) {
if (isFallingBack){
await api.sendEvent(event.room_id, "m.room.message", {
...ctx,
@ -340,20 +313,18 @@ const commands = [{
msgtype: "m.text",
body: "There already exists a Discord thread for the message you ran this command on" + (thread ? " - you may join its bridged room here: https://matrix.to/#/"+thread+"?"+(await mxUtils.getViaServersQuery(thread, api)).toString() : ", so a new one cannot be crated. However, it seems like that thread isn't bridged to any Matrix rooms. Please ask the space/server admins to rectify this issue by creating the bridge. (If you're said admin and you can see that said bridge already exists, but this error message is still showing up, please report that as a bug.)")
})
case (50024): return api.sendEvent(event.room_id, "m.room.message", {
}
if (err?.includes("50024")) return api.sendEvent(event.room_id, "m.room.message", {
...ctx,
msgtype: "m.text",
body: "You cannot create threads in a Discord channel of the type, to which this Matrix room is bridged to. Did you try to create a thread inside a thread?"
})
case (50035): return api.sendEvent(event.room_id, "m.room.message", {
if (err?.includes("50035")) return api.sendEvent(event.room_id, "m.room.message", {
...ctx,
msgtype: "m.text",
body: "Specified thread name is too long - thread creation failed. Please yap a bit less in the title, the thread body is for that. ;)"
})
default:
await api.sendEvent(event.room_id, "m.room.message", {
...ctx,
msgtype: "m.text",
@ -362,7 +333,6 @@ const commands = [{
throw e
}
}
}
)
}, {
aliases: ["invite"],
@ -422,9 +392,9 @@ const commands = [{
/**
* @param {Ty.Event.Outer_M_Room_Message} event
* @returns {Promise<string|undefined>} the executed command's name or undefined if no command execution was performed
* @returns {Promise<any>|undefined} the executed command's in-process promise or undefined if no command execution was performed
*/
async function parseAndExecute(event) {
function parseAndExecute(event) {
let realBody = event.content.body
while (realBody.startsWith("> ")) {
const i = realBody.indexOf("\n")
@ -444,8 +414,7 @@ async function parseAndExecute(event) {
const command = commands.find(c => c.aliases.includes(commandName))
if (!command) return
await command.execute(event, realBody, words)
return words[0]
return command.execute(event, realBody, words)
}
module.exports.parseAndExecute = parseAndExecute