use std::time::Duration; use anyhow::bail; use futures_util::TryStreamExt; use reqwest::Client; use reqwest_websocket::{Message, RequestBuilderExt, WebSocket}; use serde::Deserialize; use serde_json::json; use tokio::time::timeout; #[derive(Deserialize)] struct PulsoidResponseError{ message: String } #[derive(Deserialize)] struct PulsoidResponseResult{ #[serde(rename = "ramielUrl")] ramiel_url: String } #[derive(Deserialize)] struct PulsoidResponse{ error: Option, result: Option, } #[derive(Deserialize)] struct PulsoidHRUpdateData{ #[serde(rename = "heartRate")] hr: usize } #[derive(Deserialize)] struct PulsoidHRUpdate{ data: PulsoidHRUpdateData } pub struct Pulsoid(WebSocket); impl Pulsoid{ pub async fn poll( &mut self ) -> anyhow::Result{ let Some(message) = self.0.try_next().await? else { bail!("Could not get message from pulsoid") }; if let Message::Text(message) = message{ let json: PulsoidHRUpdate = serde_json::from_str(&message).unwrap(); Ok(json.data.hr) } else{ bail!("Message was not formatted correctly") } } pub async fn poll_timeout( &mut self, dur: Duration ) -> anyhow::Result{ let future = timeout(dur, self.0.try_next()).await?; let Some(message) = future? else { bail!("Could not get message from pulsoid") }; if let Message::Text(message) = message{ let json: PulsoidHRUpdate = serde_json::from_str(&message).unwrap(); Ok(json.data.hr) } else{ bail!("Message was not formatted correctly") } } } pub async fn pulsoid( widget_id: String ) -> anyhow::Result{ let client = Client::default(); let res = client.post("https://pulsoid.net/v1/api/public/rpc") .header("Content-Type", "application/json") .body(serde_json::to_string(&json!({ "id": "1", "jsonrpc": "2.0", "method": "getWidget", "params": { "widgetId": widget_id } }))?).send().await?; if res.status() != 200{ bail!("Request Failed.") } let res: PulsoidResponse = serde_json::from_str(&res.text().await?).unwrap(); if let Some(error) = res.error{ bail!(error.message) }; let Some(result) = res.result else { bail!("Failed to get result") }; let ws_url = result.ramiel_url; let ws = client.get(ws_url).upgrade().send().await?.into_websocket().await?; Ok(Pulsoid(ws)) }