use crate::tile::FleetTile;
use crate::state::ConstraintState;
use crate::delta::ConstraintDelta;
pub struct PlatoClient {
base_url: String,
client: reqwest::blocking::Client,
}
#[derive(Debug, Clone, serde::Deserialize)]
pub struct PlatoRoom {
pub id: String,
pub tiles: Option<Vec<serde_json::Value>>,
pub tile_count: Option<usize>,
}
impl PlatoClient {
pub fn new(base_url: &str) -> Self {
Self {
base_url: base_url.trim_end_matches('/').to_string(),
client: reqwest::blocking::Client::builder()
.timeout(std::time::Duration::from_secs(10))
.build()
.unwrap_or_else(|_| reqwest::blocking::Client::new()),
}
}
pub fn fleet() -> Self {
Self::new("http://147.224.38.131:8847")
}
pub fn list_rooms(&self, prefix: Option<&str>) -> Result<Vec<String>, String> {
let url = match prefix {
Some(p) => format!("{}/rooms?prefix={}", self.base_url, p),
None => format!("{}/rooms", self.base_url),
};
let resp = self.client.get(&url)
.send()
.map_err(|e| format!("HTTP error: {}", e))?;
if !resp.status().is_success() {
return Err(format!("PLATO returned {}", resp.status()));
}
resp.json::<Vec<String>>()
.map_err(|e| format!("Parse error: {}", e))
}
pub fn get_room(&self, room_id: &str) -> Result<PlatoRoom, String> {
let url = format!("{}/room/{}", self.base_url, room_id);
let resp = self.client.get(&url)
.send()
.map_err(|e| format!("HTTP error: {}", e))?;
if !resp.status().is_success() {
return Err(format!("PLATO returned {}", resp.status()));
}
resp.json::<PlatoRoom>()
.map_err(|e| format!("Parse error: {}", e))
}
pub fn submit_tile(&self, room_id: &str, tile: &FleetTile) -> Result<(), String> {
let url = format!("{}/room/{}/tile", self.base_url, room_id);
let body = tile.to_json();
let resp = self.client.post(&url)
.header("Content-Type", "application/json")
.body(body)
.send()
.map_err(|e| format!("HTTP error: {}", e))?;
if !resp.status().is_success() {
return Err(format!("PLATO returned {}", resp.status()));
}
Ok(())
}
pub fn send_delta(&self, room_id: &str, delta: &ConstraintDelta) -> Result<(), String> {
let url = format!("{}/room/{}/delta", self.base_url, room_id);
let body = serde_json::to_vec(delta).unwrap_or_default();
let resp = self.client.post(&url)
.header("Content-Type", "application/json")
.body(body)
.send()
.map_err(|e| format!("HTTP error: {}", e))?;
if !resp.status().is_success() {
return Err(format!("PLATO returned {}", resp.status()));
}
Ok(())
}
pub fn is_healthy(&self) -> bool {
let url = format!("{}/rooms", self.base_url);
self.client.get(&url).send().map(|r| r.status().is_success()).unwrap_or(false)
}
pub fn url(&self) -> &str {
&self.base_url
}
}
impl std::fmt::Display for PlatoClient {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "PlatoClient({})", self.base_url)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_client_creation() {
let client = PlatoClient::new("http://localhost:8847");
assert_eq!(client.url(), "http://localhost:8847");
}
#[test]
fn test_fleet_client() {
let client = PlatoClient::fleet();
assert!(client.url().contains("147.224.38.131"));
}
#[test]
fn test_display() {
let client = PlatoClient::new("http://example.com:8847");
let s = format!("{}", client);
assert!(s.contains("example.com"));
}
}