use std::fs; use std::sync::mpsc::{Receiver, RecvError, TryRecvError}; use log::{error, info, warn}; use url::Url; use dnapi_rs::client_blocking::Client; use crate::config::{load_cdata, save_cdata, TFClientConfig}; use crate::daemon::ThreadMessageSender; use crate::dirs::get_nebulaconfig_file; use crate::nebulaworker::NebulaWorkerMessage; pub enum APIWorkerMessage { Shutdown, Enroll { code: String }, Update, Timer } pub fn apiworker_main(_config: TFClientConfig, instance: String, url: String, tx: ThreadMessageSender, rx: Receiver) { let server = Url::parse(&url).unwrap(); let client = Client::new(format!("tfclient/{}", env!("CARGO_PKG_VERSION")), server).unwrap(); loop { match rx.recv() { Ok(msg) => { match msg { APIWorkerMessage::Shutdown => { info!("recv on command socket: shutdown, stopping"); break; }, APIWorkerMessage::Timer | APIWorkerMessage::Update => { info!("updating config"); let mut cdata = match load_cdata(&instance) { Ok(c) => c, Err(e) => { error!("error in api worker thread: {}", e); error!("APIWorker exiting with error"); return; } }; if cdata.creds.is_none() { info!("not enrolled, cannot perform config update"); match save_cdata(&instance, cdata) { Ok(_) => (), Err(e) => { error!("Error saving cdata: {}", e); error!("APIWorker exiting with error"); return; } } continue; } let creds = cdata.clone().creds.unwrap_or_else(|| unreachable!()); info!("checking for update"); let update_available = match client.check_for_update(&creds) { Ok(ua) => ua, Err(e) => { error!("error checking for config update: {}", e); match save_cdata(&instance, cdata) { Ok(_) => (), Err(e) => { error!("Error saving cdata: {}", e); error!("APIWorker exiting with error"); return; } } continue; } }; if !update_available { match save_cdata(&instance, cdata) { Ok(_) => (), Err(e) => { error!("Error saving cdata: {}", e); error!("APIWorker exiting with error"); return; } } info!("no config update available"); continue; } info!("updated configuration is avaliable"); info!("updating configuration"); let (config, dh_privkey, creds) = match client.do_update(&creds) { Ok(d) => d, Err(e) => { error!("error requesting updating config: {}", e); match save_cdata(&instance, cdata) { Ok(_) => (), Err(e) => { error!("Error saving cdata: {}", e); error!("APIWorker exiting with error"); return; } } continue; } }; cdata.creds = Some(creds); cdata.dh_privkey = Some(dh_privkey.try_into().expect("32 != 32")); match fs::write(get_nebulaconfig_file(&instance).expect("Unable to determine nebula config file location"), config) { Ok(_) => (), Err(e) => { error!("unable to save nebula config: {}", e); match save_cdata(&instance, cdata) { Ok(_) => (), Err(e) => { error!("Error saving cdata: {}", e); error!("APIWorker exiting with error"); return; } } continue; } } match save_cdata(&instance, cdata) { Ok(_) => (), Err(e) => { error!("Error saving cdata: {}", e); error!("APIWorker exiting with error"); return; } } info!("configuration updated successfully!"); info!("sending signal to nebula thread to reload config"); match tx.nebula_thread.send(NebulaWorkerMessage::ConfigUpdated) { Ok(_) => (), Err(e) => { error!("unable to tell nebula thread to update config: {}", e); error!("APIWorker exiting with error"); return; } } }, APIWorkerMessage::Enroll { code } => { info!("recv on command socket: enroll {}", code); let mut cdata = match load_cdata(&instance) { Ok(c) => c, Err(e) => { error!("error in api worker thread: {}", e); error!("APIWorker exiting with error"); return; } }; if cdata.creds.is_some() { warn!("enrollment failed: already enrolled"); continue; } let (config, dh_privkey, creds, meta) = match client.enroll(&code) { Ok(resp) => resp, Err(e) => { error!("error with enrollment request: {}", e); continue; } }; match fs::write(get_nebulaconfig_file(&instance).expect("Unable to determine nebula config file location"), config) { Ok(_) => (), Err(e) => { error!("unable to save nebula config: {}", e); continue; } } cdata.creds = Some(creds); cdata.dh_privkey = Some(dh_privkey.try_into().expect("32 != 32")); cdata.meta = Some(meta); // Save vardata match save_cdata(&instance, cdata) { Ok(_) => (), Err(e) => { error!("Error saving cdata: {}", e); error!("APIWorker exiting with error"); return; } } info!("Configuration updated. Sending signal to Nebula worker thread"); match tx.nebula_thread.send(NebulaWorkerMessage::ConfigUpdated) { Ok(_) => (), Err(e) => { error!("unable to tell nebula thread to update config: {}", e); error!("APIWorker exiting with error"); return; } } } } }, Err(e) => { error!("error on command socket: {}", e); return; } } } }