A small rust lib for getting live heartrate data
at main 88 lines 2.4 kB view raw
1use std::time::Duration; 2 3use anyhow::bail; 4use futures_util::TryStreamExt; 5use reqwest::Client; 6use reqwest_websocket::{Message, RequestBuilderExt, WebSocket}; 7use serde::Deserialize; 8use serde_json::json; 9use tokio::time::timeout; 10 11#[derive(Deserialize)] 12struct PulsoidResponseError{ 13 message: String 14} 15 16#[derive(Deserialize)] 17struct PulsoidResponseResult{ 18 #[serde(rename = "ramielUrl")] 19 ramiel_url: String 20} 21 22#[derive(Deserialize)] 23struct PulsoidResponse{ 24 error: Option<PulsoidResponseError>, 25 result: Option<PulsoidResponseResult>, 26} 27 28#[derive(Deserialize)] 29struct PulsoidHRUpdateData{ 30 #[serde(rename = "heartRate")] 31 hr: usize 32} 33 34#[derive(Deserialize)] 35struct PulsoidHRUpdate{ 36 data: PulsoidHRUpdateData 37} 38 39pub struct Pulsoid(WebSocket); 40 41impl Pulsoid{ 42 pub async fn poll( &mut self ) -> anyhow::Result<usize>{ 43 let Some(message) = self.0.try_next().await? else { bail!("Could not get message from pulsoid") }; 44 45 if let Message::Text(message) = message{ 46 let json: PulsoidHRUpdate = serde_json::from_str(&message).unwrap(); 47 Ok(json.data.hr) 48 } else{ 49 bail!("Message was not formatted correctly") 50 } 51 } 52 53 pub async fn poll_timeout( &mut self, dur: Duration ) -> anyhow::Result<usize>{ 54 let future = timeout(dur, self.0.try_next()).await?; 55 let Some(message) = future? else { bail!("Could not get message from pulsoid") }; 56 57 if let Message::Text(message) = message{ 58 let json: PulsoidHRUpdate = serde_json::from_str(&message).unwrap(); 59 Ok(json.data.hr) 60 } else{ 61 bail!("Message was not formatted correctly") 62 } 63 } 64} 65 66pub async fn pulsoid( widget_id: String ) -> anyhow::Result<Pulsoid>{ 67 let client = Client::default(); 68 69 let res = client.post("https://pulsoid.net/v1/api/public/rpc") 70 .header("Content-Type", "application/json") 71 .body(serde_json::to_string(&json!({ 72 "id": "1", 73 "jsonrpc": "2.0", 74 "method": "getWidget", 75 "params": { "widgetId": widget_id } 76 }))?).send().await?; 77 78 if res.status() != 200{ bail!("Request Failed.") } 79 let res: PulsoidResponse = serde_json::from_str(&res.text().await?).unwrap(); 80 81 if let Some(error) = res.error{ bail!(error.message) }; 82 let Some(result) = res.result else { bail!("Failed to get result") }; 83 84 let ws_url = result.ramiel_url; 85 let ws = client.get(ws_url).upgrade().send().await?.into_websocket().await?; 86 87 Ok(Pulsoid(ws)) 88}