summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-11-06 18:24:20 -0800
committerFuwn <[email protected]>2025-11-06 18:24:35 -0800
commit7fde9bf0b76d929605f7981f8cc7f1846438a938 (patch)
treef8888def52950aa60d43a5ffda28984646dab13d
parentfeat(gateway:listeners): Add privileged access monitoring (diff)
downloadumabotdiscord-7fde9bf0b76d929605f7981f8cc7f1846438a938.tar.xz
umabotdiscord-7fde9bf0b76d929605f7981f8cc7f1846438a938.zip
feat(gateway:listeners): Add #super-freak manager
-rw-r--r--packages/gateway/src/listeners/clientReady/index.ts2
-rw-r--r--packages/gateway/src/listeners/superFreakChannel.ts163
2 files changed, 165 insertions, 0 deletions
diff --git a/packages/gateway/src/listeners/clientReady/index.ts b/packages/gateway/src/listeners/clientReady/index.ts
index 06c24b2..8c43d3b 100644
--- a/packages/gateway/src/listeners/clientReady/index.ts
+++ b/packages/gateway/src/listeners/clientReady/index.ts
@@ -6,6 +6,7 @@ import { initializeMessageStatistics } from "../messageStatistics";
import { initializePersonaSystem } from "../messageCreate/personaRandomMessage";
import { initializeConversationStarterSystem } from "../messageCreate/dailyConversationStarter";
import { initializeWelcomeSystem } from "../memberJoin";
+import { initializeSuperFreakChannelSystem } from "../superFreakChannel";
export const handleClientReady = (client: Client) => {
client.once(Events.ClientReady, async (readyClient) => {
@@ -15,6 +16,7 @@ export const handleClientReady = (client: Client) => {
initializePersonaSystem(readyClient);
initializeConversationStarterSystem(readyClient);
initializeWelcomeSystem(readyClient);
+ await initializeSuperFreakChannelSystem(readyClient);
await handleUmagramCatchup(readyClient);
// Character claim tracker will initialize on first use
});
diff --git a/packages/gateway/src/listeners/superFreakChannel.ts b/packages/gateway/src/listeners/superFreakChannel.ts
new file mode 100644
index 0000000..8c292f4
--- /dev/null
+++ b/packages/gateway/src/listeners/superFreakChannel.ts
@@ -0,0 +1,163 @@
+import { Client, EmbedBuilder } from "discord.js";
+import { CENTRAL_GUILD_ID } from "../constants";
+import { logUnexpectedDiscordAPIError } from "../utilities";
+
+const SUPER_FREAK_CHANNEL_ID = "1410333697701314791";
+const PRIVILEGED_ACCESS_ROLE_ID = "1423213971422580736";
+const ALERT_CHANNEL_ID = "1436163337955184752";
+
+const getRandomNonMultipleOf24Hours = (
+ minHours: number = 1,
+ maxHours: number = 23,
+): number => {
+ let hours: number;
+
+ do {
+ hours = Math.floor(Math.random() * (maxHours - minHours + 1)) + minHours;
+ } while (24 % hours === 0);
+
+ return hours * 60 * 60 * 1000;
+};
+
+class SuperFreakChannelSystem {
+ private client: Client | null = null;
+ private isOpen: boolean = false;
+ private timeoutHandle: any | null = null;
+ private nextToggleTime: Date | null = null;
+
+ constructor() {
+ //
+ }
+
+ public async initialize(client: Client) {
+ this.client = client;
+
+ await this.checkCurrentState();
+ this.scheduleNextToggle();
+ }
+
+ private async checkCurrentState() {
+ if (!this.client) return;
+
+ try {
+ const guild = this.client.guilds.cache.get(CENTRAL_GUILD_ID);
+
+ if (!guild) return;
+
+ const channel = guild.channels.cache.get(SUPER_FREAK_CHANNEL_ID);
+
+ if (!channel || !channel.isTextBased() || channel.isThread()) return;
+
+ const privilegedRole = guild.roles.cache.get(PRIVILEGED_ACCESS_ROLE_ID);
+
+ if (!privilegedRole) return;
+
+ const permissions = channel.permissionsFor(privilegedRole);
+ this.isOpen = permissions?.has("ViewChannel") ?? false;
+ } catch (error) {
+ logUnexpectedDiscordAPIError(error);
+ }
+ }
+
+ private async sendAlert() {
+ if (!this.client) return;
+
+ try {
+ const alertChannel = this.client.channels.cache.get(ALERT_CHANNEL_ID);
+
+ if (
+ !alertChannel ||
+ !alertChannel.isTextBased() ||
+ alertChannel.isDMBased()
+ ) {
+ return;
+ }
+
+ const embed = new EmbedBuilder()
+ .setTitle(this.isOpen ? "🔓 Channel Opened" : "🔒 Channel Closed")
+ .setColor(this.isOpen ? "#00ff00" : "#ff0000")
+ .addFields({
+ name: "Channel",
+ value: `<#${SUPER_FREAK_CHANNEL_ID}>`,
+ inline: true,
+ });
+
+ if (this.nextToggleTime) {
+ const nextAction = this.isOpen ? "close" : "reopen";
+ const unixTimestamp = Math.floor(this.nextToggleTime.getTime() / 1000);
+ const discordTimestamp = `<t:${unixTimestamp}:F>`;
+
+ embed.addFields({
+ name: `Will ${nextAction}`,
+ value: discordTimestamp,
+ inline: false,
+ });
+ }
+
+ embed.setTimestamp();
+ await alertChannel.send({ embeds: [embed] });
+ } catch (error) {
+ logUnexpectedDiscordAPIError(error);
+ }
+ }
+
+ private async toggleChannel() {
+ if (!this.client) return;
+
+ try {
+ const guild = this.client.guilds.cache.get(CENTRAL_GUILD_ID);
+
+ if (!guild) return;
+
+ const channel = guild.channels.cache.get(SUPER_FREAK_CHANNEL_ID);
+
+ if (!channel || !channel.isTextBased() || channel.isThread()) return;
+
+ const privilegedRole = guild.roles.cache.get(PRIVILEGED_ACCESS_ROLE_ID);
+
+ if (!privilegedRole) return;
+
+ this.isOpen = !this.isOpen;
+
+ await channel.permissionOverwrites.edit(privilegedRole, {
+ ViewChannel: this.isOpen,
+ });
+
+ this.scheduleNextToggle();
+ await this.sendAlert();
+ } catch (error) {
+ logUnexpectedDiscordAPIError(error);
+ }
+ }
+
+ private scheduleNextToggle() {
+ if (this.timeoutHandle) clearTimeout(this.timeoutHandle);
+
+ const minHours = this.isOpen ? 5 : 3;
+ const maxHours = this.isOpen ? 11 : 5;
+ const duration = getRandomNonMultipleOf24Hours(minHours, maxHours);
+
+ this.nextToggleTime = new Date(Date.now() + duration);
+ this.timeoutHandle = setTimeout(() => {
+ this.toggleChannel();
+ }, duration);
+ }
+
+ public destroy() {
+ if (this.timeoutHandle) {
+ clearTimeout(this.timeoutHandle);
+
+ this.timeoutHandle = null;
+ }
+ }
+}
+
+let superFreakChannelSystem: SuperFreakChannelSystem | null = null;
+
+export const initializeSuperFreakChannelSystem = async (client: Client) => {
+ if (superFreakChannelSystem) superFreakChannelSystem.destroy();
+
+ superFreakChannelSystem = new SuperFreakChannelSystem();
+
+ await superFreakChannelSystem.initialize(client);
+};