vendored teslatte + some refactoring

This commit is contained in:
Alex Janka 2023-12-27 12:20:45 +11:00
parent b4a03f5e54
commit f2e0bb6dc5
8 changed files with 136 additions and 23 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/target
/test-config

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "vendored/teslatte"]
path = vendored/teslatte
url = https://github.com/gak/teslatte

55
Cargo.lock generated
View file

@ -571,7 +571,7 @@ dependencies = [
"futures-util",
"http",
"hyper",
"rustls",
"rustls 0.21.10",
"tokio",
"tokio-rustls",
]
@ -1083,7 +1083,7 @@ dependencies = [
"once_cell",
"percent-encoding",
"pin-project-lite",
"rustls",
"rustls 0.21.10",
"rustls-pemfile",
"serde",
"serde_json",
@ -1163,10 +1163,24 @@ checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
dependencies = [
"log",
"ring",
"rustls-webpki",
"rustls-webpki 0.101.7",
"sct",
]
[[package]]
name = "rustls"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe6b63262c9fcac8659abfaa96cac103d28166d3ff3eaf8f412e19f3ae9e5a48"
dependencies = [
"log",
"ring",
"rustls-pki-types",
"rustls-webpki 0.102.0",
"subtle",
"zeroize",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.4"
@ -1176,6 +1190,12 @@ dependencies = [
"base64",
]
[[package]]
name = "rustls-pki-types"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a"
[[package]]
name = "rustls-webpki"
version = "0.101.7"
@ -1186,6 +1206,17 @@ dependencies = [
"untrusted",
]
[[package]]
name = "rustls-webpki"
version = "0.102.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de2635c8bc2b88d367767c5de8ea1d8db9af3f6219eba28442242d9ab81d1b89"
dependencies = [
"ring",
"rustls-pki-types",
"untrusted",
]
[[package]]
name = "rustversion"
version = "1.0.14"
@ -1389,6 +1420,12 @@ dependencies = [
"syn 2.0.43",
]
[[package]]
name = "subtle"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "supports-color"
version = "2.1.0"
@ -1498,8 +1535,6 @@ dependencies = [
[[package]]
name = "teslatte"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caf300415380acad835db51dc04d5f331dfab81aa24e425d7da39af5d17b0830"
dependencies = [
"chrono",
"clap",
@ -1509,7 +1544,7 @@ dependencies = [
"pkce",
"rand",
"reqwest",
"rustls",
"rustls 0.22.1",
"serde",
"serde_json",
"strum",
@ -1652,7 +1687,7 @@ version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [
"rustls",
"rustls 0.21.10",
"tokio",
]
@ -2100,3 +2135,9 @@ name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]]
name = "zeroize"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"

View file

@ -28,5 +28,5 @@ clap = { version = "4.0", features = ["derive"] }
ron = "0.8"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.35.1", features = ["full"] }
teslatte = "0.1.11"
teslatte = { path = "vendored/teslatte" }
thiserror = "1.0"

3
src/control.rs Normal file
View file

@ -0,0 +1,3 @@
use teslatte::OwnerApi;
pub async fn control_loop(_api: OwnerApi) {}

View file

@ -1,18 +1,40 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum SaveError {
#[error("stdio error")]
StdIo(#[from] std::io::Error),
#[error("ron")]
RonSpanned(#[from] ron::Error),
}
impl SaveError {
pub fn error_string(&self) -> String {
match self {
SaveError::StdIo(e) => format!("Error reading access token from disk: {e:?}"),
SaveError::RonSpanned(e) => format!("Error deserialising access token: {e:?}"),
}
}
}
#[derive(Error, Debug)]
pub enum AuthLoadError {
#[error("stdio error")]
StdIo(#[from] std::io::Error),
#[error("ron - spanned error")]
RonSpanned(#[from] ron::error::SpannedError),
#[error("teslatte error")]
Teslatte(#[from] teslatte::error::TeslatteError),
#[error("save error")]
Save(#[from] SaveError),
}
impl AuthLoadError {
pub fn error_string(&self) -> String {
match self {
AuthLoadError::Teslatte(e) => format!("Error refreshing access token: {e:?}"),
AuthLoadError::StdIo(e) => format!("Error reading access token from disk: {e:?}"),
AuthLoadError::RonSpanned(e) => format!("Error deserialising access token: {e:?}"),
AuthLoadError::Save(e) => e.error_string(),
}
}
}
@ -21,18 +43,15 @@ impl AuthLoadError {
pub enum LoginError {
#[error("teslatte error")]
Teslatte(#[from] teslatte::error::TeslatteError),
#[error("ron error")]
Ron(#[from] ron::Error),
#[error("stdio error")]
StdIo(#[from] std::io::Error),
#[error("save error")]
Save(#[from] SaveError),
}
impl LoginError {
pub fn error_string(&self) -> String {
match self {
LoginError::Teslatte(e) => format!("Authentication flow error: {e:?}"),
LoginError::Ron(e) => format!("Error serialising access token: {e:?}"),
LoginError::StdIo(e) => format!("Error saving access token to disk: {e:?}"),
LoginError::Save(e) => e.error_string(),
}
}
}

View file

@ -1,10 +1,15 @@
use clap::{Parser, Subcommand};
use serde::{Deserialize, Serialize};
use std::{io::BufRead, path::PathBuf};
use teslatte::{auth::AccessToken, OwnerApi};
use teslatte::{
auth::{AccessToken, RefreshToken},
OwnerApi, VehicleApi,
};
use crate::{config::Config, errors::*};
mod config;
mod control;
mod errors;
#[derive(Parser, Debug, Clone)]
@ -19,7 +24,10 @@ struct Args {
#[derive(Subcommand, Debug, Clone)]
enum Commands {
/// Run charge controller server
Watch,
Watch {
#[clap(long)]
flash: bool,
},
/// Authenticate with Tesla login
Auth,
/// Print the default config file
@ -43,7 +51,7 @@ fn press_y_to_continue() -> bool {
async fn main() {
let args = Args::parse();
let auth_path = args.config_dir.join("auth");
let config_path = args.config_dir.join("config");
// let config_path = args.config_dir.join("config");
match args.command {
Commands::GenerateConfig => {
@ -63,24 +71,61 @@ async fn main() {
println!("{}", e.error_string());
}
}
Commands::Watch => match get_auth(auth_path) {
Commands::Watch { flash } => match get_auth(auth_path).await {
Ok(api) => {
println!("got products: {:#?}", api.products().await)
let products = api.products().await;
println!("got products: {:#?}", products);
if flash {
if let Ok(res) = products {
if let Some(teslatte::products::Product::Vehicle(vehicle)) = res.first() {
let _ = api.honk_horn(&vehicle.id).await;
match api.flash_lights(&vehicle.id).await {
Ok(_r) => println!("flashed"),
Err(e) => println!("error: {e:#?}"),
}
}
}
}
control::control_loop(api).await;
}
Err(e) => println!("{}", e.error_string()),
},
}
}
fn get_auth(auth_path: PathBuf) -> Result<OwnerApi, AuthLoadError> {
let key: AccessToken = ron::from_str(&std::fs::read_to_string(auth_path)?)?;
Ok(OwnerApi::new(key, None))
async fn get_auth(auth_path: PathBuf) -> Result<OwnerApi, AuthLoadError> {
let key: AuthInfo = ron::from_str(&std::fs::read_to_string(&auth_path)?)?;
let mut api = OwnerApi::new(key.access_token, key.refresh_token);
api.refresh().await?;
println!("Refreshed auth key");
save_key(auth_path, &api)?;
Ok(api)
}
#[derive(Serialize, Deserialize)]
struct AuthInfo {
access_token: AccessToken,
refresh_token: Option<RefreshToken>,
}
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)?)?;
let products = v.products().await;
println!("got products: {:#?}", products);
save_key(auth_path, &v)?;
Ok(())
}
fn save_key(auth_path: PathBuf, api: &OwnerApi) -> Result<(), SaveError> {
std::fs::write(
auth_path,
ron::ser::to_string(&AuthInfo {
access_token: api.access_token.clone(),
refresh_token: api.refresh_token.clone(),
})?,
)?;
println!("Auth successfully saved");
Ok(())
}

1
vendored/teslatte Submodule

@ -0,0 +1 @@
Subproject commit 491d9a58a8183b91314990274da805c156a6f48c