mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-03-07 11:59:59 +03:00
Save config (#345)
* add setters for clients and authorized keys * impl change config request * basic saving functionality * save config automatically * add TODO comment
This commit is contained in:
committed by
GitHub
parent
a987f93133
commit
648b2b58a4
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1872,6 +1872,7 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"toml",
|
"toml",
|
||||||
|
"toml_edit",
|
||||||
"webrtc-dtls",
|
"webrtc-dtls",
|
||||||
"webrtc-util",
|
"webrtc-util",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ shadow-rs = { version = "1.2.0", features = ["metadata"] }
|
|||||||
|
|
||||||
hickory-resolver = "0.25.2"
|
hickory-resolver = "0.25.2"
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
|
toml_edit = { version = "0.22", features = ["serde"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
log = "0.4.20"
|
log = "0.4.20"
|
||||||
env_logger = "0.11.3"
|
env_logger = "0.11.3"
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ enum CliSubcommand {
|
|||||||
},
|
},
|
||||||
/// deauthorize a public key
|
/// deauthorize a public key
|
||||||
RemoveAuthorizedKey { sha256_fingerprint: String },
|
RemoveAuthorizedKey { sha256_fingerprint: String },
|
||||||
|
/// save configuration to file
|
||||||
|
SaveConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(args: CliArgs) -> Result<(), CliError> {
|
pub async fn run(args: CliArgs) -> Result<(), CliError> {
|
||||||
@@ -162,6 +164,7 @@ async fn execute(cmd: CliSubcommand) -> Result<(), CliError> {
|
|||||||
tx.request(FrontendRequest::RemoveAuthorizedKey(sha256_fingerprint))
|
tx.request(FrontendRequest::RemoveAuthorizedKey(sha256_fingerprint))
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
CliSubcommand::SaveConfig => tx.request(FrontendRequest::SaveConfiguration).await?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,6 +253,8 @@ pub enum FrontendRequest {
|
|||||||
RemoveAuthorizedKey(String),
|
RemoveAuthorizedKey(String),
|
||||||
/// change the hook command
|
/// change the hook command
|
||||||
UpdateEnterHook(u64, Option<String>),
|
UpdateEnterHook(u64, Option<String>),
|
||||||
|
/// save config file
|
||||||
|
SaveConfiguration,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -15,6 +15,15 @@ pub struct ClientManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ClientManager {
|
impl ClientManager {
|
||||||
|
/// get all clients
|
||||||
|
pub fn clients(&self) -> Vec<(ClientConfig, ClientState)> {
|
||||||
|
self.clients
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.map(|(_, c)| c.clone())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
/// add a new client to this manager
|
/// add a new client to this manager
|
||||||
pub fn add_client(&self) -> ClientHandle {
|
pub fn add_client(&self) -> ClientHandle {
|
||||||
self.clients.borrow_mut().insert(Default::default()) as ClientHandle
|
self.clients.borrow_mut().insert(Default::default()) as ClientHandle
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::{collections::HashSet, io};
|
use std::{collections::HashSet, io};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use toml;
|
use toml;
|
||||||
|
use toml_edit::{self, DocumentMut};
|
||||||
|
|
||||||
use lan_mouse_cli::CliArgs;
|
use lan_mouse_cli::CliArgs;
|
||||||
use lan_mouse_ipc::{DEFAULT_PORT, Position};
|
use lan_mouse_ipc::{DEFAULT_PORT, Position};
|
||||||
@@ -44,7 +45,7 @@ fn default_path() -> Result<PathBuf, VarError> {
|
|||||||
Ok(PathBuf::from(default_path))
|
Ok(PathBuf::from(default_path))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
struct ConfigToml {
|
struct ConfigToml {
|
||||||
capture_backend: Option<CaptureBackend>,
|
capture_backend: Option<CaptureBackend>,
|
||||||
emulation_backend: Option<EmulationBackend>,
|
emulation_backend: Option<EmulationBackend>,
|
||||||
@@ -274,6 +275,33 @@ impl From<TomlClient> for ConfigClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ConfigClient> for TomlClient {
|
||||||
|
fn from(client: ConfigClient) -> Self {
|
||||||
|
let hostname = client.hostname;
|
||||||
|
let host_name = None;
|
||||||
|
let mut ips = client.ips.into_iter().collect::<Vec<_>>();
|
||||||
|
ips.sort();
|
||||||
|
let ips = Some(ips);
|
||||||
|
let port = if client.port == DEFAULT_PORT {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(client.port)
|
||||||
|
};
|
||||||
|
let position = Some(client.pos);
|
||||||
|
let activate_on_startup = if client.active { Some(true) } else { None };
|
||||||
|
let enter_hook = client.enter_hook;
|
||||||
|
Self {
|
||||||
|
hostname,
|
||||||
|
host_name,
|
||||||
|
ips,
|
||||||
|
port,
|
||||||
|
position,
|
||||||
|
activate_on_startup,
|
||||||
|
enter_hook,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ConfigError {
|
pub enum ConfigError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
@@ -384,4 +412,57 @@ impl Config {
|
|||||||
.and_then(|c| c.release_bind.clone())
|
.and_then(|c| c.release_bind.clone())
|
||||||
.unwrap_or(Vec::from_iter(DEFAULT_RELEASE_KEYS.iter().cloned()))
|
.unwrap_or(Vec::from_iter(DEFAULT_RELEASE_KEYS.iter().cloned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// set configured clients
|
||||||
|
pub fn set_clients(&mut self, clients: Vec<ConfigClient>) {
|
||||||
|
if clients.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.config_toml.is_none() {
|
||||||
|
self.config_toml = Default::default();
|
||||||
|
}
|
||||||
|
self.config_toml.as_mut().expect("config").clients =
|
||||||
|
Some(clients.into_iter().map(|c| c.into()).collect::<Vec<_>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// set authorized keys
|
||||||
|
pub fn set_authorized_keys(&mut self, fingerprints: HashMap<String, String>) {
|
||||||
|
if fingerprints.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.config_toml.is_none() {
|
||||||
|
self.config_toml = Default::default();
|
||||||
|
}
|
||||||
|
self.config_toml
|
||||||
|
.as_mut()
|
||||||
|
.expect("config")
|
||||||
|
.authorized_fingerprints = Some(fingerprints);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_back(&self) -> Result<(), io::Error> {
|
||||||
|
log::info!("writing config to {:?}", &self.config_path);
|
||||||
|
/* load the current configuration file */
|
||||||
|
let current_config = fs::read_to_string(&self.config_path)?;
|
||||||
|
let current_config = current_config.parse::<DocumentMut>().expect("fix me");
|
||||||
|
let _current_config =
|
||||||
|
toml_edit::de::from_document::<ConfigToml>(current_config).expect("fixme");
|
||||||
|
|
||||||
|
/* the new config */
|
||||||
|
let new_config = self.config_toml.clone().unwrap_or_default();
|
||||||
|
// let new_config = toml_edit::ser::to_document::<ConfigToml>(&new_config).expect("fixme");
|
||||||
|
let new_config = toml_edit::ser::to_string_pretty(&new_config).expect("config");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO merge documents => eventually we might want to split this up into clients configured
|
||||||
|
* via the config file and clients managed through the GUI / frontend.
|
||||||
|
* The latter should be saved to $XDG_DATA_HOME instead of $XDG_CONFIG_HOME,
|
||||||
|
* and clients configured through .config could be made permanent.
|
||||||
|
* For now we just override the config file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* write new config to file */
|
||||||
|
fs::write(&self.config_path, new_config)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
capture::{Capture, CaptureType, ICaptureEvent},
|
capture::{Capture, CaptureType, ICaptureEvent},
|
||||||
client::ClientManager,
|
client::ClientManager,
|
||||||
config::Config,
|
config::{Config, ConfigClient},
|
||||||
connect::LanMouseConnection,
|
connect::LanMouseConnection,
|
||||||
crypto,
|
crypto,
|
||||||
dns::{DnsEvent, DnsResolver},
|
dns::{DnsEvent, DnsResolver},
|
||||||
@@ -39,6 +39,8 @@ pub enum ServiceError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Service {
|
pub struct Service {
|
||||||
|
/// configuration
|
||||||
|
config: Config,
|
||||||
/// input capture
|
/// input capture
|
||||||
capture: Capture,
|
capture: Capture,
|
||||||
/// input emulation
|
/// input emulation
|
||||||
@@ -122,6 +124,7 @@ impl Service {
|
|||||||
|
|
||||||
let port = config.port();
|
let port = config.port();
|
||||||
let service = Self {
|
let service = Self {
|
||||||
|
config,
|
||||||
capture,
|
capture,
|
||||||
emulation,
|
emulation,
|
||||||
frontend_listener,
|
frontend_listener,
|
||||||
@@ -182,24 +185,73 @@ impl Service {
|
|||||||
Err(e) => return log::error!("error receiving request: {e}"),
|
Err(e) => return log::error!("error receiving request: {e}"),
|
||||||
};
|
};
|
||||||
match request {
|
match request {
|
||||||
FrontendRequest::Activate(handle, active) => self.set_client_active(handle, active),
|
FrontendRequest::Activate(handle, active) => {
|
||||||
FrontendRequest::AuthorizeKey(desc, fp) => self.add_authorized_key(desc, fp),
|
self.set_client_active(handle, active);
|
||||||
|
self.save_config();
|
||||||
|
}
|
||||||
|
FrontendRequest::AuthorizeKey(desc, fp) => {
|
||||||
|
self.add_authorized_key(desc, fp);
|
||||||
|
self.save_config();
|
||||||
|
}
|
||||||
FrontendRequest::ChangePort(port) => self.change_port(port),
|
FrontendRequest::ChangePort(port) => self.change_port(port),
|
||||||
FrontendRequest::Create => self.add_client(),
|
FrontendRequest::Create => {
|
||||||
FrontendRequest::Delete(handle) => self.remove_client(handle),
|
self.add_client();
|
||||||
|
self.save_config();
|
||||||
|
}
|
||||||
|
FrontendRequest::Delete(handle) => {
|
||||||
|
self.remove_client(handle);
|
||||||
|
self.save_config();
|
||||||
|
}
|
||||||
FrontendRequest::EnableCapture => self.capture.reenable(),
|
FrontendRequest::EnableCapture => self.capture.reenable(),
|
||||||
FrontendRequest::EnableEmulation => self.emulation.reenable(),
|
FrontendRequest::EnableEmulation => self.emulation.reenable(),
|
||||||
FrontendRequest::Enumerate() => self.enumerate(),
|
FrontendRequest::Enumerate() => self.enumerate(),
|
||||||
FrontendRequest::UpdateFixIps(handle, fix_ips) => self.update_fix_ips(handle, fix_ips),
|
FrontendRequest::UpdateFixIps(handle, fix_ips) => {
|
||||||
FrontendRequest::UpdateHostname(handle, host) => self.update_hostname(handle, host),
|
self.update_fix_ips(handle, fix_ips);
|
||||||
FrontendRequest::UpdatePort(handle, port) => self.update_port(handle, port),
|
self.save_config();
|
||||||
FrontendRequest::UpdatePosition(handle, pos) => self.update_pos(handle, pos),
|
}
|
||||||
|
FrontendRequest::UpdateHostname(handle, host) => {
|
||||||
|
self.update_hostname(handle, host);
|
||||||
|
self.save_config();
|
||||||
|
}
|
||||||
|
FrontendRequest::UpdatePort(handle, port) => {
|
||||||
|
self.update_port(handle, port);
|
||||||
|
self.save_config();
|
||||||
|
}
|
||||||
|
FrontendRequest::UpdatePosition(handle, pos) => {
|
||||||
|
self.update_pos(handle, pos);
|
||||||
|
self.save_config();
|
||||||
|
}
|
||||||
FrontendRequest::ResolveDns(handle) => self.resolve(handle),
|
FrontendRequest::ResolveDns(handle) => self.resolve(handle),
|
||||||
FrontendRequest::Sync => self.sync_frontend(),
|
FrontendRequest::Sync => self.sync_frontend(),
|
||||||
FrontendRequest::RemoveAuthorizedKey(key) => self.remove_authorized_key(key),
|
FrontendRequest::RemoveAuthorizedKey(key) => {
|
||||||
|
self.remove_authorized_key(key);
|
||||||
|
self.save_config();
|
||||||
|
}
|
||||||
FrontendRequest::UpdateEnterHook(handle, enter_hook) => {
|
FrontendRequest::UpdateEnterHook(handle, enter_hook) => {
|
||||||
self.update_enter_hook(handle, enter_hook)
|
self.update_enter_hook(handle, enter_hook)
|
||||||
}
|
}
|
||||||
|
FrontendRequest::SaveConfiguration => self.save_config(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_config(&mut self) {
|
||||||
|
let clients = self.client_manager.clients();
|
||||||
|
let clients = clients
|
||||||
|
.into_iter()
|
||||||
|
.map(|(c, s)| ConfigClient {
|
||||||
|
ips: HashSet::from_iter(c.fix_ips),
|
||||||
|
hostname: c.hostname,
|
||||||
|
port: c.port,
|
||||||
|
pos: c.pos,
|
||||||
|
active: s.active,
|
||||||
|
enter_hook: c.cmd,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
self.config.set_clients(clients);
|
||||||
|
let authorized_keys = self.authorized_keys.read().expect("lock").clone();
|
||||||
|
self.config.set_authorized_keys(authorized_keys);
|
||||||
|
if let Err(e) = self.config.write_back() {
|
||||||
|
log::warn!("failed to write config: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user