diff --git a/src/its_api.rs b/src/its_api.rs index 4da46f8..2b86dd6 100644 --- a/src/its_api.rs +++ b/src/its_api.rs @@ -1,4 +1,5 @@ use reqwest::{Client, Url}; +use serde::Deserialize; use thiserror::Error; use tracing::{event, instrument, Level}; @@ -6,8 +7,10 @@ use tracing::{event, instrument, Level}; pub enum Error { #[error("invalid URL")] InvalidUrl(#[from] url::ParseError), - #[error("invalid response")] - InvalidResponse(#[source] reqwest::Error), + #[error("error retrieving API response")] + ResponseBody(#[source] reqwest::Error), + #[error("invalid JSON in response")] + InvalidJson(#[source] serde_json::Error), #[error("network request failed")] Network(#[source] reqwest::Error), } @@ -20,6 +23,41 @@ pub struct ItsApi { client: Client, } +fn response_get_lastchange(value: &mut serde_json::Value) -> Option<&mut serde_json::Value> { + value + .as_object_mut()? + .get_mut("state")? + .as_object_mut()? + .get_mut("lastchange") +} + +fn response_get_icon( + value: &mut serde_json::Value, +) -> Option<&mut serde_json::Map> { + value + .as_object_mut()? + .get_mut("state")? + .as_object_mut()? + .get_mut("icon")? + .as_object_mut() +} + +fn patch_response(value: &mut serde_json::Value) { + // https://github.com/home-assistant/core/pull/83871 + if let Some(lastchange) = response_get_lastchange(value) { + if let Some(f) = lastchange.as_f64() { + *lastchange = (f as u64).into(); + } + } + + // https://github.com/home-assistant/core/pull/108596 + if let Some(icon) = response_get_icon(value) { + if let Some(closed) = icon.remove("close") { + icon.insert("closed".to_owned(), closed); + } + } +} + impl ItsApi { /// Constructs a new IT-Syndikat API handler. #[instrument] @@ -40,15 +78,20 @@ impl ItsApi { #[instrument] pub async fn status(&self) -> Result { event!(Level::DEBUG, "requesting spaceapi status"); - let status = self + let response = self .client .get(self.base_url.join("status.php")?) .send() .await .map_err(Error::Network)? - .json() + .bytes() .await - .map_err(Error::InvalidResponse)?; + .map_err(Error::ResponseBody)?; + let mut response = serde_json::from_slice(&response).map_err(Error::InvalidJson)?; + + patch_response(&mut response); + + let status = spaceapi::Status::deserialize(response).map_err(Error::InvalidJson)?; event!(Level::DEBUG, ?status); Ok(status) @@ -70,7 +113,7 @@ impl ItsApi { .await .map_err(Error::Network)? .error_for_status() - .map_err(Error::InvalidResponse)?; + .map_err(Error::ResponseBody)?; Ok(()) }