mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-03-17 02:00:54 +03:00
explicit state synchronisation (#129)
prevents unnecessary state updates and makes synchronization less error prone
This commit is contained in:
committed by
GitHub
parent
9969f997d3
commit
e9738fc024
@@ -107,16 +107,18 @@ pub enum FrontendRequest {
|
||||
UpdatePosition(ClientHandle, Position),
|
||||
/// update fix-ips
|
||||
UpdateFixIps(ClientHandle, Vec<IpAddr>),
|
||||
/// 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() {
|
||||
|
||||
@@ -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} {}",
|
||||
|
||||
@@ -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());
|
||||
},
|
||||
|
||||
@@ -51,6 +51,10 @@ impl Window {
|
||||
.expect("Could not get clients")
|
||||
}
|
||||
|
||||
fn client_by_idx(&self, idx: u32) -> Option<ClientObject> {
|
||||
self.clients().item(idx).map(|o| o.downcast().unwrap())
|
||||
}
|
||||
|
||||
fn setup_clients(&self) {
|
||||
let model = gio::ListStore::new::<ClientObject>();
|
||||
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::<ClientObject>().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::<ClientObject>().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::<u16>() {
|
||||
@@ -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();
|
||||
|
||||
@@ -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<CaptureEvent>,
|
||||
emulate: &Sender<EmulationEvent>,
|
||||
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<CaptureEvent>,
|
||||
emulate: &Sender<EmulationEvent>,
|
||||
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<CaptureEvent>,
|
||||
emulate: &Sender<EmulationEvent>,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user