enforce only one client at a position (#102)

This commit is contained in:
Ferdinand Schober
2024-04-10 14:16:19 +02:00
committed by GitHub
parent cc7984c066
commit 9ca7e2378c
2 changed files with 128 additions and 92 deletions

View File

@@ -178,6 +178,19 @@ impl ClientManager {
.map(|p| p as ClientHandle) .map(|p| p as ClientHandle)
} }
pub fn find_client(&self, pos: Position) -> Option<ClientHandle> {
self.clients
.iter()
.position(|c| {
if let Some(c) = c {
c.active && c.client.pos == pos
} else {
false
}
})
.map(|p| p as ClientHandle)
}
/// remove a client from the list /// remove a client from the list
pub fn remove_client(&mut self, client: ClientHandle) -> Option<ClientState> { pub fn remove_client(&mut self, client: ClientHandle) -> Option<ClientState> {
// remove id from occupied ids // remove id from occupied ids

View File

@@ -29,8 +29,8 @@ pub(crate) fn new(
mut frontend: FrontendListener, mut frontend: FrontendListener,
mut notify_rx: Receiver<FrontendNotify>, mut notify_rx: Receiver<FrontendNotify>,
server: Server, server: Server,
capture_notify: Sender<CaptureEvent>, capture: Sender<CaptureEvent>,
emulate_notify: Sender<EmulationEvent>, emulate: Sender<EmulationEvent>,
resolve_ch: Sender<DnsRequest>, resolve_ch: Sender<DnsRequest>,
port_tx: Sender<u16>, port_tx: Sender<u16>,
) -> (JoinHandle<Result<()>>, Sender<FrontendEvent>) { ) -> (JoinHandle<Result<()>>, Sender<FrontendEvent>) {
@@ -51,7 +51,7 @@ pub(crate) fn new(
} }
event = event_rx.recv() => { event = event_rx.recv() => {
let frontend_event = event.ok_or(anyhow!("frontend channel closed"))?; let frontend_event = event.ok_or(anyhow!("frontend channel closed"))?;
if handle_frontend_event(&server, &capture_notify, &emulate_notify, &resolve_ch, &mut frontend, &port_tx, frontend_event).await { if handle_frontend_event(&server, &capture, &emulate, &resolve_ch, &mut frontend, &port_tx, frontend_event).await {
break; break;
} }
} }
@@ -106,30 +106,31 @@ async fn handle_frontend_event(
event: FrontendEvent, event: FrontendEvent,
) -> bool { ) -> bool {
log::debug!("frontend: {event:?}"); log::debug!("frontend: {event:?}");
let response = match event { match event {
FrontendEvent::AddClient(hostname, port, pos) => { FrontendEvent::AddClient(hostname, port, pos) => {
let handle = add_client(server, resolve_tx, hostname, HashSet::new(), port, pos).await; add_client(
server,
let client = server frontend,
.client_manager resolve_tx,
.borrow() hostname,
.get(handle) HashSet::new(),
.unwrap() port,
.client pos,
.clone(); )
Some(FrontendNotify::NotifyClientCreate(client)) .await;
} }
FrontendEvent::ActivateClient(handle, active) => { FrontendEvent::ActivateClient(handle, active) => {
activate_client(server, capture_tx, emulate_tx, handle, active).await; if active {
Some(FrontendNotify::NotifyClientActivate(handle, active)) activate_client(server, frontend, capture_tx, emulate_tx, handle).await;
} else {
deactivate_client(server, frontend, capture_tx, emulate_tx, handle).await;
}
} }
FrontendEvent::ChangePort(port) => { FrontendEvent::ChangePort(port) => {
let _ = port_tx.send(port).await; let _ = port_tx.send(port).await;
None
} }
FrontendEvent::DelClient(handle) => { FrontendEvent::DelClient(handle) => {
remove_client(server, capture_tx, emulate_tx, frontend, handle).await; remove_client(server, frontend, capture_tx, emulate_tx, handle).await;
Some(FrontendNotify::NotifyClientDelete(handle))
} }
FrontendEvent::Enumerate() => { FrontendEvent::Enumerate() => {
let clients = server let clients = server
@@ -138,7 +139,7 @@ async fn handle_frontend_event(
.get_client_states() .get_client_states()
.map(|s| (s.client.clone(), s.active)) .map(|s| (s.client.clone(), s.active))
.collect(); .collect();
Some(FrontendNotify::Enumerate(clients)) notify_all(frontend, FrontendNotify::Enumerate(clients)).await;
} }
FrontendEvent::Shutdown() => { FrontendEvent::Shutdown() => {
log::info!("terminating gracefully..."); log::info!("terminating gracefully...");
@@ -147,40 +148,33 @@ async fn handle_frontend_event(
FrontendEvent::UpdateClient(handle, hostname, port, pos) => { FrontendEvent::UpdateClient(handle, hostname, port, pos) => {
update_client( update_client(
server, server,
frontend,
capture_tx, capture_tx,
emulate_tx, emulate_tx,
resolve_tx, resolve_tx,
(handle, hostname, port, pos), (handle, hostname, port, pos),
) )
.await; .await;
let client = server
.client_manager
.borrow()
.get(handle)
.unwrap()
.client
.clone();
Some(FrontendNotify::NotifyClientUpdate(client))
} }
}; };
let Some(response) = response else { false
return false; }
};
if let Err(e) = frontend.notify_all(response).await { async fn notify_all(frontend: &mut FrontendListener, event: FrontendNotify) {
if let Err(e) = frontend.notify_all(event).await {
log::error!("error notifying frontend: {e}"); log::error!("error notifying frontend: {e}");
} }
false
} }
pub async fn add_client( pub async fn add_client(
server: &Server, server: &Server,
frontend: &mut FrontendListener,
resolver_tx: &Sender<DnsRequest>, resolver_tx: &Sender<DnsRequest>,
hostname: Option<String>, hostname: Option<String>,
addr: HashSet<IpAddr>, addr: HashSet<IpAddr>,
port: u16, port: u16,
pos: Position, pos: Position,
) -> ClientHandle { ) {
log::info!( log::info!(
"adding client [{}]{} @ {:?}", "adding client [{}]{} @ {:?}",
pos, pos,
@@ -198,77 +192,105 @@ pub async fn add_client(
if let Some(hostname) = hostname { if let Some(hostname) = hostname {
let _ = resolver_tx.send(DnsRequest { hostname, handle }).await; let _ = resolver_tx.send(DnsRequest { hostname, handle }).await;
} }
let client = server
handle .client_manager
.borrow()
.get(handle)
.unwrap()
.client
.clone();
notify_all(frontend, FrontendNotify::NotifyClientCreate(client)).await;
} }
pub async fn activate_client( pub async fn deactivate_client(
server: &Server, server: &Server,
capture_notify_tx: &Sender<CaptureEvent>, frontend: &mut FrontendListener,
emulate_notify_tx: &Sender<EmulationEvent>, capture: &Sender<CaptureEvent>,
emulate: &Sender<EmulationEvent>,
client: ClientHandle, client: ClientHandle,
active: bool,
) { ) {
let (client, pos) = match server.client_manager.borrow_mut().get_mut(client) { let (client, _) = match server.client_manager.borrow_mut().get_mut(client) {
Some(state) => { Some(state) => {
state.active = active; state.active = false;
(state.client.handle, state.client.pos) (state.client.handle, state.client.pos)
} }
None => return, None => return,
}; };
if active {
let _ = capture_notify_tx let event = ClientEvent::Destroy(client);
.send(CaptureEvent::ClientEvent(ClientEvent::Create(client, pos))) let _ = capture.send(CaptureEvent::ClientEvent(event)).await;
.await; let _ = emulate.send(EmulationEvent::ClientEvent(event)).await;
let _ = emulate_notify_tx let event = FrontendNotify::NotifyClientActivate(client, false);
.send(EmulationEvent::ClientEvent(ClientEvent::Create( notify_all(frontend, event).await;
client, pos, }
)))
.await; pub async fn activate_client(
} else { server: &Server,
let _ = capture_notify_tx frontend: &mut FrontendListener,
.send(CaptureEvent::ClientEvent(ClientEvent::Destroy(client))) capture: &Sender<CaptureEvent>,
.await; emulate: &Sender<EmulationEvent>,
let _ = emulate_notify_tx handle: ClientHandle,
.send(EmulationEvent::ClientEvent(ClientEvent::Destroy(client))) ) {
.await; /* deactivate potential other client at this position */
let pos = match server.client_manager.borrow().get(handle) {
Some(state) => state.client.pos,
None => return,
};
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;
}
} }
/* activate the client */
server
.client_manager
.borrow_mut()
.get_mut(handle)
.unwrap()
.active = true;
/* notify emulation, capture and frontends */
let event = ClientEvent::Create(handle, pos);
let _ = capture.send(CaptureEvent::ClientEvent(event)).await;
let _ = emulate.send(EmulationEvent::ClientEvent(event)).await;
let event = FrontendNotify::NotifyClientActivate(handle, true);
notify_all(frontend, event).await;
} }
pub async fn remove_client( pub async fn remove_client(
server: &Server, server: &Server,
capture_notify_tx: &Sender<CaptureEvent>,
emulate_notify_tx: &Sender<EmulationEvent>,
frontend: &mut FrontendListener, frontend: &mut FrontendListener,
capture: &Sender<CaptureEvent>,
emulate: &Sender<EmulationEvent>,
client: ClientHandle, client: ClientHandle,
) -> Option<ClientHandle> { ) {
let (client, active) = server let Some((client, active)) = server
.client_manager .client_manager
.borrow_mut() .borrow_mut()
.remove_client(client) .remove_client(client)
.map(|s| (s.client.handle, s.active))?; .map(|s| (s.client.handle, s.active))
else {
return;
};
if active { if active {
let _ = capture_notify_tx let destroy = ClientEvent::Destroy(client);
.send(CaptureEvent::ClientEvent(ClientEvent::Destroy(client))) let _ = capture.send(CaptureEvent::ClientEvent(destroy)).await;
.await; let _ = emulate.send(EmulationEvent::ClientEvent(destroy)).await;
let _ = emulate_notify_tx
.send(EmulationEvent::ClientEvent(ClientEvent::Destroy(client)))
.await;
} }
let notify = FrontendNotify::NotifyClientDelete(client); let event = FrontendNotify::NotifyClientDelete(client);
log::debug!("{notify:?}"); notify_all(frontend, event).await;
if let Err(e) = frontend.notify_all(notify).await {
log::error!("error notifying frontend: {e}");
}
Some(client)
} }
async fn update_client( async fn update_client(
server: &Server, server: &Server,
capture_notify_tx: &Sender<CaptureEvent>, frontend: &mut FrontendListener,
emulate_notify_tx: &Sender<EmulationEvent>, capture: &Sender<CaptureEvent>,
emulate: &Sender<EmulationEvent>,
resolve_tx: &Sender<DnsRequest>, resolve_tx: &Sender<DnsRequest>,
client_update: (ClientHandle, Option<String>, u16, Position), client_update: (ClientHandle, Option<String>, u16, Position),
) { ) {
@@ -321,19 +343,20 @@ async fn update_client(
// update state in event input emulator & input capture // update state in event input emulator & input capture
if changed && active { if changed && active {
// update state // update state
let _ = capture_notify_tx let destroy = ClientEvent::Destroy(handle);
.send(CaptureEvent::ClientEvent(ClientEvent::Destroy(handle))) let create = ClientEvent::Create(handle, pos);
.await; let _ = capture.send(CaptureEvent::ClientEvent(destroy)).await;
let _ = emulate_notify_tx let _ = emulate.send(EmulationEvent::ClientEvent(destroy)).await;
.send(EmulationEvent::ClientEvent(ClientEvent::Destroy(handle))) let _ = capture.send(CaptureEvent::ClientEvent(create)).await;
.await; let _ = emulate.send(EmulationEvent::ClientEvent(create)).await;
let _ = capture_notify_tx
.send(CaptureEvent::ClientEvent(ClientEvent::Create(handle, pos)))
.await;
let _ = emulate_notify_tx
.send(EmulationEvent::ClientEvent(ClientEvent::Create(
handle, pos,
)))
.await;
} }
let client = server
.client_manager
.borrow()
.get(handle)
.unwrap()
.client
.clone();
notify_all(frontend, FrontendNotify::NotifyClientUpdate(client)).await;
} }