use std::{
cell::RefCell,
collections::HashSet,
net::{IpAddr, SocketAddr},
rc::Rc,
};
use slab::Slab;
use mousehop_ipc::{ClientConfig, ClientHandle, ClientState, Position};
use crate::config::ConfigClient;
#[derive(Clone, Default)]
pub struct ClientManager {
clients: Rc<RefCell<Slab<(ClientConfig, ClientState)>>>,
}
impl ClientManager {
pub fn clients(&self) -> Vec<(ClientConfig, ClientState)> {
self.clients
.borrow()
.iter()
.map(|(_, c)| c.clone())
.collect::<Vec<_>>()
}
pub fn add_with_config(&self, config_client: ConfigClient) -> ClientHandle {
let config = ClientConfig {
hostname: config_client.hostname,
fix_ips: config_client.ips.into_iter().collect(),
port: config_client.port,
pos: config_client.pos,
cmd: config_client.enter_hook,
clipboard_send: config_client.clipboard_send,
};
let state = ClientState {
active: config_client.active,
ips: HashSet::from_iter(config.fix_ips.iter().cloned()),
..Default::default()
};
let handle = self.add_client();
self.set_config(handle, config);
self.set_state(handle, state);
handle
}
pub fn add_client(&self) -> ClientHandle {
self.clients.borrow_mut().insert(Default::default()) as ClientHandle
}
pub fn set_config(&self, handle: ClientHandle, config: ClientConfig) {
if let Some((c, _)) = self.clients.borrow_mut().get_mut(handle as usize) {
*c = config;
}
}
pub fn set_state(&self, handle: ClientHandle, state: ClientState) {
if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) {
*s = state;
}
}
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,
}
}
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,
}
}
pub fn get_client(&self, addr: SocketAddr) -> Option<ClientHandle> {
self.clients
.borrow()
.iter()
.find_map(|(k, (_, s))| {
if !s.active {
return None;
}
let ip = addr.ip();
let active_match = s.active_addr.is_some_and(|a| a.ip() == ip);
if s.ips.contains(&ip) || active_match {
Some(k)
} else {
None
}
})
.map(|p| p as ClientHandle)
}
pub fn client_at(&self, pos: Position) -> Option<ClientHandle> {
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<String> {
self.clients
.borrow_mut()
.get_mut(handle as usize)
.and_then(|(c, _)| c.hostname.clone())
}
pub(crate) fn get_pos(&self, handle: ClientHandle) -> Option<Position> {
self.clients
.borrow()
.get(handle as usize)
.map(|(c, _)| c.pos)
}
pub fn remove_client(&self, client: ClientHandle) -> Option<(ClientConfig, ClientState)> {
self.clients.borrow_mut().try_remove(client as usize)
}
pub fn get_state(&self, handle: ClientHandle) -> Option<(ClientConfig, ClientState)> {
self.clients.borrow().get(handle as usize).cloned()
}
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()
}
pub fn set_fix_ips(&self, handle: ClientHandle, fix_ips: Vec<IpAddr>) {
if let Some((c, _)) = self.clients.borrow_mut().get_mut(handle as usize) {
c.fix_ips = fix_ips
}
self.update_ips(handle);
}
pub fn set_dns_ips(&self, handle: ClientHandle, dns_ips: Vec<IpAddr>) {
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::<HashSet<_>>();
}
}
pub fn set_hostname(&self, handle: ClientHandle, hostname: Option<String>) -> bool {
let mut clients = self.clients.borrow_mut();
let Some((c, s)) = clients.get_mut(handle as usize) else {
return false;
};
if c.hostname != hostname {
c.hostname = hostname;
s.active_addr = None;
s.dns_ips.clear();
drop(clients);
self.update_ips(handle);
true
} else {
false
}
}
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));
}
_ => {}
};
}
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,
}
}
pub(crate) fn set_enter_hook(&self, handle: ClientHandle, enter_hook: Option<String>) {
if let Some((c, _s)) = self.clients.borrow_mut().get_mut(handle as usize) {
c.cmd = enter_hook;
}
}
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;
}
}
pub(crate) fn get_enter_cmd(&self, handle: ClientHandle) -> Option<String> {
self.clients
.borrow()
.get(handle as usize)
.and_then(|(c, _)| c.cmd.clone())
}
pub(crate) fn registered_clients(&self) -> Vec<ClientHandle> {
self.clients
.borrow()
.iter()
.map(|(h, _)| h as ClientHandle)
.collect()
}
pub(crate) fn active_clients(&self) -> Vec<ClientHandle> {
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<SocketAddr>) {
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 set_peer_commit(&self, handle: ClientHandle, commit: Option<[u8; 8]>) {
if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) {
s.peer_commit = commit;
}
}
pub(crate) fn active_addr(&self, handle: ClientHandle) -> Option<SocketAddr> {
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<u16> {
self.clients
.borrow()
.get(handle as usize)
.map(|(c, _)| c.port)
}
pub(crate) fn get_ips(&self, handle: ClientHandle) -> Option<HashSet<IpAddr>> {
self.clients
.borrow()
.get(handle as usize)
.map(|(_, s)| s.ips.clone())
}
pub(crate) fn set_clipboard_send(&self, handle: ClientHandle, enabled: bool) -> bool {
match self.clients.borrow_mut().get_mut(handle as usize) {
Some((c, _)) if c.clipboard_send != enabled => {
c.clipboard_send = enabled;
true
}
_ => false,
}
}
pub(crate) fn clipboard_send_targets(&self) -> Vec<ClientHandle> {
self.clients
.borrow()
.iter()
.filter(|(_, (c, s))| c.clipboard_send && s.active)
.map(|(k, _)| k as ClientHandle)
.collect()
}
}