use crate::data::IoTData;
use crate::devices::DeviceInfo;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RpcDeviceInfo {
pub address: String,
pub name: String,
pub connection_type: String,
}
impl RpcDeviceInfo {
pub fn new(address: String, name: String, connection_type: String) -> Self {
Self {
address,
name,
connection_type,
}
}
}
impl From<&DeviceInfo> for RpcDeviceInfo {
fn from(device: &DeviceInfo) -> Self {
Self {
address: device.address.clone(),
name: device.name.clone(),
connection_type: device.connection_type.clone().unwrap_or_else(|| "bluetooth_le".to_string()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RpcDataBatch {
pub device: RpcDeviceInfo,
pub data: Vec<IoTData>,
}
impl RpcDataBatch {
pub fn new(device: RpcDeviceInfo, data: Vec<IoTData>) -> Self {
Self { device, data }
}
pub fn to_rpc_format(&self) -> crate::Result<(RpcDeviceInfo, Vec<String>)> {
let json_data: Result<Vec<String>, _> = self
.data
.iter()
.map(|item| serde_json::to_string(item))
.collect();
match json_data {
Ok(data_strings) => Ok((self.device.clone(), data_strings)),
Err(e) => Err(crate::Error::General(format!("Failed to serialize IoT data: {}", e))),
}
}
}
pub mod helpers {
use crate::data::*;
use std::collections::HashMap;
pub fn create_heart_rate_data(address: String, rate: i32, timestamp: i64) -> IoTData {
let mut data = HashMap::new();
data.insert("rate".to_string(), serde_json::Value::Number(rate.into()));
let heart_rate_data = HeartRateData::new(data, address, timestamp);
IoTData::HeartRate(heart_rate_data)
}
pub fn create_temperature_data(address: String, level: f64, timestamp: i64) -> IoTData {
let mut data = HashMap::new();
data.insert("level".to_string(), serde_json::Value::Number(
serde_json::Number::from_f64(level).unwrap_or_else(|| serde_json::Number::from(0))
));
let temperature_data = TemperatureData::new(data, address, timestamp);
IoTData::Temperature(temperature_data)
}
pub fn create_battery_level_data(address: String, level: i32, timestamp: i64) -> IoTData {
let mut data = HashMap::new();
data.insert("level".to_string(), serde_json::Value::Number(level.into()));
let battery_data = BatteryLevelData::new(data, address, timestamp);
IoTData::BatteryLevel(battery_data)
}
pub fn create_pressure_data(address: String, level: f64, timestamp: i64) -> IoTData {
let mut data = HashMap::new();
data.insert("level".to_string(), serde_json::Value::Number(
serde_json::Number::from_f64(level).unwrap_or_else(|| serde_json::Number::from(0))
));
let pressure_data = PressureData::new(data, address, timestamp);
IoTData::Pressure(pressure_data)
}
pub fn create_blood_pressure_data(address: String, sys: i32, dias: i32, timestamp: i64) -> IoTData {
let mut data = HashMap::new();
data.insert("sys".to_string(), serde_json::Value::Number(sys.into()));
data.insert("dias".to_string(), serde_json::Value::Number(dias.into()));
let blood_pressure_data = BloodPressureData::new(data, address, timestamp);
IoTData::BloodPressure(blood_pressure_data)
}
pub fn create_humidity_data(address: String, level: f64, timestamp: i64) -> IoTData {
let mut data = HashMap::new();
data.insert("level".to_string(), serde_json::Value::Number(
serde_json::Number::from_f64(level).unwrap_or_else(|| serde_json::Number::from(0))
));
let humidity_data = HumidityData::new(data, address, timestamp);
IoTData::Humidity(humidity_data)
}
pub fn create_alert_data(address: String, id: String, timestamp: i64) -> IoTData {
let mut data = HashMap::new();
data.insert("id".to_string(), serde_json::Value::String(id));
let alert_data = AlertData::new(data, address, timestamp);
IoTData::Alert(alert_data)
}
pub fn create_generic_data(address: String, name: String, data: HashMap<String, serde_json::Value>, timestamp: i64) -> IoTData {
let generic_data = DataType::new(data, address, timestamp, name);
IoTData::Generic(generic_data)
}
pub fn current_timestamp() -> i64 {
use std::time::{SystemTime, UNIX_EPOCH};
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as i64
}
}
pub struct RpcHelper {
client: crate::rpc::RpcClient,
}
impl RpcHelper {
pub fn new(server_address: std::net::SocketAddr) -> Self {
Self {
client: crate::rpc::RpcClient::new(server_address),
}
}
pub async fn submit_data_batch(&self, batch: RpcDataBatch) -> crate::Result<(bool, Vec<String>)> {
let (device_info, data_strings) = batch.to_rpc_format()?;
self.client.submit_data(
&device_info.address,
&device_info.name,
&device_info.connection_type,
batch.data
).await
}
pub async fn submit_single_data(
&self,
device: RpcDeviceInfo,
data: IoTData
) -> crate::Result<(bool, Vec<String>)> {
let batch = RpcDataBatch::new(device, vec![data]);
self.submit_data_batch(batch).await
}
}