import { botId, DiscordenoMessage, Embed, FileContent, sendDirectMessage, sendMessage } from '@discordeno'; import { log, LogTypes as LT } from '@Log4Deno'; import config from '~config'; import { DEVMODE } from '~flags'; import { SolvedRoll } from 'artigen/artigen.d.ts'; import { RollModifiers } from 'artigen/dice/dice.d.ts'; import { removeWorker } from 'artigen/managers/countManager.ts'; import { QueuedRoll } from 'artigen/managers/manager.d.ts'; import { generateCountDetailsEmbed, generateDMFailed, generateRollDistsEmbed, generateRollEmbed } from 'artigen/utils/embeds.ts'; import { loggingEnabled } from 'artigen/utils/logFlag.ts'; import dbClient from 'db/client.ts'; import { queries } from 'db/common.ts'; import stdResp from 'endpoints/stdResponses.ts'; import utils from 'utils/utils.ts'; import { infoColor1 } from 'embeds/colors.ts'; import { basicReducer } from 'artigen/utils/reducers.ts'; export const onWorkerComplete = async (workerMessage: MessageEvent, workerTimeout: number, rollRequest: QueuedRoll) => { let apiErroredOut = false; try { removeWorker(); clearTimeout(workerTimeout); const returnMsg = workerMessage.data; loggingEnabled && log(LT.LOG, `Roll came back from worker: ${returnMsg.line1.length} |&| ${returnMsg.line2.length} |&| ${returnMsg.line3.length} `); loggingEnabled && log(LT.LOG, `Roll came back from worker: ${returnMsg.line1} |&| ${returnMsg.line2} |&| ${returnMsg.line3} `); const pubEmbedDetails = generateRollEmbed( rollRequest.apiRoll ? rollRequest.api.userId : rollRequest.dd.originalMessage.authorId, returnMsg, rollRequest.modifiers, ); const gmEmbedDetails = generateRollEmbed(rollRequest.apiRoll ? rollRequest.api.userId : rollRequest.dd.originalMessage.authorId, returnMsg, { ...rollRequest.modifiers, gmRoll: false, }); let pubRespCharCount = pubEmbedDetails.charCount; let gmRespCharCount = gmEmbedDetails.charCount; const pubEmbeds: Embed[] = [pubEmbedDetails.embed]; const gmEmbeds: Embed[] = [gmEmbedDetails.embed]; const pubAttachments: FileContent[] = pubEmbedDetails.hasAttachment ? [pubEmbedDetails.attachment] : []; const gmAttachments: FileContent[] = gmEmbedDetails.hasAttachment ? [gmEmbedDetails.attachment] : []; // Handle adding count embed to correct list if (rollRequest.modifiers.count) { const countEmbed = generateCountDetailsEmbed(returnMsg.counts); if (rollRequest.modifiers.gmRoll) { gmEmbeds.push(countEmbed.embed); gmRespCharCount += countEmbed.charCount; } else { pubEmbeds.push(countEmbed.embed); pubRespCharCount += countEmbed.charCount; } } // Handle adding rollDist embed to correct list if (rollRequest.modifiers.rollDist) { const rollDistEmbed = generateRollDistsEmbed(returnMsg.rollDistributions); if (rollRequest.modifiers.gmRoll) { gmEmbeds.push(rollDistEmbed.embed); rollDistEmbed.hasAttachment && gmAttachments.push(rollDistEmbed.attachment); gmRespCharCount += rollDistEmbed.charCount; } else { pubEmbeds.push(rollDistEmbed.embed); rollDistEmbed.hasAttachment && pubAttachments.push(rollDistEmbed.attachment); pubRespCharCount += rollDistEmbed.charCount; } } loggingEnabled && log(LT.LOG, `Embeds are generated: ${pubRespCharCount} ${JSON.stringify(pubEmbeds)} |&| ${gmRespCharCount} ${JSON.stringify(gmEmbeds)}`); // If there was an error, report it to the user in hopes that they can determine what they did wrong if (returnMsg.error) { if (rollRequest.apiRoll) { rollRequest.api.resolve(stdResp.InternalServerError(returnMsg.errorMsg)); } else { rollRequest.dd.myResponse.edit({ embeds: pubEmbeds }); } if (rollRequest.apiRoll || (DEVMODE && config.logRolls)) { // If enabled, log rolls so we can see what went wrong dbClient .execute(queries.insertRollLogCmd(rollRequest.apiRoll ? 1 : 0, 1), [ rollRequest.originalCommand, returnMsg.errorCode, rollRequest.apiRoll ? null : rollRequest.dd.myResponse.id, ]) .catch((e) => utils.commonLoggers.dbError('rollQueue.ts:82', 'insert into', e)); } return; } let newMsg: DiscordenoMessage | void = undefined; // Determine if we are to send a GM roll or a normal roll if (rollRequest.modifiers.gmRoll) { if (rollRequest.apiRoll) { newMsg = await sendMessage(rollRequest.api.channelId, { content: rollRequest.modifiers.apiWarn, embeds: pubEmbeds, }).catch(() => { apiErroredOut = true; rollRequest.api.resolve(stdResp.InternalServerError('Message failed to send - location 0.')); }); } else { // Send the public embed to correct channel rollRequest.dd.myResponse.edit({ embeds: pubEmbeds }); } if (!apiErroredOut) { // And message the full details to each of the GMs, alerting roller of every GM that could not be messaged rollRequest.modifiers.gms.forEach(async (gm) => { const gmId: bigint = BigInt(gm.startsWith('<') ? gm.substring(2, gm.length - 1) : gm); log(LT.LOG, `Messaging GM ${gm} | ${gmId}`); // Attempt to DM the GM and send a warning if it could not DM a GM await sendDirectMessage(gmId, { content: `Original GM Roll Request: ${rollRequest.apiRoll ? newMsg && newMsg.link : rollRequest.dd.myResponse.link}`, embeds: gmEmbeds, }) .then(async () => { // Check if we need to attach a file and send it after the initial details sent if (gmAttachments.length) { await sendDirectMessage(gmId, { file: gmAttachments, }).catch(() => { if (newMsg && rollRequest.apiRoll) { newMsg.reply(generateDMFailed(gmId)); } else if (!rollRequest.apiRoll) { rollRequest.dd.originalMessage.reply(generateDMFailed(gmId)); } }); } }) .catch(() => { if (rollRequest.apiRoll && newMsg) { newMsg.reply(generateDMFailed(gmId)); } else if (!rollRequest.apiRoll) { rollRequest.dd.originalMessage.reply(generateDMFailed(gmId)); } }); }); } } else { // Not a gm roll, so just send normal embed to correct channel if (rollRequest.apiRoll) { newMsg = await sendMessage(rollRequest.api.channelId, { content: rollRequest.modifiers.apiWarn, embeds: pubEmbeds, }).catch(() => { apiErroredOut = true; rollRequest.api.resolve(stdResp.InternalServerError('Message failed to send - location 1.')); }); } else { newMsg = await rollRequest.dd.myResponse.edit({ embeds: pubEmbeds, }); } if (pubAttachments.length && newMsg) { // Attachment requires you to send a new message const respMessage: Embed[] = [ { color: infoColor1, description: `This message contains information for a previous roll.\nPlease click on "<@${botId}> *Click to see attachment*" above this message to see the previous roll.`, }, ]; if (pubAttachments.map((file) => file.blob.size).reduce(basicReducer, 0) < config.maxFileSize) { // All attachments will fit in one message newMsg.reply({ embeds: respMessage, file: pubAttachments, }); } else { pubAttachments.forEach((file) => { newMsg && newMsg.reply({ embeds: respMessage, file, }); }); } } } if (rollRequest.apiRoll && !apiErroredOut) { dbClient .execute(queries.insertRollLogCmd(1, 0), [rollRequest.originalCommand, returnMsg.errorCode, newMsg ? newMsg.id : null]) .catch((e) => utils.commonLoggers.dbError('rollQueue.ts:155', 'insert into', e)); rollRequest.api.resolve( stdResp.OK( JSON.stringify( rollRequest.modifiers.count ? { counts: returnMsg.counts, details: pubEmbedDetails, } : { details: pubEmbedDetails, }, ), ), ); } } catch (e) { log(LT.ERROR, `Unhandled rollRequest Error: ${JSON.stringify(e)}`); if (!rollRequest.apiRoll) { rollRequest.dd.myResponse.edit({ embeds: [ ( await generateRollEmbed( rollRequest.dd.originalMessage.authorId, { error: true, errorMsg: `Something weird went wrong, likely the requested roll is too complex and caused the response to be too large for Discord. Try breaking the request down into smaller messages and try again.\n\nIf this error continues to come up, please \`${config.prefix}report\` this to my developer.`, errorCode: 'UnhandledWorkerComplete', }, {}, ) ).embed, ], }); } if (rollRequest.apiRoll && !apiErroredOut) { rollRequest.api.resolve(stdResp.InternalServerError(JSON.stringify(e))); } } };