mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-03-31 17:10:54 +03:00
Frontend improvement (#27)
* removed redundant dns lookups * frontend now correctly reflects the state of the backend * config.toml is loaded when starting gtk frontend
This commit is contained in:
committed by
Ferdinand Schober
parent
603646c799
commit
06725f4b14
213
src/client.rs
213
src/client.rs
@@ -1,4 +1,4 @@
|
||||
use std::{net::SocketAddr, collections::{HashSet, hash_set::Iter}, fmt::Display, time::{Instant, Duration}, iter::Cloned};
|
||||
use std::{net::{SocketAddr, IpAddr}, collections::HashSet, fmt::Display, time::Instant};
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
@@ -10,6 +10,12 @@ pub enum Position {
|
||||
Bottom,
|
||||
}
|
||||
|
||||
impl Default for Position {
|
||||
fn default() -> Self {
|
||||
Self::Left
|
||||
}
|
||||
}
|
||||
|
||||
impl Position {
|
||||
pub fn opposite(&self) -> Self {
|
||||
match self {
|
||||
@@ -34,7 +40,9 @@ impl Display for Position {
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct Client {
|
||||
/// handle to refer to the client.
|
||||
/// hostname of this client
|
||||
pub hostname: Option<String>,
|
||||
/// unique handle to refer to the client.
|
||||
/// This way any event consumer / producer backend does not
|
||||
/// need to know anything about a client other than its handle.
|
||||
pub handle: ClientHandle,
|
||||
@@ -46,6 +54,8 @@ pub struct Client {
|
||||
/// e.g. Laptops usually have at least an ethernet and a wifi port
|
||||
/// which have different ip addresses
|
||||
pub addrs: HashSet<SocketAddr>,
|
||||
/// both active_addr and addrs can be None / empty so port needs to be stored seperately
|
||||
pub port: u16,
|
||||
/// position of a client on screen
|
||||
pub pos: Position,
|
||||
}
|
||||
@@ -53,159 +63,118 @@ pub struct Client {
|
||||
pub enum ClientEvent {
|
||||
Create(ClientHandle, Position),
|
||||
Destroy(ClientHandle),
|
||||
UpdatePos(ClientHandle, Position),
|
||||
AddAddr(ClientHandle, SocketAddr),
|
||||
RemoveAddr(ClientHandle, SocketAddr),
|
||||
}
|
||||
|
||||
pub type ClientHandle = u32;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClientState {
|
||||
pub client: Client,
|
||||
pub active: bool,
|
||||
pub last_ping: Option<Instant>,
|
||||
pub last_seen: Option<Instant>,
|
||||
pub last_replied: Option<Instant>,
|
||||
}
|
||||
|
||||
pub struct ClientManager {
|
||||
/// probably not beneficial to use a hashmap here
|
||||
clients: Vec<Client>,
|
||||
last_ping: Vec<(ClientHandle, Option<Instant>)>,
|
||||
last_seen: Vec<(ClientHandle, Option<Instant>)>,
|
||||
last_replied: Vec<(ClientHandle, Option<Instant>)>,
|
||||
next_client_id: u32,
|
||||
clients: Vec<Option<ClientState>>, // HashMap likely not beneficial
|
||||
}
|
||||
|
||||
impl ClientManager {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
clients: vec![],
|
||||
next_client_id: 0,
|
||||
last_ping: vec![],
|
||||
last_seen: vec![],
|
||||
last_replied: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// add a new client to this manager
|
||||
pub fn add_client(&mut self, addrs: HashSet<SocketAddr>, pos: Position) -> ClientHandle {
|
||||
let handle = self.next_id();
|
||||
pub fn add_client(
|
||||
&mut self,
|
||||
hostname: Option<String>,
|
||||
addrs: HashSet<IpAddr>,
|
||||
port: u16,
|
||||
pos: Position,
|
||||
) -> ClientHandle {
|
||||
// get a new client_handle
|
||||
let handle = self.free_id();
|
||||
|
||||
// we dont know, which IP is initially active
|
||||
let active_addr = None;
|
||||
|
||||
// map ip addresses to socket addresses
|
||||
let addrs = HashSet::from_iter(
|
||||
addrs
|
||||
.into_iter()
|
||||
.map(|ip| SocketAddr::new(ip, port))
|
||||
);
|
||||
|
||||
// store the client
|
||||
let client = Client { handle, active_addr, addrs, pos };
|
||||
self.clients.push(client);
|
||||
self.last_ping.push((handle, None));
|
||||
self.last_seen.push((handle, None));
|
||||
self.last_replied.push((handle, None));
|
||||
let client = Client { hostname, handle, active_addr, addrs, port, pos };
|
||||
|
||||
// client was never seen, nor pinged
|
||||
let client_state = ClientState {
|
||||
client,
|
||||
last_ping: None,
|
||||
last_seen: None,
|
||||
last_replied: None,
|
||||
active: false,
|
||||
};
|
||||
|
||||
if handle as usize >= self.clients.len() {
|
||||
assert_eq!(handle as usize, self.clients.len());
|
||||
self.clients.push(Some(client_state));
|
||||
} else {
|
||||
self.clients[handle as usize] = Some(client_state);
|
||||
}
|
||||
handle
|
||||
}
|
||||
|
||||
/// add a socket address to the given client
|
||||
pub fn add_addr(&mut self, client: ClientHandle, addr: SocketAddr) {
|
||||
if let Some(client) = self.get_mut(client) {
|
||||
client.addrs.insert(addr);
|
||||
}
|
||||
}
|
||||
|
||||
/// remove socket address from the given client
|
||||
pub fn remove_addr(&mut self, client: ClientHandle, addr: SocketAddr) {
|
||||
if let Some(client) = self.get_mut(client) {
|
||||
client.addrs.remove(&addr);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_default_addr(&mut self, client: ClientHandle, addr: SocketAddr) {
|
||||
if let Some(client) = self.get_mut(client) {
|
||||
client.active_addr = Some(addr)
|
||||
}
|
||||
}
|
||||
|
||||
/// update the position of a client
|
||||
pub fn update_pos(&mut self, client: ClientHandle, pos: Position) {
|
||||
if let Some(client) = self.get_mut(client) {
|
||||
client.pos = pos;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_active_addr(&self, client: ClientHandle) -> Option<SocketAddr> {
|
||||
self.get(client)?.active_addr
|
||||
}
|
||||
|
||||
pub fn get_addrs(&self, client: ClientHandle) -> Option<Cloned<Iter<'_, SocketAddr>>> {
|
||||
Some(self.get(client)?.addrs.iter().cloned())
|
||||
}
|
||||
|
||||
pub fn last_ping(&self, client: ClientHandle) -> Option<Duration> {
|
||||
let last_ping = self.last_ping
|
||||
.iter()
|
||||
.find(|(c,_)| *c == client)?.1;
|
||||
last_ping.map(|p| p.elapsed())
|
||||
}
|
||||
|
||||
pub fn last_seen(&self, client: ClientHandle) -> Option<Duration> {
|
||||
let last_seen = self.last_seen
|
||||
.iter()
|
||||
.find(|(c, _)| *c == client)?.1;
|
||||
last_seen.map(|t| t.elapsed())
|
||||
}
|
||||
|
||||
pub fn last_replied(&self, client: ClientHandle) -> Option<Duration> {
|
||||
let last_replied = self.last_replied
|
||||
.iter()
|
||||
.find(|(c, _)| *c == client)?.1;
|
||||
last_replied.map(|t| t.elapsed())
|
||||
}
|
||||
|
||||
pub fn reset_last_ping(&mut self, client: ClientHandle) {
|
||||
if let Some(c) = self.last_ping
|
||||
.iter_mut()
|
||||
.find(|(c, _)| *c == client) {
|
||||
c.1 = Some(Instant::now());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_last_seen(&mut self, client: ClientHandle) {
|
||||
if let Some(c) = self.last_seen
|
||||
.iter_mut()
|
||||
.find(|(c, _)| *c == client) {
|
||||
c.1 = Some(Instant::now());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_last_replied(&mut self, client: ClientHandle) {
|
||||
if let Some(c) = self.last_replied
|
||||
.iter_mut()
|
||||
.find(|(c, _)| *c == client) {
|
||||
c.1 = Some(Instant::now());
|
||||
}
|
||||
}
|
||||
|
||||
/// find a client by its address
|
||||
pub fn get_client(&self, addr: SocketAddr) -> Option<ClientHandle> {
|
||||
// since there shouldn't be more than a handful of clients at any given
|
||||
// time this is likely faster than using a HashMap
|
||||
self.clients
|
||||
.iter()
|
||||
.find(|c| c.addrs.contains(&addr))
|
||||
.map(|c| c.handle)
|
||||
.position(|c| if let Some(c) = c {
|
||||
c.active && c.client.addrs.contains(&addr)
|
||||
} else {
|
||||
false
|
||||
})
|
||||
.map(|p| p as ClientHandle)
|
||||
}
|
||||
|
||||
pub fn remove_client(&mut self, client: ClientHandle) {
|
||||
if let Some(i) = self.clients.iter().position(|c| c.handle == client) {
|
||||
self.clients.remove(i);
|
||||
self.last_ping.remove(i);
|
||||
self.last_seen.remove(i);
|
||||
self.last_replied.remove(i);
|
||||
/// remove a client from the list
|
||||
pub fn remove_client(&mut self, client: ClientHandle) -> Option<ClientState> {
|
||||
// remove id from occupied ids
|
||||
self.clients.get_mut(client as usize)?.take()
|
||||
}
|
||||
|
||||
/// get a free slot in the client list
|
||||
fn free_id(&mut self) -> ClientHandle {
|
||||
for i in 0..u32::MAX {
|
||||
if self.clients.get(i as usize).is_none()
|
||||
|| self.clients.get(i as usize).unwrap().is_none() {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
panic!("Out of client ids");
|
||||
}
|
||||
|
||||
fn next_id(&mut self) -> ClientHandle {
|
||||
let handle = self.next_client_id;
|
||||
self.next_client_id += 1;
|
||||
handle
|
||||
// returns an immutable reference to the client state corresponding to `client`
|
||||
pub fn get<'a>(&'a self, client: ClientHandle) -> Option<&'a ClientState> {
|
||||
self.clients.get(client as usize)?.as_ref()
|
||||
}
|
||||
|
||||
fn get<'a>(&'a self, client: ClientHandle) -> Option<&'a Client> {
|
||||
/// returns a mutable reference to the client state corresponding to `client`
|
||||
pub fn get_mut<'a>(&'a mut self, client: ClientHandle) -> Option<&'a mut ClientState> {
|
||||
self.clients.get_mut(client as usize)?.as_mut()
|
||||
}
|
||||
|
||||
pub fn enumerate(&self) -> Vec<(Client, bool)> {
|
||||
self.clients
|
||||
.iter()
|
||||
.find(|c| c.handle == client)
|
||||
}
|
||||
|
||||
fn get_mut<'a>(&'a mut self, client: ClientHandle) -> Option<&'a mut Client> {
|
||||
self.clients
|
||||
.iter_mut()
|
||||
.find(|c| c.handle == client)
|
||||
.filter_map(|s|s.as_ref())
|
||||
.map(|s| (s.client.clone(), s.active))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user