mod aggregator; mod types; mod plugin; mod util; use twilight_gateway::{Intents, Shard, ShardId}; use twilight_http::Client; use twilight_model::channel::Message; pub use types::SystemThreadCommand; use crate::SystemUiEvent; use std::{num::NonZeroU64, sync::Arc}; use tokio::sync::Mutex; use plugin::SeancePlugin; use std::sync::mpsc::Sender as ThreadSender; use types::{Member, Response, System}; pub struct Manager; impl Manager { pub async fn start(system_name: String, system_config: crate::config::System, ui_sender : ThreadSender<(String, SystemUiEvent)>) { let gateway_intents = Intents::GUILD_MEMBERS | Intents::GUILD_PRESENCES | Intents::GUILD_MESSAGES | Intents::MESSAGE_CONTENT; let system = System { followed_user: NonZeroU64::try_from(system_config.reference_user_id.parse::().unwrap()).unwrap().into(), command_prefix: "!".to_string(), members: system_config.members.iter().map(|member| Member { discord_token: member.discord_token.clone(), message_pattern: member.message_pattern.clone(), shard: Arc::new(Mutex::new(Shard::new( ShardId::ONE, member.discord_token.clone(), gateway_intents.clone(), ))), client: Arc::new(Mutex::new(Client::new(member.discord_token.clone()))) }).collect(), }; let mut message_receiver = aggregator::MessageAggregator::start(&system); let mut plugins : Vec> = vec![ Box::new(plugin::ProxyPrefixes), Box::new(plugin::Autoproxy::new()), ]; loop { match message_receiver.recv().await { None => (), Some((message, seen_by)) => { println!("Checking message: {}", message.content.clone()); if message.content.starts_with(&system.command_prefix) { for plugin in &mut plugins { match plugin.handle_command(&system, &message).await { plugin::CommandOutcome::Skipped => continue, plugin::CommandOutcome::Handled => break, plugin::CommandOutcome::Errored {message} => { println!("Error: {message}"); break }, } } } else { let mut message_response = Response::Noop { delete_source: false }; for plugin in &plugins { plugin.handle_message(&system, &message, &mut message_response).await; } match message_response.clone() { Response::Noop { delete_source } => { if delete_source { println!("Deleting source message"); let client = system.members.iter().find(|m| m.discord_token == seen_by).map(|m| m.client.clone()) .expect("No such client"); let _ = client.lock().await.delete_message(message.channel_id, message.id) .await; } }, Response::Proxy { member, content } => { if let Ok(new_message) = util::duplicate_message(&member.client, &message, content.as_str()).await { if let Err(err) = {member.client.lock().await.delete_message(message.channel_id, message.id).await.map(|_| ()).map_err(|err| err.to_string()).clone() } { println!("Error proxying message: {err}"); {let _ = member.client.lock().await.delete_message(new_message.channel_id, new_message.id).await;} } for plugin in &plugins { plugin.post_response(&system, &new_message, message.channel_id, &message_response).await; } } }, } } }, } } } }