mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-04-02 21:01:27 +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
161
src/frontend.rs
161
src/frontend.rs
@@ -1,20 +1,25 @@
|
||||
use std::io::{Read, Result};
|
||||
use std::net::IpAddr;
|
||||
use std::collections::HashMap;
|
||||
use std::io::{Read, Result, Write};
|
||||
use std::str;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::{env, path::{Path, PathBuf}};
|
||||
|
||||
use mio::Interest;
|
||||
use mio::{Registry, Token, event::Source};
|
||||
|
||||
#[cfg(unix)]
|
||||
use mio::net::UnixStream;
|
||||
#[cfg(unix)]
|
||||
use mio::net::UnixListener;
|
||||
#[cfg(windows)]
|
||||
use mio::net::TcpStream;
|
||||
#[cfg(windows)]
|
||||
use mio::net::TcpListener;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use crate::client::{Client, Position};
|
||||
use crate::client::{Position, ClientHandle, Client};
|
||||
|
||||
/// cli frontend
|
||||
pub mod cli;
|
||||
@@ -25,29 +30,40 @@ pub mod gtk;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub enum FrontendEvent {
|
||||
ChangePort(u16),
|
||||
AddClient(String, u16, Position),
|
||||
DelClient(String, u16),
|
||||
AddIp(String, Option<IpAddr>),
|
||||
/// add a new client
|
||||
AddClient(Option<String>, u16, Position),
|
||||
/// activate/deactivate client
|
||||
ActivateClient(ClientHandle, bool),
|
||||
/// update a client (hostname, port, position)
|
||||
UpdateClient(ClientHandle, Option<String>, u16, Position),
|
||||
/// remove a client
|
||||
DelClient(ClientHandle),
|
||||
/// request an enumertaion of all clients
|
||||
Enumerate(),
|
||||
/// service shutdown
|
||||
Shutdown(),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum FrontendNotify {
|
||||
NotifyClientCreate(Client),
|
||||
NotifyClientCreate(ClientHandle, Option<String>, u16, Position),
|
||||
NotifyClientUpdate(ClientHandle, Option<String>, u16, Position),
|
||||
NotifyClientDelete(ClientHandle),
|
||||
Enumerate(Vec<(Client, bool)>),
|
||||
NotifyError(String),
|
||||
}
|
||||
|
||||
pub struct FrontendAdapter {
|
||||
pub struct FrontendListener {
|
||||
#[cfg(windows)]
|
||||
listener: TcpListener,
|
||||
#[cfg(unix)]
|
||||
listener: UnixListener,
|
||||
#[cfg(unix)]
|
||||
socket_path: PathBuf,
|
||||
frontend_connections: HashMap<Token, FrontendConnection>,
|
||||
}
|
||||
|
||||
impl FrontendAdapter {
|
||||
impl FrontendListener {
|
||||
pub fn new() -> std::result::Result<Self, Box<dyn std::error::Error>> {
|
||||
#[cfg(unix)]
|
||||
let socket_path = Path::new(env::var("XDG_RUNTIME_DIR")?.as_str()).join("lan-mouse-socket.sock");
|
||||
@@ -67,28 +83,57 @@ impl FrontendAdapter {
|
||||
listener,
|
||||
#[cfg(unix)]
|
||||
socket_path,
|
||||
frontend_connections: HashMap::new(),
|
||||
};
|
||||
|
||||
Ok(adapter)
|
||||
}
|
||||
|
||||
pub fn read_event(&mut self) -> Result<FrontendEvent>{
|
||||
#[cfg(unix)]
|
||||
pub fn handle_incoming<F>(&mut self, register_frontend: F) -> Result<()>
|
||||
where F: Fn(&mut UnixStream, Interest) -> Result<Token> {
|
||||
let (mut stream, _) = self.listener.accept()?;
|
||||
let mut buf = [0u8; 128]; // FIXME
|
||||
stream.read(&mut buf)?;
|
||||
let json = str::from_utf8(&buf)
|
||||
.unwrap()
|
||||
.trim_end_matches(char::from(0)); // remove trailing 0-bytes
|
||||
log::debug!("{json}");
|
||||
let event = serde_json::from_str(json).unwrap();
|
||||
log::debug!("{:?}", event);
|
||||
Ok(event)
|
||||
let token = register_frontend(&mut stream, Interest::READABLE)?;
|
||||
let con = FrontendConnection::new(stream);
|
||||
self.frontend_connections.insert(token, con);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn notify(&self, _event: FrontendNotify) { }
|
||||
#[cfg(windows)]
|
||||
pub fn handle_incoming<F>(&mut self, register_frontend: F) -> Result<()>
|
||||
where F: Fn(&mut TcpStream, Interest) -> Result<Token> {
|
||||
let (mut stream, _) = self.listener.accept()?;
|
||||
let token = register_frontend(&mut stream, Interest::READABLE)?;
|
||||
let con = FrontendConnection::new(stream);
|
||||
self.frontend_connections.insert(token, con);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_event(&mut self, token: Token) -> Result<Option<FrontendEvent>> {
|
||||
if let Some(con) = self.frontend_connections.get_mut(&token) {
|
||||
con.handle_event()
|
||||
} else {
|
||||
panic!("unknown token");
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn notify_all(&mut self, notify: FrontendNotify) -> Result<()> {
|
||||
// encode event
|
||||
let json = serde_json::to_string(¬ify).unwrap();
|
||||
let payload = json.as_bytes();
|
||||
let len = payload.len().to_ne_bytes();
|
||||
log::debug!("json: {json}, len: {}", payload.len());
|
||||
|
||||
for con in self.frontend_connections.values_mut() {
|
||||
// write len + payload
|
||||
con.stream.write(&len)?;
|
||||
con.stream.write(payload)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Source for FrontendAdapter {
|
||||
impl Source for FrontendListener {
|
||||
fn register(
|
||||
&mut self,
|
||||
registry: &Registry,
|
||||
@@ -113,9 +158,79 @@ impl Source for FrontendAdapter {
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl Drop for FrontendAdapter {
|
||||
impl Drop for FrontendListener {
|
||||
fn drop(&mut self) {
|
||||
log::debug!("remove socket: {:?}", self.socket_path);
|
||||
let _ = std::fs::remove_file(&self.socket_path);
|
||||
}
|
||||
}
|
||||
|
||||
enum ReceiveState {
|
||||
Len, Data,
|
||||
}
|
||||
|
||||
pub struct FrontendConnection {
|
||||
#[cfg(unix)]
|
||||
stream: UnixStream,
|
||||
#[cfg(windows)]
|
||||
stream: TcpStream,
|
||||
state: ReceiveState,
|
||||
len: usize,
|
||||
len_buf: [u8; std::mem::size_of::<usize>()],
|
||||
recieve_buf: [u8; 256], // FIXME
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl FrontendConnection {
|
||||
#[cfg(unix)]
|
||||
pub fn new(stream: UnixStream) -> Self {
|
||||
Self {
|
||||
stream,
|
||||
state: ReceiveState::Len,
|
||||
len: 0,
|
||||
len_buf: [0u8; std::mem::size_of::<usize>()],
|
||||
recieve_buf: [0u8; 256],
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn new(stream: TcpStream) -> Self {
|
||||
Self {
|
||||
stream,
|
||||
state: ReceiveState::Len,
|
||||
len: 0,
|
||||
len_buf: [0u8; std::mem::size_of::<usize>()],
|
||||
recieve_buf: [0u8; 256],
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_event(&mut self) -> Result<Option<FrontendEvent>> {
|
||||
match self.state {
|
||||
ReceiveState::Len => {
|
||||
// we receive sizeof(usize) Bytes
|
||||
let n = self.stream.read(&mut self.len_buf)?;
|
||||
self.pos += n;
|
||||
if self.pos == self.len_buf.len() {
|
||||
self.state = ReceiveState::Data;
|
||||
self.len = usize::from_ne_bytes(self.len_buf);
|
||||
self.pos = 0;
|
||||
}
|
||||
Ok(None)
|
||||
},
|
||||
ReceiveState::Data => {
|
||||
// read at most as many bytes as the length of the next event
|
||||
let n = self.stream.read(&mut self.recieve_buf[..self.len])?;
|
||||
self.pos += n;
|
||||
if n == self.len {
|
||||
self.state = ReceiveState::Len;
|
||||
self.pos = 0;
|
||||
Ok(Some(serde_json::from_slice(&self.recieve_buf[..self.len])?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user