From f4a23747499fed606c30d85f2382e0bc9cce6048 Mon Sep 17 00:00:00 2001 From: Techbot121 Date: Sat, 4 Jan 2025 16:26:25 +0100 Subject: [PATCH] huge service refactor: services are now guranteed to exist at all times --- app/Container.ts | 38 +++- app/index.ts | 8 - app/services/DiscordMetadata.ts | 18 +- app/services/IRC.ts | 12 +- app/services/Motd.ts | 167 +++++++++--------- app/services/Resonite.ts | 3 +- app/services/Starboard.ts | 19 +- app/services/discord/index.ts | 22 ++- .../discord/modules/commands/Markov.ts | 14 +- .../commands/RemoveHighlightMessage.ts | 7 +- .../modules/commands/TempVoiceChannel.ts | 7 +- .../discord/modules/commands/WhyBan.ts | 13 +- .../discord/modules/commands/WhyRole.ts | 6 +- .../discord/modules/commands/developer/Ban.ts | 4 +- .../commands/developer/ManageMediaLinks.ts | 4 +- .../modules/commands/developer/Rules.ts | 13 +- .../discord/modules/commands/developer/SQL.ts | 29 ++- .../modules/commands/developer/UnBan.ts | 8 +- .../discord/modules/discord-events.ts | 11 +- .../discord/modules/discord-guild-icon.ts | 6 +- app/services/discord/modules/iotdrollback.ts | 42 ++--- app/services/discord/modules/perma-roles.ts | 3 +- app/services/discord/modules/shitposting.ts | 15 +- app/services/discord/modules/starboard.ts | 6 +- .../discord/modules/temp-voice-channels.ts | 3 +- .../discord/modules/webhook-handler.ts | 5 +- app/services/gamebridge/GameBridge.ts | 12 +- .../gamebridge/payloads/AdminNotifyPayload.ts | 47 +++-- .../gamebridge/payloads/BanAppealPayload.ts | 6 +- .../gamebridge/payloads/BanPayload.ts | 16 +- .../gamebridge/payloads/ChatPayload.ts | 10 +- .../gamebridge/payloads/JoinLeavePayload.ts | 4 +- .../gamebridge/payloads/StatusPayload.ts | 6 +- .../gamebridge/payloads/UnbanPayload.ts | 6 +- .../gamebridge/payloads/VoteKickPayload.ts | 42 +++-- app/services/index.ts | 30 ++-- app/services/webapp/api/discord-oauth.ts | 22 +-- app/services/webapp/api/emojis.ts | 8 +- app/services/webapp/api/game-server-status.ts | 13 +- app/services/webapp/api/gamemode.ts | 9 +- app/services/webapp/api/gmod-error-handler.ts | 9 +- app/services/webapp/api/steam-oauth.ts | 7 +- 42 files changed, 348 insertions(+), 382 deletions(-) diff --git a/app/Container.ts b/app/Container.ts index 10a509b2..b535f6a9 100644 --- a/app/Container.ts +++ b/app/Container.ts @@ -6,7 +6,8 @@ type ProviderFactory = { (container: Container): Service | Promise }[]; export class Container { readonly app: App; private providers: ProviderFactory; - private services: ServiceMap = {}; + private services = {} as ServiceMap; + private initPromises = new Map>(); constructor(app: App, providers: ProviderFactory) { this.app = app; @@ -28,7 +29,38 @@ export class Container { this.services[service.name] = service; } - getService(type: Name): ServiceMap[Name] { - return this.services[type]; + async getService(name: T): Promise { + const service = this.services[name]; + if (service) { + return service as ServiceMap[T]; + } + + // If already initializing, wait for it + if (this.initPromises.has(String(name))) { + return this.initPromises.get(String(name)) as Promise; + } + + // Find the provider + const provider = this.providers.find(p => { + const temp = p(this); + if (temp instanceof Promise) { + return temp.then(s => s.name === name); + } + return temp.name === name; + }); + + if (!provider) { + throw new Error(`Service ${String(name)} not found`); + } + + // Initialize the service + const promise = Promise.resolve(provider(this)).then(service => { + this.services[name] = service; + this.initPromises.delete(String(name)); + return service as ServiceMap[T]; + }); + + this.initPromises.set(String(name), promise); + return promise; } } diff --git a/app/index.ts b/app/index.ts index fc7f353b..f3acef38 100644 --- a/app/index.ts +++ b/app/index.ts @@ -6,13 +6,5 @@ export class App { constructor() { this.container = new Container(this, providers); - - this.init(); - } - - async init(): Promise { - for (const provider of this.container.getProviders()) { - await this.container.addService(provider(this.container)); - } } } diff --git a/app/services/DiscordMetadata.ts b/app/services/DiscordMetadata.ts index a46066f2..3783b97d 100644 --- a/app/services/DiscordMetadata.ts +++ b/app/services/DiscordMetadata.ts @@ -70,13 +70,13 @@ export class DiscordMetadata extends Service { constructor(container: Container) { super(container); - const sql = this.container.getService("SQL"); - const bot = this.container.getService("DiscordBot"); - const bans = this.container.getService("Bans"); - if (!sql || !bot || !bans) return; - this.sql = sql; - this.bot = bot; - this.bans = bans; + this.initServices(); + } + + private async initServices() { + this.sql = await this.container.getService("SQL"); + this.bot = await this.container.getService("DiscordBot"); + this.bans = await this.container.getService("Bans"); } private async getAccessToken(userId: string, data: LocalDatabaseEntry) { @@ -202,8 +202,8 @@ export class DiscordMetadata extends Service { if (query3[0]) { nick = bytea.toString("utf-8").replace(/<[^>]*>/g, ""); } else { - const steam = this.bot.container.getService("Steam"); - const summary = await steam?.getUserSummaries(data.steam_id); + const steam = await this.bot.container.getService("Steam"); + const summary = await steam.getUserSummaries(data.steam_id); nick = summary?.personaname; } diff --git a/app/services/IRC.ts b/app/services/IRC.ts index 66a338d8..7aef37fd 100644 --- a/app/services/IRC.ts +++ b/app/services/IRC.ts @@ -53,11 +53,8 @@ export class IRC extends Service { this.client.say(config.relayIRCChannel, `\u000314[Discord]\u000f ${text}`); } - constructor(container: Container) { - super(container); - const bot = this.container.getService("DiscordBot"); - - if (!bot) return; + private async setupDiscord() { + const bot = await this.container.getService("DiscordBot"); // Discord bot.discord.on("messageCreate", async msg => { if (msg.channelId === config.relayDiscordChannel) { @@ -76,6 +73,11 @@ export class IRC extends Service { ); } }); + } + + constructor(container: Container) { + super(container); + this.setupDiscord(); // IRC this.client.on("registered", () => { this.client.say("NICKSERV", `IDENTIFY ${config.nick} ${config.password}`); diff --git a/app/services/Motd.ts b/app/services/Motd.ts index 7867633b..c65ffb97 100644 --- a/app/services/Motd.ts +++ b/app/services/Motd.ts @@ -1,5 +1,5 @@ import { Container } from "@/app/Container"; -import { Data, DiscordBot, Service } from "@/app/services"; +import { DiscordBot, Service } from "@/app/services"; import { scheduleJob } from "node-schedule"; import FormData from "form-data"; import axios, { AxiosResponse } from "axios"; @@ -93,7 +93,6 @@ export class Motd extends Service { images: ImgurImage[] = []; lastimages: ImgurImage[] = []; - private data: Data; private bot: DiscordBot; private rerolls = 0; @@ -102,14 +101,10 @@ export class Motd extends Service { constructor(container: Container) { super(container); this.messages = []; + this.initServices(); scheduleJob("0 12 * * *", this.executeMessageJob.bind(this)); // scheduleJob("0 20 * * *", this.executeImageJob.bind(this)); // scheduleJob("0 0 * * 0", this.clearImageAlbumAndHistory.bind(this)); - const data = this.container.getService("Data"); - const bot = this.container.getService("DiscordBot"); - if (!data || !bot) return; - this.data = data; - this.bot = bot; // axios // .get(`https://api.imgur.com/3/album/${config.imgurAlbumId}/images`, { // headers: { @@ -122,6 +117,10 @@ export class Motd extends Service { // } // }); } + private async initServices() { + const bot = await this.container.getService("DiscordBot"); + this.bot = bot; + } pushMessage(msg: string): void { msg = msg.trim(); @@ -160,8 +159,9 @@ export class Motd extends Service { const msg: string = this.messages[(Math.random() * this.messages.length) | 0]; this.messages = []; if (msg == null || msg.length === 0) return; - this.data.lastMotd = msg; - this.data.save(); + const data = await this.container.getService("Data"); + data.lastMotd = msg; + data.save(); await axios.post( config.webhook + "?wait=true", @@ -179,85 +179,84 @@ export class Motd extends Service { await this.setNicknameFromSentence(msg); } - private async executeImageJob(patch?: boolean, msgId?: string): Promise { - const res = await axios.get(`https://api.imgur.com/3/album/${config.imgurAlbumId}/images`, { - headers: { - Authorization: `Client-ID ${config.imgurClientId}`, - }, - }); + // private async executeImageJob(patch?: boolean, msgId?: string): Promise { + // const res = await axios.get(`https://api.imgur.com/3/album/${config.imgurAlbumId}/images`, { + // headers: { + // Authorization: `Client-ID ${config.imgurClientId}`, + // }, + // }); - if (res.status === 200) { - const yesterday = dayjs().subtract(1, "d").unix(); - this.images = res.data.data; - const urls: ImgurImage[] = res.data.data.filter( - (img: ImgurImage) => - img.datetime >= yesterday && - !this.lastimages.includes(img) && - !this.ignorelist.some(id => img.title.includes(id)) - ); // keep only recent images - const authors = [...new Set(urls.map(image => image.title))]; - const index = (Math.random() * urls.length) | 0; - const image = urls[index]; - const url: string = image.link; - if (!url) return; + // if (res.status === 200) { + // const yesterday = dayjs().subtract(1, "d").unix(); + // this.images = res.data.data; + // const urls: ImgurImage[] = res.data.data.filter( + // (img: ImgurImage) => + // img.datetime >= yesterday && + // !this.lastimages.includes(img) && + // !this.ignorelist.some(id => img.title.includes(id)) + // ); // keep only recent images + // const authors = [...new Set(urls.map(image => image.title))]; + // const index = (Math.random() * urls.length) | 0; + // const image = urls[index]; + // const url: string = image.link; + // if (!url) return; - let msg = `Image of the day\n(No. ${index + 1} out of ${urls.length} total from ${ - authors.length - } user${authors.length > 1 ? "s" : ""})`; + // let msg = `Image of the day\n(No. ${index + 1} out of ${urls.length} total from ${ + // authors.length + // } user${authors.length > 1 ? "s" : ""})`; - if (patch !== undefined && msgId) { - this.rerolls++; - msg = `Image of the day\n(No. ${index + 1} out of ${urls.length} total from ${ - authors.length - } user${authors.length > 1 ? "s" : ""})\n(♻ rerolled ${this.rerolls}x)`; - await axios.patch( - `${config.webhook}/messages/${msgId}`, - JSON.stringify({ - content: msg + `\n${url}`, - username: "Meta Construct", - avatar_url: - "https://pbs.twimg.com/profile_images/1503242277/meta4_crop.png", - }), - { - headers: { - "Content-Type": "application/json", - }, - } - ); - } else { - this.rerolls = 0; - await axios.post( - config.webhook, - JSON.stringify({ - content: msg + `\n${url}`, - username: "Meta Construct", - avatar_url: - "https://pbs.twimg.com/profile_images/1503242277/meta4_crop.png", - }), - { - headers: { - "Content-Type": "application/json", - }, - } - ); - } - this.bot.setServerBanner(url); - this.lastimages.push(image); - await this.data.save(); - setTimeout(async () => { - const last = await this.bot.getLastMotdMsg(); - await last?.react("♻️"); - }, 1000 * 10); - } - } - async rerollImageJob(): Promise { - if (!(await this.bot.overLvl2())) return; - const lastmsg = await this.bot.getLastMotdMsg(); - if (!lastmsg) return; + // if (patch !== undefined && msgId) { + // this.rerolls++; + // msg = `Image of the day\n(No. ${index + 1} out of ${urls.length} total from ${ + // authors.length + // } user${authors.length > 1 ? "s" : ""})\n(♻ rerolled ${this.rerolls}x)`; + // await axios.patch( + // `${config.webhook}/messages/${msgId}`, + // JSON.stringify({ + // content: msg + `\n${url}`, + // username: "Meta Construct", + // avatar_url: + // "https://pbs.twimg.com/profile_images/1503242277/meta4_crop.png", + // }), + // { + // headers: { + // "Content-Type": "application/json", + // }, + // } + // ); + // } else { + // this.rerolls = 0; + // await axios.post( + // config.webhook, + // JSON.stringify({ + // content: msg + `\n${url}`, + // username: "Meta Construct", + // avatar_url: + // "https://pbs.twimg.com/profile_images/1503242277/meta4_crop.png", + // }), + // { + // headers: { + // "Content-Type": "application/json", + // }, + // } + // ); + // } + // this.bot.setServerBanner(url); + // this.lastimages.push(image); + // setTimeout(async () => { + // const last = await this.bot.getLastMotdMsg(); + // await last?.react("♻️"); + // }, 1000 * 10); + // } + // } + // async rerollImageJob(): Promise { + // if (!(await this.bot.overLvl2())) return; + // const lastmsg = await this.bot.getLastMotdMsg(); + // if (!lastmsg) return; - await this.executeImageJob(true, lastmsg.id); - await this.bot.removeMotdReactions(); - } + // await this.executeImageJob(true, lastmsg.id); + // await this.bot.removeMotdReactions(); + // } async getImageInfo(id: string): Promise { try { diff --git a/app/services/Resonite.ts b/app/services/Resonite.ts index d827db71..bb5b894f 100644 --- a/app/services/Resonite.ts +++ b/app/services/Resonite.ts @@ -121,8 +121,7 @@ export class Resonite extends Service { } async GetOrFetchToken(): Promise { - const data = this.container.getService("Data"); - if (!data) return; + const data = await this.container.getService("Data"); let lastToken = data.lastResoniteToken; let lastTokenTime = data.lastResoniteTokenTime ?? Date.now(); diff --git a/app/services/Starboard.ts b/app/services/Starboard.ts index c85a7f04..c9a4873b 100644 --- a/app/services/Starboard.ts +++ b/app/services/Starboard.ts @@ -1,6 +1,5 @@ import { Container } from "../Container"; -import { SQL } from "./SQL"; -import { Service } from "."; +import { DiscordBot, SQL, Service } from "."; import Discord from "discord.js"; import config from "@/config/starboard.json"; import discordConfig from "@/config/discord.json"; @@ -14,18 +13,22 @@ const STARBOARD_CONFIG = { export class Starboard extends Service { name = "Starboard"; private isBusy = false; - private sql: SQL | undefined; + private sql: SQL; + private bot: DiscordBot; constructor(container: Container) { super(container); - this.sql = this.container.getService("SQL"); + this.initServices(); + } + + private async initServices(): Promise { + this.sql = await this.container.getService("SQL"); + this.bot = await this.container.getService("DiscordBot"); - const bot = this.container.getService("DiscordBot"); - if (bot) { const filter = (btn: Discord.MessageComponentInteraction) => btn.customId.startsWith("starboard"); - bot.discord.on("interactionCreate", async interaction => { + this.bot.discord.on("interactionCreate", async interaction => { if (!interaction.isButton()) return; if (!filter(interaction)) return; if (interaction.message.author.username !== interaction.user.username) return; @@ -43,7 +46,6 @@ export class Starboard extends Service { } async isMsgStarred(msgId: string): Promise { - if (!this.sql) return true; const db = await this.sql.getLocalDatabase(); if (!(await this.sql.tableExists("starboard"))) { await db.exec(`CREATE TABLE starboard (MessageId VARCHAR(1000));`); @@ -54,7 +56,6 @@ export class Starboard extends Service { } private async starMsg(msgId: string): Promise { - if (!this.sql) return; const db = await this.sql.getLocalDatabase(); await db.run("INSERT INTO starboard(MessageId) VALUES(?)", msgId); } diff --git a/app/services/discord/index.ts b/app/services/discord/index.ts index 57a5b94b..1499224b 100644 --- a/app/services/discord/index.ts +++ b/app/services/discord/index.ts @@ -1,8 +1,7 @@ import { Container } from "@/app/Container"; -import { Service } from "@/app/services"; +import { Data, GameBridge, Service } from "@/app/services"; import Discord from "discord.js"; import DiscordConfig from "@/config/discord.json"; -import axios from "axios"; import modules from "./modules"; import motdConfig from "@/config/motd.json"; @@ -18,9 +17,9 @@ const ImgurRegex = /https?:\/\/(?:i.)?imgur.com\/(\w+)(?:.mp4)?/g; export class DiscordBot extends Service { name = "DiscordBot"; - bridge = this.container.getService("GameBridge"); - config = DiscordConfig; - discord: Discord.Client = new Discord.Client({ + bridge: GameBridge; + readonly config = DiscordConfig; + readonly discord: Discord.Client = new Discord.Client({ allowedMentions: { parse: ["users", "roles"] }, intents: [ "Guilds", @@ -41,10 +40,13 @@ export class DiscordBot extends Service { rest: { timeout: 30000 }, }); ready: boolean; + private data: Data; constructor(container: Container) { super(container); + this.initServices(); + this.discord.on("ready", async client => { this.ready = true; console.log(`'${client.user.username}' Discord Bot has logged in`); @@ -63,6 +65,10 @@ export class DiscordBot extends Service { this.discord.login(this.config.bot.token); } + private async initServices() { + this.data = await this.container.getService("Data"); + this.bridge = await this.container.getService("GameBridge"); + } getTextChannel(channelId: string): Discord.TextChannel | undefined { if (!this.ready) return; return this.discord.channels.cache.get(channelId) as Discord.TextChannel; @@ -139,8 +145,8 @@ export class DiscordBot extends Service { if (!perms.has("SendMessages", false)) return; // don't get text from channels that are not "public" const content = msg.content; - if (this.container.getService("Motd")?.isValidMsg(content)) - this.container.getService("Markov")?.learn(msg.content); + if ((await this.container.getService("Motd")).isValidMsg(content)) + (await this.container.getService("Markov")).learn(msg.content); } async fixEmbeds(msg: Discord.Message): Promise { @@ -156,7 +162,7 @@ export class DiscordBot extends Service { if (imgurUrls) { for (const imageUrl of imgurUrls) { const id = Array.from(imageUrl.matchAll(ImgurRegex), m => m[1])[0]; // wtf there has to be a better way - const info = await this.container.getService("Motd")?.getImageInfo(id); + const info = await (await this.container.getService("Motd")).getImageInfo(id); if (info?.has_sound) { urls.push(imageUrl.replace(/(?:i\.)?imgur\.com/g, "i.imgur.io")); } diff --git a/app/services/discord/modules/commands/Markov.ts b/app/services/discord/modules/commands/Markov.ts index 5027eb72..54b9cfea 100644 --- a/app/services/discord/modules/commands/Markov.ts +++ b/app/services/discord/modules/commands/Markov.ts @@ -39,13 +39,13 @@ export const SlashMarkovCommand: SlashCommand = { execute: async (ctx, bot) => { await ctx.deferReply(); - const res = await bot.container - .getService("Markov") - ?.generate(ctx.options.getString("sentence") ?? undefined, { - depth: ctx.options.getInteger("insanity") ?? undefined, - length: ctx.options.getInteger("length") ?? undefined, - continuation: ctx.options.getBoolean("continuation") ?? undefined, - }); + const res = await ( + await bot.container.getService("Markov") + ).generate(ctx.options.getString("sentence") ?? undefined, { + depth: ctx.options.getInteger("insanity") ?? undefined, + length: ctx.options.getInteger("length") ?? undefined, + continuation: ctx.options.getBoolean("continuation") ?? undefined, + }); if (res) { await ctx.followUp(res); diff --git a/app/services/discord/modules/commands/RemoveHighlightMessage.ts b/app/services/discord/modules/commands/RemoveHighlightMessage.ts index e58eb7fd..9517b005 100644 --- a/app/services/discord/modules/commands/RemoveHighlightMessage.ts +++ b/app/services/discord/modules/commands/RemoveHighlightMessage.ts @@ -15,12 +15,9 @@ export const MenuRemoveHighlightMessageCommand: MenuCommand = { return; } - const starboardService = bot.container.getService("Starboard"); - if (!starboardService) { - throw new Error("Starboard service not found"); - } - + const starboardService = await bot.container.getService("Starboard"); const starred = await starboardService.isMsgStarred(ctx.targetId); + if (!starred) { await ctx.reply( EphemeralResponse( diff --git a/app/services/discord/modules/commands/TempVoiceChannel.ts b/app/services/discord/modules/commands/TempVoiceChannel.ts index 4098e68a..970f4354 100644 --- a/app/services/discord/modules/commands/TempVoiceChannel.ts +++ b/app/services/discord/modules/commands/TempVoiceChannel.ts @@ -26,12 +26,7 @@ export const SlashVoiceCommand: SlashCommand = { }, async execute(ctx, bot) { - const data = bot.container.getService("Data"); - if (!data) { - await ctx.reply(EphemeralResponse("data provider missing :(")); - console.error("TempVoiceChannel: data provider missing?"); - return; - } + const data = await bot.container.getService("Data"); const existing = data.tempVoiceChannels[ctx.user.id]; if (existing) { diff --git a/app/services/discord/modules/commands/WhyBan.ts b/app/services/discord/modules/commands/WhyBan.ts index 7589aa01..d5878ce4 100644 --- a/app/services/discord/modules/commands/WhyBan.ts +++ b/app/services/discord/modules/commands/WhyBan.ts @@ -21,17 +21,15 @@ export const SlashWhyBanCommand: SlashCommand = { async execute(ctx, bot) { await ctx.deferReply({ ephemeral: true }); - const banService = bot.container.getService("Bans"); - if (!banService) { - ctx.followUp(EphemeralResponse("ban service offline for some reason :(")); - return; - } + const banService = await bot.container.getService("Bans"); const ban = await banService.getBan(ctx.options.getString("query", true)); if (!ban) { ctx.followUp(EphemeralResponse("That SteamID has never been banned before.")); return; } - const banner = await bot.container.getService("Steam")?.getUserSummaries(ban.bannersid); + const banner = await ( + await bot.container.getService("Steam") + ).getUserSummaries(ban.bannersid); if (!ban.b) { ctx.followUp( @@ -71,8 +69,7 @@ export const SlashWhyBanCommand: SlashCommand = { }, async autocomplete(ctx, bot) { - const banService = bot.container.getService("Bans"); - if (!banService) return; + const banService = await bot.container.getService("Bans"); const list = await banService.getBanList(); if (!list) { ctx.respond([]); diff --git a/app/services/discord/modules/commands/WhyRole.ts b/app/services/discord/modules/commands/WhyRole.ts index 21dc23ba..180b5d6d 100644 --- a/app/services/discord/modules/commands/WhyRole.ts +++ b/app/services/discord/modules/commands/WhyRole.ts @@ -10,11 +10,7 @@ export const MenuWhyRoleCommand: MenuCommand = { default_member_permissions: Discord.PermissionsBitField.Flags.ManageRoles.toString(), }, execute: async (ctx: Discord.MessageContextMenuCommandInteraction, bot: DiscordBot) => { - const dataService = bot.container.getService("Data"); - if (!dataService) { - ctx.reply(EphemeralResponse("DataProvider missing :(")); - return; - } + const dataService = await bot.container.getService("Data"); const { permaRoles } = dataService; const userId = ctx.targetId; if (!userId) { diff --git a/app/services/discord/modules/commands/developer/Ban.ts b/app/services/discord/modules/commands/developer/Ban.ts index a9d5f375..58f6274a 100644 --- a/app/services/discord/modules/commands/developer/Ban.ts +++ b/app/services/discord/modules/commands/developer/Ban.ts @@ -145,8 +145,8 @@ export const SlashBanCommand: SlashCommand = { }, async execute(ctx, bot) { - const steam = bot.container.getService("Steam"); - const summary = await steam?.getUserSummaries(ctx.options.getString("steamid", true)); + const steam = await bot.container.getService("Steam"); + const summary = await steam.getUserSummaries(ctx.options.getString("steamid", true)); if (!summary) { await ctx.showModal({ title: "couldn't get nick please enter manually:", diff --git a/app/services/discord/modules/commands/developer/ManageMediaLinks.ts b/app/services/discord/modules/commands/developer/ManageMediaLinks.ts index 54be7bd0..c667351b 100644 --- a/app/services/discord/modules/commands/developer/ManageMediaLinks.ts +++ b/app/services/discord/modules/commands/developer/ManageMediaLinks.ts @@ -29,7 +29,7 @@ export const SlashManageMediaLinks: SlashCommand = { case "remove": const url = ctx.options.getString("url", true); await ctx.deferReply({ ephemeral: true }); - const db = await bot.container.getService("SQL")?.getLocalDatabase(); + const db = await (await bot.container.getService("SQL")).getLocalDatabase(); if (!db) { ctx.followUp(EphemeralResponse("Could not get the DB :(")); return; @@ -71,7 +71,7 @@ export const MenuManageMediaLinksCommand: MenuCommand = { return; } await ctx.deferReply({ ephemeral: true }); - const db = await bot.container.getService("SQL")?.getLocalDatabase(); + const db = await (await bot.container.getService("SQL")).getLocalDatabase(); if (!db) { ctx.followUp(EphemeralResponse("Could not get the DB :(")); return; diff --git a/app/services/discord/modules/commands/developer/Rules.ts b/app/services/discord/modules/commands/developer/Rules.ts index 7be512e7..357af2bf 100644 --- a/app/services/discord/modules/commands/developer/Rules.ts +++ b/app/services/discord/modules/commands/developer/Rules.ts @@ -7,12 +7,7 @@ import Discord from "discord.js"; let ruleCache: Rule[] = []; const refreshRules = async (ctx: Discord.ChatInputCommandInteraction, bot: DiscordBot) => { - const data = bot.container.getService("Data"); - if (!bot || !data) { - await ctx.reply(EphemeralResponse("wtf")); - console.error("RefreshRules: bot or data missing???"); - return; - } + const data = await bot.container.getService("Data"); if (ruleCache.length === 0) { await ctx.reply(EphemeralResponse("Something went wrong with saving the rules")); return; @@ -234,11 +229,7 @@ export const SlashRuleCommand: SlashCommand = { }) ); } else { - const data = bot.container.getService("Data"); - if (!data) { - await ctx.respond([]); - return; - } + const data = await bot.container.getService("Data"); ruleCache = data.rules; await ctx.respond( ruleCache.map((rule, idx) => { diff --git a/app/services/discord/modules/commands/developer/SQL.ts b/app/services/discord/modules/commands/developer/SQL.ts index 78502e2a..c7d72a68 100644 --- a/app/services/discord/modules/commands/developer/SQL.ts +++ b/app/services/discord/modules/commands/developer/SQL.ts @@ -45,7 +45,7 @@ export const SlashSQLCommand: SlashCommand = { execute: async (ctx, bot) => { const target = ctx.options.getString("target"); const query = ctx.options.getString("query", true); - const sql = bot.container.getService("SQL"); + const sql = await bot.container.getService("SQL"); if (!ctx.member) { await ctx.reply(EphemeralResponse("if this happens ping @techbot")); console.error("SlashSQL: WTF"); @@ -64,27 +64,20 @@ export const SlashSQLCommand: SlashCommand = { `You need the <@&${bot.config.roles.elevated}> role to run SQL commands on me!` ) ); - if (sql) { - await ctx.deferReply(); - const db = await sql?.getLocalDatabase(); - const res = await db?.all(query); - const file = makeFile(res); - await ctx.followUp(file); - } else { - await ctx.reply(EphemeralResponse("SQL service not running")); - } + await ctx.deferReply(); + const db = await sql?.getLocalDatabase(); + const res = await db?.all(query); + const file = makeFile(res); + await ctx.followUp(file); break; } case "metastruct": default: - if (sql) { - await ctx.deferReply(); - const res = await sql.queryPool(query); - const file = makeFile(res); - await ctx.followUp(file); - } else { - await ctx.reply(EphemeralResponse("SQL service not running")); - } + await ctx.deferReply(); + const res = await sql.queryPool(query); + const file = makeFile(res); + await ctx.followUp(file); + break; } } catch (err) { diff --git a/app/services/discord/modules/commands/developer/UnBan.ts b/app/services/discord/modules/commands/developer/UnBan.ts index e2d621d2..4751b36e 100644 --- a/app/services/discord/modules/commands/developer/UnBan.ts +++ b/app/services/discord/modules/commands/developer/UnBan.ts @@ -37,11 +37,6 @@ export const SlashUnBanCommand: SlashCommand = { async execute(ctx, bot) { const bridge = bot.bridge; - if (!bridge) { - ctx.reply(EphemeralResponse("GameBridge is missing :(")); - console.error(`SlashUnBan: GameBridge missing?`, ctx); - return; - } await ctx.deferReply(); const server = bridge.servers[ctx.options.getInteger("server") ?? 2]; const steamid = ctx.options.getString("steamid", true); @@ -72,8 +67,7 @@ export const SlashUnBanCommand: SlashCommand = { }, async autocomplete(ctx, bot) { - const banService = bot.container.getService("Bans"); - if (!banService) return; + const banService = await bot.container.getService("Bans"); const list = await banService.getBanList(); if (!list) { ctx.respond([]); diff --git a/app/services/discord/modules/discord-events.ts b/app/services/discord/modules/discord-events.ts index 36a854e1..25fd97ee 100644 --- a/app/services/discord/modules/discord-events.ts +++ b/app/services/discord/modules/discord-events.ts @@ -5,7 +5,7 @@ import DiscordConfig from "@/config/discord.json"; const iconsPath = join(process.cwd(), "resources/discord-event-icons"); -export default (bot: DiscordBot): void => { +export default async (bot: DiscordBot): Promise => { const events = [ { icon: "vr", @@ -16,17 +16,14 @@ export default (bot: DiscordBot): void => { icon: "ttt", triggers: ["ttt"], nicks: ["terror", "detective", "innocent", "trouble", "clue", "banana", "protogen"], - execute: () => - bot.container - .getService("GameBridge") - ?.servers[3]?.sendLua( + execute: async () => + (await bot.container.getService("GameBridge")).servers[3]?.sendLua( `local request = require("gm_request") if request and not request:IsServerGamemode(3,"terrortown") then request:SwitchGamemodeAsync("terrortown",print) end` ), }, ]; - const data = bot.container.getService("Data"); - if (!data) return; + const data = await bot.container.getService("Data"); const GetParticipants = async ( event: Discord.GuildScheduledEvent | Discord.PartialGuildScheduledEvent diff --git a/app/services/discord/modules/discord-guild-icon.ts b/app/services/discord/modules/discord-guild-icon.ts index 66cc482b..e89b2b94 100644 --- a/app/services/discord/modules/discord-guild-icon.ts +++ b/app/services/discord/modules/discord-guild-icon.ts @@ -44,10 +44,8 @@ const fileExists = async (filePath: PathLike) => .then(stats => stats.isFile()) .catch(() => false); -export default (bot: DiscordBot): void => { - const data = bot.container.getService("Data"); - if (!data) return; - +export default async (bot: DiscordBot): Promise => { + const data = await bot.container.getService("Data"); bot.discord.on("ready", async () => { const guild = bot.getGuild(); if (!guild) return; diff --git a/app/services/discord/modules/iotdrollback.ts b/app/services/discord/modules/iotdrollback.ts index dd6f7702..5a5d1601 100644 --- a/app/services/discord/modules/iotdrollback.ts +++ b/app/services/discord/modules/iotdrollback.ts @@ -1,25 +1,25 @@ import { DiscordBot } from ".."; -import config from "@/config/motd.json"; +// import config from "@/config/motd.json"; export default (bot: DiscordBot): void => { - bot.discord.on("messageReactionAdd", async reaction => { - if (reaction.partial) { - try { - reaction = await reaction.fetch(); - } catch { - return; - } - } - if ( - reaction.message.channel.id !== config.channelId || - reaction.emoji.name !== "♻️" || - reaction.count < 8 - ) - return; - const lastmsg = await bot.getLastMotdMsg(); - if (!lastmsg) return; // could be undefined if the bot was just launched and the msg is not cached - if (reaction.message.id !== lastmsg.id) return; - if (!lastmsg.content.includes("Image of the day")) return; - await bot.container.getService("Motd")?.rerollImageJob(); - }); + // bot.discord.on("messageReactionAdd", async reaction => { + // if (reaction.partial) { + // try { + // reaction = await reaction.fetch(); + // } catch { + // return; + // } + // } + // if ( + // reaction.message.channel.id !== config.channelId || + // reaction.emoji.name !== "♻️" || + // reaction.count < 8 + // ) + // return; + // const lastmsg = await bot.getLastMotdMsg(); + // if (!lastmsg) return; // could be undefined if the bot was just launched and the msg is not cached + // if (reaction.message.id !== lastmsg.id) return; + // if (!lastmsg.content.includes("Image of the day")) return; + // await (await bot.container.getService("Motd")).rerollImageJob(); + // }); }; diff --git a/app/services/discord/modules/perma-roles.ts b/app/services/discord/modules/perma-roles.ts index 58c0a8d9..d4b3e1c5 100644 --- a/app/services/discord/modules/perma-roles.ts +++ b/app/services/discord/modules/perma-roles.ts @@ -9,8 +9,7 @@ function isEmpty(obj: { [roleId: string]: { adderId: string; timeStamp: number } } export default async (bot: DiscordBot): Promise => { - const data = bot.container.getService("Data"); - if (!data) return; + const data = await bot.container.getService("Data"); const permaRoles = data.permaRoles; const permaPrefix = "#"; diff --git a/app/services/discord/modules/shitposting.ts b/app/services/discord/modules/shitposting.ts index 4f617270..ffd1aa9f 100644 --- a/app/services/discord/modules/shitposting.ts +++ b/app/services/discord/modules/shitposting.ts @@ -159,9 +159,8 @@ const COMMON_EMOJIS = [ ]; export default async (bot: DiscordBot) => { - const data = bot.container.getService("Data"); - const db = await bot.container.getService("SQL")?.getLocalDatabase(); - if (!data || !db) return; + const data = await bot.container.getService("Data"); + const db = await (await bot.container.getService("SQL")).getLocalDatabase(); db.exec("CREATE TABLE IF NOT EXISTS media_urls (url VARCHAR(255) NOT NULL UNIQUE);"); const now = Date.now(); let lastActivityChange = now; @@ -265,7 +264,9 @@ export default async (bot: DiscordBot) => { const prefix = selection.ctx[(Math.random() * selection.ctx.length) | 0]; - const sentence = await bot.container.getService("Markov")?.generate(prefix, { + const sentence = await ( + await bot.container.getService("Markov") + ).generate(prefix, { ...DefaultMarkovConfig, continuation: false, }); @@ -377,9 +378,9 @@ export default async (bot: DiscordBot) => { !lastRespondedReactionMsgs.includes(message.id) && Math.random() <= (reaction.emoji.name === "h_" ? 0.025 : MSG_REPLY_REACTION_FREQ) ) { - const mk = await bot.container - .getService("Markov") - ?.generate(reaction.emoji.toString(), DefaultMarkovConfig); + const mk = await ( + await bot.container.getService("Markov") + ).generate(reaction.emoji.toString(), DefaultMarkovConfig); if (mk) { lastReactionUserId = user.id; lastRespondedReactionMsgs.push(message.id); diff --git a/app/services/discord/modules/starboard.ts b/app/services/discord/modules/starboard.ts index 6eb1913a..c0d2bbf5 100644 --- a/app/services/discord/modules/starboard.ts +++ b/app/services/discord/modules/starboard.ts @@ -10,8 +10,8 @@ export default (bot: DiscordBot): void => { return; } } - await bot.container - .getService("Starboard") - ?.handleReactionAdded(reaction as MessageReaction); + await ( + await bot.container.getService("Starboard") + ).handleReactionAdded(reaction as MessageReaction); }); }; diff --git a/app/services/discord/modules/temp-voice-channels.ts b/app/services/discord/modules/temp-voice-channels.ts index c4821966..502521c7 100644 --- a/app/services/discord/modules/temp-voice-channels.ts +++ b/app/services/discord/modules/temp-voice-channels.ts @@ -1,8 +1,7 @@ import { DiscordBot } from ".."; export default async (bot: DiscordBot): Promise => { - const data = bot.container.getService("Data"); - if (!data) return; + const data = await bot.container.getService("Data"); const channels = data.tempVoiceChannels; bot.discord.on("voiceStateUpdate", async oldState => { diff --git a/app/services/discord/modules/webhook-handler.ts b/app/services/discord/modules/webhook-handler.ts index 03252875..51d53547 100644 --- a/app/services/discord/modules/webhook-handler.ts +++ b/app/services/discord/modules/webhook-handler.ts @@ -68,9 +68,8 @@ const isRemoteMergeCommit = (message: string) => const isMergeCommit = (message: string) => message.startsWith("Merge branch") || isRemoteMergeCommit(message); -export default (bot: DiscordBot): void => { - const webapp = bot.container.getService("WebApp"); - if (!webapp) return; +export default async (bot: DiscordBot): Promise => { + const webapp = await bot.container.getService("WebApp"); webapp.app.use(createNodeMiddleware(GitHub, { path: "/webhooks/github" })); diff --git a/app/services/gamebridge/GameBridge.ts b/app/services/gamebridge/GameBridge.ts index 51d4cf53..d9b57d3f 100644 --- a/app/services/gamebridge/GameBridge.ts +++ b/app/services/gamebridge/GameBridge.ts @@ -25,10 +25,7 @@ export default class GameBridge extends Service { constructor(container: Container) { super(container); - - const webApp = container.getService("WebApp"); - if (!webApp) return; - this.webApp = webApp; + this.setupWebApp(); this.ws = new WebSocketServer({ httpServer: this.webApp.http, autoAcceptConnections: false, @@ -42,6 +39,10 @@ export default class GameBridge extends Service { this.handleResoniteConnection(); } + private async setupWebApp() { + this.webApp = await this.container.getService("WebApp"); + } + async handleConnection(req: WebSocketRequest): Promise { const ip = req.httpRequest.socket.remoteAddress; @@ -80,8 +81,7 @@ export default class GameBridge extends Service { } async handleResoniteConnection(): Promise { - const resonite = this.container.getService("Resonite"); - if (!resonite) return; + const resonite = await this.container.getService("Resonite"); const id = 9; const con = new signalR.HubConnectionBuilder() diff --git a/app/services/gamebridge/payloads/AdminNotifyPayload.ts b/app/services/gamebridge/payloads/AdminNotifyPayload.ts index a4d934a6..247d6a4c 100644 --- a/app/services/gamebridge/payloads/AdminNotifyPayload.ts +++ b/app/services/gamebridge/payloads/AdminNotifyPayload.ts @@ -18,7 +18,7 @@ export default class AdminNotifyPayload extends Payload { server.discord.config.threads.reports ) as Discord.ThreadChannel; if (!notificationsChannel) return; - const steam = server.bridge.container.getService("Steam"); + const steam = await server.bridge.container.getService("Steam"); const filter = (btn: Discord.MessageComponentInteraction) => btn.customId.endsWith("_REPORT_KICK"); @@ -46,7 +46,7 @@ export default class AdminNotifyPayload extends Payload { ); if (res.data.returns[0] !== "false") { - const summary = await steam?.getUserSummaries(interactionId64); + const summary = await steam.getUserSummaries(interactionId64); await ctx.followUp({ content: `${ctx.user.mention} kicked player \`${ summary ? summary.personaname : "[nickname not found]" @@ -88,9 +88,9 @@ export default class AdminNotifyPayload extends Payload { const steamId64 = new SteamID(player.steamId).getSteamID64(); const reportedSteamId64 = new SteamID(reported.steamId).getSteamID64(); - const steam = bridge.container.getService("Steam"); - const avatar = await steam?.getUserAvatar(steamId64); - const reportedAvatar = await steam?.getUserAvatar(reportedSteamId64); + const steam = await bridge.container.getService("Steam"); + const avatar = await steam.getUserAvatar(steamId64); + const reportedAvatar = await steam.getUserAvatar(reportedSteamId64); if (message.trim().length < 1) message = "No message provided..?"; const embed = new Discord.EmbedBuilder() @@ -110,28 +110,27 @@ export default class AdminNotifyPayload extends Payload { .setThumbnail(reportedAvatar) .setColor(0xc4af21); - const sql = bridge.container.getService("SQL"); - if (sql) { - if (!this.reportCache[reportedSteamId64]) { - const res = await sql.queryPool( - `SELECT report_amount FROM playerstats WHERE accountid = ${ - new SteamID(reported.steamId).accountid - }` - ); - if (res[0]) { - this.reportCache[reportedSteamId64] = res[0].report_amount; - } else { - this.reportCache[reportedSteamId64] = 0; - } + const sql = await bridge.container.getService("SQL"); + if (!this.reportCache[reportedSteamId64]) { + const res = await sql.queryPool( + `SELECT report_amount FROM playerstats WHERE accountid = ${ + new SteamID(reported.steamId).accountid + }` + ); + if (res[0]) { + this.reportCache[reportedSteamId64] = res[0].report_amount; + } else { + this.reportCache[reportedSteamId64] = 0; } - this.reportCache[reportedSteamId64]++; + } + this.reportCache[reportedSteamId64]++; - if (this.reportCache[reportedSteamId64] > 0) { - embed.addFields( - f("Total Report Amount", this.reportCache[reportedSteamId64].toString()) - ); - } + if (this.reportCache[reportedSteamId64] > 0) { + embed.addFields( + f("Total Report Amount", this.reportCache[reportedSteamId64].toString()) + ); } + // You can have a maximum of five ActionRows per message, and five buttons within an ActionRow. const row = new Discord.ActionRowBuilder().addComponents( new Discord.ButtonBuilder() diff --git a/app/services/gamebridge/payloads/BanAppealPayload.ts b/app/services/gamebridge/payloads/BanAppealPayload.ts index 6b2c136b..716b6497 100644 --- a/app/services/gamebridge/payloads/BanAppealPayload.ts +++ b/app/services/gamebridge/payloads/BanAppealPayload.ts @@ -25,13 +25,13 @@ export default class UnbanPayload extends Payload { const notificationsChannel = guild.channels.cache.get(bridge.config.banUnbanChannelId); if (!notificationsChannel) return; - const steam = bridge.container.getService("Steam"); + const steam = await bridge.container.getService("Steam"); let steamId64 = ""; let bannerName = ""; let avatar = ""; try { steamId64 = new SteamID(player.steamId).getSteamID64(); - const summary: PlayerSummary | undefined = await steam?.getUserSummaries(steamId64); + const summary: PlayerSummary | undefined = await steam.getUserSummaries(steamId64); if (summary) { bannerName = summary.personaname; avatar = summary.avatarfull; @@ -41,7 +41,7 @@ export default class UnbanPayload extends Payload { } const bannedSteamId64 = new SteamID(banned.steamId).getSteamID64(); - const bannedAvatar = await steam?.getUserAvatar(bannedSteamId64); + const bannedAvatar = await steam.getUserAvatar(bannedSteamId64); const unixTime = parseInt(unbanTime); if (!unixTime || isNaN(unixTime)) throw new Error(`Unban time is not a number? Supplied time: ${unbanTime}`); diff --git a/app/services/gamebridge/payloads/BanPayload.ts b/app/services/gamebridge/payloads/BanPayload.ts index 48a4ca97..0152001e 100644 --- a/app/services/gamebridge/payloads/BanPayload.ts +++ b/app/services/gamebridge/payloads/BanPayload.ts @@ -25,13 +25,13 @@ export default class BanPayload extends Payload { const notificationsChannel = guild.channels.cache.get(bridge.config.banUnbanChannelId); if (!notificationsChannel) return; - const steam = bridge.container.getService("Steam"); + const steam = await bridge.container.getService("Steam"); let steamId64 = ""; let bannerName = ""; let avatar = ""; try { steamId64 = new SteamID(player.steamId).getSteamID64(); - const summary: PlayerSummary | undefined = await steam?.getUserSummaries(steamId64); + const summary: PlayerSummary | undefined = await steam.getUserSummaries(steamId64); if (summary) { bannerName = summary.personaname; avatar = summary.avatarfull; @@ -41,7 +41,7 @@ export default class BanPayload extends Payload { } const bannedSteamId64 = new SteamID(banned.steamId).getSteamID64(); - const bannedAvatar = await steam?.getUserAvatar(bannedSteamId64); + const bannedAvatar = await steam.getUserAvatar(bannedSteamId64); const unixTime = parseInt(unbanTime); if (!unixTime || isNaN(unixTime)) throw new Error(`Unban time is not a number? Supplied time: ${unbanTime}`); @@ -87,12 +87,10 @@ export default class BanPayload extends Payload { embeds: [embed], }); - const metadata = bridge.container.getService("DiscordMetadata"); - if (metadata) { - const discordId = await metadata.discordIDfromSteam64(bannedSteamId64); - if (discordId) { - metadata.update(discordId); - } + const metadata = await bridge.container.getService("DiscordMetadata"); + const discordId = await metadata.discordIDfromSteam64(bannedSteamId64); + if (discordId) { + metadata.update(discordId); } } } diff --git a/app/services/gamebridge/payloads/ChatPayload.ts b/app/services/gamebridge/payloads/ChatPayload.ts index 22dd0e40..5a79af66 100644 --- a/app/services/gamebridge/payloads/ChatPayload.ts +++ b/app/services/gamebridge/payloads/ChatPayload.ts @@ -111,7 +111,9 @@ export default class ChatPayload extends Payload { const webhook = discordWH; - const avatar = await bridge.container.getService("Steam")?.getUserAvatar(player.steamId64); + const avatar = await ( + await bridge.container.getService("Steam") + ).getUserAvatar(player.steamId64); const matches = content.matchAll(/@(\S*)/g); @@ -128,10 +130,10 @@ export default class ChatPayload extends Payload { content = content.substring(0, 2000); - const motd = bridge.container.getService("Motd"); - if (motd?.isValidMsg(content)) { + const motd = await bridge.container.getService("Motd"); + if (motd.isValidMsg(content)) { motd.pushMessage(content); - bridge.container.getService("Markov")?.learn(content); + (await bridge.container.getService("Markov")).learn(content); } // 9312 = ①, 9313 = ②, and so on until 20 diff --git a/app/services/gamebridge/payloads/JoinLeavePayload.ts b/app/services/gamebridge/payloads/JoinLeavePayload.ts index 6f411759..c7a5c41e 100644 --- a/app/services/gamebridge/payloads/JoinLeavePayload.ts +++ b/app/services/gamebridge/payloads/JoinLeavePayload.ts @@ -21,7 +21,9 @@ export default class JoinLeavePayload extends Payload { const relayChannel = guild.channels.cache.get(bridge.config.relayChannelId); if (!relayChannel) return; - const avatar = await bridge.container.getService("Steam")?.getUserAvatar(player.steamId64); + const avatar = await ( + await bridge.container.getService("Steam") + ).getUserAvatar(player.steamId64); const embed = new Discord.EmbedBuilder() .setAuthor({ name: `${player.nick} has ${spawned ? "spawned" : "left"}`, diff --git a/app/services/gamebridge/payloads/StatusPayload.ts b/app/services/gamebridge/payloads/StatusPayload.ts index f5ff00e5..cbeeb470 100644 --- a/app/services/gamebridge/payloads/StatusPayload.ts +++ b/app/services/gamebridge/payloads/StatusPayload.ts @@ -80,7 +80,7 @@ export default class StatusPayload extends Payload { const { config: { host, port, url }, } = bridge.webApp; - const Steam = bridge.container.getService("Steam"); + const Steam = await bridge.container.getService("Steam"); const updateStatus = async () => { const current_countdown = countdown; @@ -220,7 +220,7 @@ export default class StatusPayload extends Payload { } if (mapThumbnail === null && current_workshopMap) { - const res = await Steam?.getPublishedFileDetails([current_workshopMap.id]).catch( + const res = await Steam.getPublishedFileDetails([current_workshopMap.id]).catch( console.error ); const thumbnailURI = res?.publishedfiledetails?.[0]?.preview_url; @@ -258,7 +258,7 @@ export default class StatusPayload extends Payload { if (!player.avatar) { let avatar: string | undefined; if (player.accountId) { - avatar = await Steam?.getUserAvatar( + avatar = await Steam.getUserAvatar( SteamID.fromIndividualAccountID(player.accountId).getSteamID64() ); } diff --git a/app/services/gamebridge/payloads/UnbanPayload.ts b/app/services/gamebridge/payloads/UnbanPayload.ts index 2a91824a..b82e8629 100644 --- a/app/services/gamebridge/payloads/UnbanPayload.ts +++ b/app/services/gamebridge/payloads/UnbanPayload.ts @@ -25,13 +25,13 @@ export default class UnbanPayload extends Payload { const notificationsChannel = guild.channels.cache.get(bridge.config.banUnbanChannelId); if (!notificationsChannel) return; - const steam = bridge.container.getService("Steam"); + const steam = await bridge.container.getService("Steam"); let steamId64 = ""; let bannerName = ""; let avatar = ""; try { steamId64 = new SteamID(player.steamId).getSteamID64(); - const summary: PlayerSummary | undefined = await steam?.getUserSummaries(steamId64); + const summary: PlayerSummary | undefined = await steam.getUserSummaries(steamId64); if (summary) { bannerName = summary.personaname; avatar = summary.avatarfull; @@ -41,7 +41,7 @@ export default class UnbanPayload extends Payload { } const bannedSteamId64 = new SteamID(banned.steamId).getSteamID64(); - const bannedAvatar = await steam?.getUserAvatar(bannedSteamId64); + const bannedAvatar = await steam.getUserAvatar(bannedSteamId64); const unixTime = parseInt(banTime); if (!unixTime || isNaN(unixTime)) throw new Error(`ban time is not a number? Supplied time: ${banTime}`); diff --git a/app/services/gamebridge/payloads/VoteKickPayload.ts b/app/services/gamebridge/payloads/VoteKickPayload.ts index f0942142..bf318444 100644 --- a/app/services/gamebridge/payloads/VoteKickPayload.ts +++ b/app/services/gamebridge/payloads/VoteKickPayload.ts @@ -17,7 +17,7 @@ export default class NotificationPayload extends Payload { const { offender, reporter, reason, result } = payload.data; const { bridge, discord: discordClient } = server; - const steam = bridge.container.getService("Steam"); + const steam = await bridge.container.getService("Steam"); if (!discordClient.ready) return; @@ -81,8 +81,8 @@ export default class NotificationPayload extends Payload { const reporterSteamId64 = new SteamID(reporter.steamID).getSteamID64(); const offenderSteamId64 = new SteamID(offender.steamID).getSteamID64(); - const reporterAvatar = await steam?.getUserAvatar(reporterSteamId64); - const offenderAvatar = await steam?.getUserAvatar(offenderSteamId64); + const reporterAvatar = await steam.getUserAvatar(reporterSteamId64); + const offenderAvatar = await steam.getUserAvatar(offenderSteamId64); const embed = new Discord.EmbedBuilder() .setAuthor({ @@ -101,27 +101,25 @@ export default class NotificationPayload extends Payload { .setThumbnail(offenderAvatar) .setColor(0xc4af21); - const sql = bridge.container.getService("SQL"); - if (sql) { - if (!this.votekickCache[offenderSteamId64]) { - const res = await sql.queryPool( - `SELECT votekick_amount FROM playerstats WHERE accountid = ${ - new SteamID(offender.steamID).accountid - }` - ); - if (res[0]) { - this.votekickCache[offenderSteamId64] = res[0].votekick_amount; - } else { - this.votekickCache[offenderSteamId64] = 0; - } - } - this.votekickCache[offenderSteamId64]++; - if (this.votekickCache[offenderSteamId64] > 0) { - embed.addFields( - f("Total Votekick Amount", this.votekickCache[offenderSteamId64].toString()) - ); + const sql = await bridge.container.getService("SQL"); + if (!this.votekickCache[offenderSteamId64]) { + const res = await sql.queryPool( + `SELECT votekick_amount FROM playerstats WHERE accountid = ${ + new SteamID(offender.steamID).accountid + }` + ); + if (res[0]) { + this.votekickCache[offenderSteamId64] = res[0].votekick_amount; + } else { + this.votekickCache[offenderSteamId64] = 0; } } + this.votekickCache[offenderSteamId64]++; + if (this.votekickCache[offenderSteamId64] > 0) { + embed.addFields( + f("Total Votekick Amount", this.votekickCache[offenderSteamId64].toString()) + ); + } await (notificationsChannel as TextChannel).send({ embeds: [embed], diff --git a/app/services/index.ts b/app/services/index.ts index 468ef17e..a3387907 100644 --- a/app/services/index.ts +++ b/app/services/index.ts @@ -57,19 +57,19 @@ export { }; export type ServiceMap = { - [key: string]: Service | undefined; - Bans?: Bans; - Data?: Data; - DiscordBot?: DiscordBot; - DiscordMetadata?: DiscordMetadata; - GameBridge?: GameBridge; - IRC?: IRC; - Markov?: Markov; - Motd?: Motd; - Resonite?: Resonite; - SQL?: SQL; - Starboard?: Starboard; - Steam?: Steam; - Tenor?: Tenor; - WebApp?: WebApp; + [key: string]: Service; + Bans: Bans; + Data: Data; + DiscordBot: DiscordBot; + DiscordMetadata: DiscordMetadata; + GameBridge: GameBridge; + IRC: IRC; + Markov: Markov; + Motd: Motd; + Resonite: Resonite; + SQL: SQL; + Starboard: Starboard; + Steam: Steam; + Tenor: Tenor; + WebApp: WebApp; }; diff --git a/app/services/webapp/api/discord-oauth.ts b/app/services/webapp/api/discord-oauth.ts index 2e259796..61309fb4 100644 --- a/app/services/webapp/api/discord-oauth.ts +++ b/app/services/webapp/api/discord-oauth.ts @@ -73,8 +73,7 @@ export const getOAuthTokens = async (code: any) => { }; export const revokeOAuthToken = async (token: string, localOnly?: boolean) => { - const sql: SQL = globalThis.MetaConcord.container.getService("SQL"); - if (!sql) return false; + const sql: SQL = await globalThis.MetaConcord.container.getService("SQL"); if (!localOnly) { const res = await axios @@ -110,10 +109,9 @@ export const revokeOAuthToken = async (token: string, localOnly?: boolean) => { return true; }; -export default (webApp: WebApp): void => { - const sql = webApp.container.getService("SQL"); - let metadata: DiscordMetadata | undefined; - if (!sql) return; +export default async (webApp: WebApp): Promise => { + const sql = await webApp.container.getService("SQL"); + const metadata = await webApp.container.getService("DiscordMetadata"); const getAuthorizationData = async (tokens: AccessTokenResponse) => { const res = await axios @@ -154,14 +152,12 @@ export default (webApp: WebApp): void => { res.redirect(url); }); webApp.app.get("/discord/link/:id", async (req, res) => { - metadata = metadata || webApp.container.getService("DiscordMetadata"); - const data = await metadata?.get(req.params.id); + const data = await metadata.get(req.params.id); if (!data) return res.status(404).send("no data"); res.send(data); }); webApp.app.get("/discord/link/:id/refresh", rateLimit(), async (req, res) => { - metadata = metadata || webApp.container.getService("DiscordMetadata"); - res.send((await metadata?.update(req.params.id)) ? "👌" : "👎"); + res.send((await metadata.update(req.params.id)) ? "👌" : "👎"); }); webApp.app.get("/discord/link/:id/revoke", rateLimit(), async (req, res) => { const secret = req.query.secret; @@ -189,7 +185,6 @@ export default (webApp: WebApp): void => { res.send("👌"); }); webApp.app.get("/discord/linkrefreshall", rateLimit(), async (req, res) => { - metadata = metadata || webApp.container.getService("DiscordMetadata"); const secret = req.query.secret; if (secret !== webApp.config.cookieSecret) return res.sendStatus(403); const entries = await ( @@ -197,12 +192,11 @@ export default (webApp: WebApp): void => { ).all("SELECT user_id FROM discord_tokens"); if (!entries || entries.length === 0) for (const entry of entries) { - await metadata?.update(entry.user_id); + await metadata.update(entry.user_id); } res.send("👌"); }); webApp.app.get("/discord/auth/callback", rateLimit(), async (req, res) => { - metadata = metadata || webApp.container.getService("DiscordMetadata"); try { const code = req.query["code"]; if (!code) return res.sendStatus(403); @@ -260,7 +254,7 @@ export default (webApp: WebApp): void => { } ); - await metadata?.update(userId); + await metadata.update(userId); res.send( "👍" + diff --git a/app/services/webapp/api/emojis.ts b/app/services/webapp/api/emojis.ts index fe2aa93f..8df80593 100644 --- a/app/services/webapp/api/emojis.ts +++ b/app/services/webapp/api/emojis.ts @@ -1,12 +1,10 @@ -import { DiscordBot } from "../../discord"; import { WebApp } from ".."; -export default (webApp: WebApp): void => { - let bot: DiscordBot | undefined; +export default async (webApp: WebApp): Promise => { + const bot = await webApp.container.getService("DiscordBot"); webApp.app.get("/discord/guild/emojis", async (_, res) => { - bot = bot || webApp.container.getService("DiscordBot"); - if (!bot || !bot.discord.readyAt) + if (!bot.discord.readyAt) return res.status(500).json({ error: "Bot is not connected", }); diff --git a/app/services/webapp/api/game-server-status.ts b/app/services/webapp/api/game-server-status.ts index 684e6518..54a45bca 100644 --- a/app/services/webapp/api/game-server-status.ts +++ b/app/services/webapp/api/game-server-status.ts @@ -1,20 +1,13 @@ -import { GameBridge } from "@/app/services"; import { GameServer } from "../../gamebridge"; import { WebApp } from ".."; import nodeHtmlToImage from "node-html-to-image"; import path from "path"; import pug from "pug"; -export default (webApp: WebApp): void => { - let gameBridge: GameBridge | undefined; - webApp.app.get("/server-status/:id/:bruh?", async (req, res) => { - gameBridge = gameBridge || webApp.container.getService("GameBridge"); - - if (!gameBridge) { - console.warn("Game Bridge is missing?"); - return res.sendStatus(503); - } +export default async (webApp: WebApp): Promise => { + const gameBridge = await webApp.container.getService("GameBridge"); + webApp.app.get("/server-status/:id/:bruh?", async (req, res) => { const server: GameServer = gameBridge.servers[req.params.id]; if (!server) { diff --git a/app/services/webapp/api/gamemode.ts b/app/services/webapp/api/gamemode.ts index 284f8f0a..fb21ee14 100644 --- a/app/services/webapp/api/gamemode.ts +++ b/app/services/webapp/api/gamemode.ts @@ -1,11 +1,10 @@ -import { DiscordBot } from "../../discord"; import { WebApp } from ".."; import servers from "@/config/gamebridge.servers.json"; const HOSTING_IDS = { 3: true, 1: true }; -export default (webApp: WebApp): void => { - let bot: DiscordBot | undefined; +export default async (webApp: WebApp): Promise => { + const bot = await webApp.container.getService("DiscordBot"); webApp.app.get("/gamemode/:id/", async (req, res) => { const ip = req.header("x-forwarded-for")?.split(",")[0]; @@ -18,9 +17,7 @@ export default (webApp: WebApp): void => { return res.sendStatus(403); } - bot = bot || webApp.container.getService("DiscordBot"); - - const server = bot?.bridge?.servers[id]; + const server = bot.bridge.servers[id]; if (!server) { return res.sendStatus(404); } diff --git a/app/services/webapp/api/gmod-error-handler.ts b/app/services/webapp/api/gmod-error-handler.ts index 40653f0a..081f0756 100644 --- a/app/services/webapp/api/gmod-error-handler.ts +++ b/app/services/webapp/api/gmod-error-handler.ts @@ -1,5 +1,5 @@ import { AddonURIS, getOrFetchGmodFile } from "@/utils"; -import { GameBridge, GameServer, Player } from "../../gamebridge"; +import { GameServer, Player } from "../../gamebridge"; import { WebApp } from ".."; import Discord from "discord.js"; import SteamID from "steamid"; @@ -84,8 +84,8 @@ const ignoreRegex = [ ]; //const fileIgnore = []; -export default (webApp: WebApp): void => { - let gameBridge: GameBridge | undefined; +export default async (webApp: WebApp): Promise => { + const gameBridge = await webApp.container.getService("GameBridge"); const webhook = new Discord.WebhookClient({ url: config.webhookUrl, @@ -104,9 +104,6 @@ export default (webApp: WebApp): void => { res.status(204); res.end(); - gameBridge = gameBridge || webApp.container.getService("GameBridge"); - if (!gameBridge) return res.sendStatus(400); - const server = servers.find(srv => srv.ip === ip); let gameserver: GameServer; let player: Player | undefined; diff --git a/app/services/webapp/api/steam-oauth.ts b/app/services/webapp/api/steam-oauth.ts index 2be6b89c..8b0e4833 100644 --- a/app/services/webapp/api/steam-oauth.ts +++ b/app/services/webapp/api/steam-oauth.ts @@ -17,9 +17,9 @@ import axios from "axios"; // openid.signed=signed,op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle& // openid.sig=W0u5DRbtHE1GG0ZKXjerUZDUGmc= -export default (webApp: WebApp): void => { - const sql = webApp.container.getService("SQL"); - if (!sql) return; +export default async (webApp: WebApp): Promise => { + const sql = await webApp.container.getService("SQL"); + webApp.app.get("/steam/auth/callback/:id", rateLimit(), async (req, res) => { const query = req.query; const userId = req.params.id; @@ -47,6 +47,7 @@ export default (webApp: WebApp): void => { return res.redirect("/discord/link"); }); + webApp.app.get("/steam/link/:id", async (req, res) => { const userId = req.params.id; if (!userId) res.status(403).send("Missing userid for linking");