Skip to content

Commit

Permalink
err... whoops
Browse files Browse the repository at this point in the history
* requests were returning when they were 'ok'
* autocompleteInteractions are now logged (including [focused])
* index.ts - allSettled uses the deferred promise, not ready field itself
  • Loading branch information
sudojunior committed Jul 6, 2024
1 parent 6aca7ba commit 9785cc2
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 104 deletions.
188 changes: 90 additions & 98 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
import {
SlashCreator,
CommandOptionType,
type ApplicationCommandOption,
BunServer,
ChannelType,
SlashCreator,
CommandOptionType,
type ApplicationCommandOption,
BunServer,
ChannelType,
BaseInteractionContext,
} from "slash-create";
import path from "node:path";

import { hashMapToString, titleCase } from "&common/helpers";
import registerComponents from "./components";

import { logPrefix } from "&console/context";
import { logPrefix, stringResolver } from "&console/context";
import { duration } from "&console/helpers";
import { commandTypeStrings } from "&discord/constants";
import { displayUser } from "&discord/helpers";
import { displayUser, getCommandInfo } from "&discord/helpers";
import RequestQuota from "&console/request-quota";
import { Provider } from "&docs/source";

console.time("Startup");

const creator = new SlashCreator({
applicationID: process.env.DISCORD_APP_ID,
publicKey: process.env.DISCORD_PUBLIC_KEY,
token: process.env.DISCORD_BOT_TOKEN,
serverPort: Number.parseInt(process.env.PORT, 10) || 8020,
serverHost: "0.0.0.0",
applicationID: process.env.DISCORD_APP_ID,
publicKey: process.env.DISCORD_PUBLIC_KEY,
token: process.env.DISCORD_BOT_TOKEN,
serverPort: Number.parseInt(process.env.PORT, 10) || 8020,
serverHost: "0.0.0.0",
});

// creator.on('debug', (message) => console.debug(message));
Expand All @@ -33,104 +34,95 @@ const creator = new SlashCreator({
// creator.on('synced', () => console.info('Commands synced!'));

creator.on("commandRun", async (command, promise, ctx) => {
const options = ctx.subcommands.reduce(
(target, command) => target[command],
ctx.options,
);
const stringResolver = (value: string | number | boolean) => {
if (typeof value === "string") {
if (ctx.users.has(value)) {
const user = ctx.users.get(value);
return `<${user.bot ? "App" : "User"} | @${displayUser(user)}>`;
}
if (ctx.channels.has(value)) {
const channel = ctx.channels.get(value);
return `<Channel {${ChannelType[channel.type]}} | #${channel.name} (${
channel.id
})>`;
}
if (ctx.roles.has(value)) {
const role = ctx.roles.get(value);
return `<Role | @${role.name} (${role.id}) 🎨 ${role.colorHex}>`;
}
}
return JSON.stringify(value);
};
const commandString = `/${command.commandName} ${ctx.subcommands.join(
" ",
)} { ${hashMapToString(options, " = ", ", ", stringResolver)} }`;
const wrappedTimer = duration();
await promise;
console.info(`${logPrefix(ctx)} ran ${commandString} in ${wrappedTimer()}`);
const options = ctx.subcommands.reduce(
(target, command) => target[command],
ctx.options,
);

const commandString = `/${command.commandName} ${ctx.subcommands.join(
" ",
)} { ${hashMapToString(options, " = ", ", ", (value) => stringResolver(ctx, value))} }`;

const wrappedTimer = duration();
await promise;
console.info(`${logPrefix(ctx)} ran ${commandString} in ${wrappedTimer()}`);
});

creator.on('autocompleteInteraction', (ctx, command) => {
const { options, focused, subCommands } = getCommandInfo<object>(ctx);

const commandString = `/${command.commandName} ${subCommands.join(" ")} { ${hashMapToString(options, " = ", ", ", (value) => stringResolver(ctx, value))} } [${focused}]`;

console.info(`${logPrefix(ctx)} queried ${commandString}`);
})

creator.on("commandRegister", async (command) => {
const [typeString, typeSymbol] = commandTypeStrings[command.type];

console.info(`$ /${command.commandName} (${typeString} [${typeSymbol}])`);
const commandPaths: Record<string, Record<string, string>> = {};

function searchOptions(
subCommand: ApplicationCommandOption,
commandPath: string[] = [],
) {
switch (subCommand.type) {
case CommandOptionType.SUB_COMMAND:
case CommandOptionType.SUB_COMMAND_GROUP: {
if (
!Array.isArray(subCommand.options) &&
subCommand.type === CommandOptionType.SUB_COMMAND
) {
commandPaths[commandPath.concat(subCommand.name).join(" ")] = {};
break;
}

if (subCommand.options) {
for (const childOption of subCommand.options)
searchOptions(childOption, commandPath.concat(subCommand.name));
}
break;
}

default: {
const pathTarget =
subCommand.name +
(!subCommand.required ? "?" : "") +
("autocomplete" in subCommand && subCommand.autocomplete ? "*" : "");

commandPaths[commandPath.join(" ")] ??= {};
commandPaths[commandPath.join(" ")][pathTarget] = titleCase(
CommandOptionType[subCommand.type].toLowerCase(),
);
if ("choices" in subCommand)
commandPaths[commandPath.join(" ")][pathTarget] +=
`[${subCommand.choices.length}]`;
}
}
}

if (command.options)
for (const option of command.options) searchOptions(option);

for (const key in commandPaths)
console.info(
`^ ${`/${command.commandName} ${key}`.trim()} { ${hashMapToString(
commandPaths[key],
)} }`,
);
const [typeString, typeSymbol] = commandTypeStrings[command.type];

console.info(`$ /${command.commandName} (${typeString} [${typeSymbol}])`);
const commandPaths: Record<string, Record<string, string>> = {};

function searchOptions(
subCommand: ApplicationCommandOption,
commandPath: string[] = [],
) {
switch (subCommand.type) {
case CommandOptionType.SUB_COMMAND:
case CommandOptionType.SUB_COMMAND_GROUP: {
if (
!Array.isArray(subCommand.options) &&
subCommand.type === CommandOptionType.SUB_COMMAND
) {
commandPaths[commandPath.concat(subCommand.name).join(" ")] = {};
break;
}

if (subCommand.options) {
for (const childOption of subCommand.options)
searchOptions(childOption, commandPath.concat(subCommand.name));
}
break;
}

default: {
const pathTarget =
subCommand.name +
(!subCommand.required ? "?" : "") +
("autocomplete" in subCommand && subCommand.autocomplete ? "*" : "");

commandPaths[commandPath.join(" ")] ??= {};
commandPaths[commandPath.join(" ")][pathTarget] = titleCase(
CommandOptionType[subCommand.type].toLowerCase(),
);
if ("choices" in subCommand)
commandPaths[commandPath.join(" ")][pathTarget] +=
`[${subCommand.choices.length}]`;
}
}
}

if (command.options)
for (const option of command.options) searchOptions(option);

for (const key in commandPaths)
console.info(
`^ ${`/${command.commandName} ${key}`.trim()} { ${hashMapToString(
commandPaths[key],
)} }`,
);
});

creator.on("commandError", (command, error) =>
console.error(`Command ${command.commandName}:`, error),
console.error(`Command ${command.commandName}:`, error),
);

creator.on("componentInteraction", (ctx) => {
console.info(`${logPrefix(ctx)} = $${ctx.customID}`);
console.info(`${logPrefix(ctx)} = $${ctx.customID}`);
});

registerComponents(creator);
await creator.registerCommandsIn(path.resolve(import.meta.dir, "./commands"), [
".ts",
".ts",
]);
console.timeLog("Startup", "Commands & Components Loaded");

Expand All @@ -143,5 +135,5 @@ console.timeEnd("Startup");

// Expect 2n requests to be used
// docs manifest list + latest docs manfiest for each provider
await Promise.allSettled(Provider.all.map((provider) => provider.aggregator.ready));
await Promise.allSettled(Provider.all.map((provider) => provider.aggregator.onReady));
RequestQuota.debug();
33 changes: 31 additions & 2 deletions src/modules/console/context.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import type { CommandContext, ComponentContext } from "slash-create";
import { ChannelType } from 'slash-create';
import type { AutocompleteContext, BaseInteractionContext, CommandContext, ComponentContext, MessageInteractionContext, ModalInteractionContext } from "slash-create";

import { displayUser } from "&discord/helpers";
import { channelTypeStrings } from "&discord/constants";

export function logPrefix(ctx: CommandContext | ComponentContext) {
type AnyContext =
| CommandContext
| ComponentContext
| ModalInteractionContext
| AutocompleteContext
| MessageInteractionContext
| BaseInteractionContext

export function logPrefix(ctx: AnyContext) {
const userString = displayUser(ctx.user);
const messagePath = `${ctx.guildID ?? "@me"}/${ctx.channelID}${
"message" in ctx ? `/${ctx.message.id}` : ""
Expand All @@ -28,3 +37,23 @@ export function timeScope(
if (result instanceof Promise) result.then(end);
else end();
}

export const stringResolver = (ctx: BaseInteractionContext, value: unknown) => {
if (typeof value === "string") {
if (ctx.users.has(value)) {
const user = ctx.users.get(value);
return `<${user.bot ? "App" : "User"} | @${displayUser(user)}>`;
}
if (ctx.channels.has(value)) {
const channel = ctx.channels.get(value);
return `<Channel {${ChannelType[channel.type]}} | #${channel.name} (${
channel.id
})>`;
}
if (ctx.roles.has(value)) {
const role = ctx.roles.get(value);
return `<Role | @${role.name} (${role.id}) 🎨 ${role.colorHex}>`;
}
}
return JSON.stringify(value);
};
4 changes: 2 additions & 2 deletions src/modules/docs/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ export class Provider implements ProviderOptions {
})
});

RequestQuota.patch(res.headers);

if (res.status > 400 && res.status < 600) {
console.error(this.label, res.status, res.statusText);
if (res.status === 403) {
Expand All @@ -81,6 +79,8 @@ export class Provider implements ProviderOptions {
}
}

RequestQuota.patch(res.headers);

return res;
}

Expand Down
4 changes: 2 additions & 2 deletions src/modules/docs/version-aggregator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ export default class VersionAggregator {
const res = await this.provider.fetchGitHubAPI(
this.provider.baseStructURL("docs"),
);
if (res.ok) {

if (!res.ok) {
if (res.status === 403) {
const resetHeader = new Date(+res.headers.get('x-ratelimit-reset') * 1000);
if (this.#interval.nextCallAt > resetHeader.getTime())
Expand Down

0 comments on commit 9785cc2

Please sign in to comment.