From 0038178f0d5d9712922c841a0a017e7d66e33726 Mon Sep 17 00:00:00 2001 From: Ferdinand Schober Date: Fri, 27 Sep 2024 12:05:34 +0200 Subject: [PATCH] fingerprint add ui mockup --- lan-mouse-gtk/resources/fingerprint_window.ui | 68 +++++ .../resources/resources.gresource.xml | 1 + lan-mouse-gtk/src/fingerprint_window.rs | 24 ++ lan-mouse-gtk/src/fingerprint_window/imp.rs | 45 ++++ lan-mouse-gtk/src/lib.rs | 1 + lan-mouse-gtk/src/window.rs | 14 +- lan-mouse-gtk/src/window/imp.rs | 2 +- lan-mouse-ipc/src/lib.rs | 15 ++ lan-mouse-proto/src/lib.rs | 2 +- src/capture.rs | 46 ++-- src/client.rs | 223 ++++++++++++++-- src/connect.rs | 17 +- src/dns.rs | 2 +- src/server.rs | 252 +++++------------- 14 files changed, 478 insertions(+), 234 deletions(-) create mode 100644 lan-mouse-gtk/resources/fingerprint_window.ui create mode 100644 lan-mouse-gtk/src/fingerprint_window.rs create mode 100644 lan-mouse-gtk/src/fingerprint_window/imp.rs diff --git a/lan-mouse-gtk/resources/fingerprint_window.ui b/lan-mouse-gtk/resources/fingerprint_window.ui new file mode 100644 index 0000000..f042b74 --- /dev/null +++ b/lan-mouse-gtk/resources/fingerprint_window.ui @@ -0,0 +1,68 @@ + + + + + + diff --git a/lan-mouse-gtk/resources/resources.gresource.xml b/lan-mouse-gtk/resources/resources.gresource.xml index b5d9209..bec7393 100644 --- a/lan-mouse-gtk/resources/resources.gresource.xml +++ b/lan-mouse-gtk/resources/resources.gresource.xml @@ -2,6 +2,7 @@ window.ui + fingerprint_window.ui client_row.ui diff --git a/lan-mouse-gtk/src/fingerprint_window.rs b/lan-mouse-gtk/src/fingerprint_window.rs new file mode 100644 index 0000000..6f51ad3 --- /dev/null +++ b/lan-mouse-gtk/src/fingerprint_window.rs @@ -0,0 +1,24 @@ +mod imp; + +use adw::prelude::*; +use adw::subclass::prelude::*; +use glib::{clone, Object}; +use gtk::{ + gio, + glib::{self, closure_local}, + ListBox, NoSelection, +}; + +glib::wrapper! { + pub struct FingerprintWindow(ObjectSubclass) + @extends adw::Window, gtk::Window, gtk::Widget, + @implements gio::ActionGroup, gio::ActionMap, gtk::Accessible, gtk::Buildable, + gtk::ConstraintTarget, gtk::Native, gtk::Root, gtk::ShortcutManager; +} + +impl FingerprintWindow { + pub(crate) fn new() -> Self { + let window: Self = Object::builder().build(); + window + } +} diff --git a/lan-mouse-gtk/src/fingerprint_window/imp.rs b/lan-mouse-gtk/src/fingerprint_window/imp.rs new file mode 100644 index 0000000..ad87a3c --- /dev/null +++ b/lan-mouse-gtk/src/fingerprint_window/imp.rs @@ -0,0 +1,45 @@ +use adw::subclass::prelude::*; +use glib::subclass::InitializingObject; +use gtk::{glib, template_callbacks, CompositeTemplate, Entry}; + +#[derive(CompositeTemplate, Default)] +#[template(resource = "/de/feschber/LanMouse/fingerprint_window.ui")] +pub struct FingerprintWindow { + // #[template_child] + // pub fingerprint_entry: TemplateChild, +} + +#[glib::object_subclass] +impl ObjectSubclass for FingerprintWindow { + const NAME: &'static str = "FingerprintWindow"; + const ABSTRACT: bool = false; + + type Type = super::FingerprintWindow; + type ParentType = adw::Window; + + fn class_init(klass: &mut Self::Class) { + klass.bind_template(); + klass.bind_template_callbacks(); + } + + fn instance_init(obj: &InitializingObject) { + obj.init_template(); + } +} + +#[template_callbacks] +impl FingerprintWindow { + // #[template_callback] + // fn handle_confirm() {} +} + +impl ObjectImpl for FingerprintWindow { + fn constructed(&self) { + self.parent_constructed(); + } +} + +impl WidgetImpl for FingerprintWindow {} +impl WindowImpl for FingerprintWindow {} +impl ApplicationWindowImpl for FingerprintWindow {} +impl AdwWindowImpl for FingerprintWindow {} diff --git a/lan-mouse-gtk/src/lib.rs b/lan-mouse-gtk/src/lib.rs index c2ec581..78045ae 100644 --- a/lan-mouse-gtk/src/lib.rs +++ b/lan-mouse-gtk/src/lib.rs @@ -1,5 +1,6 @@ mod client_object; mod client_row; +mod fingerprint_window; mod window; use std::{env, process, str}; diff --git a/lan-mouse-gtk/src/window.rs b/lan-mouse-gtk/src/window.rs index 269a46d..d9afa3e 100644 --- a/lan-mouse-gtk/src/window.rs +++ b/lan-mouse-gtk/src/window.rs @@ -6,7 +6,7 @@ use glib::{clone, Object}; use gtk::{ gio, glib::{self, closure_local}, - ListBox, NoSelection, + ListBox, NoSelection, Widget, }; use lan_mouse_ipc::{ @@ -14,6 +14,8 @@ use lan_mouse_ipc::{ DEFAULT_PORT, }; +use crate::fingerprint_window::FingerprintWindow; + use super::{client_object::ClientObject, client_row::ClientRow}; glib::wrapper! { @@ -286,6 +288,16 @@ impl Window { self.request(FrontendRequest::Delete(client.handle())); } + pub fn open_fingerprint_dialog(&self) { + let window = FingerprintWindow::new(); + window.set_transient_for(Some(self)); + window.present(); + } + + pub fn request_fingerprint_add(&self, fp: String) { + self.request(FrontendRequest::FingerprintAdd(fp)); + } + pub fn request(&self, request: FrontendRequest) { let mut requester = self.imp().frontend_request_writer.borrow_mut(); let requester = requester.as_mut().unwrap(); diff --git a/lan-mouse-gtk/src/window/imp.rs b/lan-mouse-gtk/src/window/imp.rs index fb67873..6a76ad1 100644 --- a/lan-mouse-gtk/src/window/imp.rs +++ b/lan-mouse-gtk/src/window/imp.rs @@ -120,7 +120,7 @@ impl Window { #[template_callback] fn handle_add_cert_fingerprint(&self, _button: &Button) { - log::info!("TODO: impl add certificate fingerprint"); + self.obj().open_fingerprint_dialog(); } pub fn set_port(&self, port: u16) { diff --git a/lan-mouse-ipc/src/lib.rs b/lan-mouse-ipc/src/lib.rs index cdc2dd1..892f846 100644 --- a/lan-mouse-ipc/src/lib.rs +++ b/lan-mouse-ipc/src/lib.rs @@ -65,6 +65,17 @@ pub enum Position { Bottom, } +impl Position { + pub fn opposite(&self) -> Self { + match self { + Position::Left => Position::Right, + Position::Right => Position::Left, + Position::Top => Position::Bottom, + Position::Bottom => Position::Top, + } + } +} + #[derive(Debug, Error)] #[error("not a valid position: {pos}")] pub struct PositionParseError { @@ -218,6 +229,10 @@ pub enum FrontendRequest { EnableEmulation, /// synchronize all state Sync, + /// authorize fingerprint + FingerprintAdd(String), + /// remove fingerprint + FingerprintRemove(String), } #[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)] diff --git a/lan-mouse-proto/src/lib.rs b/lan-mouse-proto/src/lib.rs index e490136..2e342d3 100644 --- a/lan-mouse-proto/src/lib.rs +++ b/lan-mouse-proto/src/lib.rs @@ -48,7 +48,7 @@ impl Display for Position { /// main lan-mouse protocol event type #[derive(Clone, Copy, Debug)] pub enum ProtoEvent { - /// notify a client that the cursor entered its region + /// notify a client that the cursor entered its region at the given position /// [`ProtoEvent::Ack`] with the same serial is used for synchronization between devices Enter(Position), /// notify a client that the cursor left its region diff --git a/src/capture.rs b/src/capture.rs index 7703373..e0dd6ee 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -47,9 +47,9 @@ impl Capture { } } - pub(crate) fn create(&self, handle: CaptureHandle, pos: Position) { + pub(crate) fn create(&self, handle: CaptureHandle, pos: lan_mouse_ipc::Position) { self.tx - .send(CaptureRequest::Create(handle, pos)) + .send(CaptureRequest::Create(handle, to_capture_pos(pos))) .expect("channel closed"); } @@ -100,11 +100,16 @@ async fn do_capture( }; server.set_capture_status(Status::Enabled); - let clients = server.active_clients(); - let clients = clients - .iter() - .copied() - .map(|handle| (handle, server.get_pos(handle).expect("no such client"))); + let clients = server.client_manager.active_clients(); + let clients = clients.iter().copied().map(|handle| { + ( + handle, + server + .client_manager + .get_pos(handle) + .expect("no such client"), + ) + }); /* create barriers for active clients */ for (handle, pos) in clients { @@ -201,7 +206,7 @@ async fn handle_capture_event( return release_capture(capture, server).await; } - if capture.keys_pressed(&server.release_bind) { + if capture.keys_pressed(&server.config.release_bind) { log::info!("releasing capture: release-bind pressed"); return release_capture(capture, server).await; } @@ -214,11 +219,16 @@ async fn handle_capture_event( spawn_hook_command(server, handle); } + let pos = match server.client_manager.get_pos(handle) { + Some(pos) => to_proto_pos(pos.opposite()), + None => return release_capture(capture, server).await, + }; + let event = match event { - CaptureEvent::Begin => ProtoEvent::Enter(lan_mouse_proto::Position::Left), + CaptureEvent::Begin => ProtoEvent::Enter(pos), CaptureEvent::Input(e) => match state { // connection not acknowledged, repeat `Enter` event - State::WaitingForAck => ProtoEvent::Enter(lan_mouse_proto::Position::Left), + State::WaitingForAck => ProtoEvent::Enter(pos), _ => ProtoEvent::Input(e), }, }; @@ -245,13 +255,17 @@ fn to_capture_pos(pos: lan_mouse_ipc::Position) -> input_capture::Position { } } +fn to_proto_pos(pos: lan_mouse_ipc::Position) -> lan_mouse_proto::Position { + match pos { + lan_mouse_ipc::Position::Left => lan_mouse_proto::Position::Left, + lan_mouse_ipc::Position::Right => lan_mouse_proto::Position::Right, + lan_mouse_ipc::Position::Top => lan_mouse_proto::Position::Top, + lan_mouse_ipc::Position::Bottom => lan_mouse_proto::Position::Bottom, + } +} + fn spawn_hook_command(server: &Server, handle: ClientHandle) { - let Some(cmd) = server - .client_manager - .borrow() - .get(handle) - .and_then(|(c, _)| c.cmd.clone()) - else { + let Some(cmd) = server.client_manager.get_enter_cmd(handle) else { return; }; tokio::task::spawn_local(async move { diff --git a/src/client.rs b/src/client.rs index 79ebd00..debf3c5 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,18 +1,63 @@ -use std::net::SocketAddr; +use std::{ + cell::RefCell, + collections::HashSet, + net::{IpAddr, SocketAddr}, + rc::Rc, +}; use slab::Slab; use lan_mouse_ipc::{ClientConfig, ClientHandle, ClientState, Position}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct ClientManager { - clients: Slab<(ClientConfig, ClientState)>, + clients: Rc>>, } impl ClientManager { /// add a new client to this manager - pub fn add_client(&mut self) -> ClientHandle { - self.clients.insert(Default::default()) as ClientHandle + 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 == false => { + 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 @@ -20,6 +65,7 @@ impl ClientManager { // 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()) { @@ -31,8 +77,10 @@ impl ClientManager { .map(|p| p as ClientHandle) } - pub fn find_client(&self, pos: Position) -> Option { + /// 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 { @@ -44,31 +92,162 @@ impl ClientManager { .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(&mut self, client: ClientHandle) -> Option<(ClientConfig, ClientState)> { + pub fn remove_client(&self, client: ClientHandle) -> Option<(ClientConfig, ClientState)> { // remove id from occupied ids - self.clients.try_remove(client as usize) + self.clients.borrow_mut().try_remove(client as usize) } - // returns an immutable reference to the client state corresponding to `client` - pub fn get(&self, handle: ClientHandle) -> Option<&(ClientConfig, ClientState)> { - self.clients.get(handle 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() } - /// returns a mutable reference to the client state corresponding to `client` - pub fn get_mut(&mut self, handle: ClientHandle) -> Option<&mut (ClientConfig, ClientState)> { - self.clients.get_mut(handle as usize) + /// 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() } - pub fn get_client_states( - &self, - ) -> impl Iterator { - self.clients.iter().map(|(k, v)| (k as ClientHandle, v)) + /// 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); } - pub fn get_client_states_mut( - &mut self, - ) -> impl Iterator { - self.clients.iter_mut().map(|(k, v)| (k as ClientHandle, v)) + /// 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, + } + } + + /// 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: u64, addr: Option) { + if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) { + s.active_addr = addr; + } + } + + pub(crate) fn active_addr(&self, handle: u64) -> Option { + self.clients + .borrow() + .get(handle as usize) + .and_then(|(_, s)| s.active_addr) + } + + pub(crate) fn get_port(&self, handle: u64) -> Option { + self.clients + .borrow() + .get(handle as usize) + .map(|(c, _)| c.port) + } + + pub(crate) fn get_ips(&self, handle: u64) -> Option> { + self.clients + .borrow() + .get(handle as usize) + .map(|(_, s)| s.ips.clone()) } } diff --git a/src/connect.rs b/src/connect.rs index 9e26f0b..ba48569 100644 --- a/src/connect.rs +++ b/src/connect.rs @@ -95,7 +95,7 @@ impl LanMouseConnection { ) -> Result<(), LanMouseConnectionError> { let (buf, len): ([u8; MAX_EVENT_SIZE], usize) = event.into(); let buf = &buf[..len]; - if let Some(addr) = self.server.active_addr(handle) { + if let Some(addr) = self.server.client_manager.active_addr(handle) { let conn = { let conns = self.conns.lock().await; conns.get(&addr).cloned() @@ -138,8 +138,11 @@ async fn connect_to_handle( ) -> Result<(), LanMouseConnectionError> { log::info!("client {handle} connecting ..."); // sending did not work, figure out active conn. - if let Some(addrs) = server.get_ips(handle) { - let port = server.get_port(handle).unwrap_or(DEFAULT_PORT); + if let Some(addrs) = server.client_manager.get_ips(handle) { + let port = server + .client_manager + .get_port(handle) + .unwrap_or(DEFAULT_PORT); let addrs = addrs .into_iter() .map(|a| SocketAddr::new(a, port)) @@ -154,7 +157,7 @@ async fn connect_to_handle( } }; log::info!("client ({handle}) connected @ {addr}"); - server.set_active_addr(handle, Some(addr)); + server.client_manager.set_active_addr(handle, Some(addr)); conns.lock().await.insert(addr, conn.clone()); connecting.lock().await.remove(&handle); @@ -193,7 +196,7 @@ async fn ping_pong( tokio::time::sleep(Duration::from_millis(500)).await; - if server.active_addr(handle).is_none() { + if server.client_manager.active_addr(handle).is_none() { log::warn!("no active addr"); disconnect(&server, handle, addr, &conns).await; } @@ -212,7 +215,7 @@ async fn receive_loop( while let Ok(_) = conn.recv(&mut buf).await { if let Ok(event) = buf.try_into() { match event { - ProtoEvent::Pong => server.set_active_addr(handle, Some(addr)), + ProtoEvent::Pong => server.client_manager.set_active_addr(handle, Some(addr)), event => tx.send((handle, event)).expect("channel closed"), } } @@ -229,7 +232,7 @@ async fn disconnect( ) { log::warn!("client ({handle}) @ {addr} connection closed"); conns.lock().await.remove(&addr); - server.set_active_addr(handle, None); + server.client_manager.set_active_addr(handle, None); let active: Vec = conns.lock().await.keys().copied().collect(); log::info!("active connections: {active:?}"); } diff --git a/src/dns.rs b/src/dns.rs index bea583f..3c7f7da 100644 --- a/src/dns.rs +++ b/src/dns.rs @@ -39,7 +39,7 @@ impl DnsResolver { let handle = rx.recv().await.expect("channel closed"); /* update resolving status */ - let hostname = match server.get_hostname(handle) { + let hostname = match server.client_manager.get_hostname(handle) { Some(hostname) => hostname, None => continue, }; diff --git a/src/server.rs b/src/server.rs index 92cbe0d..5b6b3e9 100644 --- a/src/server.rs +++ b/src/server.rs @@ -16,7 +16,7 @@ use lan_mouse_ipc::{ use log; use std::{ cell::{Cell, RefCell}, - collections::{HashSet, VecDeque}, + collections::{HashMap, HashSet, VecDeque}, io, net::{IpAddr, SocketAddr}, rc::Rc, @@ -42,16 +42,17 @@ pub struct ReleaseToken; #[derive(Clone)] pub struct Server { active: Rc>>, - pub(crate) client_manager: Rc>, + authorized_keys: Rc>>, + known_hosts: Rc>>, + pub(crate) client_manager: ClientManager, port: Rc>, - pub(crate) release_bind: Vec, notifies: Rc, pub(crate) config: Rc, pending_frontend_events: Rc>>, capture_status: Rc>, pub(crate) emulation_status: Rc>, pub(crate) should_release: Rc>>, - incoming_conns: Rc>>, + incoming_conns: Rc>>, } #[derive(Default)] @@ -65,44 +66,43 @@ struct Notifies { impl Server { pub fn new(config: Config) -> Self { - let client_manager = Rc::new(RefCell::new(ClientManager::default())); + let client_manager = ClientManager::default(); let port = Rc::new(Cell::new(config.port)); - for config_client in config.get_clients() { - let client = 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, + for client in config.get_clients() { + let config = ClientConfig { + hostname: client.hostname, + fix_ips: client.ips.into_iter().collect(), + port: client.port, + pos: client.pos, + cmd: client.enter_hook, }; let state = ClientState { - active: config_client.active, - ips: HashSet::from_iter(client.fix_ips.iter().cloned()), + active: client.active, + ips: HashSet::from_iter(config.fix_ips.iter().cloned()), ..Default::default() }; - let mut client_manager = client_manager.borrow_mut(); let handle = client_manager.add_client(); - let c = client_manager.get_mut(handle).expect("invalid handle"); - *c = (client, state); + client_manager.set_config(handle, config); + client_manager.set_state(handle, state); } // task notification tokens let notifies = Rc::new(Notifies::default()); - let release_bind = config.release_bind.clone(); let config = Rc::new(config); Self { active: Rc::new(Cell::new(None)), + authorized_keys: Default::default(), + known_hosts: Default::default(), config, client_manager, port, - release_bind, notifies, pending_frontend_events: Rc::new(RefCell::new(VecDeque::new())), capture_status: Default::default(), emulation_status: Default::default(), - incoming_conns: Rc::new(RefCell::new(Vec::new())), + incoming_conns: Rc::new(RefCell::new(HashMap::new())), should_release: Default::default(), } } @@ -129,7 +129,7 @@ impl Server { // create dns resolver let resolver = DnsResolver::new(self.clone())?; - for handle in self.active_clients() { + for handle in self.client_manager.active_clients() { resolver.resolve(handle); } @@ -221,15 +221,6 @@ impl Server { self.notify_frontend(FrontendEvent::Changed(handle)); } - pub(crate) fn active_clients(&self) -> Vec { - self.client_manager - .borrow() - .get_client_states() - .filter(|(_, (_, s))| s.active) - .map(|(h, _)| h) - .collect() - } - fn handle_request(&self, capture: &Capture, event: FrontendRequest, dns: &DnsResolver) -> bool { log::debug!("frontend: {event:?}"); match event { @@ -267,183 +258,109 @@ impl Server { self.notify_frontend(FrontendEvent::CaptureStatus(self.capture_status.get())); self.notify_frontend(FrontendEvent::PortChanged(self.port.get(), None)); } + FrontendRequest::FingerprintAdd(key) => { + self.add_authorized_key(key); + } + FrontendRequest::FingerprintRemove(key) => { + self.remove_authorized_key(key); + } }; false } + fn add_authorized_key(&self, key: String) { + self.authorized_keys.borrow_mut().insert(key); + } + + fn remove_authorized_key(&self, key: String) { + self.authorized_keys.borrow_mut().remove(&key); + } + fn enumerate(&self) { - let clients = self - .client_manager - .borrow() - .get_client_states() - .map(|(h, (c, s))| (h, c.clone(), s.clone())) - .collect(); + let clients = self.client_manager.get_client_states(); self.notify_frontend(FrontendEvent::Enumerate(clients)); } fn add_client(&self) -> ClientHandle { - let handle = self.client_manager.borrow_mut().add_client(); + let handle = self.client_manager.add_client(); log::info!("added client {handle}"); - let (c, s) = self.client_manager.borrow().get(handle).unwrap().clone(); + let (c, s) = self.client_manager.get_state(handle).unwrap(); self.notify_frontend(FrontendEvent::Created(handle, c, s)); handle } fn deactivate_client(&self, capture: &Capture, handle: ClientHandle) { log::debug!("deactivating client {handle}"); - match self.client_manager.borrow_mut().get_mut(handle) { - None => return, - Some((_, s)) if !s.active => return, - Some((_, s)) => s.active = false, - }; - - capture.destroy(handle); - self.client_updated(handle); - log::info!("deactivated client {handle}"); + if self.client_manager.deactivate_client(handle) { + capture.destroy(handle); + self.client_updated(handle); + log::info!("deactivated client {handle}"); + } } fn activate_client(&self, capture: &Capture, handle: ClientHandle) { log::debug!("activating client"); /* deactivate potential other client at this position */ - let pos = match self.client_manager.borrow().get(handle) { - None => return, - Some((_, s)) if s.active => return, - Some((client, _)) => client.pos, + let Some(pos) = self.client_manager.get_pos(handle) else { + return; }; - let other = self.client_manager.borrow_mut().find_client(pos); - if let Some(other) = other { - self.deactivate_client(capture, other); + if let Some(other) = self.client_manager.client_at(pos) { + if other != handle { + self.deactivate_client(capture, other); + } } /* activate the client */ - if let Some((_, s)) = self.client_manager.borrow_mut().get_mut(handle) { - s.active = true; - } else { - return; - }; - - /* notify capture and frontends */ - capture.create(handle, to_capture_pos(pos)); - self.client_updated(handle); - log::info!("activated client {handle} ({pos})"); + if self.client_manager.activate_client(handle) { + /* notify capture and frontends */ + capture.create(handle, pos); + self.client_updated(handle); + log::info!("activated client {handle} ({pos})"); + } } fn remove_client(&self, capture: &Capture, handle: ClientHandle) { - let Some(active) = self + if let Some(true) = self .client_manager - .borrow_mut() .remove_client(handle) .map(|(_, s)| s.active) - else { - return; - }; - - if active { + { capture.destroy(handle); } } fn update_fix_ips(&self, handle: ClientHandle, fix_ips: Vec) { - if let Some((c, _)) = self.client_manager.borrow_mut().get_mut(handle) { - c.fix_ips = fix_ips; - }; - self.update_ips(handle); + self.client_manager.set_fix_ips(handle, fix_ips); self.client_updated(handle); } pub(crate) fn update_dns_ips(&self, handle: ClientHandle, dns_ips: Vec) { - if let Some((_, s)) = self.client_manager.borrow_mut().get_mut(handle) { - s.dns_ips = dns_ips; - }; - self.update_ips(handle); + self.client_manager.set_dns_ips(handle, dns_ips); self.client_updated(handle); } - fn update_ips(&self, handle: ClientHandle) { - if let Some((c, s)) = self.client_manager.borrow_mut().get_mut(handle) { - s.ips = c - .fix_ips - .iter() - .cloned() - .chain(s.dns_ips.iter().cloned()) - .collect::>(); - } - } - - pub(crate) fn get_ips(&self, handle: ClientHandle) -> Option> { - if let Some((_, s)) = self.client_manager.borrow().get(handle) { - Some(s.ips.iter().copied().collect()) - } else { - None - } - } - - pub(crate) fn get_port(&self, handle: ClientHandle) -> Option { - if let Some((c, _)) = self.client_manager.borrow().get(handle) { - Some(c.port) - } else { - None - } - } - fn update_hostname(&self, handle: ClientHandle, hostname: Option, dns: &DnsResolver) { - let mut client_manager = self.client_manager.borrow_mut(); - let Some((c, s)) = client_manager.get_mut(handle) else { - return; - }; - - // hostname changed - if c.hostname != hostname { - c.hostname = hostname; - s.active_addr = None; - s.dns_ips.clear(); - drop(client_manager); - self.update_ips(handle); + if self.client_manager.set_hostname(handle, hostname) { dns.resolve(handle); + self.client_updated(handle); } - self.client_updated(handle); } fn update_port(&self, handle: ClientHandle, port: u16) { - let mut client_manager = self.client_manager.borrow_mut(); - let Some((c, s)) = client_manager.get_mut(handle) else { - return; - }; - - if c.port != port { - c.port = port; - s.active_addr = s.active_addr.map(|a| SocketAddr::new(a.ip(), port)); - } + self.client_manager.set_port(handle, port); } fn update_pos(&self, handle: ClientHandle, capture: &Capture, pos: Position) { - let (changed, active) = { - let mut client_manager = self.client_manager.borrow_mut(); - let Some((c, s)) = client_manager.get_mut(handle) else { - return; - }; - - let changed = c.pos != pos; - if changed { - log::info!("update pos {handle} {} -> {}", c.pos, pos); - } - c.pos = pos; - (changed, s.active) - }; - // update state in event input emulator & input capture - if changed { + if self.client_manager.set_pos(handle, pos) { self.deactivate_client(capture, handle); - if active { - self.activate_client(capture, handle); - } + self.activate_client(capture, handle); } } fn broadcast_client(&self, handle: ClientHandle) { - let client = self.client_manager.borrow().get(handle).cloned(); - let event = if let Some((config, state)) = client { + let event = if let Some((config, state)) = self.client_manager.get_state(handle) { FrontendEvent::State(handle, config, state) } else { FrontendEvent::NoSuchClient(handle) @@ -464,36 +381,10 @@ impl Server { } pub(crate) fn set_resolving(&self, handle: ClientHandle, status: bool) { - if let Some((_, s)) = self.client_manager.borrow_mut().get_mut(handle) { - s.resolving = status; - } + self.client_manager.set_resolving(handle, status); self.client_updated(handle); } - pub(crate) fn get_hostname(&self, handle: ClientHandle) -> Option { - self.client_manager - .borrow_mut() - .get_mut(handle) - .and_then(|(c, _)| c.hostname.clone()) - } - - pub(crate) fn get_pos(&self, handle: ClientHandle) -> Option { - self.client_manager.borrow().get(handle).map(|(c, _)| c.pos) - } - - pub(crate) fn set_active_addr(&self, handle: ClientHandle, addr: Option) { - if let Some((_, s)) = self.client_manager.borrow_mut().get_mut(handle) { - s.active_addr = addr; - } - } - - pub(crate) fn active_addr(&self, handle: ClientHandle) -> Option { - self.client_manager - .borrow() - .get(handle) - .and_then(|(_, s)| s.active_addr) - } - pub(crate) fn release_capture(&self) { self.should_release.replace(Some(ReleaseToken)); } @@ -507,15 +398,6 @@ impl Server { } pub(crate) fn register_incoming(&self, addr: SocketAddr, pos: Position) { - self.incoming_conns.borrow_mut().push((addr, pos)); - } -} - -fn to_capture_pos(pos: Position) -> input_capture::Position { - match pos { - Position::Left => input_capture::Position::Left, - Position::Right => input_capture::Position::Right, - Position::Top => input_capture::Position::Top, - Position::Bottom => input_capture::Position::Bottom, + self.incoming_conns.borrow_mut().insert(addr, pos); } }