use std::{ cell::RefCell, collections::HashSet, net::{IpAddr, SocketAddr}, rc::Rc, }; use slab::Slab; use lan_mouse_ipc::{ClientConfig, ClientHandle, ClientState, Position}; #[derive(Clone, Default)] pub struct ClientManager { clients: Rc>>, } impl ClientManager { /// get all clients pub fn clients(&self) -> Vec<(ClientConfig, ClientState)> { self.clients .borrow() .iter() .map(|(_, c)| c.clone()) .collect::>() } /// add a new client to this manager pub fn add_client(&self) -> ClientHandle { self.clients.borrow_mut().insert(Default::default()) as ClientHandle } /// set the config of the given client pub fn set_config(&self, handle: ClientHandle, config: ClientConfig) { if let Some((c, _)) = self.clients.borrow_mut().get_mut(handle as usize) { *c = config; } } /// set the state of the given client pub fn set_state(&self, handle: ClientHandle, state: ClientState) { if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) { *s = state; } } /// activate the given client /// returns, whether the client was activated pub fn activate_client(&self, handle: ClientHandle) -> bool { let mut clients = self.clients.borrow_mut(); match clients.get_mut(handle as usize) { Some((_, s)) if !s.active => { s.active = true; true } _ => false, } } /// deactivate the given client /// returns, whether the client was deactivated pub fn deactivate_client(&self, handle: ClientHandle) -> bool { let mut clients = self.clients.borrow_mut(); match clients.get_mut(handle as usize) { Some((_, s)) if s.active => { s.active = false; true } _ => false, } } /// find a client by its address pub fn get_client(&self, addr: SocketAddr) -> Option { // since there shouldn't be more than a handful of clients at any given // time this is likely faster than using a HashMap self.clients .borrow() .iter() .find_map(|(k, (_, s))| { if s.active && s.ips.contains(&addr.ip()) { Some(k) } else { None } }) .map(|p| p as ClientHandle) } /// get the client at the given position pub fn client_at(&self, pos: Position) -> Option { self.clients .borrow() .iter() .find_map(|(k, (c, s))| { if s.active && c.pos == pos { Some(k) } else { None } }) .map(|p| p as ClientHandle) } pub(crate) fn get_hostname(&self, handle: ClientHandle) -> Option { self.clients .borrow_mut() .get_mut(handle as usize) .and_then(|(c, _)| c.hostname.clone()) } /// get the position of the corresponding client pub(crate) fn get_pos(&self, handle: ClientHandle) -> Option { self.clients .borrow() .get(handle as usize) .map(|(c, _)| c.pos) } /// remove a client from the list pub fn remove_client(&self, client: ClientHandle) -> Option<(ClientConfig, ClientState)> { // remove id from occupied ids self.clients.borrow_mut().try_remove(client as usize) } /// get the config & state of the given client pub fn get_state(&self, handle: ClientHandle) -> Option<(ClientConfig, ClientState)> { self.clients.borrow().get(handle as usize).cloned() } /// get the current config & state of all clients pub fn get_client_states(&self) -> Vec<(ClientHandle, ClientConfig, ClientState)> { self.clients .borrow() .iter() .map(|(k, v)| (k as ClientHandle, v.0.clone(), v.1.clone())) .collect() } /// update the fix ips of the client pub fn set_fix_ips(&self, handle: ClientHandle, fix_ips: Vec) { if let Some((c, _)) = self.clients.borrow_mut().get_mut(handle as usize) { c.fix_ips = fix_ips } self.update_ips(handle); } /// update the dns-ips of the client pub fn set_dns_ips(&self, handle: ClientHandle, dns_ips: Vec) { if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) { s.dns_ips = dns_ips } self.update_ips(handle); } fn update_ips(&self, handle: ClientHandle) { if let Some((c, s)) = self.clients.borrow_mut().get_mut(handle as usize) { s.ips = c .fix_ips .iter() .cloned() .chain(s.dns_ips.iter().cloned()) .collect::>(); } } /// update the hostname of the given client /// this automatically clears the active ip address and ips from dns pub fn set_hostname(&self, handle: ClientHandle, hostname: Option) -> bool { let mut clients = self.clients.borrow_mut(); let Some((c, s)) = clients.get_mut(handle as usize) else { return false; }; // hostname changed if c.hostname != hostname { c.hostname = hostname; s.active_addr = None; s.dns_ips.clear(); drop(clients); self.update_ips(handle); true } else { false } } /// update the port of the client pub(crate) fn set_port(&self, handle: ClientHandle, port: u16) { match self.clients.borrow_mut().get_mut(handle as usize) { Some((c, s)) if c.port != port => { c.port = port; s.active_addr = s.active_addr.map(|a| SocketAddr::new(a.ip(), port)); } _ => {} }; } /// update the position of the client /// returns true, if a change in capture position is required (pos changed & client is active) pub(crate) fn set_pos(&self, handle: ClientHandle, pos: Position) -> bool { match self.clients.borrow_mut().get_mut(handle as usize) { Some((c, s)) if c.pos != pos => { log::info!("update pos {handle} {} -> {}", c.pos, pos); c.pos = pos; s.active } _ => false, } } /// update the enter hook command of the client pub(crate) fn set_enter_hook(&self, handle: ClientHandle, enter_hook: Option) { if let Some((c, _s)) = self.clients.borrow_mut().get_mut(handle as usize) { c.cmd = enter_hook; } } /// set resolving status of the client pub(crate) fn set_resolving(&self, handle: ClientHandle, status: bool) { if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) { s.resolving = status; } } /// get the enter hook command pub(crate) fn get_enter_cmd(&self, handle: ClientHandle) -> Option { self.clients .borrow() .get(handle as usize) .and_then(|(c, _)| c.cmd.clone()) } /// returns all clients that are currently active pub(crate) fn active_clients(&self) -> Vec { self.clients .borrow() .iter() .filter(|(_, (_, s))| s.active) .map(|(h, _)| h as ClientHandle) .collect() } pub(crate) fn set_active_addr(&self, handle: ClientHandle, addr: Option) { if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) { s.active_addr = addr; } } pub(crate) fn set_alive(&self, handle: ClientHandle, alive: bool) { if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) { s.alive = alive; } } pub(crate) fn active_addr(&self, handle: ClientHandle) -> Option { self.clients .borrow() .get(handle as usize) .and_then(|(_, s)| s.active_addr) } pub(crate) fn alive(&self, handle: ClientHandle) -> bool { self.clients .borrow() .get(handle as usize) .map(|(_, s)| s.alive) .unwrap_or(false) } pub(crate) fn get_port(&self, handle: ClientHandle) -> Option { self.clients .borrow() .get(handle as usize) .map(|(c, _)| c.port) } pub(crate) fn get_ips(&self, handle: ClientHandle) -> Option> { self.clients .borrow() .get(handle as usize) .map(|(_, s)| s.ips.clone()) } }