use clap::{Parser, Subcommand}; use std::{io::BufRead, path::PathBuf}; use teslatte::{auth::AccessToken, OwnerApi}; use crate::{config::Config, errors::*}; mod config; mod errors; #[derive(Parser, Debug, Clone)] #[clap(author, version, about, long_about = None)] struct Args { #[command(subcommand)] command: Commands, #[clap(long, default_value = "/etc/tesla-charge-controller")] config_dir: PathBuf, } #[derive(Subcommand, Debug, Clone)] enum Commands { /// Run charge controller server Watch, /// Authenticate with Tesla login Auth, /// Print the default config file GenerateConfig, } fn press_y_to_continue() -> bool { println!("Continue? [y/N]"); let mut line = String::new(); let stdin = std::io::stdin(); stdin.lock().read_line(&mut line).unwrap(); if line.to_uppercase() == "Y\n" { true } else { println!("Exiting now!"); false } } #[tokio::main] async fn main() { let args = Args::parse(); let auth_path = args.config_dir.join("auth"); let config_path = args.config_dir.join("config"); match args.command { Commands::GenerateConfig => { println!( "{}", ron::ser::to_string_pretty(&Config::default(), Default::default()).unwrap() ); } Commands::Auth => { if auth_path.exists() { println!("Auth file already exists"); if !press_y_to_continue() { return; } } if let Err(e) = log_in(auth_path).await { println!("{}", e.error_string()); } } Commands::Watch => match get_auth(auth_path) { Ok(api) => { println!("got products: {:#?}", api.products().await) } Err(e) => println!("{}", e.error_string()), }, } } fn get_auth(auth_path: PathBuf) -> Result { let key: AccessToken = ron::from_str(&std::fs::read_to_string(auth_path)?)?; Ok(OwnerApi::new(key, None)) } async fn log_in(auth_path: PathBuf) -> Result<(), LoginError> { let v = OwnerApi::from_interactive_url().await?; std::fs::write(auth_path, ron::ser::to_string(&v.access_token)?)?; println!("Auth successfully saved"); Ok(()) }