From a8a89d4b1622544e315f76df098036ccf958a49c Mon Sep 17 00:00:00 2001 From: Jonathan Ho <48591478+H01001000@users.noreply.github.com> Date: Sat, 22 Oct 2022 20:28:33 +0800 Subject: [PATCH] feat(Bigbot): added docker-compose (#2538) * chore: fix script extension * chore: remove extention * fix: at least it run can now * chore: fix dev script * refactor: change to use env file for config * chore: update readme * refactor: put dotenv to top * feat: add docker and influxdb * chore: disable deno fmt on bigbot node_modules * style: deno fmt * style: deno fmt after upgrade deno * chore: remove dev console.log * chore: reverse the influxdb env * chore: limit the influxdb to localhost * refactor: seperate build process * chore: add user pass docs * refactor: route all to handler * fix: skip if webhook not exist * fix: change to use runMethod for send response * chore: gateway don't depend on bot * fix: skip if webhook not exist * fix: first command and error reply not sending * fix: add try catch to error reply * fix: reverse interactive.reply * feat: add fetch analytics to bot process --- deno.json | 3 +- site/docs/amethyst/AmethystCollection.md | 14 +- site/docs/amethyst/AmethystEmbed.md | 14 +- site/docs/amethyst/_category_.json | 2 +- site/docs/amethyst/client.md | 196 +++++++++--------- site/docs/amethyst/exampleBot.md | 147 +++++++------ site/docs/amethyst/intro.md | 6 +- template/bigbot/.env.example | 15 +- template/bigbot/Dockerfile | 33 +++ template/bigbot/README.md | 39 +++- template/bigbot/docker-compose.yml | 32 +++ template/bigbot/nodemon.json | 10 +- template/bigbot/package.json | 2 +- template/bigbot/src/analytics.ts | 56 ++++- template/bigbot/src/bot/bot.ts | 8 +- .../src/bot/events/interactions/command.ts | 60 +++--- template/bigbot/src/bot/index.ts | 40 +--- .../bigbot/src/bot/languages/translate.ts | 3 +- template/bigbot/src/bot/typings/discordeno.ts | 6 +- .../internals/transformers/interaction.ts | 12 +- .../src/bot/utils/slash/createCommand.ts | 152 +++++++------- template/bigbot/src/configs.ts | 4 +- template/bigbot/src/gateway/index.ts | 26 +-- template/bigbot/src/gateway/worker.ts | 5 +- template/bigbot/src/rest/index.ts | 87 ++------ template/bigbot/tsconfig.json | 4 +- 26 files changed, 535 insertions(+), 441 deletions(-) create mode 100644 template/bigbot/Dockerfile create mode 100644 template/bigbot/docker-compose.yml diff --git a/deno.json b/deno.json index cd8863e95..2ebd8fac9 100644 --- a/deno.json +++ b/deno.json @@ -6,7 +6,8 @@ "site/node_modules/", "site/build", "site/.docusaurus", - "site/.cache-loader" + "site/.cache-loader", + "template/bigbot/node_modules" ] }, "options": { diff --git a/site/docs/amethyst/AmethystCollection.md b/site/docs/amethyst/AmethystCollection.md index 59fd0ff76..14e0ddf68 100644 --- a/site/docs/amethyst/AmethystCollection.md +++ b/site/docs/amethyst/AmethystCollection.md @@ -1,7 +1,7 @@ ---- -sidebar_position: 5 ---- - -# Same as discord.js [collection][def] - -[def]: https://discord.js.org/#/docs/collection/main/class/Collection +--- +sidebar_position: 5 +--- + +# Same as discord.js [collection][def] + +[def]: https://discord.js.org/#/docs/collection/main/class/Collection diff --git a/site/docs/amethyst/AmethystEmbed.md b/site/docs/amethyst/AmethystEmbed.md index 45bfd6d36..8a1a68dbf 100644 --- a/site/docs/amethyst/AmethystEmbed.md +++ b/site/docs/amethyst/AmethystEmbed.md @@ -1,7 +1,7 @@ ---- -sidebar_position: 4 ---- - -# Documentation [at][def] - -[def]: https://deno.land/x/amethyst@v4.2.0/mod.ts?s=AmethystEmbed +--- +sidebar_position: 4 +--- + +# Documentation [at][def] + +[def]: https://deno.land/x/amethyst@v4.2.0/mod.ts?s=AmethystEmbed diff --git a/site/docs/amethyst/_category_.json b/site/docs/amethyst/_category_.json index 05b2a8b40..e69147cb1 100644 --- a/site/docs/amethyst/_category_.json +++ b/site/docs/amethyst/_category_.json @@ -1 +1 @@ -{ "label": "Amethyst Framework", "position": 3 } +{ "label": "Amethyst Framework", "position": 3 } diff --git a/site/docs/amethyst/client.md b/site/docs/amethyst/client.md index 39399f28d..cc2fba13d 100644 --- a/site/docs/amethyst/client.md +++ b/site/docs/amethyst/client.md @@ -1,97 +1,99 @@ ---- -sidebar_position: 2 ---- - -# Creating an client - -Let's review each choice and what it does. - -- `owners`, You may specify the proprietors of the bot using this. The inhibitors make use of this. -- `prefix`, The string a user should use at the beginning of their message to identify it as a command to the bot. Only message commands can use this, and the parameter can be either a string or a function. -- `botMentionAsPrefix`, Determines whether a user's mention of a bot qualifies as a prefix. -- `ignoreBots`, Allow bots to execute commands. -- `defaultCooldown`, Defualt cooldown for all commands. -- `ignoreCooldown`, List of people who bypass cooldowns. -- `commandDir`, Path to the command directory used by the fileloader. -- `eventDir`, Path to the event directory used by the fileloader. -- `inhibitorDir`, Path to the inhibitor directory used by the fileloader. -- `prefixCaseSensitive`, Indicates whether or not the prefix is case-sensitive. -- `extras`, Extras that are used by your client, such as a database instance or a music player. - -## Client Extras - -When using discord.js we often do stuff like `client.musicplayer=player;` and in order to maintain this ease Amethyst allows you to do `client.extras.musicplayer=player;`. - -NOTE: Typing will not work on `client.extras`. - -## Client Properties - -```ts - user: User; - events: AmethystEvents; - messageCollectors: AmethystCollection; - componentCollectors: AmethystCollection; - reactionCollectors: AmethystCollection; - runningTasks: runningTasks; - tasks: AmethystCollection; - category: AmethystCollection; - inhibitors: AmethystCollection< - string, - ( - bot: AmethystBot, - command: T, - options: { memberId?: bigint; channelId: bigint; guildId?: bigint } - ) => true | AmethystError - >; - owners?: bigint[]; - botMentionAsPrefix?: boolean; - prefixCaseSensitive?: boolean; - defaultCooldown?: CommandCooldown; - ignoreCooldown?: bigint[]; - guildOnly?: boolean; - messageQuotedArguments?: boolean; - ignoreBots?: boolean; - dmOnly?: boolean; - eventHandler: AmethystEventHandler; - extras: any; - prefix?: - | string - | string[] - | ((bot: AmethystBot, message: Message) => Async); - - on(name: string, callback: (...args: any) => unknown): void; - once(name: string, callback: (...args: any) => unknown): void; - - amethystUtils: { - awaitComponent( - messageId: bigint, - options?: ComponentCollectorOptions & { maxUsage?: number } - ): Promise, - awaitReaction( - messageId: bigint, - options?: ReactionCollectorOptions & { maxUsage?: number } - ): Promise, - awaitMessage( - memberId: bigint, - channelId: bigint, - options?: MessageCollectorOptions & { maxUsage?: number } - ): Promise, - createCommand(command: CommandOptions): void, - createCategory(category: CategoryOptions): void, - updateCategory(category: CategoryOptions): void, - createTask(task: AmethystTask): void, - clearTasks(): void, - createInhibitor( - name: string, - inhibitor: ( - bot: AmethystBot, - command: T, - options?: { memberId?: bigint; guildId?: bigint; channelId: bigint } - ) => true | AmethystError - ): void, - deleteInhibitor(name: string): void, - updateSlashCommands(): void, - } -``` - -## [Documentation](https://deno.land/x/amethyst@v4.2.0/mod.ts?s=AmethystBotOptions) +--- +sidebar_position: 2 +--- + +# Creating an client + +Let's review each choice and what it does. + +- `owners`, You may specify the proprietors of the bot using this. The inhibitors make use of this. +- `prefix`, The string a user should use at the beginning of their message to identify it as a command to the bot. Only + message commands can use this, and the parameter can be either a string or a function. +- `botMentionAsPrefix`, Determines whether a user's mention of a bot qualifies as a prefix. +- `ignoreBots`, Allow bots to execute commands. +- `defaultCooldown`, Defualt cooldown for all commands. +- `ignoreCooldown`, List of people who bypass cooldowns. +- `commandDir`, Path to the command directory used by the fileloader. +- `eventDir`, Path to the event directory used by the fileloader. +- `inhibitorDir`, Path to the inhibitor directory used by the fileloader. +- `prefixCaseSensitive`, Indicates whether or not the prefix is case-sensitive. +- `extras`, Extras that are used by your client, such as a database instance or a music player. + +## Client Extras + +When using discord.js we often do stuff like `client.musicplayer=player;` and in order to maintain this ease Amethyst +allows you to do `client.extras.musicplayer=player;`. + +NOTE: Typing will not work on `client.extras`. + +## Client Properties + +```ts + user: User; + events: AmethystEvents; + messageCollectors: AmethystCollection; + componentCollectors: AmethystCollection; + reactionCollectors: AmethystCollection; + runningTasks: runningTasks; + tasks: AmethystCollection; + category: AmethystCollection; + inhibitors: AmethystCollection< + string, + ( + bot: AmethystBot, + command: T, + options: { memberId?: bigint; channelId: bigint; guildId?: bigint } + ) => true | AmethystError + >; + owners?: bigint[]; + botMentionAsPrefix?: boolean; + prefixCaseSensitive?: boolean; + defaultCooldown?: CommandCooldown; + ignoreCooldown?: bigint[]; + guildOnly?: boolean; + messageQuotedArguments?: boolean; + ignoreBots?: boolean; + dmOnly?: boolean; + eventHandler: AmethystEventHandler; + extras: any; + prefix?: + | string + | string[] + | ((bot: AmethystBot, message: Message) => Async); + + on(name: string, callback: (...args: any) => unknown): void; + once(name: string, callback: (...args: any) => unknown): void; + + amethystUtils: { + awaitComponent( + messageId: bigint, + options?: ComponentCollectorOptions & { maxUsage?: number } + ): Promise, + awaitReaction( + messageId: bigint, + options?: ReactionCollectorOptions & { maxUsage?: number } + ): Promise, + awaitMessage( + memberId: bigint, + channelId: bigint, + options?: MessageCollectorOptions & { maxUsage?: number } + ): Promise, + createCommand(command: CommandOptions): void, + createCategory(category: CategoryOptions): void, + updateCategory(category: CategoryOptions): void, + createTask(task: AmethystTask): void, + clearTasks(): void, + createInhibitor( + name: string, + inhibitor: ( + bot: AmethystBot, + command: T, + options?: { memberId?: bigint; guildId?: bigint; channelId: bigint } + ) => true | AmethystError + ): void, + deleteInhibitor(name: string): void, + updateSlashCommands(): void, + } +``` + +## [Documentation](https://deno.land/x/amethyst@v4.2.0/mod.ts?s=AmethystBotOptions) diff --git a/site/docs/amethyst/exampleBot.md b/site/docs/amethyst/exampleBot.md index 758310b04..d1e9437e3 100644 --- a/site/docs/amethyst/exampleBot.md +++ b/site/docs/amethyst/exampleBot.md @@ -1,77 +1,70 @@ ---- -sidebar_position: 3 ---- - -# Lets Create a simple bot in Node.js - -- **Step 1**: Create a typescript project with index.ts as main file. - -- **Step 2**: Installing packages. -Install following packages. - -```bash -npm i @thereallonewolf/amethystframework -``` - -- **Step 3**: Create a index.ts file. - -- **Step 4**: Add following code in index.ts file, replacing TOKEN with your bot token. - -```ts -import { ActivityTypes, Bot, createBot,GatewayIntents,startBot } from "discordeno"; -import { enableCachePlugin, enableCacheSweepers } from "discordeno/cache-plugin"; -import { - AmethystBot, - Context, - enableAmethystPlugin, -} from "@thereallonewolf/amethystframework"; - - -config(); -let baseClient = createBot({ - token: "TOKEN", - intents: GatewayIntents.Guilds | GatewayIntents.GuildMessages | GatewayIntents.MessageContent, -}); - -//@ts-ignore -let client = enableAmethystPlugin(enableCachePlugin(baseClient), { - botMentionAsPrefix: true, - prefix: "!",//Can be a function or a string. - ignoreBots: false, -}); -enableCacheSweepers(client); - - -client.on("ready", () => { - console.log("I am up and running"); -}); - -client.amethystUtils.createCategory({ - name: "general", - description: "My general commands", - uniqueCommands: true, - default: "", -}); -client.amethystUtils.createCommand({ - name: "ping", - description: "Pong!", - commandType: ["application", "message"], - category: "general", - args: [], - async execute(bot: AmethystBot, ctx: Context) { - ctx.reply({content:"Pong!"}); - }, -}); - -client.amethystUtils.updateSlashCommands(); -startBot(client); -``` - -- **Step 5**: Invite your bot and compile index.ts and run it. -Then you can use `/general ping` or `!ping` - -- **Step 6**: Useful links: - -1. Command Options can be found [here](https://github.com/AmethystFramework/framework/blob/master/src/types/commandOptions.ts). -2. Category Options [here](https://github.com/AmethystFramework/framework/blob/master/src/types/categoryOptions.ts) -3. Full [Documentation](https://deno.land/x/amethyst) +--- +sidebar_position: 3 +--- + +# Lets Create a simple bot in Node.js + +- **Step 1**: Create a typescript project with index.ts as main file. + +- **Step 2**: Installing packages. Install following packages. + +```bash +npm i @thereallonewolf/amethystframework +``` + +- **Step 3**: Create a index.ts file. + +- **Step 4**: Add following code in index.ts file, replacing TOKEN with your bot token. + +```ts +import { ActivityTypes, Bot, createBot, GatewayIntents, startBot } from "discordeno"; +import { enableCachePlugin, enableCacheSweepers } from "discordeno/cache-plugin"; +import { AmethystBot, Context, enableAmethystPlugin } from "@thereallonewolf/amethystframework"; + +config(); +let baseClient = createBot({ + token: "TOKEN", + intents: GatewayIntents.Guilds | GatewayIntents.GuildMessages | GatewayIntents.MessageContent, +}); + +//@ts-ignore +let client = enableAmethystPlugin(enableCachePlugin(baseClient), { + botMentionAsPrefix: true, + prefix: "!", //Can be a function or a string. + ignoreBots: false, +}); +enableCacheSweepers(client); + +client.on("ready", () => { + console.log("I am up and running"); +}); + +client.amethystUtils.createCategory({ + name: "general", + description: "My general commands", + uniqueCommands: true, + default: "", +}); +client.amethystUtils.createCommand({ + name: "ping", + description: "Pong!", + commandType: ["application", "message"], + category: "general", + args: [], + async execute(bot: AmethystBot, ctx: Context) { + ctx.reply({ content: "Pong!" }); + }, +}); + +client.amethystUtils.updateSlashCommands(); +startBot(client); +``` + +- **Step 5**: Invite your bot and compile index.ts and run it. Then you can use `/general ping` or `!ping` + +- **Step 6**: Useful links: + +1. Command Options can be found + [here](https://github.com/AmethystFramework/framework/blob/master/src/types/commandOptions.ts). +2. Category Options [here](https://github.com/AmethystFramework/framework/blob/master/src/types/categoryOptions.ts) +3. Full [Documentation](https://deno.land/x/amethyst) diff --git a/site/docs/amethyst/intro.md b/site/docs/amethyst/intro.md index f8b18e02e..174d5e428 100644 --- a/site/docs/amethyst/intro.md +++ b/site/docs/amethyst/intro.md @@ -7,8 +7,8 @@ sidebar_position: 1 Amethyst is a [Discordeno](https://github.com/discordeno/discordeno) plugin that is incredibly robust and flexible. It promotes standard practices and is geared at bigger bots. -This framework is not for you if you cannot utilise Maps and Sets without reading them up. We -presume you have a solid foundation in typescript/javascript and dicord bots. +This framework is not for you if you cannot utilise Maps and Sets without reading them up. We presume you have a solid +foundation in typescript/javascript and dicord bots. [Documentation](https://deno.land/x/amethyst) @@ -50,5 +50,5 @@ Deno: [link](https://deno.land/x/amethyst) Npm: ```bash - npm i @thereallonewolf/amethystframework +npm i @thereallonewolf/amethystframework ``` diff --git a/template/bigbot/.env.example b/template/bigbot/.env.example index 6f538a571..2f99c8987 100644 --- a/template/bigbot/.env.example +++ b/template/bigbot/.env.example @@ -19,7 +19,7 @@ DISCORD_TOKEN= # Bot Configurations # The secret passcode that the bot code (event handler) is listening for. This is used to prevent someone else from trying to send malicious messages to your bot. */ # SETUP-DD-TEMP: Add a secret passcode here. -EVENT_HANDLER_AUTHORIZATION=server +EVENT_HANDLER_AUTHORIZATION=SuperSecretPassword # The host where the event handler will run. Must follow https:#nodejs.org/api/net.html#serverlistenoptions-callback. */ # SETUP-DD-TEMP: Set the event handler's host here. @@ -40,7 +40,7 @@ BUGS_ERRORS_REPORT_WEBHOOK= # Rest Proxy Configurations # The authorization code that the REST proxy will check for to make sure the requests are coming from you. */ # SETUP-DD-TEMP: Add a secret passcode here. -REST_AUTHORIZATION=secret +REST_AUTHORIZATION=password123 # The host where the REST proxy will run. Must follow https:#nodejs.org/api/net.html#serverlistenoptions-callback. */ # SETUP-DD-TEMP: Set the REST proxy's host here. @@ -80,7 +80,14 @@ GATEWAY_PORT=8080 # These INFLUX configs are only if you wish to enable analytics. */ # SETUP-DD-TEMP: This is optional. If you want to build analytics, add influxdb here. -INFLUX_BUCKET= INFLUX_ORG= +INFLUX_BUCKET= INFLUX_TOKEN= -INFLUX_URL= +INFLUX_URL=http://influxdb:8086 + +DOCKER_INFLUXDB_INIT_MODE=setup +DOCKER_INFLUXDB_INIT_USERNAME=skillz +DOCKER_INFLUXDB_INIT_PASSWORD=ILoveskillz +DOCKER_INFLUXDB_INIT_ORG=discordeno +DOCKER_INFLUXDB_INIT_BUCKET=discordeno +DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=skillzPrefersID diff --git a/template/bigbot/Dockerfile b/template/bigbot/Dockerfile new file mode 100644 index 000000000..a12106ebc --- /dev/null +++ b/template/bigbot/Dockerfile @@ -0,0 +1,33 @@ +FROM node:16.18.0-alpine3.16 AS deps +WORKDIR /app +COPY package.json package-lock.json .swcrc ./ +RUN npm install + +FROM node:16.18.0-alpine3.16 as rest +COPY --from=deps /app /app +WORKDIR /app +COPY src/analytics.ts src/configs.ts src/ +COPY src/rest src/rest +RUN npm run build +EXPOSE 8000 +CMD ["npm","run","startr"] + +FROM node:16.18.0-alpine3.16 as gateway +COPY --from=deps /app /app +WORKDIR /app +COPY src/configs.ts src/ +COPY src/gateway src/gateway +RUN npm run build +EXPOSE 8080 +CMD ["npm","run","startg"] + +FROM node:16.18.0-alpine3.16 as bot +COPY --from=deps /app /app +WORKDIR /app +COPY prisma prisma +COPY node_modules/.prisma/client node_modules/.prisma/client +COPY src/analytics.ts src/prisma.ts src/configs.ts src/ +COPY src/bot src/bot +RUN npm run build +EXPOSE 8080 +CMD ["npm","run","startb"] diff --git a/template/bigbot/README.md b/template/bigbot/README.md index 7c71c117a..baf8d26df 100644 --- a/template/bigbot/README.md +++ b/template/bigbot/README.md @@ -14,14 +14,43 @@ Make sure to install the latest version when you use it. ## Startup -To start your bot, you will need to start a few processes. The instructions below will use `node` but you can use -something like `pm2` to help keep your processes alive. +There are two ways to start your bot, using docker and node. Using docker will be the simplest and easiest way to start +your bot. The default configuation will be set for Docker. -Please compile everything first with `npm run build`. +### Using Docker + +The docker compose file include the discordeno bot and influxdb, this would create an enviroment more close to the +production enviroment. + +First, rename the .env.example file to .env, and set the discord token and your dev guild id, change the `REST_URL` to +`rest` and `EVENT_HANDLER_URL` to `bot`, copy the value of `DOCKER_INFLUXDB_INIT_xxxx` to `INFLUX_xxxx` + +Then, run ... to build/rebuild the bot + +- `docker-compose build` + +And, run ... to start + +- `docker-compose up -d` + +Your bot should be running now, and you can check the rest process fetch analytics in influxdb's webgui - + with the username and password in the .env file. + +### Using Node + +you will need to start a few processes. The instructions below will use `node` but you can use something like `pm2` to +help keep your processes alive. + +First, rename the .env.example file to .env, and set the discord token and your dev guild id, change the `REST_URL` and +`EVENT_HANDLER_URL` to `localhost`, change value of `INFLUX_xxxx` to your influxdb config + +Then compile everything with `npm run build`. + +After that, you can start your bot one by one with the following order. - Start REST - `npm run startr` -- Start Gateway - - `npm run startg` - Start Bot - `npm run startb` +- Start Gateway + - `npm run startg` diff --git a/template/bigbot/docker-compose.yml b/template/bigbot/docker-compose.yml new file mode 100644 index 000000000..eb831b769 --- /dev/null +++ b/template/bigbot/docker-compose.yml @@ -0,0 +1,32 @@ +version: '3.8' +services: + influxdb: + image: "influxdb:2.4.0-alpine" + ports: + - 127.0.0.1:8086:8086 + env_file: + - .env + rest: + build: + context: . + target: rest + depends_on: + - influxdb + env_file: + - .env + gateway: + build: + context: . + target: gateway + depends_on: + - rest + env_file: + - .env + bot: + build: + context: . + target: bot + depends_on: + - rest + env_file: + - .env \ No newline at end of file diff --git a/template/bigbot/nodemon.json b/template/bigbot/nodemon.json index 7cc03a26e..b8a6dff89 100644 --- a/template/bigbot/nodemon.json +++ b/template/bigbot/nodemon.json @@ -1,6 +1,6 @@ { - "watch": "./src/**/*.ts", - "ext ": "env,ts", - "signal": "SIGKILL", - "exec": "npm run build && node --experimental-specifier-resolution=node" -} \ No newline at end of file + "watch": "./src/**/*.ts", + "ext ": "env,ts", + "signal": "SIGKILL", + "exec": "npm run build && node --experimental-specifier-resolution=node" +} diff --git a/template/bigbot/package.json b/template/bigbot/package.json index 219118e4f..518583708 100644 --- a/template/bigbot/package.json +++ b/template/bigbot/package.json @@ -47,4 +47,4 @@ "semi": true, "printWidth": 120 } -} \ No newline at end of file +} diff --git a/template/bigbot/src/analytics.ts b/template/bigbot/src/analytics.ts index a2018e257..cb383debf 100644 --- a/template/bigbot/src/analytics.ts +++ b/template/bigbot/src/analytics.ts @@ -1,9 +1,55 @@ -import { InfluxDB } from "@influxdata/influxdb-client"; +import { InfluxDB, Point } from "@influxdata/influxdb-client"; +import { RestManager } from "discordeno/rest"; -const INFLUX_BUCKET = process.env.INFLUX_BUCKET as string -const INFLUX_ORG = process.env.INFLUX_ORG as string -const INFLUX_TOKEN = process.env.INFLUX_TOKEN as string -const INFLUX_URL = process.env.INFLUX_URL as string +const INFLUX_ORG = process.env.INFLUX_ORG as string; +const INFLUX_BUCKET = process.env.INFLUX_BUCKET as string; +const INFLUX_TOKEN = process.env.INFLUX_TOKEN as string; +const INFLUX_URL = process.env.INFLUX_URL as string; export const influxDB = INFLUX_URL && INFLUX_TOKEN ? new InfluxDB({ url: INFLUX_URL, token: INFLUX_TOKEN }) : undefined; export const Influx = influxDB?.getWriteApi(INFLUX_ORG, INFLUX_BUCKET); + +export const setupAnalyticsHooks = (rest: RestManager) => { + // If influxdb data is provided, enable analytics in this proxy. + if (Influx) { + rest.fetching = function (options) { + Influx?.writePoint( + new Point("restEvents") + // MARK THE TIME WHEN EVENT ARRIVED + .timestamp(new Date()) + // SET THE GUILD ID + .stringField("type", "REQUEST_FETCHING") + .tag("method", options.method) + .tag("url", options.url) + .tag("bucket", options.bucketId ?? "NA"), + ); + }; + + rest.fetched = function (options, response) { + Influx?.writePoint( + new Point("restEvents") + // MARK THE TIME WHEN EVENT ARRIVED + .timestamp(new Date()) + // SET THE GUILD ID + .stringField("type", "REQUEST_FETCHED") + .tag("method", options.method) + .tag("url", options.url) + .tag("bucket", options.bucketId ?? "NA") + .intField("status", response.status) + .tag("statusText", response.statusText), + ); + }; + + setInterval(() => { + console.log(`[Influx - REST] Saving events...`); + Influx?.flush() + .then(() => { + console.log(`[Influx - REST] Saved events!`); + }) + .catch((error) => { + console.log(`[Influx - REST] Error saving events!`, error); + }); + // Every 30seconds + }, 30000); + } +}; diff --git a/template/bigbot/src/bot/bot.ts b/template/bigbot/src/bot/bot.ts index f6773f62d..b802576a7 100644 --- a/template/bigbot/src/bot/bot.ts +++ b/template/bigbot/src/bot/bot.ts @@ -1,13 +1,14 @@ import { Bot, Collection, createBot, createRestManager } from "discordeno"; import enableHelpersPlugin from "discordeno/helpers-plugin"; import { createLogger } from "discordeno/logger"; +import { setupAnalyticsHooks } from "../analytics"; import { INTENTS, REST_URL } from "../configs"; import { setupEventHandlers } from "./events/mod"; import { MessageCollector } from "./utils/collectors"; import { customizeInternals } from "./utils/internals/mod"; -const DISCORD_TOKEN = process.env.DISCORD_TOKEN as string -const REST_AUTHORIZATION = process.env.REST_AUTHORIZATION as string +const DISCORD_TOKEN = process.env.DISCORD_TOKEN as string; +const REST_AUTHORIZATION = process.env.REST_AUTHORIZATION as string; export const bot = enableHelpersPlugin( customizeBot( @@ -56,3 +57,6 @@ bot.rest = createRestManager({ secretKey: REST_AUTHORIZATION, customUrl: REST_URL, }); + +// Add send fetching analytics hook to rest +setupAnalyticsHooks(bot.rest); diff --git a/template/bigbot/src/bot/events/interactions/command.ts b/template/bigbot/src/bot/events/interactions/command.ts index 903579cf1..6c6c6eec5 100644 --- a/template/bigbot/src/bot/events/interactions/command.ts +++ b/template/bigbot/src/bot/events/interactions/command.ts @@ -10,7 +10,7 @@ import { InteractionResponseTypes, Member, Role, - User + User, } from "discordeno"; import { bot, BotWithCustomProps } from "../../bot.js"; import COMMANDS from "../../commands/mod.js"; @@ -23,10 +23,11 @@ function logCommand( type: "Failure" | "Success" | "Trigger" | "Slowmode" | "Missing" | "Inhibit", commandName: string, ) { - const command = `[COMMAND: ${bgYellow(black(commandName || "Unknown"))} - ${bgBlack( - ["Failure", "Slowmode", "Missing"].includes(type) ? red(type) : type === "Success" ? green(type) : white(type), - ) - }]`; + const command = `[COMMAND: ${bgYellow(black(commandName || "Unknown"))} - ${ + bgBlack( + ["Failure", "Slowmode", "Missing"].includes(type) ? red(type) : type === "Success" ? green(type) : white(type), + ) + }]`; const user = bgGreen( black(`${info.user.username}#${info.user.discriminator.toString().padStart(4, "0")}(${info.id})`), @@ -58,9 +59,10 @@ export async function executeSlashCommand(bot: BotWithCustomProps, interaction: // Load the language for this guild if (interaction.guildId && !serverLanguages.has(interaction.guildId)) { - await interaction.reply({ - type: InteractionResponseTypes.DeferredChannelMessageWithSource, - }); + // Todo: make command.execute reply change to editReply after running this + // await interaction.reply({ + // type: InteractionResponseTypes.DeferredChannelMessageWithSource, + // }); await loadLanguage(interaction.guildId); } // Load the language for this guild else if (command.acknowledge) { @@ -84,7 +86,15 @@ export async function executeSlashCommand(bot: BotWithCustomProps, interaction: console.error(error); logCommand(interaction, "Failure", name); - return await interaction.reply(translate(interaction.id, "EXECUTE_COMMAND_ERROR")).catch(bot.logger.error); + try { + console.log("try"); + // try to reply the interaction, becuase we don't know if it replied or deffered + return await interaction.reply(translate(interaction.id, "EXECUTE_COMMAND_ERROR")); + } catch { + console.log("catch"); + // edit the reply or deffered reply of interaction + return await interaction.editReply(translate(interaction.id, "EXECUTE_COMMAND_ERROR")).catch(bot.logger.error); + } } } @@ -149,21 +159,21 @@ function convertOptionValue( option: InteractionDataOption, translateOptions?: Record, ): [ - string, - ( - | { user: User; member: Member } - | Role - | { - id: bigint; - name: string; - type: ChannelTypes; - permissions: bigint; - } - | boolean - | string - | number - ), - ] { + string, + ( + | { user: User; member: Member } + | Role + | { + id: bigint; + name: string; + type: ChannelTypes; + permissions: bigint; + } + | boolean + | string + | number + ), +] { // THE OPTION IS A CHANNEL if (option.type === ApplicationCommandOptionTypes.Channel) { const channel = interaction.data?.resolved?.channels?.get(BigInt(option.value as string)); @@ -269,7 +279,7 @@ export function optionParser( [translateOptions?.[interaction.data.options[0].name] ?? interaction.data.options[0].name]: { [ translateOptions?.[interaction.data.options[0]!.options![0]!.name] ?? - interaction.data.options[0]!.options![0]!.name + interaction.data.options[0]!.options![0]!.name ]: convertedOptions, }, }; diff --git a/template/bigbot/src/bot/index.ts b/template/bigbot/src/bot/index.ts index 64acf4266..4405bb667 100644 --- a/template/bigbot/src/bot/index.ts +++ b/template/bigbot/src/bot/index.ts @@ -1,22 +1,23 @@ +import dotenv from "dotenv"; +dotenv.config(); + import { DiscordGatewayPayload } from "discordeno"; // ReferenceError: publishMessage is not defined // import Embeds from "discordeno/embeds"; -import dotenv from 'dotenv'; import express from "express"; import { BOT_ID, EVENT_HANDLER_URL } from "../configs.js"; import { bot } from "./bot.js"; import { updateDevCommands } from "./utils/slash/updateCommands.js"; import { webhookURLToIDAndToken } from "./utils/webhook.js"; -dotenv.config() - -const BUGS_ERRORS_REPORT_WEBHOOK = process.env.BUGS_ERRORS_REPORT_WEBHOOK as string -const DEVELOPMENT = process.env.DEVELOPMENT as string -const EVENT_HANDLER_AUTHORIZATION = process.env.EVENT_HANDLER_AUTHORIZATION as string -const EVENT_HANDLER_PORT = process.env.EVENT_HANDLER_PORT as string +const BUGS_ERRORS_REPORT_WEBHOOK = process.env.BUGS_ERRORS_REPORT_WEBHOOK; +const DEVELOPMENT = process.env.DEVELOPMENT as string; +const EVENT_HANDLER_AUTHORIZATION = process.env.EVENT_HANDLER_AUTHORIZATION as string; +const EVENT_HANDLER_PORT = process.env.EVENT_HANDLER_PORT as string; process .on("unhandledRejection", (error) => { + if (!BUGS_ERRORS_REPORT_WEBHOOK) return; const { id, token } = webhookURLToIDAndToken(BUGS_ERRORS_REPORT_WEBHOOK); if (!id || !token) return; @@ -42,6 +43,7 @@ process */ }) .on("uncaughtException", async (error) => { + if (!BUGS_ERRORS_REPORT_WEBHOOK) return; const { id, token } = webhookURLToIDAndToken(BUGS_ERRORS_REPORT_WEBHOOK); if (!id || !token) return; @@ -82,27 +84,7 @@ app.use( app.use(express.json()); -app.post("/", async (req, res) => { - handleRequest(req, res); -}); - -app.put("/", async (req, res) => { - handleRequest(req, res); -}); - -app.patch("/", async (req, res) => { - handleRequest(req, res); -}); - -app.delete("/", async (req, res) => { - handleRequest(req, res); -}); - -app.get("/", async (req, res) => { - handleRequest(req, res); -}); - -async function handleRequest(req: express.Request, res: express.Response) { +app.all("/", async (req, res) => { try { if (!EVENT_HANDLER_AUTHORIZATION || EVENT_HANDLER_AUTHORIZATION !== req.headers.authorization) { return res.status(401).json({ error: "Invalid authorization key." }); @@ -130,7 +112,7 @@ async function handleRequest(req: express.Request, res: express.Response) { bot.logger.error(error); res.status(error.code).json(error); } -} +}); app.listen(EVENT_HANDLER_PORT, () => { console.log(`Bot is listening at ${EVENT_HANDLER_URL};`); diff --git a/template/bigbot/src/bot/languages/translate.ts b/template/bigbot/src/bot/languages/translate.ts index 5c0c8a100..4ec2e05d0 100644 --- a/template/bigbot/src/bot/languages/translate.ts +++ b/template/bigbot/src/bot/languages/translate.ts @@ -4,7 +4,7 @@ import { webhookURLToIDAndToken } from "../utils/webhook.js"; import english from "./english.js"; import languages from "./languages.js"; -const MISSING_TRANSLATION_WEBHOOK = process.env.MISSING_TRANSLATION_WEBHOOK as string; +const MISSING_TRANSLATION_WEBHOOK = process.env.MISSING_TRANSLATION_WEBHOOK; /** This should hold the language names per guild id. */ export const serverLanguages = new Map(); @@ -57,6 +57,7 @@ export async function loadLanguage(guildId: bigint) { /** Send a webhook for a missing translation key */ export async function missingTranslation(language: keyof typeof languages, key: string) { + if (!MISSING_TRANSLATION_WEBHOOK) return; const { id, token } = webhookURLToIDAndToken(MISSING_TRANSLATION_WEBHOOK); if (!id || !token) return; diff --git a/template/bigbot/src/bot/typings/discordeno.ts b/template/bigbot/src/bot/typings/discordeno.ts index ef559bf80..fc2a5e6f5 100644 --- a/template/bigbot/src/bot/typings/discordeno.ts +++ b/template/bigbot/src/bot/typings/discordeno.ts @@ -1,5 +1,5 @@ // This file allows you to tell typescript about any additions you have made to the internal discordeno objects. -import { Interaction, InteractionResponse, Message } from "discordeno"; +import { Interaction, InteractionCallbackData, InteractionResponse, Message } from "discordeno"; export interface InteractionWithCustomProps extends Interaction { // Normally, to send a response you would have to do something like bot.helpers.sendInteractionResponse(interaction.id, interaction.token, { type: InteractionResponseTypes.ChannelMessageWithSource, data: { content: "text here" } }) @@ -7,4 +7,6 @@ export interface InteractionWithCustomProps extends Interaction { // Feel free to delete these comments once you have understood the concept. /** Send a reply to an interaction. */ reply(response: InteractionResponse | string): Promise; -} \ No newline at end of file + /** Edit a deferred reply of an interaction. */ + editReply(response: InteractionCallbackData | string): Promise; +} diff --git a/template/bigbot/src/bot/utils/internals/transformers/interaction.ts b/template/bigbot/src/bot/utils/internals/transformers/interaction.ts index 768c12eae..87299a26f 100644 --- a/template/bigbot/src/bot/utils/internals/transformers/interaction.ts +++ b/template/bigbot/src/bot/utils/internals/transformers/interaction.ts @@ -1,5 +1,5 @@ // SETUP-DD-TEMP: This file serves as an example, of how to customize internal discordeno objects. Feel free to use, add more or remove as desired. -import { InteractionResponse, InteractionResponseTypes } from "discordeno"; +import { InteractionCallbackData, InteractionResponse, InteractionResponseTypes } from "discordeno"; import { BotWithCustomProps } from "../../../bot.js"; export function customizeInteractionTransformer(bot: BotWithCustomProps) { @@ -17,9 +17,19 @@ export function customizeInteractionTransformer(bot: BotWithCustomProps) { if (typeof response === "string") { response = { type: InteractionResponseTypes.ChannelMessageWithSource, data: { content: response } }; } + return bot.helpers.sendInteractionResponse(interaction.id, interaction.token, response); }, }); + Object.defineProperty(interaction, "editReply", { + value: function (response: InteractionCallbackData | string) { + if (typeof response === "string") { + response = { content: response }; + } + + return bot.helpers.editOriginalInteractionResponse(interaction.token, response); + }, + }); // Add as many properties or methods you would like here. // NOTE: Whenever you add anything here, in order to get nice autocomplete you should also add it to the src/types/discordeno.ts file. diff --git a/template/bigbot/src/bot/utils/slash/createCommand.ts b/template/bigbot/src/bot/utils/slash/createCommand.ts index 74ec36817..6f0f8b500 100644 --- a/template/bigbot/src/bot/utils/slash/createCommand.ts +++ b/template/bigbot/src/bot/utils/slash/createCommand.ts @@ -7,7 +7,7 @@ import { Member, PermissionStrings, Role, - User + User, } from "discordeno"; import english from "../../languages/english.js"; import { translationKeys } from "../../languages/translate.js"; @@ -157,79 +157,79 @@ export type ConvertArgumentDefinitionsToArgs // STRING - ? { - // @ts-ignore TODO: fix this some day - [_ in getName]?: T[P]["choices"] extends readonly { name: string; value: string }[] // @ts-ignore - ? T[P]["choices"][number]["value"] - : string; - } - : T[P] extends StringArgumentDefinition ? { - // @ts-ignore TODO: fix this some day - [_ in getName]: T[P]["choices"] extends readonly { name: string; value: string }[] // @ts-ignore - ? T[P]["choices"][number]["value"] - : string; - } - // INTEGER - : T[P] extends IntegerOptionalArgumentDefinition ? { - [_ in getName]?: T[P]["choices"] extends readonly { name: string; value: number }[] // @ts-ignore - ? T[P]["choices"][number]["value"] - : number; - } - : T[P] extends IntegerArgumentDefinition ? { - [_ in getName]: T[P]["choices"] extends readonly { name: string; value: number }[] // @ts-ignore - ? T[P]["choices"][number]["value"] - : number; - } - // BOOLEAN - : T[P] extends BooleanOptionalArgumentDefinition ? { [_ in getName]?: boolean } - : T[P] extends BooleanArgumentDefinition ? { [_ in getName]: boolean } - // USER - : T[P] extends UserOptionalArgumentDefinition ? { - [_ in getName]?: { - user: User; - member: Member; - }; - } - : T[P] extends UserArgumentDefinition ? { - [_ in getName]: { - user: User; - member: Member; - }; - } - // CHANNEL - : T[P] extends ChannelOptionalArgumentDefinition ? { [_ in getName]?: Channel } - : T[P] extends ChannelArgumentDefinition ? { [_ in getName]: Channel } - // ROLE - : T[P] extends RoleOptionalArgumentDefinition ? { [_ in getName]?: Role } - : T[P] extends RoleArgumentDefinition ? { [_ in getName]: Role } - // MENTIONABLE - : T[P] extends MentionableOptionalArgumentDefinition ? { - [_ in getName]?: - | Role - | { - user: User; - member: Member; - }; - } - : T[P] extends MentionableArgumentDefinition ? { - [_ in getName]: - | Role - | { - user: User; - member: Member; - }; - } - // SUBCOMMAND - : T[P] extends SubcommandArgumentDefinition ? { - [_ in getName]?: T[P]["options"] extends readonly ArgumentDefinition[] // @ts-ignore somehow this check does not work - ? ConvertArgumentDefinitionsToArgs - : {}; - } - // SUBCOMMANDGROUP - : T[P] extends SubcommandGroupArgumentDefinition ? { - [_ in getName]?: ConvertArgumentDefinitionsToArgs; - } - : never; + ? { + // @ts-ignore TODO: fix this some day + [_ in getName]?: T[P]["choices"] extends readonly { name: string; value: string }[] // @ts-ignore + ? T[P]["choices"][number]["value"] + : string; + } + : T[P] extends StringArgumentDefinition ? { + // @ts-ignore TODO: fix this some day + [_ in getName]: T[P]["choices"] extends readonly { name: string; value: string }[] // @ts-ignore + ? T[P]["choices"][number]["value"] + : string; + } + // INTEGER + : T[P] extends IntegerOptionalArgumentDefinition ? { + [_ in getName]?: T[P]["choices"] extends readonly { name: string; value: number }[] // @ts-ignore + ? T[P]["choices"][number]["value"] + : number; + } + : T[P] extends IntegerArgumentDefinition ? { + [_ in getName]: T[P]["choices"] extends readonly { name: string; value: number }[] // @ts-ignore + ? T[P]["choices"][number]["value"] + : number; + } + // BOOLEAN + : T[P] extends BooleanOptionalArgumentDefinition ? { [_ in getName]?: boolean } + : T[P] extends BooleanArgumentDefinition ? { [_ in getName]: boolean } + // USER + : T[P] extends UserOptionalArgumentDefinition ? { + [_ in getName]?: { + user: User; + member: Member; + }; + } + : T[P] extends UserArgumentDefinition ? { + [_ in getName]: { + user: User; + member: Member; + }; + } + // CHANNEL + : T[P] extends ChannelOptionalArgumentDefinition ? { [_ in getName]?: Channel } + : T[P] extends ChannelArgumentDefinition ? { [_ in getName]: Channel } + // ROLE + : T[P] extends RoleOptionalArgumentDefinition ? { [_ in getName]?: Role } + : T[P] extends RoleArgumentDefinition ? { [_ in getName]: Role } + // MENTIONABLE + : T[P] extends MentionableOptionalArgumentDefinition ? { + [_ in getName]?: + | Role + | { + user: User; + member: Member; + }; + } + : T[P] extends MentionableArgumentDefinition ? { + [_ in getName]: + | Role + | { + user: User; + member: Member; + }; + } + // SUBCOMMAND + : T[P] extends SubcommandArgumentDefinition ? { + [_ in getName]?: T[P]["options"] extends readonly ArgumentDefinition[] // @ts-ignore somehow this check does not work + ? ConvertArgumentDefinitionsToArgs + : {}; + } + // SUBCOMMANDGROUP + : T[P] extends SubcommandGroupArgumentDefinition ? { + [_ in getName]?: ConvertArgumentDefinitionsToArgs; + } + : never; }[number] > >; @@ -273,8 +273,8 @@ export interface Command { acknowledge?: boolean; permissionLevels?: - | (keyof typeof PermissionLevelHandlers)[] - | ((data: Interaction, command: Command) => boolean | Promise); + | (keyof typeof PermissionLevelHandlers)[] + | ((data: Interaction, command: Command) => boolean | Promise); botServerPermissions?: PermissionStrings[]; botChannelPermissions?: PermissionStrings[]; userServerPermissions?: PermissionStrings[]; diff --git a/template/bigbot/src/configs.ts b/template/bigbot/src/configs.ts index d96ac073f..f9bc3a955 100644 --- a/template/bigbot/src/configs.ts +++ b/template/bigbot/src/configs.ts @@ -1,6 +1,6 @@ import { getBotIdFromToken, Intents } from "discordeno"; -import dotenv from 'dotenv'; -dotenv.config() +import dotenv from "dotenv"; +dotenv.config(); /** The bot id, derived from the bot token. */ export const BOT_ID = getBotIdFromToken(process.env.DISCORD_TOKEN as string); diff --git a/template/bigbot/src/gateway/index.ts b/template/bigbot/src/gateway/index.ts index 956aba051..43dae81f8 100644 --- a/template/bigbot/src/gateway/index.ts +++ b/template/bigbot/src/gateway/index.ts @@ -1,3 +1,6 @@ +import dotenv from "dotenv"; +dotenv.config(); + import { Collection, createBot, createGatewayManager, createRestManager } from "discordeno"; import { createLogger } from "discordeno/logger"; import fastify from "fastify"; @@ -6,18 +9,15 @@ import { Worker } from "worker_threads"; import { EVENT_HANDLER_URL, INTENTS, REST_URL } from "../configs.js"; import { WorkerCreateData, WorkerGetShardInfo, WorkerMessage, WorkerShardInfo, WorkerShardPayload } from "./worker"; -import dotenv from "dotenv"; -dotenv.config() - -const DISCORD_TOKEN = process.env.DISCORD_TOKEN as string -const EVENT_HANDLER_AUTHORIZATION = process.env.EVENT_HANDLER_AUTHORIZATION as string -const GATEWAY_AUTHORIZATION = process.env.GATEWAY_AUTHORIZATION as string -const GATEWAY_HOST = process.env.GATEWAY_HOST as string -const GATEWAY_PORT = Number(process.env.GATEWAY_PORT as string) -const REST_AUTHORIZATION = process.env.REST_AUTHORIZATION as string -const SHARDS_PER_WORKER = Number(process.env.SHARDS_PER_WORKER as string) -const TOTAL_SHARDS = process.env.TOTAL_SHARDS ? Number(process.env.TOTAL_SHARDS) : undefined -const TOTAL_WORKERS = Number(process.env.TOTAL_WORKERS as string) +const DISCORD_TOKEN = process.env.DISCORD_TOKEN as string; +const EVENT_HANDLER_AUTHORIZATION = process.env.EVENT_HANDLER_AUTHORIZATION as string; +const GATEWAY_AUTHORIZATION = process.env.GATEWAY_AUTHORIZATION as string; +const GATEWAY_HOST = process.env.GATEWAY_HOST as string; +const GATEWAY_PORT = Number(process.env.GATEWAY_PORT as string); +const REST_AUTHORIZATION = process.env.REST_AUTHORIZATION as string; +const SHARDS_PER_WORKER = Number(process.env.SHARDS_PER_WORKER as string); +const TOTAL_SHARDS = process.env.TOTAL_SHARDS ? Number(process.env.TOTAL_SHARDS) : undefined; +const TOTAL_WORKERS = Number(process.env.TOTAL_WORKERS as string); async function main() { const log = createLogger({ name: "[MANAGER]" }); @@ -45,7 +45,7 @@ async function main() { shardsPerWorker: SHARDS_PER_WORKER, totalWorkers: TOTAL_WORKERS, - handleDiscordPayload: () => { }, + handleDiscordPayload: () => {}, tellWorkerToIdentify: async (_gateway, workerId, shardId, _bucketId) => { log.info("TELL TO IDENTIFY", { workerId, shardId, _bucketId }); diff --git a/template/bigbot/src/gateway/worker.ts b/template/bigbot/src/gateway/worker.ts index ab362f3f8..15953280b 100644 --- a/template/bigbot/src/gateway/worker.ts +++ b/template/bigbot/src/gateway/worker.ts @@ -1,3 +1,6 @@ +import dotenv from "dotenv"; +dotenv.config(); + import { createShardManager, DiscordGuild, @@ -6,7 +9,7 @@ import { GatewayEventNames, Shard, ShardSocketRequest, - ShardState + ShardState, } from "discordeno"; import { createLogger } from "discordeno/logger"; import fetch from "node-fetch"; diff --git a/template/bigbot/src/rest/index.ts b/template/bigbot/src/rest/index.ts index 661055c81..7613c61dd 100644 --- a/template/bigbot/src/rest/index.ts +++ b/template/bigbot/src/rest/index.ts @@ -1,15 +1,14 @@ -import { Point } from "@influxdata/influxdb-client"; -import { BASE_URL, createRestManager } from "discordeno"; -import express, { Request, Response } from "express"; -import { Influx } from "../analytics"; -import { REST_URL } from '../configs'; - import dotenv from "dotenv"; -dotenv.config() +dotenv.config(); -const DISCORD_TOKEN = process.env.DISCORD_TOKEN as string -const REST_AUTHORIZATION = process.env.REST_AUTHORIZATION as string -const REST_PORT = process.env.REST_PORT as string +import { BASE_URL, createRestManager } from "discordeno"; +import express from "express"; +import { setupAnalyticsHooks } from "../analytics"; +import { REST_URL } from "../configs"; + +const DISCORD_TOKEN = process.env.DISCORD_TOKEN as string; +const REST_AUTHORIZATION = process.env.REST_AUTHORIZATION as string; +const REST_PORT = process.env.REST_PORT as string; const rest = createRestManager({ token: DISCORD_TOKEN, @@ -18,48 +17,8 @@ const rest = createRestManager({ debug: console.log, }); -// If influxdb data is provided, enable analytics in this proxy. -if (Influx) { - rest.fetching = function (options) { - Influx?.writePoint( - new Point("restEvents") - // MARK THE TIME WHEN EVENT ARRIVED - .timestamp(new Date()) - // SET THE GUILD ID - .stringField("type", "REQUEST_FETCHING") - .tag("method", options.method) - .tag("url", options.url) - .tag("bucket", options.bucketId ?? "NA"), - ); - }; - - rest.fetched = function (options, response) { - Influx?.writePoint( - new Point("restEvents") - // MARK THE TIME WHEN EVENT ARRIVED - .timestamp(new Date()) - // SET THE GUILD ID - .stringField("type", "REQUEST_FETCHED") - .tag("method", options.method) - .tag("url", options.url) - .tag("bucket", options.bucketId ?? "NA") - .intField("status", response.status) - .tag("statusText", response.statusText), - ); - }; - - setInterval(() => { - console.log(`[Influx - REST] Saving events...`); - Influx?.flush() - .then(() => { - console.log(`[Influx - REST] Saved events!`); - }) - .catch((error) => { - console.log(`[Influx - REST] Error saving events!`, error); - }); - // Every 30seconds - }, 30000); -} +// Add send fetching analytics hook to rest +setupAnalyticsHooks(rest); //@ts-ignore rest.convertRestError = (errorStack, data) => { @@ -77,27 +36,7 @@ app.use( app.use(express.json()); -app.post("/*", async (req, res) => { - handleRequest(req, res); -}); - -app.get("/*", async (req, res) => { - handleRequest(req, res); -}); - -app.put("/*", async (req, res) => { - handleRequest(req, res); -}); - -app.delete("/*", async (req, res) => { - handleRequest(req, res); -}); - -app.patch("/*", async (req, res) => { - handleRequest(req, res); -}); - -async function handleRequest(req: Request, res: Response) { +app.all("/*", async (req, res) => { if (!REST_AUTHORIZATION || REST_AUTHORIZATION !== req.headers.authorization) { return res.status(401).json({ error: "Invalid authorization key." }); } @@ -114,7 +53,7 @@ async function handleRequest(req: Request, res: Response) { console.log(error); res.status(500).json(error); } -} +}); app.listen(REST_PORT, () => { console.log(`REST listening at ${REST_URL}`); diff --git a/template/bigbot/tsconfig.json b/template/bigbot/tsconfig.json index 58aaaa9b2..324c863fc 100644 --- a/template/bigbot/tsconfig.json +++ b/template/bigbot/tsconfig.json @@ -19,7 +19,7 @@ "useUnknownInCatchVariables": false, "allowUnreachableCode": false, "skipLibCheck": true, - "moduleResolution": "node", + "moduleResolution": "node" }, "include": [ "./src/**/*", @@ -30,4 +30,4 @@ "experimentalSpecifierResolution": "node", "swc": true } -} \ No newline at end of file +}