feat: cli show json on POST and some errors

This commit is contained in:
gak 2023-08-29 16:13:43 +10:00
parent 3fd59df8b8
commit 900be5aa1f
No known key found for this signature in database
8 changed files with 53 additions and 27 deletions

View file

@ -2,17 +2,36 @@ pub mod energy;
pub mod powerwall; pub mod powerwall;
pub mod vehicle; pub mod vehicle;
use crate::error::TeslatteError;
use crate::Data; use crate::Data;
use std::process::exit;
pub fn print_json<T>(data: Data<T>) { pub fn print_json<T>(result: Result<Data<T>, TeslatteError>) {
match result {
Ok(data) => print_json_data(data),
Err(TeslatteError::ServerError { ref body, .. }) if body.is_some() => {
print_json_str(&body.clone().unwrap())
}
Err(e) => {
eprintln!("{}", e);
exit(1);
}
}
}
pub fn print_json_data<T>(data: Data<T>) {
// TODO: pretty print cli option
print_json_str(data.body());
}
pub fn print_json_str(body: &str) {
#[cfg(feature = "cli-pretty-json")] #[cfg(feature = "cli-pretty-json")]
{ {
use colored_json::prelude::*; use colored_json::prelude::*;
println!("{}", data.body().to_colored_json_auto().unwrap()); println!("{}", body.to_colored_json_auto().unwrap());
} }
#[cfg(not(feature = "cli-pretty-json"))] #[cfg(not(feature = "cli-pretty-json"))]
{ {
println!("{}", data.body()); println!("{}", body);
} }
} }

View file

@ -42,7 +42,7 @@ impl EnergySiteArgs {
start_date, start_date,
end_date, end_date,
}; };
print_json(api.energy_sites_calendar_history(&values).await?); print_json(api.energy_sites_calendar_history(&values).await);
} }
} }
Ok(()) Ok(())

View file

@ -1,5 +1,5 @@
use crate::calendar_history::{HistoryKind, HistoryPeriod}; use crate::calendar_history::{HistoryKind, HistoryPeriod};
use crate::cli::print_json; use crate::cli::print_json_data;
use crate::powerwall::{PowerwallEnergyHistoryValues, PowerwallId}; use crate::powerwall::{PowerwallEnergyHistoryValues, PowerwallId};
use crate::Api; use crate::Api;
use clap::{Args, Subcommand}; use clap::{Args, Subcommand};
@ -24,10 +24,10 @@ impl PowerwallArgs {
pub async fn run(&self, api: &Api) -> miette::Result<()> { pub async fn run(&self, api: &Api) -> miette::Result<()> {
match self.command { match self.command {
PowerwallCommand::Status => { PowerwallCommand::Status => {
print_json(api.powerwall_status(&self.id).await?); print_json_data(api.powerwall_status(&self.id).await?);
} }
PowerwallCommand::History => { PowerwallCommand::History => {
print_json( print_json_data(
api.powerwall_energy_history(&PowerwallEnergyHistoryValues { api.powerwall_energy_history(&PowerwallEnergyHistoryValues {
powerwall_id: self.id.clone(), powerwall_id: self.id.clone(),
period: HistoryPeriod::Day, period: HistoryPeriod::Day,

View file

@ -36,24 +36,28 @@ impl VehicleArgs {
pub async fn run(self, api: &Api) -> miette::Result<()> { pub async fn run(self, api: &Api) -> miette::Result<()> {
match self.command { match self.command {
VehicleCommand::Data => { VehicleCommand::Data => {
print_json(api.vehicle_data(&self.id).await?); print_json(api.vehicle_data(&self.id).await);
} }
VehicleCommand::ChargeState => { VehicleCommand::ChargeState => {
print_json(api.charge_state(&self.id).await?); print_json(api.charge_state(&self.id).await);
} }
VehicleCommand::SetChargeLimit { percent } => { VehicleCommand::SetChargeLimit { percent } => {
print_json(
api.set_charge_limit(&self.id, &SetChargeLimit { percent }) api.set_charge_limit(&self.id, &SetChargeLimit { percent })
.await?; .await,
);
} }
VehicleCommand::SetChargingAmps { charging_amps } => { VehicleCommand::SetChargingAmps { charging_amps } => {
print_json(
api.set_charging_amps(&self.id, &SetChargingAmps { charging_amps }) api.set_charging_amps(&self.id, &SetChargingAmps { charging_amps })
.await?; .await,
);
} }
VehicleCommand::ChargeStart => { VehicleCommand::ChargeStart => {
api.charge_start(&self.id).await?; print_json(api.charge_start(&self.id).await);
} }
VehicleCommand::ChargeStop => { VehicleCommand::ChargeStop => {
api.charge_stop(&self.id).await?; print_json(api.charge_stop(&self.id).await);
} }
} }
Ok(()) Ok(())

View file

@ -6,6 +6,7 @@ pub enum TeslatteError {
request: String, request: String,
msg: String, msg: String,
description: Option<String>, description: Option<String>,
body: Option<String>,
}, },
#[error("{request} unhandled server response: {body}")] #[error("{request} unhandled server response: {body}")]

View file

@ -89,7 +89,7 @@ impl Api {
} }
#[instrument(skip(self))] #[instrument(skip(self))]
async fn post<S>(&self, url: &str, body: S) -> Result<(), TeslatteError> async fn post<S>(&self, url: &str, body: S) -> Result<Data<PostResponse>, TeslatteError>
where where
S: Serialize + Debug, S: Serialize + Debug,
{ {
@ -122,16 +122,17 @@ impl Api {
source, source,
request: req_ctx(), request: req_ctx(),
})?; })?;
let json = Self::parse_json::<PostResponse, _>(&body, req_ctx)?; let data = Self::parse_json::<PostResponse, _>(&body, req_ctx)?;
trace!(?json); trace!(?data);
if json.result { if data.result {
Ok(()) Ok(Data { data, body })
} else { } else {
Err(TeslatteError::ServerError { Err(TeslatteError::ServerError {
request: req_ctx(), request: req_ctx(),
msg: json.reason, msg: data.reason,
description: None, description: None,
body: Some(body),
}) })
} }
} }
@ -157,6 +158,7 @@ impl Api {
request: request(), request: request(),
msg: e.error, msg: e.error,
description: e.error_description, description: e.error_description,
body: Some(body.to_owned()),
}), }),
} }
} }
@ -187,7 +189,7 @@ impl<T> From<ResponseDeserializer<T>> for Response<T> {
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
struct PostResponse { pub struct PostResponse {
reason: String, reason: String,
result: bool, result: bool,
} }
@ -281,7 +283,7 @@ macro_rules! post_arg {
&self, &self,
arg: &$arg_type, arg: &$arg_type,
data: &$request_type, data: &$request_type,
) -> miette::Result<(), crate::error::TeslatteError> { ) -> miette::Result<crate::Data<crate::PostResponse>, crate::error::TeslatteError> {
let url = format!($url, arg); let url = format!($url, arg);
let url = format!("{}{}", crate::API_URL, url); let url = format!("{}{}", crate::API_URL, url);
self.post(&url, data).await self.post(&url, data).await
@ -296,7 +298,7 @@ macro_rules! post_arg_empty {
pub async fn $name( pub async fn $name(
&self, &self,
arg: &$arg_type, arg: &$arg_type,
) -> miette::Result<(), crate::error::TeslatteError> { ) -> miette::Result<crate::Data<crate::PostResponse>, crate::error::TeslatteError> {
let url = format!($url, arg); let url = format!($url, arg);
let url = format!("{}{}", crate::API_URL, url); let url = format!("{}{}", crate::API_URL, url);
self.post(&url, &Empty {}).await self.post(&url, &Empty {}).await

View file

@ -106,13 +106,13 @@ async fn main() -> miette::Result<()> {
let api = Api::new(access_token, refresh_token); let api = Api::new(access_token, refresh_token);
match api_args.command { match api_args.command {
ApiCommand::Vehicles => { ApiCommand::Vehicles => {
print_json(api.vehicles().await?); print_json(api.vehicles().await);
} }
ApiCommand::Vehicle(v) => { ApiCommand::Vehicle(v) => {
v.run(&api).await?; v.run(&api).await?;
} }
ApiCommand::EnergySites => { ApiCommand::EnergySites => {
print_json(api.energy_sites().await?); print_json(api.energy_sites().await);
} }
ApiCommand::EnergySite(e) => { ApiCommand::EnergySite(e) => {
e.run(&api).await?; e.run(&api).await?;

View file

@ -38,7 +38,7 @@ pub struct VehicleData {
/// gak: This was null for me, assuming String. /// gak: This was null for me, assuming String.
pub backseat_token_updated_at: Option<String>, pub backseat_token_updated_at: Option<String>,
/// Some of these have been null for me, so making them all Option. /// gak: Some of these have been null for me, so making them all Option.
pub charge_state: Option<ChargeState>, pub charge_state: Option<ChargeState>,
pub climate_state: Option<ClimateState>, pub climate_state: Option<ClimateState>,
pub drive_state: Option<DriveState>, pub drive_state: Option<DriveState>,