use serde::{Deserialize, Serialize};
use serde_json::json;
use tokio_tungstenite::tungstenite::protocol::Message;
use crate::error::{ObnizError, ObnizResult};
use crate::obniz::Obniz;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemInfo {
pub version: String,
pub hardware: String,
pub device_type: String,
pub region: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResetConfig {
pub reset_obniz_on_ws_disconnection: bool,
}
#[derive(Debug, Clone)]
pub struct SystemManager {
obniz: Obniz,
}
impl SystemManager {
pub fn new(obniz: Obniz) -> Self {
Self { obniz }
}
pub async fn reset(&self) -> ObnizResult<()> {
let request = json!([{"system": {"reset": true}}]);
let message = Message::from(request.to_string());
self.obniz
.send_message(message)
.map_err(|e| ObnizError::Connection(e.to_string()))
}
pub async fn info(&self) -> ObnizResult<SystemInfo> {
let request = json!([{"system": {"info": "get"}}]);
let message = Message::from(request.to_string());
let response = self
.obniz
.send_await_response(message, "system".to_string())
.await
.map_err(|e| ObnizError::Connection(e.to_string()))?;
if let Some(array) = response.as_array() {
if let Some(first_item) = array.first() {
if let Some(system_info) = first_item.get("system") {
return serde_json::from_value(system_info.clone())
.map_err(|e| ObnizError::JsonParse(e.to_string()));
}
}
}
if let Some(system_info) = response.get("system") {
serde_json::from_value(system_info.clone())
.map_err(|e| ObnizError::JsonParse(e.to_string()))
} else {
Err(ObnizError::Generic(
"No system information in response".to_string(),
))
}
}
pub async fn reset_on_disconnect(&self, enable: bool) -> ObnizResult<()> {
let request = json!([{"ws": {"reset_obniz_on_ws_disconnection": enable}}]);
let message = Message::from(request.to_string());
self.obniz
.send_message(message)
.map_err(|e| ObnizError::Connection(e.to_string()))
}
pub async fn keep_alive(&self) -> ObnizResult<()> {
let request = json!([{"system": {"keep_working_at_offline": true}}]);
let message = Message::from(request.to_string());
self.obniz
.send_message(message)
.map_err(|e| ObnizError::Connection(e.to_string()))
}
pub async fn ping_interval(&self, interval_ms: u32) -> ObnizResult<()> {
if interval_ms == 0 {
return Err(ObnizError::Generic(
"Ping interval must be greater than 0".to_string(),
));
}
let request = json!([{"ws": {"ping": {"interval": interval_ms}}}]);
let message = Message::from(request.to_string());
self.obniz
.send_message(message)
.map_err(|e| ObnizError::Connection(e.to_string()))
}
pub async fn status(&self) -> ObnizResult<serde_json::Value> {
let request = json!([{"system": {"status": "get"}}]);
let message = Message::from(request.to_string());
let response = self
.obniz
.send_await_response(message, "system".to_string())
.await
.map_err(|e| ObnizError::Connection(e.to_string()))?;
Ok(response)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_reset_config_serialization() {
use serde_json;
let config = ResetConfig {
reset_obniz_on_ws_disconnection: true,
};
let serialized = serde_json::to_string(&config).unwrap();
assert!(serialized.contains("reset_obniz_on_ws_disconnection"));
assert!(serialized.contains("true"));
}
#[test]
fn test_system_info_deserialization() {
use serde_json;
let json_str = r#"{
"version": "3.5.0",
"hardware": "obnizb1",
"device_type": "obnizb1",
"region": "jp"
}"#;
let info: SystemInfo = serde_json::from_str(json_str).unwrap();
assert_eq!(info.version, "3.5.0");
assert_eq!(info.hardware, "obnizb1");
assert_eq!(info.device_type, "obnizb1");
assert_eq!(info.region, Some("jp".to_string()));
}
}