diff --git a/src/bot.rs b/src/bot.rs index 48a19de..7a24236 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -3,8 +3,14 @@ use serenity::{ model::{channel::Message, gateway::Ready}, prelude::*, }; +use serenity::model::prelude::GuildId; use std::sync::mpsc; use std::sync::Mutex; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::time::Duration; +use std::thread; +use std::sync::Arc; + use crate::postman; use crate::discord_structure; @@ -12,8 +18,11 @@ mod token; const HELP_MESSAGE: &str = "Hello there, Human! I am a messenger for the wandering penwing."; const HELP_COMMAND: &str = "!jiji"; +const PACKET_REFRESH : u64 = 500; -struct Handler; +struct Handler { + is_loop_running: AtomicBool, +} #[async_trait] @@ -30,31 +39,84 @@ impl EventHandler for Handler { } async fn ready(&self, context: Context, ready: Ready) { - println!("{} is connected!", ready.user.name); - let guilds = context.cache.guilds().await; + println!("bot : {} is connected!", ready.user.name); + } + + async fn cache_ready(&self, context: Context, _guilds: Vec) { + println!("bot : cache built successfully!"); - if let Some(sender) = context.data.read().await.get::() { - for guild_id in guilds { - let guild_name : String = if let Some(guild) = context.cache.guild(guild_id).await { - guild.name.clone() - } else { - "not found".to_string() - }; - println!("bot : found guild : '{}' ({})", guild_name.clone(), guild_id.clone()); - - let guild = discord_structure::Guild::new(guild_name, guild_id.to_string()); - sender.send(postman::Packet::Guild(guild)).expect("Failed to send packet"); + let context = Arc::new(context); + + if !self.is_loop_running.load(Ordering::Relaxed) { + // We have to clone the Arc, as it gets moved into the new thread. + let context1 = Arc::clone(&context); + // tokio::spawn creates a new green thread that can run in parallel with the rest of + // the application. + tokio::spawn(async move { + get_guilds(&context1).await; + }); + + let context2 = Arc::clone(&context); + tokio::spawn(async move { + loop { + check_packets(&context2).await; + thread::sleep(Duration::from_millis(PACKET_REFRESH)); + } + }); + + // Now that the loop is running, we set the bool to true + self.is_loop_running.swap(true, Ordering::Relaxed); + } + } +} + +async fn check_packets(context: &Context) { + if let Some(receiver_mutex) = context.data.read().await.get::() { + if let Ok(receiver) = receiver_mutex.lock() { + while let Ok(packet) = receiver.try_recv() { + match packet { + postman::Packet::FetchChannels(guild_id) => { + println!("bot : fetch channels request received : '{}'", guild_id); + } + _ => { + println!("bot : unhandled packet"); + } + } } } else { - println!("bot : failed to retrieve sender"); + println!("bot : failed to lock receiver"); } + } else { + println!("bot : failed to retrieve receiver"); + } +} + +async fn get_guilds(context: &Context) { + let guilds = context.cache.guilds().await; + + if let Some(sender) = context.data.read().await.get::() { + for guild_id in guilds { + let guild_name : String = if let Some(guild) = context.cache.guild(guild_id).await { + guild.name.clone() + } else { + "not found".to_string() + }; + println!("bot : found guild : '{}' ({})", guild_name.clone(), guild_id.clone()); + + let guild = discord_structure::Guild::new(guild_name, guild_id.to_string()); + sender.send(postman::Packet::Guild(guild)).expect("Failed to send packet"); + } + } else { + println!("bot : failed to retrieve sender"); } } pub async fn start_discord_bot(sender: mpsc::Sender, receiver: Mutex>) { println!("bot : connection process started..."); let maybe_client = Client::builder(token::TOKEN) - .event_handler(Handler) + .event_handler(Handler { + is_loop_running: AtomicBool::new(false), + }) .type_map_insert::(sender) .type_map_insert::(receiver) .await