mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-03-07 20:09:59 +03:00
This allows to dynamically add clients when an event is received from an unknown IP address. The user is asked to confirm any unknown connection from new clients. Currently the back-ends for event producing and consuming are not yet notified, so events will not be received and sent to the newly created clients.
107 lines
2.7 KiB
Rust
107 lines
2.7 KiB
Rust
use std::{net::SocketAddr, error::Error, fmt::Display, sync::{Arc, atomic::{AtomicBool, Ordering, AtomicU32}, RwLock}};
|
|
|
|
use crate::{config, dns};
|
|
|
|
#[derive(Eq, Hash, PartialEq, Clone, Copy)]
|
|
pub enum Position {
|
|
Left,
|
|
Right,
|
|
Top,
|
|
Bottom,
|
|
}
|
|
|
|
#[derive(Clone, Copy)]
|
|
pub struct Client {
|
|
pub addr: SocketAddr,
|
|
pub pos: Position,
|
|
pub handle: ClientHandle,
|
|
}
|
|
|
|
impl Client {
|
|
pub fn handle(&self) -> ClientHandle {
|
|
return self.handle;
|
|
}
|
|
}
|
|
|
|
pub enum ClientEvent {
|
|
Create(Client),
|
|
Destroy(Client),
|
|
}
|
|
|
|
pub struct ClientManager {
|
|
next_id: AtomicU32,
|
|
clients: RwLock<Vec<Client>>,
|
|
subscribers: RwLock<Vec<Arc<AtomicBool>>>,
|
|
}
|
|
|
|
pub type ClientHandle = u32;
|
|
|
|
#[derive(Debug)]
|
|
struct ClientConfigError;
|
|
|
|
impl Display for ClientConfigError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "neither ip nor hostname specified")
|
|
}
|
|
}
|
|
|
|
impl Error for ClientConfigError {}
|
|
|
|
impl ClientManager {
|
|
fn add_client(&self, client: &config::Client, pos: Position) -> Result<(), Box<dyn Error>> {
|
|
let ip = match client.ip {
|
|
Some(ip) => ip,
|
|
None => match &client.host_name {
|
|
Some(host_name) => dns::resolve(host_name)?,
|
|
None => return Err(Box::new(ClientConfigError{})),
|
|
},
|
|
};
|
|
let addr = SocketAddr::new(ip, client.port.unwrap_or(42069));
|
|
self.register_client(addr, pos);
|
|
Ok(())
|
|
}
|
|
|
|
fn notify(&self) {
|
|
for subscriber in self.subscribers.read().unwrap().iter() {
|
|
subscriber.store(true, Ordering::SeqCst);
|
|
}
|
|
}
|
|
|
|
fn new_id(&self) -> ClientHandle {
|
|
let id = self.next_id.load(Ordering::Acquire);
|
|
self.next_id.store(id + 1, Ordering::Release);
|
|
id as ClientHandle
|
|
}
|
|
|
|
pub fn new(config: &config::Config) -> Result<Self, Box<dyn Error>> {
|
|
|
|
let client_manager = ClientManager {
|
|
next_id: AtomicU32::new(0),
|
|
clients: RwLock::new(Vec::new()),
|
|
subscribers: RwLock::new(vec![]),
|
|
};
|
|
|
|
// add clients from config
|
|
for (client, pos) in config.clients.iter() {
|
|
client_manager.add_client(&client, *pos)?;
|
|
}
|
|
|
|
Ok(client_manager)
|
|
}
|
|
|
|
pub fn register_client(&self, addr: SocketAddr, pos: Position) {
|
|
let handle = self.new_id();
|
|
let client = Client { addr, pos, handle };
|
|
self.clients.write().unwrap().push(client);
|
|
self.notify();
|
|
}
|
|
|
|
pub fn get_clients(&self) -> Vec<Client> {
|
|
self.clients.read().unwrap().clone()
|
|
}
|
|
|
|
pub fn subscribe(&self, subscriber: Arc<AtomicBool>) {
|
|
self.subscribers.write().unwrap().push(subscriber);
|
|
}
|
|
}
|