refresh token infrastructure
This commit is contained in:
parent
dc81a3cf6e
commit
be5b787be5
|
@ -1,3 +1,5 @@
|
|||
#![feature(async_closure)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
|
||||
|
@ -5,7 +7,10 @@ use anyhow::Result;
|
|||
use clap::{Parser, Subcommand};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use std::{
|
||||
path::PathBuf,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use teslatte::{
|
||||
auth::{AccessToken, RefreshToken},
|
||||
FleetApi,
|
||||
|
@ -49,16 +54,16 @@ async fn main() {
|
|||
);
|
||||
}
|
||||
Commands::Watch => match get_auth(auth_path).await {
|
||||
Ok(api) => {
|
||||
Ok(auth) => {
|
||||
let config: Config =
|
||||
ron::from_str(&std::fs::read_to_string(&config_path).unwrap()).unwrap();
|
||||
let products = api.products().await;
|
||||
let products = auth.api().products().await;
|
||||
match products {
|
||||
Ok(res) => match res.first() {
|
||||
Some(teslatte::products::Product::Vehicle(vehicle)) => {
|
||||
server::launch_server(server::ServerState {
|
||||
config,
|
||||
api,
|
||||
auth,
|
||||
vehicle: vehicle.clone(),
|
||||
})
|
||||
.await;
|
||||
|
@ -88,23 +93,61 @@ impl Coords {
|
|||
}
|
||||
}
|
||||
|
||||
async fn get_auth(auth_path: PathBuf) -> Result<FleetApi, AuthLoadError> {
|
||||
async fn get_auth(auth_path: PathBuf) -> Result<FleetApiAuth, AuthLoadError> {
|
||||
let key: AuthInfo = ron::from_str(&std::fs::read_to_string(&auth_path)?)?;
|
||||
let mut api = FleetApi::new(key.access_token, key.refresh_token);
|
||||
api.refresh().await?;
|
||||
println!("Refreshed auth key");
|
||||
save_key(auth_path, &api)?;
|
||||
save_key(&auth_path, &api)?;
|
||||
// api.print_responses = teslatte::PrintResponses::Pretty;
|
||||
Ok(api)
|
||||
Ok(FleetApiAuth::new(api, Instant::now(), auth_path))
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct FleetApiAuth {
|
||||
api: FleetApi,
|
||||
last_refresh: Instant,
|
||||
auth_path: PathBuf,
|
||||
}
|
||||
|
||||
const REFRESH_INTERVAL: Duration = Duration::from_secs(12 * 60 * 60);
|
||||
|
||||
impl FleetApiAuth {
|
||||
fn new(api: FleetApi, last_refresh: Instant, auth_path: PathBuf) -> Self {
|
||||
Self {
|
||||
api,
|
||||
last_refresh,
|
||||
auth_path,
|
||||
}
|
||||
}
|
||||
|
||||
fn api(&self) -> &FleetApi {
|
||||
&self.api
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
async fn refresh(&mut self) {
|
||||
if Instant::now().duration_since(self.last_refresh) >= REFRESH_INTERVAL {
|
||||
match self.api.refresh().await {
|
||||
Ok(_) => {
|
||||
let now = Instant::now();
|
||||
match save_key(&self.auth_path, &self.api) {
|
||||
Ok(_) => self.last_refresh = now,
|
||||
Err(e) => eprintln!("error saving auth token: {e:?}"),
|
||||
}
|
||||
}
|
||||
Err(e) => eprintln!("error refreshing auth token: {e:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
struct AuthInfo {
|
||||
access_token: AccessToken,
|
||||
refresh_token: Option<RefreshToken>,
|
||||
}
|
||||
|
||||
fn save_key(auth_path: PathBuf, api: &FleetApi) -> Result<(), SaveError> {
|
||||
fn save_key(auth_path: &PathBuf, api: &FleetApi) -> Result<(), SaveError> {
|
||||
std::fs::write(
|
||||
auth_path,
|
||||
ron::ser::to_string(&AuthInfo {
|
||||
|
|
|
@ -13,14 +13,14 @@ use rocket::{
|
|||
};
|
||||
use teslatte::{
|
||||
vehicles::{Endpoint, GetVehicleData, VehicleData},
|
||||
FleetApi, FleetVehicleApi,
|
||||
FleetVehicleApi,
|
||||
};
|
||||
|
||||
use crate::{config::Config, Coords};
|
||||
use crate::{config::Config, Coords, FleetApiAuth};
|
||||
|
||||
pub struct ServerState {
|
||||
pub config: Config,
|
||||
pub api: FleetApi,
|
||||
pub auth: FleetApiAuth,
|
||||
pub vehicle: Box<VehicleData>,
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,8 @@ async fn flash(state: &State<ServerState>) {
|
|||
impl ServerState {
|
||||
async fn get_coords(&self) -> Result<Coords> {
|
||||
let vehicle_data = self
|
||||
.api
|
||||
.auth
|
||||
.api()
|
||||
.vehicle_data(&GetVehicleData {
|
||||
vehicle_id: self.vehicle.id.clone(),
|
||||
endpoints: vec![Endpoint::LocationData].into(),
|
||||
|
@ -143,7 +144,8 @@ impl ServerState {
|
|||
|
||||
async fn get_charge_state(&self) -> Result<shared_types::ChargeState> {
|
||||
let vehicle_data = self
|
||||
.api
|
||||
.auth
|
||||
.api()
|
||||
.vehicle_data(&GetVehicleData {
|
||||
vehicle_id: self.vehicle.id.clone(),
|
||||
endpoints: vec![Endpoint::ChargeState].into(),
|
||||
|
@ -154,7 +156,7 @@ impl ServerState {
|
|||
}
|
||||
|
||||
async fn flash(&self) {
|
||||
let _ = self.api.flash_lights(&self.vehicle.vin).await;
|
||||
let _ = self.auth.api().flash_lights(&self.vehicle.vin).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue