refresh token infrastructure
This commit is contained in:
parent
dc81a3cf6e
commit
be5b787be5
|
@ -1,3 +1,5 @@
|
||||||
|
#![feature(async_closure)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
|
|
||||||
|
@ -5,7 +7,10 @@ use anyhow::Result;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::{
|
||||||
|
path::PathBuf,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
use teslatte::{
|
use teslatte::{
|
||||||
auth::{AccessToken, RefreshToken},
|
auth::{AccessToken, RefreshToken},
|
||||||
FleetApi,
|
FleetApi,
|
||||||
|
@ -49,16 +54,16 @@ async fn main() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Commands::Watch => match get_auth(auth_path).await {
|
Commands::Watch => match get_auth(auth_path).await {
|
||||||
Ok(api) => {
|
Ok(auth) => {
|
||||||
let config: Config =
|
let config: Config =
|
||||||
ron::from_str(&std::fs::read_to_string(&config_path).unwrap()).unwrap();
|
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 {
|
match products {
|
||||||
Ok(res) => match res.first() {
|
Ok(res) => match res.first() {
|
||||||
Some(teslatte::products::Product::Vehicle(vehicle)) => {
|
Some(teslatte::products::Product::Vehicle(vehicle)) => {
|
||||||
server::launch_server(server::ServerState {
|
server::launch_server(server::ServerState {
|
||||||
config,
|
config,
|
||||||
api,
|
auth,
|
||||||
vehicle: vehicle.clone(),
|
vehicle: vehicle.clone(),
|
||||||
})
|
})
|
||||||
.await;
|
.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 key: AuthInfo = ron::from_str(&std::fs::read_to_string(&auth_path)?)?;
|
||||||
let mut api = FleetApi::new(key.access_token, key.refresh_token);
|
let mut api = FleetApi::new(key.access_token, key.refresh_token);
|
||||||
api.refresh().await?;
|
api.refresh().await?;
|
||||||
println!("Refreshed auth key");
|
println!("Refreshed auth key");
|
||||||
save_key(auth_path, &api)?;
|
save_key(&auth_path, &api)?;
|
||||||
// api.print_responses = teslatte::PrintResponses::Pretty;
|
// 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 {
|
struct AuthInfo {
|
||||||
access_token: AccessToken,
|
access_token: AccessToken,
|
||||||
refresh_token: Option<RefreshToken>,
|
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(
|
std::fs::write(
|
||||||
auth_path,
|
auth_path,
|
||||||
ron::ser::to_string(&AuthInfo {
|
ron::ser::to_string(&AuthInfo {
|
||||||
|
|
|
@ -13,14 +13,14 @@ use rocket::{
|
||||||
};
|
};
|
||||||
use teslatte::{
|
use teslatte::{
|
||||||
vehicles::{Endpoint, GetVehicleData, VehicleData},
|
vehicles::{Endpoint, GetVehicleData, VehicleData},
|
||||||
FleetApi, FleetVehicleApi,
|
FleetVehicleApi,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{config::Config, Coords};
|
use crate::{config::Config, Coords, FleetApiAuth};
|
||||||
|
|
||||||
pub struct ServerState {
|
pub struct ServerState {
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
pub api: FleetApi,
|
pub auth: FleetApiAuth,
|
||||||
pub vehicle: Box<VehicleData>,
|
pub vehicle: Box<VehicleData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +126,8 @@ async fn flash(state: &State<ServerState>) {
|
||||||
impl ServerState {
|
impl ServerState {
|
||||||
async fn get_coords(&self) -> Result<Coords> {
|
async fn get_coords(&self) -> Result<Coords> {
|
||||||
let vehicle_data = self
|
let vehicle_data = self
|
||||||
.api
|
.auth
|
||||||
|
.api()
|
||||||
.vehicle_data(&GetVehicleData {
|
.vehicle_data(&GetVehicleData {
|
||||||
vehicle_id: self.vehicle.id.clone(),
|
vehicle_id: self.vehicle.id.clone(),
|
||||||
endpoints: vec![Endpoint::LocationData].into(),
|
endpoints: vec![Endpoint::LocationData].into(),
|
||||||
|
@ -143,7 +144,8 @@ impl ServerState {
|
||||||
|
|
||||||
async fn get_charge_state(&self) -> Result<shared_types::ChargeState> {
|
async fn get_charge_state(&self) -> Result<shared_types::ChargeState> {
|
||||||
let vehicle_data = self
|
let vehicle_data = self
|
||||||
.api
|
.auth
|
||||||
|
.api()
|
||||||
.vehicle_data(&GetVehicleData {
|
.vehicle_data(&GetVehicleData {
|
||||||
vehicle_id: self.vehicle.id.clone(),
|
vehicle_id: self.vehicle.id.clone(),
|
||||||
endpoints: vec![Endpoint::ChargeState].into(),
|
endpoints: vec![Endpoint::ChargeState].into(),
|
||||||
|
@ -154,7 +156,7 @@ impl ServerState {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn flash(&self) {
|
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