diff --git a/src/frontend.rs b/src/frontend.rs index ac4b15d..2adb78b 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -107,16 +107,18 @@ pub enum FrontendRequest { UpdatePosition(ClientHandle, Position), /// update fix-ips UpdateFixIps(ClientHandle, Vec), + /// request the state of the given client + GetState(ClientHandle), } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum FrontendEvent { /// a client was created Created(ClientHandle, ClientConfig, ClientState), - /// a client was updated - Updated(ClientHandle, ClientConfig), + /// no such client + NoSuchClient(ClientHandle), /// state changed - StateChange(ClientHandle, ClientState), + State(ClientHandle, ClientConfig, ClientState), /// the client was deleted Deleted(ClientHandle), /// new port, reason of failure (if failed) @@ -235,9 +237,7 @@ impl FrontendListener { let json = serde_json::to_string(¬ify).unwrap(); let payload = json.as_bytes(); let len = payload.len().to_be_bytes(); - log::debug!("json: {json}, len: {}", payload.len()); - - log::debug!("broadcasting event to streams: {:?}", self.tx_streams); + log::debug!("broadcasting event to streams: {json}"); let mut keep = vec![]; // TODO do simultaneously for tx in self.tx_streams.iter_mut() { diff --git a/src/frontend/cli.rs b/src/frontend/cli.rs index 2bc1fee..89fc010 100644 --- a/src/frontend/cli.rs +++ b/src/frontend/cli.rs @@ -100,6 +100,18 @@ impl<'a> Cli<'a> { } } + async fn update_client(&mut self, handle: ClientHandle) -> Result<()> { + self.send_request(FrontendRequest::GetState(handle)).await?; + loop { + let event = self.await_event().await?; + self.handle_event(event.clone()); + if let FrontendEvent::State(_, _, _) | FrontendEvent::NoSuchClient(_) = event { + break; + } + } + Ok(()) + } + async fn execute(&mut self, cmd: Command) -> Result<()> { match cmd { Command::None => {} @@ -125,14 +137,8 @@ impl<'a> Cli<'a> { FrontendRequest::UpdatePosition(handle, pos), ] { self.send_request(request).await?; - loop { - let event = self.await_event().await?; - self.handle_event(event.clone()); - if let FrontendEvent::Updated(_, _) = event { - break; - } - } } + self.update_client(handle).await?; } Command::Disconnect(id) => { self.send_request(FrontendRequest::Delete(id)).await?; @@ -148,26 +154,12 @@ impl<'a> Cli<'a> { Command::Activate(id) => { self.send_request(FrontendRequest::Activate(id, true)) .await?; - loop { - let event = self.await_event().await?; - self.handle_event(event.clone()); - if let FrontendEvent::StateChange(_, _) = event { - self.handle_event(event); - break; - } - } + self.update_client(id).await?; } Command::Deactivate(id) => { self.send_request(FrontendRequest::Activate(id, false)) .await?; - loop { - let event = self.await_event().await?; - self.handle_event(event.clone()); - if let FrontendEvent::StateChange(_, _) = event { - self.handle_event(event); - break; - } - } + self.update_client(id).await?; } Command::List => { self.send_request(FrontendRequest::Enumerate()).await?; @@ -182,25 +174,12 @@ impl<'a> Cli<'a> { Command::SetHost(handle, host) => { let request = FrontendRequest::UpdateHostname(handle, Some(host.clone())); self.send_request(request).await?; - loop { - let event = self.await_event().await?; - self.handle_event(event.clone()); - if let FrontendEvent::Updated(_, _) = event { - self.handle_event(event); - break; - } - } + self.update_client(handle).await?; } Command::SetPort(handle, port) => { let request = FrontendRequest::UpdatePort(handle, port.unwrap_or(DEFAULT_PORT)); self.send_request(request).await?; - loop { - let event = self.await_event().await?; - self.handle_event(event.clone()); - if let FrontendEvent::Updated(_, _) = event { - break; - } - } + self.update_client(handle).await?; } Command::Help => { for cmd_type in [ @@ -244,8 +223,11 @@ impl<'a> Cli<'a> { eprintln!(); self.clients.push((h, c, s)); } - FrontendEvent::Updated(h, c) => { - if let Some((_, config, _)) = self.find_mut(h) { + FrontendEvent::NoSuchClient(h) => { + eprintln!("no such client: {h}"); + } + FrontendEvent::State(h, c, s) => { + if let Some((_, config, state)) = self.find_mut(h) { let old_host = config.hostname.clone().unwrap_or("\"\"".into()); let new_host = c.hostname.clone().unwrap_or("\"\"".into()); if old_host != new_host { @@ -261,10 +243,6 @@ impl<'a> Cli<'a> { eprintln!("client {h} ips updated: {:?}", c.fix_ips) } *config = c; - } - } - FrontendEvent::StateChange(h, s) => { - if let Some((_, _, state)) = self.find_mut(h) { if state.active ^ s.active { eprintln!( "client {h} {}", diff --git a/src/frontend/gtk.rs b/src/frontend/gtk.rs index b4cd834..9588fad 100644 --- a/src/frontend/gtk.rs +++ b/src/frontend/gtk.rs @@ -126,12 +126,11 @@ fn build_ui(app: &Application) { FrontendEvent::Deleted(client) => { window.delete_client(client); } - FrontendEvent::Updated(handle, client) => { - window.update_client_config(handle, client); - } - FrontendEvent::StateChange(handle, state) => { + FrontendEvent::State(handle, config, state) => { + window.update_client_config(handle, config); window.update_client_state(handle, state); } + FrontendEvent::NoSuchClient(_) => { } FrontendEvent::Error(e) => { window.show_toast(e.as_str()); }, diff --git a/src/frontend/gtk/window.rs b/src/frontend/gtk/window.rs index f2ae3df..eef0e73 100644 --- a/src/frontend/gtk/window.rs +++ b/src/frontend/gtk/window.rs @@ -51,6 +51,10 @@ impl Window { .expect("Could not get clients") } + fn client_by_idx(&self, idx: u32) -> Option { + self.clients().item(idx).map(|o| o.downcast().unwrap()) + } + fn setup_clients(&self) { let model = gio::ListStore::new::(); self.imp().clients.replace(Some(model)); @@ -62,27 +66,24 @@ impl Window { let client_object = obj.downcast_ref().expect("Expected object of type `ClientObject`."); let row = window.create_client_row(client_object); row.connect_closure("request-update", false, closure_local!(@strong window => move |row: ClientRow, active: bool| { - let index = row.index() as u32; - let Some(client) = window.clients().item(index) else { - return; - }; - let client = client.downcast_ref::().unwrap(); - window.request_client_activate(client, active); - window.request_client_update(client); + if let Some(client) = window.client_by_idx(row.index() as u32) { + window.request_client_activate(&client, active); + window.request_client_update(&client); + window.request_client_state(&client); + } })); row.connect_closure("request-delete", false, closure_local!(@strong window => move |row: ClientRow| { - let index = row.index() as u32; - window.request_client_delete(index); + if let Some(client) = window.client_by_idx(row.index() as u32) { + window.request_client_delete(&client); + } })); row.connect_closure("request-dns", false, closure_local!(@strong window => move |row: ClientRow| { - let index = row.index() as u32; - let Some(client) = window.clients().item(index) else { - return; - }; - let client = client.downcast_ref::().unwrap(); - window.request_client_update(client); - window.request_dns(index); + if let Some(client) = window.client_by_idx(row.index() as u32) { + window.request_client_update(&client); + window.request_dns(&client); + window.request_client_state(&client); + } })); row.upcast() }) @@ -204,20 +205,6 @@ impl Window { } } - pub fn request_dns(&self, idx: u32) { - let client_object = self.clients().item(idx).unwrap(); - let client_object: &ClientObject = client_object.downcast_ref().unwrap(); - let data = client_object.get_data(); - let event = FrontendRequest::ResolveDns(data.handle); - self.request(event); - } - - pub fn request_client_create(&self) { - let event = FrontendRequest::Create; - self.imp().set_port(DEFAULT_PORT); - self.request(event); - } - pub fn request_port_change(&self) { let port = self.imp().port_entry.get().text().to_string(); if let Ok(port) = port.as_str().parse::() { @@ -227,6 +214,23 @@ impl Window { } } + pub fn request_client_state(&self, client: &ClientObject) { + let handle = client.handle(); + let event = FrontendRequest::GetState(handle); + self.request(event); + } + + pub fn request_client_create(&self) { + let event = FrontendRequest::Create; + self.request(event); + } + + pub fn request_dns(&self, client: &ClientObject) { + let data = client.get_data(); + let event = FrontendRequest::ResolveDns(data.handle); + self.request(event); + } + pub fn request_client_update(&self, client: &ClientObject) { let handle = client.handle(); let data = client.get_data(); @@ -239,33 +243,25 @@ impl Window { FrontendRequest::UpdatePosition(handle, position), FrontendRequest::UpdatePort(handle, port), ] { - log::debug!("requesting: {event:?}"); self.request(event); } } pub fn request_client_activate(&self, client: &ClientObject, active: bool) { let handle = client.handle(); - let event = FrontendRequest::Activate(handle, active); - log::debug!("requesting: {event:?}"); self.request(event); } - pub fn request_client_delete(&self, idx: u32) { - if let Some(obj) = self.clients().item(idx) { - let client_object: &ClientObject = obj - .downcast_ref() - .expect("Expected object of type `ClientObject`."); - let handle = client_object.handle(); - let event = FrontendRequest::Delete(handle); - self.request(event); - } + pub fn request_client_delete(&self, client: &ClientObject) { + let handle = client.handle(); + let event = FrontendRequest::Delete(handle); + self.request(event); } pub fn request(&self, event: FrontendRequest) { let json = serde_json::to_string(&event).unwrap(); - log::debug!("requesting {json}"); + log::debug!("requesting: {json}"); let mut stream = self.imp().stream.borrow_mut(); let stream = stream.as_mut().unwrap(); let bytes = json.as_bytes(); diff --git a/src/server/frontend_task.rs b/src/server/frontend_task.rs index abc75b1..2ad1000 100644 --- a/src/server/frontend_task.rs +++ b/src/server/frontend_task.rs @@ -111,16 +111,17 @@ async fn handle_frontend_event( } FrontendRequest::Activate(handle, active) => { if active { - activate_client(server, frontend, capture, emulate, handle).await; + activate_client(server, capture, emulate, handle).await; } else { - deactivate_client(server, frontend, capture, emulate, handle).await; + deactivate_client(server, capture, emulate, handle).await; } } FrontendRequest::ChangePort(port) => { let _ = port_tx.send(port).await; } FrontendRequest::Delete(handle) => { - remove_client(server, frontend, capture, emulate, handle).await; + remove_client(server, capture, emulate, handle).await; + broadcast(frontend, FrontendEvent::Deleted(handle)).await; } FrontendRequest::Enumerate() => { let clients = server @@ -131,25 +132,24 @@ async fn handle_frontend_event( .collect(); broadcast(frontend, FrontendEvent::Enumerate(clients)).await; } + FrontendRequest::GetState(handle) => { + broadcast_client(server, frontend, handle).await; + } FrontendRequest::Terminate() => { log::info!("terminating gracefully..."); return true; } FrontendRequest::UpdateFixIps(handle, fix_ips) => { update_fix_ips(server, resolve_tx, handle, fix_ips).await; - broadcast_client_update(server, frontend, handle).await; } FrontendRequest::UpdateHostname(handle, hostname) => { update_hostname(server, resolve_tx, handle, hostname).await; - broadcast_client_update(server, frontend, handle).await; } FrontendRequest::UpdatePort(handle, port) => { update_port(server, handle, port).await; - broadcast_client_update(server, frontend, handle).await; } FrontendRequest::UpdatePosition(handle, pos) => { update_pos(server, handle, capture, emulate, pos).await; - broadcast_client_update(server, frontend, handle).await; } FrontendRequest::ResolveDns(handle) => { let hostname = server @@ -181,15 +181,13 @@ pub async fn add_client(server: &Server, frontend: &mut FrontendListener) { pub async fn deactivate_client( server: &Server, - frontend: &mut FrontendListener, capture: &Sender, emulate: &Sender, handle: ClientHandle, ) { - let state = match server.client_manager.borrow_mut().get_mut(handle) { + match server.client_manager.borrow_mut().get_mut(handle) { Some((_, s)) => { s.active = false; - s.clone() } None => return, }; @@ -197,13 +195,10 @@ pub async fn deactivate_client( let event = ClientEvent::Destroy(handle); let _ = capture.send(CaptureEvent::ClientEvent(event)).await; let _ = emulate.send(EmulationEvent::ClientEvent(event)).await; - let event = FrontendEvent::StateChange(handle, state); - broadcast(frontend, event).await; } pub async fn activate_client( server: &Server, - frontend: &mut FrontendListener, capture: &Sender, emulate: &Sender, handle: ClientHandle, @@ -217,14 +212,13 @@ pub async fn activate_client( let other = server.client_manager.borrow_mut().find_client(pos); if let Some(other) = other { if other != handle { - deactivate_client(server, frontend, capture, emulate, other).await; + deactivate_client(server, capture, emulate, other).await; } } /* activate the client */ - let state = if let Some((_, s)) = server.client_manager.borrow_mut().get_mut(handle) { + if let Some((_, s)) = server.client_manager.borrow_mut().get_mut(handle) { s.active = true; - s.clone() } else { return; }; @@ -233,13 +227,10 @@ pub async fn activate_client( let event = ClientEvent::Create(handle, pos); let _ = capture.send(CaptureEvent::ClientEvent(event)).await; let _ = emulate.send(EmulationEvent::ClientEvent(event)).await; - let event = FrontendEvent::StateChange(handle, state); - broadcast(frontend, event).await; } pub async fn remove_client( server: &Server, - frontend: &mut FrontendListener, capture: &Sender, emulate: &Sender, handle: ClientHandle, @@ -258,9 +249,6 @@ pub async fn remove_client( let _ = capture.send(CaptureEvent::ClientEvent(destroy)).await; let _ = emulate.send(EmulationEvent::ClientEvent(destroy)).await; } - - let event = FrontendEvent::Deleted(handle); - broadcast(frontend, event).await; } async fn update_fix_ips( @@ -356,11 +344,11 @@ async fn update_pos( } } -async fn broadcast_client_update( - server: &Server, - frontend: &mut FrontendListener, - handle: ClientHandle, -) { - let (client, _) = server.client_manager.borrow().get(handle).unwrap().clone(); - broadcast(frontend, FrontendEvent::Updated(handle, client)).await; +async fn broadcast_client(server: &Server, frontend: &mut FrontendListener, handle: ClientHandle) { + let client = server.client_manager.borrow().get(handle).cloned(); + if let Some((config, state)) = client { + broadcast(frontend, FrontendEvent::State(handle, config, state)).await; + } else { + broadcast(frontend, FrontendEvent::NoSuchClient(handle)).await; + } } diff --git a/src/server/resolver_task.rs b/src/server/resolver_task.rs index ddfb17c..dc1e604 100644 --- a/src/server/resolver_task.rs +++ b/src/server/resolver_task.rs @@ -35,7 +35,7 @@ pub fn new( Ok(ips) => ips, Err(e) => { log::warn!("could not resolve host '{host}': {e}"); - continue; + vec![] } }; @@ -59,14 +59,10 @@ async fn notify_state_change( server: &mut Server, handle: ClientHandle, ) { - let state = server - .client_manager - .borrow_mut() - .get_mut(handle) - .map(|(_, s)| s.clone()); - if let Some(state) = state { + let state = server.client_manager.borrow_mut().get_mut(handle).cloned(); + if let Some((config, state)) = state { let _ = frontend - .send(FrontendEvent::StateChange(handle, state)) + .send(FrontendEvent::State(handle, config, state)) .await; } }