use clap::Parser; use log::{debug, error, warn}; use reqwest::blocking::Client; use serde::{Deserialize, Serialize}; use std::process::Command; fn main() -> Result<(), Box> { let args = CliArgs::parse(); if args.debug { let _ = simplelog::SimpleLogger::init( simplelog::LevelFilter::Debug, simplelog::Config::default(), ); } else { let _ = simplelog::SimpleLogger::init( simplelog::LevelFilter::Info, simplelog::Config::default(), ); } debug!("Opening Config file: {}", args.config_file); debug!( "Config file exists: {}", std::fs::metadata(args.config_file.clone()).is_ok() ); let file_contents = match std::fs::read_to_string(args.config_file) { Ok(val) => val, Err(e) => { error!("Could not read config file: {}", e.to_string()); panic!("{}", e); } }; let cfg: Config = match toml::from_str(file_contents.as_str()) { Ok(val) => val, Err(e) => { error!("Could not parse config file: {}", e.to_string()); panic!("{}", e); } }; let mut body_content: String = format!( "*Last Updated:* {} \n", chrono::Local::now().format("%D - %H:%M:%S") ); let mut drives: Vec = vec![]; match std::fs::read_dir("/dev/") { Ok(paths) => { for path in paths.flatten() { let tmp = path.path().to_string_lossy().to_string(); if tmp.starts_with("/dev/sd") && tmp.len() == 8 { drives.push(tmp); } } } Err(e) => { error!("Error opening /dev/: {}", e.to_string()); panic!("{}", e); } }; { let mut drive_temps: Vec = vec![]; for drive in drives { let output = match Command::new(args.hddtemp_executable.clone()) .arg(drive.clone()) .output() { Ok(val) => String::from_utf8_lossy(&val.stdout).into_owned(), Err(e) => { warn!("Error running hddtemp: {}", e.to_string()); warn!("Drive was: '{}'", drive); "".to_string() } }; if !output.contains("sensor") { drive_temps.push(output.replace('\n', "?")); } else { drive_temps.push(output[0..9].to_string() + " No Sensor"); } } body_content.push_str("## Hard Drive Temps\n"); body_content.push_str(drive_temps.join("\n").as_str()); } Client::new() .put(format!( "https://{}/index.php/apps/notes/api/v1/notes/{}", cfg.server_url.clone(), cfg.note_id.clone() )) .header("Accept", "application/json") .header("Content-Type", "application/json") .basic_auth(cfg.user.clone(), Some(cfg.pswd.clone())) .body( serde_json::to_string(&NoteUpdate { content: body_content, }) .unwrap(), ) .send()?; Ok(()) } #[derive(Serialize, Deserialize, Debug)] struct Note { id: usize, etag: String, readonly: bool, modified: u64, title: String, category: String, content: String, favorite: bool, } #[derive(Serialize, Deserialize, Debug)] struct NoteUpdate { content: String, } #[derive(Serialize, Deserialize)] struct Config { user: String, pswd: String, note_id: String, server_url: String, } impl Default for Config { fn default() -> Self { Self { user: "".to_string(), pswd: "".to_string(), note_id: "".to_string(), server_url: "".to_string(), } } } #[derive(Parser, Debug)] #[command(author, version, about, long_about=None)] struct CliArgs { /// Path to config .toml file #[arg(short, long)] config_file: String, #[arg(short, long)] hddtemp_executable: String, #[arg(short, long)] debug: bool, }