use derive_deref::{Deref, DerefMut}; use serenity::framework::StandardFramework; use serenity::model::prelude::*; use serenity::prelude::*; use serenity::utils::Colour; use std::collections::HashMap; use std::sync::{Arc, Mutex}; #[derive(Default)] struct Handler { inactive_map: Arc>>, } #[derive(Debug, Deref, DerefMut)] struct InactiveThreads(HashMap); impl InactiveThreads { fn new(guild: Guild) -> Self { Self( guild .threads .iter() .map(|thread| (thread.id, thread.thread_metadata.unwrap().archived)) .collect(), ) } } #[serenity::async_trait] impl EventHandler for Handler { async fn thread_update(&self, ctx: Context, thread: GuildChannel) { let parent_channel = loop { let mut inactive_map = self.inactive_map.lock().unwrap(); let inactive_threads = inactive_map .entry(thread.guild_id) .or_insert_with(|| InactiveThreads::new(ctx.cache.guild(thread.guild_id).unwrap())); let current = thread.thread_metadata.unwrap().archived; let previous = inactive_threads.insert(thread.id, current); if !(previous.unwrap_or_default() && !current) { return; } break thread.parent_id.unwrap(); }; println!( "notifying about thread {} in parent channel {}", thread.name, parent_channel ); if let Err(why) = parent_channel .send_message(&ctx.http, |msg| { msg.embed(|e| { e.colour(Colour::TEAL) .title("New activity in thread") .description(thread.mention()) }) }) .await { println!("got error while sending embed: {}", why); } } async fn guild_create(&self, _: Context, guild: Guild, _is_new: bool) { println!("discovered guild {}", guild.name); self.inactive_map .lock() .unwrap() .insert(guild.id, InactiveThreads::new(guild)); } async fn ready(&self, _: Context, ready: Ready) { println!("logged in as {}", ready.user.name); } } #[tokio::main] async fn main() { let token = std::env::var("CESSPOOL_TOKEN") .expect("Need discord bot token at environment variable CESSPOOL_TOKEN"); Client::builder(&token, GatewayIntents::GUILDS) .framework(StandardFramework::new()) .event_handler(Handler::default()) .await .unwrap() .start() .await .unwrap(); }