diff --git a/src/client.rs b/src/client.rs index 11a8bbf..db47348 100644 --- a/src/client.rs +++ b/src/client.rs @@ -9,6 +9,7 @@ use crate::models::devicestatus::DeviceStatusService; use crate::models::entries::EntriesService; use crate::models::profile::ProfileService; use crate::models::properties::PropertiesService; +use crate::models::status::StatusService; use crate::models::treatments::TreatmentsService; #[derive(Clone)] @@ -74,6 +75,12 @@ impl NightscoutClient { } } + pub fn status(&self) -> StatusService { + StatusService { + client: self.clone(), + } + } + pub async fn send_checked( &self, request: reqwest::RequestBuilder, diff --git a/src/endpoints.rs b/src/endpoints.rs index 27c22a5..97778cb 100644 --- a/src/endpoints.rs +++ b/src/endpoints.rs @@ -8,6 +8,7 @@ pub enum Endpoint { Current, DeviceStatus, Profile, + Status, } impl Endpoint { @@ -22,6 +23,7 @@ impl Endpoint { Endpoint::Properties => "api/v2/properties", Endpoint::DeviceStatus => "api/v2/devicestatus.json", Endpoint::Profile => "api/v2/profile.json", + Endpoint::Status => "api/v2/status.json", } } } diff --git a/src/models/mod.rs b/src/models/mod.rs index 7313301..eb9a889 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -2,5 +2,6 @@ pub mod devicestatus; pub mod entries; pub mod profile; pub mod properties; +pub mod status; pub mod treatments; pub mod trends; diff --git a/src/models/status.rs b/src/models/status.rs new file mode 100644 index 0000000..b0f09fd --- /dev/null +++ b/src/models/status.rs @@ -0,0 +1,537 @@ +use crate::client::NightscoutClient; +use crate::endpoints::Endpoint; +use crate::error::NightscoutError; +use napi_derive::napi; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +pub struct StatusService { + pub client: NightscoutClient, +} + +impl StatusService { + pub async fn get(&self) -> Result { + let url = self.client.base_url.join(Endpoint::Status.as_path())?; + + let mut request = self.client.http.get(url); + request = self.client.auth(request); + + let response = self.client.send_checked(request).await?; + + Ok(response.json::().await?) + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[napi(object)] +pub struct Status { + pub status: String, + #[allow(dead_code)] + pub name: String, + pub version: String, + + #[napi(js_name = "serverTime")] + #[serde(rename = "serverTime")] + pub server_time: String, + + #[napi(js_name = "serverTimeEpoch")] + #[serde(rename = "serverTimeEpoch")] + pub server_time_epoch: i64, + + #[napi(js_name = "apiEnabled")] + #[serde(rename = "apiEnabled")] + pub api_enabled: bool, + + #[napi(js_name = "carePortalEnabled")] + #[serde(rename = "careportalEnabled")] + pub care_portal_enabled: bool, + + #[napi(js_name = "bolusCalcEnabled")] + #[serde(rename = "boluscalcEnabled")] + pub bolus_calc_enabled: bool, + + #[serde(default, skip_serializing_if = "Option::is_none")] + pub settings: Option, + + #[napi(js_name = "extendedSettings")] + #[serde( + default, + rename = "extendedSettings", + skip_serializing_if = "Option::is_none" + )] + pub extended_settings: Option, + + #[serde(default, skip_serializing_if = "Option::is_none")] + pub authorized: Option, + + #[napi(js_name = "runtimeState")] + #[serde( + default, + rename = "runtimeState", + skip_serializing_if = "Option::is_none" + )] + pub runtime_state: Option, + + #[serde(flatten)] + pub extra: Value, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[napi(object)] +pub struct StatusSettings { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub units: Option, + + #[napi(js_name = "timeFormat")] + #[serde( + default, + rename = "timeFormat", + skip_serializing_if = "Option::is_none" + )] + pub time_format: Option, + + #[napi(js_name = "dayStart")] + #[serde(default, rename = "dayStart", skip_serializing_if = "Option::is_none")] + pub day_start: Option, + + #[napi(js_name = "dayEnd")] + #[serde(default, rename = "dayEnd", skip_serializing_if = "Option::is_none")] + pub day_end: Option, + + #[napi(js_name = "nightMode")] + #[serde(default, rename = "nightMode", skip_serializing_if = "Option::is_none")] + pub night_mode: Option, + + #[napi(js_name = "editMode")] + #[serde(default, rename = "editMode", skip_serializing_if = "Option::is_none")] + pub edit_mode: Option, + + #[napi(js_name = "showRawbg")] + #[serde(default, rename = "showRawbg", skip_serializing_if = "Option::is_none")] + pub show_rawbg: Option, + + #[napi(js_name = "customTitle")] + #[serde( + default, + rename = "customTitle", + skip_serializing_if = "Option::is_none" + )] + pub custom_title: Option, + + #[serde(default, skip_serializing_if = "Option::is_none")] + pub theme: Option, + + #[napi(js_name = "alarmUrgentHigh")] + #[serde( + default, + rename = "alarmUrgentHigh", + skip_serializing_if = "Option::is_none" + )] + pub alarm_urgent_high: Option, + + #[napi(js_name = "alarmUrgentHighMins")] + #[serde( + default, + rename = "alarmUrgentHighMins", + skip_serializing_if = "Option::is_none" + )] + pub alarm_urgent_high_mins: Option>, + + #[napi(js_name = "alarmHigh")] + #[serde(default, rename = "alarmHigh", skip_serializing_if = "Option::is_none")] + pub alarm_high: Option, + + #[napi(js_name = "alarmHighMins")] + #[serde( + default, + rename = "alarmHighMins", + skip_serializing_if = "Option::is_none" + )] + pub alarm_high_mins: Option>, + + #[napi(js_name = "alarmLow")] + #[serde(default, rename = "alarmLow", skip_serializing_if = "Option::is_none")] + pub alarm_low: Option, + + #[napi(js_name = "alarmLowMins")] + #[serde( + default, + rename = "alarmLowMins", + skip_serializing_if = "Option::is_none" + )] + pub alarm_low_mins: Option>, + + #[napi(js_name = "alarmUrgentLow")] + #[serde( + default, + rename = "alarmUrgentLow", + skip_serializing_if = "Option::is_none" + )] + pub alarm_urgent_low: Option, + + #[napi(js_name = "alarmUrgentLowMins")] + #[serde( + default, + rename = "alarmUrgentLowMins", + skip_serializing_if = "Option::is_none" + )] + pub alarm_urgent_low_mins: Option>, + + #[napi(js_name = "alarmUrgentMins")] + #[serde( + default, + rename = "alarmUrgentMins", + skip_serializing_if = "Option::is_none" + )] + pub alarm_urgent_mins: Option>, + + #[napi(js_name = "alarmWarnMins")] + #[serde( + default, + rename = "alarmWarnMins", + skip_serializing_if = "Option::is_none" + )] + pub alarm_warn_mins: Option>, + + #[napi(js_name = "alarmTimeagoWarn")] + #[serde( + default, + rename = "alarmTimeagoWarn", + skip_serializing_if = "Option::is_none" + )] + pub alarm_timeago_warn: Option, + + #[napi(js_name = "alarmTimeagoWarnMins")] + #[serde( + default, + rename = "alarmTimeagoWarnMins", + skip_serializing_if = "Option::is_none" + )] + pub alarm_timeago_warn_mins: Option, + + #[napi(js_name = "alarmTimeagoUrgent")] + #[serde( + default, + rename = "alarmTimeagoUrgent", + skip_serializing_if = "Option::is_none" + )] + pub alarm_timeago_urgent: Option, + + #[napi(js_name = "alarmTimeagoUrgentMins")] + #[serde( + default, + rename = "alarmTimeagoUrgentMins", + skip_serializing_if = "Option::is_none" + )] + pub alarm_timeago_urgent_mins: Option, + + #[napi(js_name = "alarmPumpBatteryLow")] + #[serde( + default, + rename = "alarmPumpBatteryLow", + skip_serializing_if = "Option::is_none" + )] + pub alarm_pump_battery_low: Option, + + #[napi(js_name = "baseURL")] + #[serde(default, rename = "baseURL", skip_serializing_if = "Option::is_none")] + pub base_url: Option, + + #[napi(js_name = "authDefaultRoles")] + #[serde( + default, + rename = "authDefaultRoles", + skip_serializing_if = "Option::is_none" + )] + pub auth_default_roles: Option, + + #[serde(default, skip_serializing_if = "Option::is_none")] + pub language: Option, + + #[napi(js_name = "scaleY")] + #[serde(default, rename = "scaleY", skip_serializing_if = "Option::is_none")] + pub scale_y: Option, + + #[napi(js_name = "showPlugins")] + #[serde( + default, + rename = "showPlugins", + skip_serializing_if = "Option::is_none" + )] + pub show_plugins: Option, + + #[napi(js_name = "showForecast")] + #[serde( + default, + rename = "showForecast", + skip_serializing_if = "Option::is_none" + )] + pub show_forecast: Option, + + #[napi(js_name = "focusHours")] + #[serde( + default, + rename = "focusHours", + skip_serializing_if = "Option::is_none" + )] + pub focus_hours: Option, + + #[serde(default, skip_serializing_if = "Option::is_none")] + pub heartbeat: Option, + + #[napi(js_name = "DEFAULT_FEATURES")] + #[serde( + default, + rename = "DEFAULT_FEATURES", + skip_serializing_if = "Option::is_none" + )] + pub default_features: Option>, + + #[serde(default, skip_serializing_if = "Option::is_none")] + pub enable: Option>, + + #[serde(default, skip_serializing_if = "Option::is_none")] + pub thresholds: Option, + + #[napi(js_name = "alarmTypes")] + #[serde( + default, + rename = "alarmTypes", + skip_serializing_if = "Option::is_none" + )] + pub alarm_types: Option>, + + #[napi(js_name = "insecureUseHttp")] + #[serde( + default, + rename = "insecureUseHttp", + skip_serializing_if = "Option::is_none" + )] + pub insecure_use_http: Option, + + #[napi(js_name = "secureHstsHeader")] + #[serde( + default, + rename = "secureHstsHeader", + skip_serializing_if = "Option::is_none" + )] + pub secure_hsts_header: Option, + + #[napi(js_name = "secureHstsHeaderIncludeSubdomains")] + #[serde( + default, + rename = "secureHstsHeaderIncludeSubdomains", + skip_serializing_if = "Option::is_none" + )] + pub secure_hsts_header_include_subdomains: Option, + + #[napi(js_name = "secureHstsHeaderPreload")] + #[serde( + default, + rename = "secureHstsHeaderPreload", + skip_serializing_if = "Option::is_none" + )] + pub secure_hsts_header_preload: Option, + + #[napi(js_name = "secureCsp")] + #[serde(default, rename = "secureCsp", skip_serializing_if = "Option::is_none")] + pub secure_csp: Option, + + #[napi(js_name = "deNormalizeDates")] + #[serde( + default, + rename = "deNormalizeDates", + skip_serializing_if = "Option::is_none" + )] + pub de_normalize_dates: Option, + + #[napi(js_name = "showClockDelta")] + #[serde( + default, + rename = "showClockDelta", + skip_serializing_if = "Option::is_none" + )] + pub show_clock_delta: Option, + + #[napi(js_name = "showClockLastTime")] + #[serde( + default, + rename = "showClockLastTime", + skip_serializing_if = "Option::is_none" + )] + pub show_clock_last_time: Option, + + #[napi(js_name = "frameUrl1")] + #[serde(default, rename = "frameUrl1", skip_serializing_if = "Option::is_none")] + pub frame_url_1: Option, + + #[napi(js_name = "frameUrl2")] + #[serde(default, rename = "frameUrl2", skip_serializing_if = "Option::is_none")] + pub frame_url_2: Option, + + #[napi(js_name = "frameUrl3")] + #[serde(default, rename = "frameUrl3", skip_serializing_if = "Option::is_none")] + pub frame_url_3: Option, + + #[napi(js_name = "frameUrl4")] + #[serde(default, rename = "frameUrl4", skip_serializing_if = "Option::is_none")] + pub frame_url_4: Option, + + #[napi(js_name = "frameUrl5")] + #[serde(default, rename = "frameUrl5", skip_serializing_if = "Option::is_none")] + pub frame_url_5: Option, + + #[napi(js_name = "frameUrl6")] + #[serde(default, rename = "frameUrl6", skip_serializing_if = "Option::is_none")] + pub frame_url_6: Option, + + #[napi(js_name = "frameUrl7")] + #[serde(default, rename = "frameUrl7", skip_serializing_if = "Option::is_none")] + pub frame_url_7: Option, + + #[napi(js_name = "frameUrl8")] + #[serde(default, rename = "frameUrl8", skip_serializing_if = "Option::is_none")] + pub frame_url_8: Option, + + #[napi(js_name = "frameName1")] + #[serde( + default, + rename = "frameName1", + skip_serializing_if = "Option::is_none" + )] + pub frame_name_1: Option, + + #[napi(js_name = "frameName2")] + #[serde( + default, + rename = "frameName2", + skip_serializing_if = "Option::is_none" + )] + pub frame_name_2: Option, + + #[napi(js_name = "frameName3")] + #[serde( + default, + rename = "frameName3", + skip_serializing_if = "Option::is_none" + )] + pub frame_name_3: Option, + + #[napi(js_name = "frameName4")] + #[serde( + default, + rename = "frameName4", + skip_serializing_if = "Option::is_none" + )] + pub frame_name_4: Option, + + #[napi(js_name = "frameName5")] + #[serde( + default, + rename = "frameName5", + skip_serializing_if = "Option::is_none" + )] + pub frame_name_5: Option, + + #[napi(js_name = "frameName6")] + #[serde( + default, + rename = "frameName6", + skip_serializing_if = "Option::is_none" + )] + pub frame_name_6: Option, + + #[napi(js_name = "frameName7")] + #[serde( + default, + rename = "frameName7", + skip_serializing_if = "Option::is_none" + )] + pub frame_name_7: Option, + + #[napi(js_name = "frameName8")] + #[serde( + default, + rename = "frameName8", + skip_serializing_if = "Option::is_none" + )] + pub frame_name_8: Option, + + #[napi(js_name = "authFailDelay")] + #[serde( + default, + rename = "authFailDelay", + skip_serializing_if = "Option::is_none" + )] + pub auth_fail_delay: Option, + + #[napi(js_name = "adminNotifiesEnabled")] + #[serde( + default, + rename = "adminNotifiesEnabled", + skip_serializing_if = "Option::is_none" + )] + pub admin_notifies_enabled: Option, + + #[napi(js_name = "authenticationPromptOnLoad")] + #[serde( + default, + rename = "authenticationPromptOnLoad", + skip_serializing_if = "Option::is_none" + )] + pub authentication_prompt_on_load: Option, + + #[serde(flatten)] + pub extra: Value, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[napi(object)] +pub struct StatusThresholds { + #[napi(js_name = "bgHigh")] + #[serde(default, rename = "bgHigh", skip_serializing_if = "Option::is_none")] + pub bg_high: Option, + + #[napi(js_name = "bgTargetTop")] + #[serde( + default, + rename = "bgTargetTop", + skip_serializing_if = "Option::is_none" + )] + pub bg_target_top: Option, + + #[napi(js_name = "bgTargetBottom")] + #[serde( + default, + rename = "bgTargetBottom", + skip_serializing_if = "Option::is_none" + )] + pub bg_target_bottom: Option, + + #[napi(js_name = "bgLow")] + #[serde(default, rename = "bgLow", skip_serializing_if = "Option::is_none")] + pub bg_low: Option, + + #[serde(flatten)] + pub extra: Value, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[napi(object)] +pub struct ExtendedSettings { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub devicestatus: Option, + + #[serde(flatten)] + pub extra: Value, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[napi(object)] +pub struct ExtendedDeviceStatusSettings { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub advanced: Option, + + #[serde(default, skip_serializing_if = "Option::is_none")] + pub days: Option, +} diff --git a/src/node_bindings.rs b/src/node_bindings.rs index d90fc0c..695b559 100644 --- a/src/node_bindings.rs +++ b/src/node_bindings.rs @@ -3,6 +3,7 @@ use crate::models::devicestatus::DeviceStatus; use crate::models::entries::{MbgEntry, SgvEntry}; use crate::models::profile::{ProfileService, ProfileSet}; use crate::models::properties::{Properties, PropertiesService, PropertyType}; +use crate::models::status::Status; use crate::models::treatments::Treatment; use crate::query_builder::Device; @@ -93,6 +94,33 @@ impl Cinnamon { at: None, } } + + #[napi] + pub fn status(&self) -> JsStatusQuery { + JsStatusQuery { + client: self.client.clone(), + } + } +} + +// ----------------------------- +// Status + +#[napi] +pub struct JsStatusQuery { + client: NightscoutClient, +} + +#[napi] +impl JsStatusQuery { + #[napi] + pub async fn fetch(&self) -> Result { + self.client + .status() + .get() + .await + .map_err(|e| Error::from_reason(e.to_string())) + } } // -----------------------------