2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
use dirs::home_dir;
|
2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
use log::{debug, error, info};
|
2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
use serde::{Deserialize, Serialize};
|
2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
use std::fs;
|
2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
use std::path::PathBuf;
|
|
|
|
|
2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
pub struct KhmSettings {
|
|
|
|
pub host: String,
|
|
|
|
pub flow: String,
|
|
|
|
pub known_hosts: String,
|
|
|
|
pub basic_auth: String,
|
|
|
|
pub in_place: bool,
|
|
|
|
pub auto_sync_interval_minutes: u32,
|
|
|
|
}
|
|
|
|
|
2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
impl Default for KhmSettings {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
host: String::new(),
|
|
|
|
flow: String::new(),
|
|
|
|
known_hosts: get_default_known_hosts_path(),
|
|
|
|
basic_auth: String::new(),
|
|
|
|
in_place: true,
|
|
|
|
auto_sync_interval_minutes: 60,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get default known_hosts file path based on OS
|
2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
fn get_default_known_hosts_path() -> String {
|
2025-07-23 23:53:46 +03:00
|
|
|
if let Some(home) = home_dir() {
|
|
|
|
let ssh_dir = home.join(".ssh");
|
|
|
|
let known_hosts_file = ssh_dir.join("known_hosts");
|
|
|
|
known_hosts_file.to_string_lossy().to_string()
|
|
|
|
} else {
|
2025-07-22 18:06:48 +03:00
|
|
|
"~/.ssh/known_hosts".to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get configuration file path
|
2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
pub fn get_config_path() -> PathBuf {
|
|
|
|
let mut path = home_dir().expect("Could not find home directory");
|
|
|
|
path.push(".khm");
|
|
|
|
fs::create_dir_all(&path).ok();
|
|
|
|
path.push("khm_config.json");
|
|
|
|
path
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Load settings from configuration file
|
2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
pub fn load_settings() -> KhmSettings {
|
|
|
|
let path = get_config_path();
|
|
|
|
match fs::read_to_string(&path) {
|
|
|
|
Ok(contents) => {
|
|
|
|
let mut settings: KhmSettings = serde_json::from_str(&contents).unwrap_or_else(|e| {
|
|
|
|
error!("Failed to parse KHM config: {}", e);
|
|
|
|
KhmSettings::default()
|
|
|
|
});
|
2025-07-23 23:53:46 +03:00
|
|
|
|
2025-07-22 18:06:48 +03:00
|
|
|
// Fill in default known_hosts path if empty
|
|
|
|
if settings.known_hosts.is_empty() {
|
|
|
|
settings.known_hosts = get_default_known_hosts_path();
|
|
|
|
}
|
2025-07-23 23:53:46 +03:00
|
|
|
|
2025-07-22 18:06:48 +03:00
|
|
|
settings
|
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
debug!("KHM config file not found, using defaults");
|
|
|
|
KhmSettings::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Save settings to configuration file
|
2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
pub fn save_settings(settings: &KhmSettings) -> Result<(), std::io::Error> {
|
|
|
|
let path = get_config_path();
|
|
|
|
let json = serde_json::to_string_pretty(settings)?;
|
|
|
|
fs::write(&path, json)?;
|
|
|
|
info!("KHM settings saved");
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Expand path with ~ substitution
|
2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
pub fn expand_path(path: &str) -> String {
|
|
|
|
if path.starts_with("~/") {
|
|
|
|
if let Some(home) = home_dir() {
|
|
|
|
return home.join(&path[2..]).to_string_lossy().to_string();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path.to_string()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Perform sync operation using KHM client logic
|
2025-07-24 00:35:13 +03:00
|
|
|
#[cfg(feature = "gui")]
|
2025-07-22 18:06:48 +03:00
|
|
|
pub async fn perform_sync(settings: &KhmSettings) -> Result<usize, std::io::Error> {
|
|
|
|
use crate::Args;
|
2025-07-23 23:53:46 +03:00
|
|
|
|
|
|
|
info!(
|
|
|
|
"Starting sync with settings: host={}, flow={}, known_hosts={}, in_place={}",
|
|
|
|
settings.host, settings.flow, settings.known_hosts, settings.in_place
|
|
|
|
);
|
|
|
|
|
2025-07-22 18:06:48 +03:00
|
|
|
// Convert KhmSettings to Args for client module
|
|
|
|
let args = Args {
|
|
|
|
server: false,
|
2025-07-24 02:36:21 +03:00
|
|
|
daemon: false,
|
2025-07-22 18:06:48 +03:00
|
|
|
settings_ui: false,
|
|
|
|
in_place: settings.in_place,
|
|
|
|
flows: vec!["default".to_string()], // Not used in client mode
|
2025-07-23 23:53:46 +03:00
|
|
|
ip: "127.0.0.1".to_string(), // Not used in client mode
|
|
|
|
port: 8080, // Not used in client mode
|
|
|
|
db_host: "127.0.0.1".to_string(), // Not used in client mode
|
|
|
|
db_name: "khm".to_string(), // Not used in client mode
|
|
|
|
db_user: None, // Not used in client mode
|
|
|
|
db_password: None, // Not used in client mode
|
2025-07-22 18:06:48 +03:00
|
|
|
host: Some(settings.host.clone()),
|
|
|
|
flow: Some(settings.flow.clone()),
|
|
|
|
known_hosts: expand_path(&settings.known_hosts),
|
|
|
|
basic_auth: settings.basic_auth.clone(),
|
|
|
|
};
|
2025-07-23 23:53:46 +03:00
|
|
|
|
2025-07-22 18:06:48 +03:00
|
|
|
info!("Expanded known_hosts path: {}", args.known_hosts);
|
2025-07-23 23:53:46 +03:00
|
|
|
|
2025-07-22 18:06:48 +03:00
|
|
|
// Get keys count before and after sync
|
|
|
|
let keys_before = crate::client::read_known_hosts(&args.known_hosts)
|
|
|
|
.unwrap_or_else(|_| Vec::new())
|
|
|
|
.len();
|
2025-07-23 23:53:46 +03:00
|
|
|
|
2025-07-22 18:06:48 +03:00
|
|
|
crate::client::run_client(args.clone()).await?;
|
2025-07-23 23:53:46 +03:00
|
|
|
|
2025-07-22 18:06:48 +03:00
|
|
|
let keys_after = if args.in_place {
|
|
|
|
crate::client::read_known_hosts(&args.known_hosts)
|
|
|
|
.unwrap_or_else(|_| Vec::new())
|
|
|
|
.len()
|
|
|
|
} else {
|
|
|
|
keys_before
|
|
|
|
};
|
2025-07-23 23:53:46 +03:00
|
|
|
|
|
|
|
info!(
|
|
|
|
"Sync completed: {} keys before, {} keys after",
|
|
|
|
keys_before, keys_after
|
|
|
|
);
|
2025-07-22 18:06:48 +03:00
|
|
|
Ok(keys_after)
|
|
|
|
}
|