API updated to user rollWorker for rolling, fixed api not working at all lol

This commit is contained in:
Ean Milligan (Bastion) 2022-06-20 20:55:12 -04:00
parent a0dae3416f
commit df8c31d6d3
7 changed files with 177 additions and 268 deletions

View File

@ -33,7 +33,7 @@ const start = async (): Promise<void> => {
const httpConn = Deno.serveHttp(conn); const httpConn = Deno.serveHttp(conn);
for await (const requestEvent of httpConn) { for await (const requestEvent of httpConn) {
const request = requestEvent.request; const request = requestEvent.request;
log(LT.LOG, `Handling request: ${JSON.stringify(request)}`); log(LT.LOG, `Handling request: ${JSON.stringify(request.headers)} | ${JSON.stringify(request.method)} | ${JSON.stringify(request.url)}`);
// Check if user is authenticated to be using this API // Check if user is authenticated to be using this API
let authenticated = false; let authenticated = false;
let rateLimited = false; let rateLimited = false;
@ -80,13 +80,14 @@ const start = async (): Promise<void> => {
if (!rateLimited) { if (!rateLimited) {
// Get path and query as a string // Get path and query as a string
const [path, tempQ] = request.url.split('?'); const [urlPath, tempQ] = request.url.split('?');
const path = urlPath.split('api')[1];
// Turn the query into a map (if it exists) // Turn the query into a map (if it exists)
const query = new Map<string, string>(); const query = new Map<string, string>();
if (tempQ !== undefined) { if (tempQ !== undefined) {
tempQ.split('&').forEach((e: string) => { tempQ.split('&').forEach((e: string) => {
log(LT.LOG, `Parsing request query #2 ${request} ${e}`); log(LT.LOG, `Parsing request query ${request} ${e}`);
const [option, params] = e.split('='); const [option, params] = e.split('=');
query.set(option.toLowerCase(), params); query.set(option.toLowerCase(), params);
}); });
@ -97,16 +98,16 @@ const start = async (): Promise<void> => {
switch (request.method) { switch (request.method) {
case 'GET': case 'GET':
switch (path.toLowerCase()) { switch (path.toLowerCase()) {
case '/api/key': case '/key':
case '/api/key/': case '/key/':
endpoints.get.apiKeyAdmin(requestEvent, query, apiUserid); endpoints.get.apiKeyAdmin(requestEvent, query, apiUserid);
break; break;
case '/api/channel': case '/channel':
case '/api/channel/': case '/channel/':
endpoints.get.apiChannel(requestEvent, query, apiUserid); endpoints.get.apiChannel(requestEvent, query, apiUserid);
break; break;
case '/api/roll': case '/roll':
case '/api/roll/': case '/roll/':
endpoints.get.apiRoll(requestEvent, query, apiUserid); endpoints.get.apiRoll(requestEvent, query, apiUserid);
break; break;
default: default:
@ -117,8 +118,8 @@ const start = async (): Promise<void> => {
break; break;
case 'POST': case 'POST':
switch (path.toLowerCase()) { switch (path.toLowerCase()) {
case '/api/channel/add': case '/channel/add':
case '/api/channel/add/': case '/channel/add/':
endpoints.post.apiChannelAdd(requestEvent, query, apiUserid); endpoints.post.apiChannelAdd(requestEvent, query, apiUserid);
break; break;
default: default:
@ -129,26 +130,26 @@ const start = async (): Promise<void> => {
break; break;
case 'PUT': case 'PUT':
switch (path.toLowerCase()) { switch (path.toLowerCase()) {
case '/api/key/ban': case '/key/ban':
case '/api/key/ban/': case '/key/ban/':
case '/api/key/unban': case '/key/unban':
case '/api/key/unban/': case '/key/unban/':
case '/api/key/activate': case '/key/activate':
case '/api/key/activate/': case '/key/activate/':
case '/api/key/deactivate': case '/key/deactivate':
case '/api/key/deactivate/': case '/key/deactivate/':
endpoints.put.apiKeyManage(requestEvent, query, apiUserid, path); endpoints.put.apiKeyManage(requestEvent, query, apiUserid, path);
break; break;
case '/api/channel/ban': case '/channel/ban':
case '/api/channel/ban/': case '/channel/ban/':
case '/api/channel/unban': case '/channel/unban':
case '/api/channel/unban/': case '/channel/unban/':
endpoints.put.apiChannelManageBan(requestEvent, query, apiUserid, path); endpoints.put.apiChannelManageBan(requestEvent, query, apiUserid, path);
break; break;
case '/api/channel/activate': case '/channel/activate':
case '/api/channel/activate/': case '/channel/activate/':
case '/api/channel/deactivate': case '/channel/deactivate':
case '/api/channel/deactivate/': case '/channel/deactivate/':
endpoints.put.apiChannelManageActive(requestEvent, query, apiUserid, path); endpoints.put.apiChannelManageActive(requestEvent, query, apiUserid, path);
break; break;
default: default:
@ -159,8 +160,8 @@ const start = async (): Promise<void> => {
break; break;
case 'DELETE': case 'DELETE':
switch (path.toLowerCase()) { switch (path.toLowerCase()) {
case '/api/key/delete': case '/key/delete':
case '/api/key/delete/': case '/key/delete/':
endpoints.delete.apiKeyDelete(requestEvent, query, apiUserid, apiUserEmail, apiUserDelCode); endpoints.delete.apiKeyDelete(requestEvent, query, apiUserid, apiUserEmail, apiUserDelCode);
break; break;
default: default:
@ -185,8 +186,8 @@ const start = async (): Promise<void> => {
switch (request.method) { switch (request.method) {
case 'GET': case 'GET':
switch (path.toLowerCase()) { switch (path.toLowerCase()) {
case '/api/key': case '/key':
case '/api/key/': case '/key/':
endpoints.get.apiKey(requestEvent, query); endpoints.get.apiKey(requestEvent, query);
break; break;
default: default:

View File

@ -52,9 +52,10 @@ export const roll = async (message: DiscordenoMessage, args: string[], command:
queueRoll( queueRoll(
<QueuedRoll> { <QueuedRoll> {
apiRoll: false, apiRoll: false,
dd: { m, message, originalCommand }, dd: { m, message },
rollCmd, rollCmd,
modifiers, modifiers,
originalCommand,
}, },
); );
} catch (e) { } catch (e) {

View File

@ -24,6 +24,7 @@ export const getModifiers = (m: DiscordenoMessage, args: string[], command: stri
order: '', order: '',
valid: false, valid: false,
count: false, count: false,
apiWarn: '',
}; };
// Check if any of the args are command flags and pull those out into the modifiers object // Check if any of the args are command flags and pull those out into the modifiers object

View File

@ -3,20 +3,17 @@ import { dbClient, queries } from '../../db.ts';
import { import {
// Discordeno deps // Discordeno deps
cache, cache,
CreateMessage,
// Log4Deno deps // Log4Deno deps
log, log,
LT, LT,
// Discordeno deps
sendDirectMessage,
sendMessage,
// httpd deps // httpd deps
Status, Status,
STATUS_TEXT, STATUS_TEXT,
} from '../../../deps.ts'; } from '../../../deps.ts';
import { RollModifiers } from '../../mod.d.ts'; import { RollModifiers, QueuedRoll } from '../../mod.d.ts';
import solver from '../../solver/_index.ts'; import { queueRoll } from '../../solver/rollQueue.ts';
import { generateDMFailed } from '../../commandUtils.ts';
const apiWarning = `The following roll was conducted using my built in API. If someone in this channel did not request this roll, please report API abuse here: <${config.api.supportURL}>`;
export const apiRoll = async (requestEvent: Deno.RequestEvent, query: Map<string, string>, apiUserid: BigInt) => { export const apiRoll = async (requestEvent: Deno.RequestEvent, query: Map<string, string>, apiUserid: BigInt) => {
// Make sure query contains all the needed parts // Make sure query contains all the needed parts
@ -56,8 +53,6 @@ export const apiRoll = async (requestEvent: Deno.RequestEvent, query: Map<string
if (authorized) { if (authorized) {
// Rest of this command is in a try-catch to protect all sends/edits from erroring out // Rest of this command is in a try-catch to protect all sends/edits from erroring out
try { try {
// Flag to tell if roll was completely successful
let errorOut = false;
// Make sure rollCmd is not undefined // Make sure rollCmd is not undefined
let rollCmd = query.get('rollstr') || ''; let rollCmd = query.get('rollstr') || '';
const originalCommand = query.get('rollstr'); const originalCommand = query.get('rollstr');
@ -88,192 +83,27 @@ export const apiRoll = async (requestEvent: Deno.RequestEvent, query: Map<string
rollCmd = rollCmd.substring(rollCmd.indexOf(config.prefix) + 2).replace(/%20/g, ' '); rollCmd = rollCmd.substring(rollCmd.indexOf(config.prefix) + 2).replace(/%20/g, ' ');
const modifiers: RollModifiers = { const modifiers: RollModifiers = {
noDetails: false, noDetails: query.has('nd'),
superNoDetails: false, superNoDetails: query.has('snd'),
spoiler: '', spoiler: query.has('s') ? '||' : '',
maxRoll: query.has('m'), maxRoll: query.has('m'),
nominalRoll: query.has('n'), nominalRoll: query.has('n'),
gmRoll: false, gmRoll: query.has('gms'),
gms: [], gms: query.has('gms') ? (query.get('gms') || '').split(',') : [],
order: query.has('o') ? (query.get('o')?.toLowerCase() || '') : '', order: query.has('o') ? (query.get('o')?.toLowerCase() || '') : '',
valid: true,
count: query.has('c'), count: query.has('c'),
valid: true,
apiWarn: hideWarn ? '' : apiWarning,
}; };
// Parse the roll and get the return text // Parse the roll and get the return text
const returnmsg = solver.parseRoll(rollCmd, modifiers); await queueRoll(<QueuedRoll> {
apiRoll: true,
// Alert users why this message just appeared and how they can report abues pf this feature api: { requestEvent, channelId: BigInt(query.get('channel') || '0'), userId: BigInt(query.get('user') || '')},
const apiPrefix = hideWarn rollCmd,
? '' modifiers,
: `The following roll was conducted using my built in API. If someone in this channel did not request this roll, please report API abuse here: <${config.api.supportURL}>\n\n`; originalCommand,
let m, returnText = ''; });
// Handle sending the error message to whoever called the api
if (returnmsg.error) {
requestEvent.respondWith(new Response(returnmsg.errorMsg, { status: Status.InternalServerError }));
// Always log API rolls for abuse detection
dbClient.execute(queries.insertRollLogCmd(1, 1), [originalCommand, returnmsg.errorCode, null]).catch((e) => {
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
});
return;
} else {
returnText = `${apiPrefix}<@${query.get('user')}>${returnmsg.line1}\n${returnmsg.line2}`;
let spoilerTxt = '';
// Determine if spoiler flag was on
if (query.has('s')) {
spoilerTxt = '||';
}
// Determine if no details flag was on
if (!query.has('snd')) {
if (query.has('nd')) {
returnText += '\nDetails suppressed by nd query.';
} else {
returnText += `\nDetails:\n${spoilerTxt}${returnmsg.line3}${spoilerTxt}`;
}
}
}
// If the roll was a GM roll, send DMs to all the GMs
if (query.has('gms')) {
// Get all the GM user IDs from the query
const gms = (query.get('gms') || '').split(',');
if (gms.length === 0) {
// Alert API user that they messed up
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
// Always log API rolls for abuse detection
dbClient.execute(queries.insertRollLogCmd(1, 1), [originalCommand, 'NoGMsSent', null]).catch((e) => {
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
});
return;
}
// Make a new return line to be sent to the roller
let normalText = `${apiPrefix}<@${query.get('user')}>${returnmsg.line1}\nResults have been messaged to the following GMs: `;
gms.forEach((e) => {
log(LT.LOG, `Appending GM ${e} to roll text`);
normalText += `<@${e}> `;
});
// Send the return message as a DM or normal message depening on if the channel is set
if ((query.get('channel') || '').length > 0) {
// todo: embedify
m = await sendMessage(BigInt(query.get('channel') || ''), normalText).catch(() => {
requestEvent.respondWith(new Response('Message 00 failed to send.', { status: Status.InternalServerError }));
errorOut = true;
});
} else {
// todo: embedify
m = await sendDirectMessage(BigInt(query.get('user') || ''), normalText).catch(() => {
requestEvent.respondWith(new Response('Message 01 failed to send.', { status: Status.InternalServerError }));
errorOut = true;
});
}
const newMessage: CreateMessage = {};
// If its too big, collapse it into a .txt file and send that instead.
const b = await new Blob([returnText as BlobPart], { 'type': 'text' });
if (b.size > 8388290) {
// Update return text
newMessage.content = `${apiPrefix}<@${
query.get('user')
}>${returnmsg.line1}\n${returnmsg.line2}\nDetails have been ommitted from this message for being over 2000 characters. Full details could not be attached to this messaged as a \`.txt\` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one.`;
} else {
// Update return text
newMessage.content = `${apiPrefix}<@${
query.get('user')
}>${returnmsg.line1}\n${returnmsg.line2}\nFull details have been attached to this messaged as a \`.txt\` file for verification purposes.`;
newMessage.file = { 'blob': b, 'name': 'rollDetails.txt' };
}
// And message the full details to each of the GMs, alerting roller of every GM that could not be messaged
gms.forEach(async (e) => {
log(LT.LOG, `Messaging GM ${e} roll results`);
// Attempt to DM the GMs and send a warning if it could not DM a GM
await sendDirectMessage(BigInt(e), newMessage).catch(async () => {
const failedSend = generateDMFailed(e);
// Send the return message as a DM or normal message depening on if the channel is set
if ((query.get('channel') || '').length > 0) {
m = await sendMessage(BigInt(query.get('channel') || ''), failedSend).catch(() => {
requestEvent.respondWith(new Response('Message failed to send.', { status: Status.InternalServerError }));
errorOut = true;
});
} else {
m = await sendDirectMessage(BigInt(query.get('user') || ''), failedSend).catch(() => {
requestEvent.respondWith(new Response('Message failed to send.', { status: Status.InternalServerError }));
errorOut = true;
});
}
});
});
// Always log API rolls for abuse detection
dbClient.execute(queries.insertRollLogCmd(1, 0), [originalCommand, returnText, (typeof m === 'object') ? m.id : null]).catch((e) => {
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
});
// Handle closing the request out
if (errorOut) {
return;
} else {
requestEvent.respondWith(new Response(normalText, { status: Status.OK }));
return;
}
} else {
// todo: embedify
const newMessage: CreateMessage = {};
newMessage.content = returnText;
// When not a GM roll, make sure the message is not too big
if (returnText.length > 2000) {
// If its too big, collapse it into a .txt file and send that instead.
const b = await new Blob([returnText as BlobPart], { 'type': 'text' });
if (b.size > 8388290) {
// Update return text
newMessage.content = `${apiPrefix}<@${
query.get('user')
}>${returnmsg.line1}\n${returnmsg.line2}\nDetails have been ommitted from this message for being over 2000 characters. Full details could not be attached to this messaged as a \`.txt\` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one.`;
} else {
// Update return text
newMessage.content = `${apiPrefix}<@${
query.get('user')
}>${returnmsg.line1}\n${returnmsg.line2}\nDetails have been ommitted from this message for being over 2000 characters. Full details have been attached to this messaged as a \`.txt\` file for verification purposes.`;
newMessage.file = { 'blob': b, 'name': 'rollDetails.txt' };
}
}
// Send the return message as a DM or normal message depening on if the channel is set
if ((query.get('channel') || '').length > 0) {
m = await sendMessage(BigInt(query.get('channel') || ''), newMessage).catch(() => {
requestEvent.respondWith(new Response('Message 20 failed to send.', { status: Status.InternalServerError }));
errorOut = true;
});
} else {
m = await sendDirectMessage(BigInt(query.get('user') || ''), newMessage).catch(() => {
requestEvent.respondWith(new Response('Message 21 failed to send.', { status: Status.InternalServerError }));
errorOut = true;
});
}
// If enabled, log rolls so we can verify the bots math
dbClient.execute(queries.insertRollLogCmd(1, 0), [originalCommand, returnText, (typeof m === 'object') ? m.id : null]).catch((e) => {
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
});
// Handle closing the request out
if (errorOut) {
return;
} else {
requestEvent.respondWith(new Response(returnText, { status: Status.OK }));
return;
}
}
} catch (err) { } catch (err) {
// Handle any errors we missed // Handle any errors we missed
log(LT.ERROR, `Unhandled Error: ${JSON.stringify(err)}`); log(LT.ERROR, `Unhandled Error: ${JSON.stringify(err)}`);
@ -281,7 +111,10 @@ export const apiRoll = async (requestEvent: Deno.RequestEvent, query: Map<string
} }
} else { } else {
// Alert API user that they messed up // Alert API user that they messed up
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.Forbidden), { status: Status.Forbidden })); requestEvent.respondWith(new Response(
`Verify you are a member of the guild you are sending this roll to. If you are, the ${config.name} may not have that registered, please send a message in the guild so ${config.name} can register this. This registration is temporary, so if you see this error again, just poke your server again.`,
{ status: Status.Forbidden, statusText: STATUS_TEXT.get(Status.Forbidden) }
));
} }
} else { } else {
// Alert API user that they shouldn't be doing this // Alert API user that they shouldn't be doing this

9
src/mod.d.ts vendored
View File

@ -20,8 +20,9 @@ export type RollModifiers = {
gmRoll: boolean; gmRoll: boolean;
gms: string[]; gms: string[];
order: string; order: string;
valid: boolean;
count: boolean; count: boolean;
valid: boolean;
apiWarn: string;
}; };
// QueuedRoll is the structure to track rolls we could not immediately handle // QueuedRoll is the structure to track rolls we could not immediately handle
@ -29,14 +30,14 @@ export type QueuedRoll = {
apiRoll: boolean; apiRoll: boolean;
api: { api: {
requestEvent: Deno.RequestEvent; requestEvent: Deno.RequestEvent;
channelId: BigInt; channelId: bigint;
userId: BigInt; userId: bigint;
}; };
dd: { dd: {
m: DiscordenoMessage; m: DiscordenoMessage;
message: DiscordenoMessage; message: DiscordenoMessage;
originalCommand: string;
}; };
originalCommand: string;
rollCmd: string; rollCmd: string;
modifiers: RollModifiers; modifiers: RollModifiers;
}; };

View File

@ -9,6 +9,10 @@ import {
LT, LT,
// Discordeno deps // Discordeno deps
sendDirectMessage, sendDirectMessage,
sendMessage,
// httpd deps
Status,
STATUS_TEXT,
} from '../../deps.ts'; } from '../../deps.ts';
import { SolvedRoll } from '../solver/solver.d.ts'; import { SolvedRoll } from '../solver/solver.d.ts';
import { QueuedRoll, RollModifiers } from '../mod.d.ts'; import { QueuedRoll, RollModifiers } from '../mod.d.ts';
@ -30,19 +34,26 @@ const handleRollWorker = async (rq: QueuedRoll) => {
const workerTimeout = setTimeout(async () => { const workerTimeout = setTimeout(async () => {
rollWorker.terminate(); rollWorker.terminate();
currentWorkers--; currentWorkers--;
rq.dd.m.edit({ if (rq.apiRoll) {
embeds: [ rq.api.requestEvent.respondWith(new Response(
(await generateRollEmbed( 'Roll took too long to process, try breaking roll down into simpler parts',
rq.dd.message.authorId, { status: Status.RequestTimeout, statusText: STATUS_TEXT.get(Status.RequestTimeout) }
<SolvedRoll> { ));
error: true, } else {
errorCode: 'TooComplex', rq.dd.m.edit({
errorMsg: 'Error: Roll took too long to process, try breaking roll down into simpler parts', embeds: [
}, (await generateRollEmbed(
<RollModifiers> {}, rq.dd.message.authorId,
)).embed, <SolvedRoll> {
], error: true,
}); errorCode: 'TooComplex',
errorMsg: 'Error: Roll took too long to process, try breaking roll down into simpler parts',
},
<RollModifiers> {},
)).embed,
],
});
}
}, config.limits.workerTimeout); }, config.limits.workerTimeout);
rollWorker.postMessage({ rollWorker.postMessage({
@ -51,64 +62,125 @@ const handleRollWorker = async (rq: QueuedRoll) => {
}); });
rollWorker.addEventListener('message', async (workerMessage) => { rollWorker.addEventListener('message', async (workerMessage) => {
let apiErroredOut = false;
try { try {
currentWorkers--; currentWorkers--;
clearTimeout(workerTimeout); clearTimeout(workerTimeout);
const returnmsg = workerMessage.data; const returnmsg = workerMessage.data;
const pubEmbedDetails = await generateRollEmbed(rq.dd.message.authorId, returnmsg, rq.modifiers); const pubEmbedDetails = await generateRollEmbed(rq.apiRoll ? rq.api.userId : rq.dd.message.authorId, returnmsg, rq.modifiers);
const gmEmbedDetails = await generateRollEmbed(rq.dd.message.authorId, returnmsg, gmModifiers); const gmEmbedDetails = await generateRollEmbed(rq.apiRoll ? rq.api.userId : rq.dd.message.authorId, returnmsg, gmModifiers);
const countEmbed = generateCountDetailsEmbed(returnmsg.counts); const countEmbed = generateCountDetailsEmbed(returnmsg.counts);
// If there was an error, report it to the user in hopes that they can determine what they did wrong // If there was an error, report it to the user in hopes that they can determine what they did wrong
if (returnmsg.error) { if (returnmsg.error) {
rq.dd.m.edit({ embeds: [pubEmbedDetails.embed] }); if (rq.apiRoll) {
rq.api.requestEvent.respondWith(new Response(
returnmsg.errorMsg,
{ status: Status.InternalServerError, statusText: STATUS_TEXT.get(Status.InternalServerError) }
));
} else {
rq.dd.m.edit({ embeds: [pubEmbedDetails.embed] });
}
if (DEVMODE && config.logRolls) { if (rq.apiRoll || DEVMODE && config.logRolls) {
// If enabled, log rolls so we can see what went wrong // If enabled, log rolls so we can see what went wrong
dbClient.execute(queries.insertRollLogCmd(0, 1), [rq.dd.originalCommand, returnmsg.errorCode, rq.dd.m.id]).catch((e) => { dbClient.execute(queries.insertRollLogCmd(rq.apiRoll ? 1 : 0, 1), [rq.originalCommand, returnmsg.errorCode, rq.apiRoll ? null : rq.dd.m.id]).catch((e) => {
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`); log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
}); });
} }
} else { } else {
let n: DiscordenoMessage | void;
// Determine if we are to send a GM roll or a normal roll // Determine if we are to send a GM roll or a normal roll
if (rq.modifiers.gmRoll) { if (rq.modifiers.gmRoll) {
// Send the public embed to correct channel if (rq.apiRoll) {
rq.dd.m.edit({ embeds: [pubEmbedDetails.embed] }); n = await sendMessage(rq.api.channelId, {
content: rq.modifiers.apiWarn,
// And message the full details to each of the GMs, alerting roller of every GM that could not be messaged embeds: [pubEmbedDetails.embed]
rq.modifiers.gms.forEach(async (gm) => {
log(LT.LOG, `Messaging GM ${gm}`);
// Attempt to DM the GM and send a warning if it could not DM a GM
await sendDirectMessage(BigInt(gm.substring(2, gm.length - 1)), {
embeds: rq.modifiers.count ? [gmEmbedDetails.embed, countEmbed] : [gmEmbedDetails.embed],
}).then(async () => {
// Check if we need to attach a file and send it after the initial details sent
if (gmEmbedDetails.hasAttachment) {
await sendDirectMessage(BigInt(gm.substring(2, gm.length - 1)), {
file: gmEmbedDetails.attachment,
}).catch(() => {
rq.dd.message.reply(generateDMFailed(gm));
});
}
}).catch(() => { }).catch(() => {
rq.dd.message.reply(generateDMFailed(gm)); apiErroredOut = true;
rq.api.requestEvent.respondWith(new Response(
'Message failed to send.',
{ status: Status.InternalServerError, statusText: STATUS_TEXT.get(Status.InternalServerError) }
));
}); });
}); } else {
// Send the public embed to correct channel
rq.dd.m.edit({ embeds: [pubEmbedDetails.embed] });
}
if (!apiErroredOut) {
// And message the full details to each of the GMs, alerting roller of every GM that could not be messaged
rq.modifiers.gms.forEach(async (gm) => {
log(LT.LOG, `Messaging GM ${gm}`);
// Attempt to DM the GM and send a warning if it could not DM a GM
await sendDirectMessage(BigInt(gm.substring(2, gm.length - 1)), {
embeds: rq.modifiers.count ? [gmEmbedDetails.embed, countEmbed] : [gmEmbedDetails.embed],
}).then(async () => {
// Check if we need to attach a file and send it after the initial details sent
if (gmEmbedDetails.hasAttachment) {
await sendDirectMessage(BigInt(gm.substring(2, gm.length - 1)), {
file: gmEmbedDetails.attachment,
}).catch(() => {
if (rq.apiRoll && n) {
n.reply(generateDMFailed(gm));
} else {
rq.dd.message.reply(generateDMFailed(gm));
}
});
}
}).catch(() => {
if (rq.apiRoll && n) {
n.reply(generateDMFailed(gm));
} else {
rq.dd.message.reply(generateDMFailed(gm));
}
});
});
}
} else { } else {
// Not a gm roll, so just send normal embed to correct channel // Not a gm roll, so just send normal embed to correct channel
const n = await rq.dd.m.edit({ if (rq.apiRoll) {
embeds: rq.modifiers.count ? [pubEmbedDetails.embed, countEmbed] : [pubEmbedDetails.embed], n = await sendMessage(rq.api.channelId, {
}); content: rq.modifiers.apiWarn,
if (pubEmbedDetails.hasAttachment) { embeds: rq.modifiers.count ? [pubEmbedDetails.embed, countEmbed] : [pubEmbedDetails.embed]
}).catch(() => {
apiErroredOut = true;
rq.api.requestEvent.respondWith(new Response(
'Message failed to send.',
{ status: Status.InternalServerError, statusText: STATUS_TEXT.get(Status.InternalServerError) }
));
});
} else {
n = await rq.dd.m.edit({
embeds: rq.modifiers.count ? [pubEmbedDetails.embed, countEmbed] : [pubEmbedDetails.embed],
});
}
if (pubEmbedDetails.hasAttachment && n) {
// Attachment requires you to send a new message // Attachment requires you to send a new message
n.reply({ n.reply({
file: pubEmbedDetails.attachment, file: pubEmbedDetails.attachment,
}); });
} }
} }
if (!apiErroredOut) {
rq.api.requestEvent.respondWith(new Response(
JSON.stringify(
rq.modifiers.count ? { counts: countEmbed, details: pubEmbedDetails } : { details: pubEmbedDetails }
),
{ status: Status.OK, statusText: STATUS_TEXT.get(Status.OK) }
));
}
} }
} catch (e) { } catch (e) {
log(LT.ERROR, `Unddandled Error: ${JSON.stringify(e)}`); log(LT.ERROR, `Unddandled Error: ${JSON.stringify(e)}`);
if (rq.apiRoll && !apiErroredOut) {
rq.api.requestEvent.respondWith(new Response(
JSON.stringify(e),
{ status: Status.InternalServerError, statusText: STATUS_TEXT.get(Status.InternalServerError) }
));
}
} }
}); });
}; };

View File

@ -1 +1 @@
deno run --allow-write=./logs --allow-read=./src/solver/rollWorker.ts --allow-net .\mod.ts deno run --allow-write=./logs/ --allow-read=./src/solver/ --allow-net .\mod.ts