mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-03-21 20:20:55 +03:00
use slab instead of reinventing the wheel (#112)
This commit is contained in:
committed by
GitHub
parent
279e582698
commit
3e96b42067
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1263,6 +1263,7 @@ dependencies = [
|
||||
"reis",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"slab",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"toml",
|
||||
|
||||
@@ -34,6 +34,7 @@ keycode = "0.4.0"
|
||||
once_cell = "1.19.0"
|
||||
num_enum = "0.7.2"
|
||||
hostname = "0.4.0"
|
||||
slab = "0.4.9"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2.148"
|
||||
|
||||
@@ -46,7 +46,7 @@ enum ProducerEvent {
|
||||
pub struct LibeiInputCapture<'a> {
|
||||
input_capture: Pin<Box<InputCapture<'a>>>,
|
||||
libei_task: JoinHandle<Result<()>>,
|
||||
event_rx: tokio::sync::mpsc::Receiver<(u32, Event)>,
|
||||
event_rx: tokio::sync::mpsc::Receiver<(ClientHandle, Event)>,
|
||||
notify_tx: tokio::sync::mpsc::Sender<ProducerEvent>,
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ async fn connect_to_eis(
|
||||
async fn libei_event_handler(
|
||||
mut ei_event_stream: EiConvertEventStream,
|
||||
context: ei::Context,
|
||||
event_tx: Sender<(u32, Event)>,
|
||||
event_tx: Sender<(ClientHandle, Event)>,
|
||||
current_client: Rc<Cell<Option<ClientHandle>>>,
|
||||
) -> Result<()> {
|
||||
loop {
|
||||
@@ -396,7 +396,7 @@ async fn handle_ei_event(
|
||||
ei_event: EiEvent,
|
||||
current_client: Option<ClientHandle>,
|
||||
context: &ei::Context,
|
||||
event_tx: &Sender<(u32, Event)>,
|
||||
event_tx: &Sender<(ClientHandle, Event)>,
|
||||
) {
|
||||
match ei_event {
|
||||
EiEvent::SeatAdded(s) => {
|
||||
|
||||
@@ -5,6 +5,7 @@ use std::{
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use slab::Slab;
|
||||
|
||||
#[derive(Debug, Eq, Hash, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum Position {
|
||||
@@ -66,10 +67,6 @@ pub struct Client {
|
||||
pub hostname: Option<String>,
|
||||
/// fix ips, determined by the user
|
||||
pub fix_ips: Vec<IpAddr>,
|
||||
/// unique handle to refer to the client.
|
||||
/// This way any emulation / capture backend does not
|
||||
/// need to know anything about a client other than its handle.
|
||||
pub handle: ClientHandle,
|
||||
/// all ip addresses associated with a particular client
|
||||
/// e.g. Laptops usually have at least an ethernet and a wifi port
|
||||
/// which have different ip addresses
|
||||
@@ -86,7 +83,7 @@ pub enum ClientEvent {
|
||||
Destroy(ClientHandle),
|
||||
}
|
||||
|
||||
pub type ClientHandle = u32;
|
||||
pub type ClientHandle = u64;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClientState {
|
||||
@@ -105,7 +102,7 @@ pub struct ClientState {
|
||||
}
|
||||
|
||||
pub struct ClientManager {
|
||||
clients: Vec<Option<ClientState>>, // HashMap likely not beneficial
|
||||
clients: Slab<ClientState>,
|
||||
}
|
||||
|
||||
impl Default for ClientManager {
|
||||
@@ -116,7 +113,8 @@ impl Default for ClientManager {
|
||||
|
||||
impl ClientManager {
|
||||
pub fn new() -> Self {
|
||||
Self { clients: vec![] }
|
||||
let clients = Slab::new();
|
||||
Self { clients }
|
||||
}
|
||||
|
||||
/// add a new client to this manager
|
||||
@@ -128,38 +126,24 @@ impl ClientManager {
|
||||
pos: Position,
|
||||
active: bool,
|
||||
) -> ClientHandle {
|
||||
// get a new client_handle
|
||||
let handle = self.free_id();
|
||||
|
||||
// store fix ip addresses
|
||||
let fix_ips = ips.iter().cloned().collect();
|
||||
|
||||
// store the client
|
||||
let client = Client {
|
||||
hostname,
|
||||
fix_ips,
|
||||
handle,
|
||||
ips,
|
||||
port,
|
||||
pos,
|
||||
};
|
||||
|
||||
// client was never seen, nor pinged
|
||||
let client_state = ClientState {
|
||||
client,
|
||||
client: Client {
|
||||
hostname,
|
||||
fix_ips,
|
||||
ips,
|
||||
port,
|
||||
pos,
|
||||
},
|
||||
active,
|
||||
active_addr: None,
|
||||
alive: false,
|
||||
pressed_keys: HashSet::new(),
|
||||
};
|
||||
|
||||
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
|
||||
self.clients.insert(client_state) as ClientHandle
|
||||
}
|
||||
|
||||
/// find a client by its address
|
||||
@@ -168,11 +152,11 @@ impl ClientManager {
|
||||
// time this is likely faster than using a HashMap
|
||||
self.clients
|
||||
.iter()
|
||||
.position(|c| {
|
||||
if let Some(c) = c {
|
||||
c.active && c.client.ips.contains(&addr.ip())
|
||||
.find_map(|(k, c)| {
|
||||
if c.active && c.client.ips.contains(&addr.ip()) {
|
||||
Some(k)
|
||||
} else {
|
||||
false
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|p| p as ClientHandle)
|
||||
@@ -181,11 +165,11 @@ impl ClientManager {
|
||||
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
|
||||
.find_map(|(k, c)| {
|
||||
if c.active && c.client.pos == pos {
|
||||
Some(k)
|
||||
} else {
|
||||
false
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|p| p as ClientHandle)
|
||||
@@ -194,36 +178,26 @@ impl ClientManager {
|
||||
/// 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");
|
||||
self.clients.try_remove(client as usize)
|
||||
}
|
||||
|
||||
// returns an immutable reference to the client state corresponding to `client`
|
||||
pub fn get(&self, client: ClientHandle) -> Option<&ClientState> {
|
||||
self.clients.get(client as usize)?.as_ref()
|
||||
self.clients.get(client as usize)
|
||||
}
|
||||
|
||||
/// returns a mutable reference to the client state corresponding to `client`
|
||||
pub fn get_mut(&mut self, client: ClientHandle) -> Option<&mut ClientState> {
|
||||
self.clients.get_mut(client as usize)?.as_mut()
|
||||
self.clients.get_mut(client as usize)
|
||||
}
|
||||
|
||||
pub fn get_client_states(&self) -> impl Iterator<Item = &ClientState> {
|
||||
self.clients.iter().filter_map(|x| x.as_ref())
|
||||
pub fn get_client_states(&self) -> impl Iterator<Item = (ClientHandle, &ClientState)> {
|
||||
self.clients.iter().map(|(k, v)| (k as ClientHandle, v))
|
||||
}
|
||||
|
||||
pub fn get_client_states_mut(&mut self) -> impl Iterator<Item = &mut ClientState> {
|
||||
self.clients.iter_mut().filter_map(|x| x.as_mut())
|
||||
pub fn get_client_states_mut(
|
||||
&mut self,
|
||||
) -> impl Iterator<Item = (ClientHandle, &mut ClientState)> {
|
||||
self.clients.iter_mut().map(|(k, v)| (k as ClientHandle, v))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,15 +106,15 @@ pub enum FrontendEvent {
|
||||
/// the given client was activated
|
||||
Activated(ClientHandle, bool),
|
||||
/// a client was created
|
||||
Created(Client),
|
||||
Created(ClientHandle, Client),
|
||||
/// a client was updated
|
||||
Updated(Client),
|
||||
Updated(ClientHandle, Client),
|
||||
/// the client was deleted
|
||||
Deleted(ClientHandle),
|
||||
/// new port, reason of failure (if failed)
|
||||
PortChanged(u16, Option<String>),
|
||||
/// list of all clients, used for initial state synchronization
|
||||
Enumerate(Vec<(Client, bool)>),
|
||||
Enumerate(Vec<(ClientHandle, Client, bool)>),
|
||||
/// an error occured
|
||||
Error(String),
|
||||
}
|
||||
|
||||
@@ -90,15 +90,13 @@ pub fn run() -> Result<()> {
|
||||
log::info!("client {handle} deactivated");
|
||||
}
|
||||
}
|
||||
FrontendEvent::Created(client) => {
|
||||
let handle = client.handle;
|
||||
FrontendEvent::Created(handle, client) => {
|
||||
let port = client.port;
|
||||
let pos = client.pos;
|
||||
let hostname = client.hostname.as_deref().unwrap_or("");
|
||||
log::info!("new client ({handle}): {hostname}:{port} - {pos}");
|
||||
}
|
||||
FrontendEvent::Updated(client) => {
|
||||
let handle = client.handle;
|
||||
FrontendEvent::Updated(handle, client) => {
|
||||
let port = client.port;
|
||||
let pos = client.pos;
|
||||
let hostname = client.hostname.as_deref().unwrap_or("");
|
||||
@@ -111,10 +109,10 @@ pub fn run() -> Result<()> {
|
||||
log::warn!("{e}");
|
||||
}
|
||||
FrontendEvent::Enumerate(clients) => {
|
||||
for (client, active) in clients.into_iter() {
|
||||
for (handle, client, active) in clients.into_iter() {
|
||||
log::info!(
|
||||
"client ({}) [{}]: active: {}, associated addresses: [{}]",
|
||||
client.handle,
|
||||
handle,
|
||||
client.hostname.as_deref().unwrap_or(""),
|
||||
if active { "yes" } else { "no" },
|
||||
client
|
||||
|
||||
@@ -122,11 +122,11 @@ fn build_ui(app: &Application) {
|
||||
FrontendEvent::Activated(handle, active) => {
|
||||
window.activate_client(handle, active);
|
||||
}
|
||||
FrontendEvent::Created(client) => {
|
||||
window.new_client(client, false);
|
||||
FrontendEvent::Created(handle, client) => {
|
||||
window.new_client(handle, client, false);
|
||||
},
|
||||
FrontendEvent::Updated(client) => {
|
||||
window.update_client(client);
|
||||
FrontendEvent::Updated(handle, client) => {
|
||||
window.update_client(handle, client);
|
||||
}
|
||||
FrontendEvent::Error(e) => {
|
||||
window.show_toast(e.as_str());
|
||||
@@ -135,12 +135,12 @@ fn build_ui(app: &Application) {
|
||||
window.delete_client(client);
|
||||
}
|
||||
FrontendEvent::Enumerate(clients) => {
|
||||
for (client, active) in clients {
|
||||
if window.client_idx(client.handle).is_some() {
|
||||
window.activate_client(client.handle, active);
|
||||
window.update_client(client);
|
||||
for (handle, client, active) in clients {
|
||||
if window.client_idx(handle).is_some() {
|
||||
window.activate_client(handle, active);
|
||||
window.update_client(handle, client);
|
||||
} else {
|
||||
window.new_client(client, active);
|
||||
window.new_client(handle, client, active);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -10,9 +10,9 @@ glib::wrapper! {
|
||||
}
|
||||
|
||||
impl ClientObject {
|
||||
pub fn new(client: Client, active: bool) -> Self {
|
||||
pub fn new(handle: ClientHandle, client: Client, active: bool) -> Self {
|
||||
Object::builder()
|
||||
.property("handle", client.handle)
|
||||
.property("handle", handle)
|
||||
.property("hostname", client.hostname)
|
||||
.property("port", client.port as u32)
|
||||
.property("position", client.pos.to_string())
|
||||
|
||||
@@ -87,8 +87,8 @@ impl Window {
|
||||
row
|
||||
}
|
||||
|
||||
pub fn new_client(&self, client: Client, active: bool) {
|
||||
let client = ClientObject::new(client, active);
|
||||
pub fn new_client(&self, handle: ClientHandle, client: Client, active: bool) {
|
||||
let client = ClientObject::new(handle, client, active);
|
||||
self.clients().append(&client);
|
||||
self.set_placeholder_visible(false);
|
||||
}
|
||||
@@ -115,9 +115,9 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_client(&self, client: Client) {
|
||||
let Some(idx) = self.client_idx(client.handle) else {
|
||||
log::warn!("could not find client with handle {}", client.handle);
|
||||
pub fn update_client(&self, handle: ClientHandle, client: Client) {
|
||||
let Some(idx) = self.client_idx(handle) else {
|
||||
log::warn!("could not find client with handle {}", handle);
|
||||
return;
|
||||
};
|
||||
let client_object = self.clients().item(idx as u32).unwrap();
|
||||
|
||||
@@ -134,9 +134,9 @@ impl Server {
|
||||
.client_manager
|
||||
.borrow()
|
||||
.get_client_states()
|
||||
.filter_map(|s| {
|
||||
.filter_map(|(h, s)| {
|
||||
if s.active {
|
||||
Some((s.client.handle, s.client.hostname.clone()))
|
||||
Some((h, s.client.hostname.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -84,8 +84,8 @@ async fn handle_capture_event(
|
||||
pressed_keys: &mut HashSet<scancode::Linux>,
|
||||
release_bind: &[scancode::Linux],
|
||||
) -> Result<()> {
|
||||
let (c, mut e) = event;
|
||||
log::trace!("({c}) {e:?}");
|
||||
let (handle, mut e) = event;
|
||||
log::trace!("({handle}) {e:?}");
|
||||
|
||||
if let Event::Keyboard(KeyboardEvent::Key { key, state, .. }) = e {
|
||||
update_pressed_keys(pressed_keys, key, state);
|
||||
@@ -107,7 +107,7 @@ async fn handle_capture_event(
|
||||
|
||||
// get client state for handle
|
||||
let mut client_manager = server.client_manager.borrow_mut();
|
||||
let client_state = match client_manager.get_mut(c) {
|
||||
let client_state = match client_manager.get_mut(handle) {
|
||||
Some(state) => state,
|
||||
None => {
|
||||
// should not happen
|
||||
@@ -123,10 +123,8 @@ async fn handle_capture_event(
|
||||
// we get a leave event
|
||||
if let Event::Enter() = e {
|
||||
server.state.replace(State::AwaitingLeave);
|
||||
server
|
||||
.active_client
|
||||
.replace(Some(client_state.client.handle));
|
||||
log::trace!("Active client => {}", client_state.client.handle);
|
||||
server.active_client.replace(Some(handle));
|
||||
log::trace!("Active client => {}", handle);
|
||||
start_timer = true;
|
||||
log::trace!("STATE ===> AwaitingLeave");
|
||||
enter = true;
|
||||
|
||||
@@ -65,7 +65,7 @@ pub fn new(
|
||||
.client_manager
|
||||
.borrow()
|
||||
.get_client_states()
|
||||
.map(|s| s.client.handle)
|
||||
.map(|(h, _)| h)
|
||||
.collect::<Vec<_>>();
|
||||
for client in clients {
|
||||
release_keys(&server, &mut emulate, client).await;
|
||||
|
||||
@@ -137,7 +137,7 @@ async fn handle_frontend_event(
|
||||
.client_manager
|
||||
.borrow()
|
||||
.get_client_states()
|
||||
.map(|s| (s.client.clone(), s.active))
|
||||
.map(|(h, s)| (h, s.client.clone(), s.active))
|
||||
.collect();
|
||||
notify_all(frontend, FrontendEvent::Enumerate(clients)).await;
|
||||
}
|
||||
@@ -199,7 +199,7 @@ pub async fn add_client(
|
||||
.unwrap()
|
||||
.client
|
||||
.clone();
|
||||
notify_all(frontend, FrontendEvent::Created(client)).await;
|
||||
notify_all(frontend, FrontendEvent::Created(handle, client)).await;
|
||||
}
|
||||
|
||||
pub async fn deactivate_client(
|
||||
@@ -207,12 +207,12 @@ pub async fn deactivate_client(
|
||||
frontend: &mut FrontendListener,
|
||||
capture: &Sender<CaptureEvent>,
|
||||
emulate: &Sender<EmulationEvent>,
|
||||
client: ClientHandle,
|
||||
handle: ClientHandle,
|
||||
) {
|
||||
let (client, _) = match server.client_manager.borrow_mut().get_mut(client) {
|
||||
let (client, _) = match server.client_manager.borrow_mut().get_mut(handle) {
|
||||
Some(state) => {
|
||||
state.active = false;
|
||||
(state.client.handle, state.client.pos)
|
||||
(handle, state.client.pos)
|
||||
}
|
||||
None => return,
|
||||
};
|
||||
@@ -265,24 +265,24 @@ pub async fn remove_client(
|
||||
frontend: &mut FrontendListener,
|
||||
capture: &Sender<CaptureEvent>,
|
||||
emulate: &Sender<EmulationEvent>,
|
||||
client: ClientHandle,
|
||||
handle: ClientHandle,
|
||||
) {
|
||||
let Some((client, active)) = server
|
||||
let Some(active) = server
|
||||
.client_manager
|
||||
.borrow_mut()
|
||||
.remove_client(client)
|
||||
.map(|s| (s.client.handle, s.active))
|
||||
.remove_client(handle)
|
||||
.map(|s| s.active)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
if active {
|
||||
let destroy = ClientEvent::Destroy(client);
|
||||
let destroy = ClientEvent::Destroy(handle);
|
||||
let _ = capture.send(CaptureEvent::ClientEvent(destroy)).await;
|
||||
let _ = emulate.send(EmulationEvent::ClientEvent(destroy)).await;
|
||||
}
|
||||
|
||||
let event = FrontendEvent::Deleted(client);
|
||||
let event = FrontendEvent::Deleted(handle);
|
||||
notify_all(frontend, event).await;
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ async fn update_client(
|
||||
) {
|
||||
let (handle, hostname, port, pos) = client_update;
|
||||
let mut changed = false;
|
||||
let (hostname, handle, active) = {
|
||||
let (hostname, active) = {
|
||||
// retrieve state
|
||||
let mut client_manager = server.client_manager.borrow_mut();
|
||||
let Some(state) = client_manager.get_mut(handle) else {
|
||||
@@ -325,11 +325,7 @@ async fn update_client(
|
||||
}
|
||||
|
||||
log::debug!("client updated: {:?}", state);
|
||||
(
|
||||
state.client.hostname.clone(),
|
||||
state.client.handle,
|
||||
state.active,
|
||||
)
|
||||
(state.client.hostname.clone(), state.active)
|
||||
};
|
||||
|
||||
// resolve dns if something changed
|
||||
@@ -358,5 +354,5 @@ async fn update_client(
|
||||
.unwrap()
|
||||
.client
|
||||
.clone();
|
||||
notify_all(frontend, FrontendEvent::Updated(client)).await;
|
||||
notify_all(frontend, FrontendEvent::Updated(handle, client)).await;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ pub fn new(
|
||||
// if receiving we care about clients with pressed keys
|
||||
client_manager
|
||||
.get_client_states_mut()
|
||||
.filter(|s| !s.pressed_keys.is_empty())
|
||||
.map(|s| s.client.handle)
|
||||
.filter(|(_, s)| !s.pressed_keys.is_empty())
|
||||
.map(|(h, _)| h)
|
||||
.collect()
|
||||
} else {
|
||||
// if sending we care about the active client
|
||||
@@ -64,7 +64,7 @@ pub fn new(
|
||||
};
|
||||
|
||||
// reset alive
|
||||
for state in client_manager.get_client_states_mut() {
|
||||
for (_, state) in client_manager.get_client_states_mut() {
|
||||
state.alive = false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user