Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement dns indicator #119

Merged
merged 1 commit into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
}
Loading