use anyhow::{anyhow, Result}; use reqwest::Client; use reqwest_middleware::{ClientBuilder, ClientWithMiddleware}; use reqwest_tracing::{DefaultSpanBackend, TracingMiddleware}; use serde::{Deserialize, Serialize}; use std::net::SocketAddr; use std::sync::Arc; type Addresses = Vec; #[derive(Deserialize, Debug, Clone)] pub struct ClusterConfig { pub metadata: ClusterMetadata, pub addresses: Addresses, } #[derive(Deserialize, Debug, Clone)] pub struct ClusterMetadata { pub node_id: u32, /// Owns all rooms and players in the cluster. pub main_owner: u32, /// Owns the room `test`. pub test_owner: u32, /// Owns the room `test2`. pub test2_owner: u32, } #[derive(Clone)] pub struct LavinaClient { addresses: Arc, client: ClientWithMiddleware, } #[derive(Serialize, Deserialize, Debug)] pub struct SendMessageReq<'a> { pub room_id: &'a str, pub player_id: &'a str, pub message: &'a str, pub created_at: &'a str, } impl LavinaClient { pub fn new(addresses: Addresses) -> Self { let client = ClientBuilder::new(Client::new()).with(TracingMiddleware::::new()).build(); Self { addresses: Arc::new(addresses), client, } } #[tracing::instrument(skip(self, req), name = "LavinaClient::send_room_message")] pub async fn send_room_message(&self, node_id: u32, req: SendMessageReq<'_>) -> Result<()> { tracing::info!("Sending a message to a room on a remote node"); let Some(address) = self.addresses.get(node_id as usize) else { tracing::error!("Failed"); return Err(anyhow!("Unknown node")); }; match self.client.post(format!("http://{}/cluster/rooms/add_message", address)).json(&req).send().await { Ok(_) => { tracing::info!("Message sent"); Ok(()) } Err(e) => { tracing::error!("Failed to send message: {e:?}"); Err(e.into()) } } } }