diff options
author | Ashelyn Rose <git@ashen.earth> | 2024-11-07 20:07:25 -0700 |
---|---|---|
committer | Ashelyn Rose <git@ashen.earth> | 2024-11-07 20:07:25 -0700 |
commit | a69d779cfff810edd375318c3d36fecd42d294b5 (patch) | |
tree | d51ce593e45a800bf63c5b41caf82df151f03245 | |
parent | ba9362908d2defa784a45c16bc142c66c3fab9a3 (diff) |
Runtime ui
-rw-r--r-- | Cargo.lock | 133 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/config.rs | 1 | ||||
-rw-r--r-- | src/main.rs | 195 | ||||
-rw-r--r-- | src/system/message_parser.rs | 14 | ||||
-rw-r--r-- | src/system/mod.rs | 84 |
6 files changed, 387 insertions, 41 deletions
diff --git a/Cargo.lock b/Cargo.lock index 26cf5ed..67cc02c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,6 +211,31 @@ dependencies = [ ] [[package]] +name = "crossterm" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" +dependencies = [ + "bitflags 2.6.0", + "crossterm_winapi", + "mio 1.0.2", + "parking_lot", + "rustix", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -476,6 +501,12 @@ dependencies = [ ] [[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] name = "http" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -697,9 +728,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.152" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libz-sys" @@ -719,6 +750,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -766,6 +807,19 @@ dependencies = [ ] [[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "log", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] name = "native-tls" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -866,6 +920,29 @@ dependencies = [ ] [[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.0", +] + +[[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -970,6 +1047,15 @@ dependencies = [ ] [[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] name = "regex" version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1078,9 +1164,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" dependencies = [ "bitflags 2.6.0", "errno", @@ -1178,6 +1264,12 @@ dependencies = [ ] [[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] name = "sct" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1191,6 +1283,7 @@ dependencies = [ name = "seance-rs" version = "0.1.0" dependencies = [ + "crossterm", "futures", "lru", "regex", @@ -1313,6 +1406,36 @@ dependencies = [ ] [[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +dependencies = [ + "libc", + "mio 1.0.2", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1479,7 +1602,7 @@ dependencies = [ "backtrace", "bytes", "libc", - "mio", + "mio 0.8.10", "pin-project-lite", "socket2", "windows-sys 0.48.0", diff --git a/Cargo.toml b/Cargo.toml index 09575e6..1a7acb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +crossterm = "0.28.1" lru = "0.12.3" futures = "0.3.30" regex = "1.10.2" diff --git a/src/config.rs b/src/config.rs index 28fe422..efbb50d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -55,6 +55,7 @@ pub struct System { pub forward_pings: bool, pub autoproxy: Option<AutoproxyConfig>, pub pluralkit: Option<PluralkitConfig>, + pub ui_color: Option<String>, } fn default_forward_pings() -> bool { diff --git a/src/main.rs b/src/main.rs index 6e37938..287cd4f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,41 +2,141 @@ mod config; mod system; +use crossterm::{cursor::{self, MoveTo}, terminal::{Clear, ClearType, DisableLineWrap, EnableLineWrap, EnterAlternateScreen, LeaveAlternateScreen}}; use system::{Manager, SystemThreadCommand}; -use std::{fs, thread::{self, sleep, JoinHandle}, time::Duration, sync::mpsc}; +use std::{collections::{HashMap, VecDeque}, fs, io::{self, Write}, sync::mpsc, thread::{self, sleep, JoinHandle}, time::Duration}; use tokio::runtime; +pub struct UiState { + pub systems: HashMap<String, SystemState>, + pub logs: VecDeque<String>, +} + +pub enum SystemState { + Running(HashMap<String, MemberState>), + Reloading, + Restarting, + Shutdown, +} + +pub struct MemberState { + pub connected: bool, + pub autoproxied: bool, +} + +pub enum SystemUiEvent { + SystemClose, + MemberAutoproxy(Option<String>), + GatewayDisconnect(String), + GatewayConnect(String), + LogLine(String), +} + +const MAX_LOG : usize = 1000; + fn main() { let initial_config = fs::read_to_string("./config.toml").expect("Could not find config file"); let config = config::Config::load(initial_config.to_string()); - let (waker, waiter) = mpsc::channel::<()>(); + let (waker, waiter) = mpsc::channel::<(String, SystemUiEvent)>(); let mut join_handles = Vec::<(String, JoinHandle<_>)>::new(); + let mut ui_state = UiState { + systems: HashMap::new(), + logs: VecDeque::new(), + }; + for (system_name, system_config) in config.systems.iter() { let handle = spawn_system(system_name, system_config.clone(), waker.clone()); + let mut member_states = HashMap::new(); + for member_name in system_config.members.iter() { + member_states.insert(member_name.name.clone(), MemberState { + connected: false, + autoproxied: false, + }); + } + + let system_state = SystemState::Running(member_states); + ui_state.systems.insert(system_name.clone(), system_state); + join_handles.push((system_name.clone(), handle)); } + crossterm::execute!(io::stdout(), EnterAlternateScreen).unwrap(); + crossterm::execute!(io::stdout(), DisableLineWrap).unwrap(); + loop { - // Check manually every 10 seconds just in case - let _ = waiter.recv_timeout(Duration::from_secs(10)); + // Wait for an event from one of the threads + let ui_event = waiter.recv_timeout(Duration::from_millis(500)); + + if let Ok((system_name, ui_event)) = ui_event { + let system_state = ui_state.systems.get_mut(&system_name).unwrap(); + match system_state { + SystemState::Running(member_states) => match ui_event { + // We will check for the join in a second + SystemUiEvent::SystemClose => (), + + SystemUiEvent::MemberAutoproxy(member_name) => { + member_states.iter_mut().for_each(|(_, member_state)| { + member_state.autoproxied = false; + }); + + if let Some(member_name) = member_name { + member_states.get_mut(&member_name).unwrap() + .autoproxied = true; + } + }, + + SystemUiEvent::GatewayDisconnect(member_name) => { + member_states.get_mut(&member_name).unwrap() + .connected = false; + }, + + SystemUiEvent::GatewayConnect(member_name) => { + member_states.get_mut(&member_name).unwrap() + .connected = true; + + }, + + SystemUiEvent::LogLine(log) => { + if log.len() == MAX_LOG { + let _ = ui_state.logs.pop_front(); + } + + ui_state.logs.push_back( + format!("{system_name:>8.8}: {log}") + ); + }, + + }, + _ => (), + } + } // Just to make sure the join handle is updated by the time we check - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(10)); if let Some(completed_index) = join_handles.iter().position(|(_, handle)| handle.is_finished()) { let (name, next_join) = join_handles.swap_remove(completed_index); match next_join.join() { Err(err) => { - println!("Thread for system {} panicked!", name); - println!("{:?}", err); + let _ = ui_state.systems.insert(name.clone(), SystemState::Shutdown); + ui_state.logs.push_back( + format!("Thread for system {} panicked!", name) + ); + + ui_state.logs.push_back( + format!("{:?}", err) + ); }, Ok(SystemThreadCommand::Restart) => { - println!("Thread for system {} requested restart", name); + let _ = ui_state.systems.insert(name.clone(), SystemState::Restarting); + ui_state.logs.push_back( + format!("Thread for system {} requested restart", name) + ); if let Some((_, config)) = config.systems.iter().find(|(system_name, _)| name == **system_name) { let handle = spawn_system(&name, config.clone(), waker.clone()); join_handles.push((name, handle)); @@ -44,15 +144,24 @@ fn main() { }, Ok(SystemThreadCommand::ShutdownSystem) => { - println!("Thread for system {} requested shutdown", name); + let _ = ui_state.systems.insert(name.clone(), SystemState::Shutdown); + ui_state.logs.push_back( + format!("Thread for system {} requested shutdown", name) + ); continue; }, + Ok(SystemThreadCommand::ReloadConfig) => { - println!("Thread for system {} requested config reload", name); + let _ = ui_state.systems.insert(name.clone(), SystemState::Reloading); + ui_state.logs.push_back( + format!("Thread for system {} requested config reload", name) + ); let config_file = if let Ok(config_file) = fs::read_to_string("./config.toml") { config_file } else { - println!("Could not open config file, continuing with initial config"); + ui_state.logs.push_back( + format!("Could not open config file, continuing with initial config") + ); initial_config.clone() }; @@ -62,17 +171,24 @@ fn main() { let handle = spawn_system(&name, system_config, waker.clone()); join_handles.push((name.clone(), handle)); } else { - println!("New config file but this system no longer exists, exiting."); + ui_state.logs.push_back( + format!("New config file but this system no longer exists, exiting.") + ); continue; } }, Ok(SystemThreadCommand::ShutdownAll) => break, } } + + update_ui(&ui_state, &config); } + + crossterm::execute!(io::stdout(), EnableLineWrap).unwrap(); + crossterm::execute!(io::stdout(), LeaveAlternateScreen).unwrap(); } -fn spawn_system(system_name : &String, system_config: config::System, waker: mpsc::Sender<()>) -> JoinHandle<SystemThreadCommand> { +fn spawn_system(system_name : &String, system_config: config::System, waker: mpsc::Sender<(String, SystemUiEvent)>) -> JoinHandle<SystemThreadCommand> { let name = system_name.clone(); let config = system_config.clone(); @@ -80,16 +196,63 @@ fn spawn_system(system_name : &String, system_config: config::System, waker: mps .name(format!("seance_{}", &name)) .spawn(move || -> _ { let thread_local_runtime = runtime::Builder::new_current_thread().enable_all().build().unwrap(); + let dup_waker = waker.clone(); - // TODO: allow system manager runtime to return a command thread_local_runtime.block_on(async { - let mut system = Manager::new(name, config); + let mut system = Manager::new(name.clone(), config, waker); system.start_clients().await; }); - let _ = waker.send(()); + let _ = dup_waker.send((name, SystemUiEvent::SystemClose)); SystemThreadCommand::Restart }).unwrap() } +fn update_ui(ui_state: &UiState, config: &config::Config) { + crossterm::execute!(io::stdout(), Clear(ClearType::FromCursorUp)).unwrap(); + crossterm::execute!(io::stdout(), MoveTo(0, 0)).unwrap(); + + let (width, height) = crossterm::terminal::size().unwrap(); + let status_lines = (ui_state.systems.len() * 2) + ui_state.systems.values().map(|system| match system { + SystemState::Running(members) => members.len(), + SystemState::Reloading => 1, + SystemState::Restarting => 1, + SystemState::Shutdown => 1, + } ).sum::<usize>() + 1; + + let log_space = height as usize - status_lines - 1; + let log_height = ui_state.logs.len(); + + for (name, state) in ui_state.systems.iter() { + println!("{name}"); + match state { + SystemState::Shutdown => println!(" - [System stopped]"), + SystemState::Reloading => println!(" - [System reloading]"), + SystemState::Restarting => println!(" - [System restarting]"), + SystemState::Running(members) => for (name, state) in members { + if !state.connected { + println!(" - {name} (connecting)") + } else if state.autoproxied { + println!(" - {name} (autoproxy)") + } else { + println!(" - {name}") + } + }, + } + + println!(""); + } + + println!("{:-<width$}", "", width = width as usize); + + let range = if log_height <= log_space { + 0..log_height + } else { + log_height - log_space .. log_height + }; + + for line in ui_state.logs.range(range) { + println!("{line}"); + } +} diff --git a/src/system/message_parser.rs b/src/system/message_parser.rs index 349ce0e..2c6d6d2 100644 --- a/src/system/message_parser.rs +++ b/src/system/message_parser.rs @@ -15,7 +15,7 @@ pub enum ParsedMessage { message_content: String, latch: bool, }, - UnproxiedMessage, + UnproxiedMessage(Option<String>), LatchClear(MemberId), // TODO: Figure out how to represent emotes @@ -28,6 +28,7 @@ pub enum Command { Reproxy(MemberId, MessageId), Delete(MessageId), Nick(MemberId, String), + Log(String), ReloadSystemConfig, ExitSéance, UnknownCommand, @@ -51,13 +52,14 @@ impl MessageParser { } if message.content.starts_with(r"\") { - return ParsedMessage::UnproxiedMessage + return ParsedMessage::UnproxiedMessage(None) } if message.content.starts_with(r"!") { if let Some(parse) = MessageParser::check_command(message, secondary_message, system_config, latch_state) { return ParsedMessage::Command(parse); - + } else { + return ParsedMessage::UnproxiedMessage(Some(format!("Unknown command string: {}", message.content))); } } @@ -76,7 +78,7 @@ impl MessageParser { } // If nothing else - ParsedMessage::UnproxiedMessage + ParsedMessage::UnproxiedMessage(None) } fn check_command(message: &FullMessage, secondary_message: Option<&FullMessage>, system_config: &System, latch_state: Option<(MemberId, Timestamp)>) -> Option<Command> { @@ -86,6 +88,10 @@ impl MessageParser { match first_word { None => return None, Some(command_name) => match command_name { + "log" => { + let remainder = words.remainder().unwrap().to_string(); + return Some(Command::Log(remainder)); + }, "edit" => { let editing_member = Self::get_member_id_from_user_id(secondary_message.as_ref().unwrap().author.id, system_config).unwrap(); return Some(Command::Edit(editing_member, secondary_message.unwrap().id, words.remainder().unwrap().to_string())); diff --git a/src/system/mod.rs b/src/system/mod.rs index 44c6da8..e2bd1ee 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -1,5 +1,6 @@ use std::{collections::HashMap, num::NonZeroUsize, str::FromStr, time::Duration}; +use std::sync::mpsc::Sender as ThreadSender; use lru::LruCache; use tokio::{ sync::mpsc::{channel, Sender}, @@ -10,6 +11,7 @@ use twilight_model::{channel::message::{MessageReference, MessageType, ReactionT use twilight_model::util::Timestamp; use crate::config::{AutoproxyConfig, AutoproxyLatchScope, Member}; +use crate::SystemUiEvent; mod aggregator; mod bot; @@ -33,10 +35,11 @@ pub struct Manager { pub aggregator: MessageAggregator, pub send_cache: LruCache<ChannelId, TwiMessage>, pub reference_user_id: UserId, + pub ui_sender: ThreadSender<(String, SystemUiEvent)>, } impl Manager { - pub fn new(system_name: String, system_config: crate::config::System) -> Self { + pub fn new(system_name: String, system_config: crate::config::System, ui_sender : ThreadSender<(String, SystemUiEvent)>) -> Self { Self { reference_user_id: Id::from_str(&system_config.reference_user_id.as_str()) .expect(format!("Invalid user id for system {}", &system_name).as_str()), @@ -47,6 +50,7 @@ impl Manager { latch_state: None, system_sender: None, send_cache: LruCache::new(NonZeroUsize::new(15).unwrap()), + ui_sender, } } @@ -71,7 +75,9 @@ impl Manager { } pub async fn start_clients(&mut self) { - println!("Starting clients for system {}", self.name); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Starting clients for system {}", self.name) + ))); let (system_sender, mut system_receiver) = channel::<SystemEvent>(100); self.system_sender = Some(system_sender.clone()); @@ -83,7 +89,9 @@ impl Manager { } if self.config.members.len() < 1 { - println!("WARNING: System {} has no configured members", &self.name); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("WARNING: System {} has no configured members", &self.name) + ))); } loop { @@ -94,19 +102,29 @@ impl Manager { let member = self.find_member_by_id(member_id).unwrap(); - println!("Gateway client {} ({}) connected", member.name, member_id); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::GatewayConnect(member.name.clone()))); + + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Gateway client {} ({}) connected", member.name, member_id) + ))); } Some(SystemEvent::GatewayError(member_id, message)) => { let member = self.find_member_by_id(member_id).unwrap(); - println!("Gateway client {} ran into error {}", member.name, message); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Gateway client {} ran into error {}", member.name, message) + ))); } Some(SystemEvent::GatewayClosed(member_id)) => { let member = self.find_member_by_id(member_id).unwrap(); - println!("Gateway client {} closed", member.name); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::GatewayDisconnect(member.name.clone()))); + + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Gateway client {} closed", member.name) + ))); self.start_bot(member_id).await; } @@ -123,7 +141,11 @@ impl Manager { Some(SystemEvent::AutoproxyTimeout(time_scheduled)) => { if let Some((_member, current_last_message)) = self.latch_state.clone() { if current_last_message == time_scheduled { - println!("Autoproxy timeout has expired: {} (last sent), {} (timeout scheduled)", current_last_message.as_secs(), time_scheduled.as_secs()); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::MemberAutoproxy(None))); + + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Autoproxy timeout has expired: {} (last sent), {} (timeout scheduled)", current_last_message.as_secs(), time_scheduled.as_secs()) + ))); self.latch_state = None; self.update_status_of_system().await; } @@ -195,7 +217,9 @@ impl Manager { if let Some(last) = last_in_channel { self.send_cache.put(message.channel_id, last); } else { - println!("WARNING: Could not look up most recent message in channel {}", message.channel_id); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("WARNING: Could not look up most recent message in channel {}", message.channel_id) + ))); }; // Return the message referenced from cache so there's no unnecessary clone @@ -206,12 +230,17 @@ impl Manager { let parsed_message = MessageParser::parse(&message, referenced_message, &self.config, self.latch_state); match parsed_message { - message_parser::ParsedMessage::UnproxiedMessage => (), + message_parser::ParsedMessage::UnproxiedMessage(log_string) => if let Some(log_string) = log_string { + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Parse error: {log_string}") + ))); + }, message_parser::ParsedMessage::LatchClear(member_id) => { let _ = self.bots.get(&member_id).unwrap().delete_message(message.channel_id, message.id).await; self.latch_state = None; self.update_status_of_system().await; + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::MemberAutoproxy(None))); }, message_parser::ParsedMessage::SetProxyAndDelete(member_id) => { @@ -234,7 +263,9 @@ impl Manager { let author = MessageParser::get_member_id_from_user_id(referenced_message.unwrap().author.id, &self.config); if author.is_none() { - println!("Cannot edit another user's message"); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Cannot edit another user's message") + ))); let _ = self.bots.get(&member_id).unwrap().react_message(message.channel_id, message.id, &RequestReactionType::Unicode { name: "🛑" }).await; return } @@ -254,14 +285,18 @@ impl Manager { message_parser::ParsedMessage::Command(Command::Reproxy(member_id, message_id)) => { if !referenced_message.map(|message| message.id == message_id).unwrap_or(false) { - println!("ERROR: Attempted reproxy on message other than referenced_message"); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("ERROR: Attempted reproxy on message other than referenced_message") + ))); let _ = self.bots.get(&member_id).unwrap().react_message(message.channel_id, message.id, &RequestReactionType::Unicode { name: "⁉️" }).await; return } let author = MessageParser::get_member_id_from_user_id(referenced_message.unwrap().author.id, &self.config); if author.is_none() { - println!("Cannot reproxy another user's message"); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Cannot reproxy another user's message") + ))); let _ = self.bots.get(&member_id).unwrap().react_message(message.channel_id, message.id, &RequestReactionType::Unicode { name: "🛑" }).await; return } @@ -274,7 +309,9 @@ impl Manager { self.update_status_of_system().await; } } else { - println!("Not reproxying under same user"); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Not reproxying under same user") + ))); } let bot = self.bots.get(&member_id).unwrap(); @@ -286,7 +323,9 @@ impl Manager { let author = MessageParser::get_member_id_from_user_id(referenced_message.unwrap().author.id, &self.config); if author.is_none() { - println!("Cannot delete another user's message"); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Cannot delete another user's message") + ))); let _ = self.bots.get(&member_id).unwrap().react_message(message.channel_id, message.id, &RequestReactionType::Unicode { name: "🛑" }).await; return } @@ -296,6 +335,12 @@ impl Manager { let _ = bot.delete_message(message.channel_id, message.id).await; } + message_parser::ParsedMessage::Command(Command::Log(log_string)) => { + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Log: {log_string}") + ))); + } + message_parser::ParsedMessage::Command(Command::UnknownCommand) => { let member_id = if let Some((member_id, _)) = self.latch_state { member_id @@ -317,7 +362,9 @@ impl Manager { let duplicate_result = bot.duplicate_message(message, content).await; if duplicate_result.is_err() { - println!("Could not copy message: {:?}", duplicate_result); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Could not copy message: {:?}", duplicate_result) + ))); return Err(()) } @@ -325,7 +372,9 @@ impl Manager { let delete_result = bot.delete_message(message.channel_id, message.id).await; if delete_result.is_err() { - println!("Could not delete message: {:?}", delete_result); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::LogLine( + format!("Could not delete message: {:?}", delete_result) + ))); // Delete the duplicated message if that failed let _ = bot.delete_message(message.channel_id, duplicate_result.unwrap().id).await; @@ -350,6 +399,9 @@ impl Manager { }) => { self.latch_state = Some((member, timestamp)); + let member = self.find_member_by_id(member).unwrap(); + let _ = self.ui_sender.send((self.name.clone(), SystemUiEvent::MemberAutoproxy(Some(member.name.clone())))); + if let Some(channel) = self.system_sender.clone() { let last_message = timestamp.clone(); let timeout_seconds = timeout_seconds.clone(); |