Skip to content

Commit

Permalink
implement dns indicator (#119)
Browse files Browse the repository at this point in the history
  • Loading branch information
feschber authored May 3, 2024
1 parent 5318f5a commit c76d9ef
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 13 deletions.
8 changes: 6 additions & 2 deletions resources/client_row.ui
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@
</child>
<child type="suffix">
<object class="GtkButton" id="dns_button">
<signal name="activate" handler="handle_request_dns" swapped="true"/>
<signal name="clicked" handler="handle_request_dns" swapped="true"/>
<!--<property name="icon-name">network-wired-disconnected-symbolic</property>-->
<property name="icon-name">network-wired-symbolic</property>
<property name="valign">center</property>
<property name="halign">end</property>
<property name="tooltip-text" translatable="yes">resolve dns</property>
<property name="tooltip-text" translatable="yes">resolve host</property>
</object>
</child>
<child type="suffix">
<object class="GtkSpinner" id="dns_loading_indicator">
</object>
</child>
<!-- host -->
Expand Down
2 changes: 2 additions & 0 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ pub struct ClientState {
pub ips: HashSet<IpAddr>,
/// keys currently pressed by this client
pub pressed_keys: HashSet<u32>,
/// dns resolving in progress
pub resolving: bool,
}

pub struct ClientManager {
Expand Down
2 changes: 2 additions & 0 deletions src/frontend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ pub enum FrontendRequest {
Delete(ClientHandle),
/// request an enumeration of all clients
Enumerate(),
/// resolve dns
ResolveDns(ClientHandle),
/// service shutdown
Terminate(),
/// update hostname
Expand Down
11 changes: 11 additions & 0 deletions src/frontend/gtk/client_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ impl ClientObject {
.property("port", client.port as u32)
.property("position", client.pos.to_string())
.property("active", state.active)
.property(
"ips",
state
.ips
.iter()
.map(|ip| ip.to_string())
.collect::<Vec<_>>(),
)
.property("resolving", state.resolving)
.build()
}

Expand All @@ -32,4 +41,6 @@ pub struct ClientData {
pub port: u32,
pub active: bool,
pub position: String,
pub resolving: bool,
pub ips: Vec<String>,
}
2 changes: 2 additions & 0 deletions src/frontend/gtk/client_object/imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub struct ClientObject {
#[property(name = "port", get, set, type = u32, member = port, maximum = u16::MAX as u32)]
#[property(name = "active", get, set, type = bool, member = active)]
#[property(name = "position", get, set, type = String, member = position)]
#[property(name = "resolving", get, set, type = bool, member = resolving)]
#[property(name = "ips", get, set, type = Vec<String>, member = ips)]
pub data: RefCell<ClientData>,
}

Expand Down
23 changes: 23 additions & 0 deletions src/frontend/gtk/client_row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,36 @@ impl ClientRow {
.sync_create()
.build();

let resolve_binding = client_object
.bind_property(
"resolving",
&self.imp().dns_loading_indicator.get(),
"spinning",
)
.sync_create()
.build();

let ip_binding = client_object
.bind_property("ips", &self.imp().dns_button.get(), "tooltip-text")
.transform_to(|_, ips: Vec<String>| {
if ips.is_empty() {
Some("no ip addresses associated with this client".into())
} else {
Some(ips.join("\n"))
}
})
.sync_create()
.build();

bindings.push(active_binding);
bindings.push(switch_position_binding);
bindings.push(hostname_binding);
bindings.push(title_binding);
bindings.push(port_binding);
bindings.push(subtitle_binding);
bindings.push(position_binding);
bindings.push(resolve_binding);
bindings.push(ip_binding);
}

pub fn unbind(&self) {
Expand Down
7 changes: 5 additions & 2 deletions src/frontend/gtk/client_row/imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ pub struct ClientRow {
pub delete_row: TemplateChild<ActionRow>,
#[template_child]
pub delete_button: TemplateChild<gtk::Button>,
#[template_child]
pub dns_loading_indicator: TemplateChild<gtk::Spinner>,
pub bindings: RefCell<Vec<Binding>>,
}

Expand Down Expand Up @@ -60,6 +62,7 @@ impl ObjectImpl for ClientRow {
static SIGNALS: OnceLock<Vec<Signal>> = OnceLock::new();
SIGNALS.get_or_init(|| {
vec![
Signal::builder("request-dns").build(),
Signal::builder("request-update")
.param_types([bool::static_type()])
.build(),
Expand All @@ -79,8 +82,8 @@ impl ClientRow {
}

#[template_callback]
fn handle_request_dns(&self) -> bool {
false
fn handle_request_dns(&self, _: Button) {
self.obj().emit_by_name::<()>("request-dns", &[]);
}

#[template_callback]
Expand Down
65 changes: 60 additions & 5 deletions src/frontend/gtk/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use glib::{clone, Object};
use gtk::{
gio,
glib::{self, closure_local},
NoSelection,
ListBox, NoSelection,
};

use crate::{
Expand Down Expand Up @@ -67,12 +67,23 @@ impl Window {
return;
};
let client = client.downcast_ref::<ClientObject>().unwrap();
window.request_client_update(client, active);
window.request_client_update(client);
window.request_client_activate(client, active)
}));
row.connect_closure("request-delete", false, closure_local!(@strong window => move |row: ClientRow| {
let index = row.index() as u32;
window.request_client_delete(index);
}));
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::<ClientObject>().unwrap();
window.request_client_update(client);
window.request_dns(index);
}));
row.upcast()
})
);
Expand Down Expand Up @@ -100,9 +111,10 @@ impl Window {
}

pub fn new_client(&self, handle: ClientHandle, client: ClientConfig, state: ClientState) {
let client = ClientObject::new(handle, client, state);
let client = ClientObject::new(handle, client, state.clone());
self.clients().append(&client);
self.set_placeholder_visible(false);
self.update_dns_state(handle, !state.ips.is_empty());
}

pub fn client_idx(&self, handle: ClientHandle) -> Option<usize> {
Expand Down Expand Up @@ -162,6 +174,42 @@ impl Window {
client_object.set_active(state.active);
log::debug!("set active to {}", state.active);
}

if state.resolving != data.resolving {
client_object.set_resolving(state.resolving);
log::debug!("resolving {}: {}", data.handle, state.active);
}

self.update_dns_state(handle, !state.ips.is_empty());
let ips = state
.ips
.into_iter()
.map(|ip| ip.to_string())
.collect::<Vec<_>>();
client_object.set_ips(ips);
}

pub fn update_dns_state(&self, handle: ClientHandle, resolved: bool) {
let Some(idx) = self.client_idx(handle) else {
log::warn!("could not find client with handle {}", handle);
return;
};
let list_box: ListBox = self.imp().client_list.get();
let row = list_box.row_at_index(idx as i32).unwrap();
let client_row: ClientRow = row.downcast().expect("expected ClientRow Object");
if resolved {
client_row.imp().dns_button.set_css_classes(&["success"])
} else {
client_row.imp().dns_button.set_css_classes(&["warning"])
}
}

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) {
Expand All @@ -179,7 +227,7 @@ impl Window {
}
}

pub fn request_client_update(&self, client: &ClientObject, active: bool) {
pub fn request_client_update(&self, client: &ClientObject) {
let handle = client.handle();
let data = client.get_data();
let position = Position::try_from(data.position.as_str()).expect("invalid position");
Expand All @@ -190,13 +238,20 @@ impl Window {
FrontendRequest::UpdateHostname(handle, hostname),
FrontendRequest::UpdatePosition(handle, position),
FrontendRequest::UpdatePort(handle, port),
FrontendRequest::Activate(handle, active),
] {
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
Expand Down
5 changes: 3 additions & 2 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ impl Server {

// udp task
let (mut udp_task, sender_tx, receiver_rx, port_tx) =
network_task::new(self.clone(), frontend_notify_tx).await?;
network_task::new(self.clone(), frontend_notify_tx.clone()).await?;

// input capture
let (mut capture_task, capture_channel) = capture_task::new(
Expand All @@ -113,7 +113,8 @@ impl Server {

// create dns resolver
let resolver = dns::DnsResolver::new().await?;
let (mut resolver_task, resolve_tx) = resolver_task::new(resolver, self.clone());
let (mut resolver_task, resolve_tx) =
resolver_task::new(resolver, self.clone(), frontend_notify_tx);

// frontend listener
let (mut frontend_task, frontend_tx) = frontend_task::new(
Expand Down
10 changes: 10 additions & 0 deletions src/server/frontend_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,16 @@ async fn handle_frontend_event(
update_pos(server, handle, capture, emulate, pos).await;
broadcast_client_update(server, frontend, handle).await;
}
FrontendRequest::ResolveDns(handle) => {
let hostname = server
.client_manager
.borrow()
.get(handle)
.and_then(|(c, _)| c.hostname.clone());
if let Some(hostname) = hostname {
let _ = resolve_tx.send(DnsRequest { hostname, handle }).await;
}
}
};
false
}
Expand Down
36 changes: 34 additions & 2 deletions src/server/resolver_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashSet;

use tokio::{sync::mpsc::Sender, task::JoinHandle};

use crate::{client::ClientHandle, dns::DnsResolver};
use crate::{client::ClientHandle, dns::DnsResolver, frontend::FrontendEvent};

use super::Server;

Expand All @@ -12,29 +12,61 @@ pub struct DnsRequest {
pub handle: ClientHandle,
}

pub fn new(resolver: DnsResolver, server: Server) -> (JoinHandle<()>, Sender<DnsRequest>) {
pub fn new(
resolver: DnsResolver,
mut server: Server,
mut frontend: Sender<FrontendEvent>,
) -> (JoinHandle<()>, Sender<DnsRequest>) {
let (dns_tx, mut dns_rx) = tokio::sync::mpsc::channel::<DnsRequest>(32);
let resolver_task = tokio::task::spawn_local(async move {
loop {
let (host, handle) = match dns_rx.recv().await {
Some(r) => (r.hostname, r.handle),
None => break,
};

/* update resolving status */
if let Some((_, s)) = server.client_manager.borrow_mut().get_mut(handle) {
s.resolving = true;
}
notify_state_change(&mut frontend, &mut server, handle).await;

let ips = match resolver.resolve(&host).await {
Ok(ips) => ips,
Err(e) => {
log::warn!("could not resolve host '{host}': {e}");
continue;
}
};

/* update ips and resolving state */
if let Some((c, s)) = server.client_manager.borrow_mut().get_mut(handle) {
let mut addrs = HashSet::from_iter(c.fix_ips.iter().cloned());
for ip in ips {
addrs.insert(ip);
}
s.ips = addrs;
s.resolving = false;
}
notify_state_change(&mut frontend, &mut server, handle).await;
}
});
(resolver_task, dns_tx)
}

async fn notify_state_change(
frontend: &mut Sender<FrontendEvent>,
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 _ = frontend
.send(FrontendEvent::StateChange(handle, state))
.await;
}
}

0 comments on commit c76d9ef

Please sign in to comment.