use std::sync::Arc; use axum::{async_trait}; use churn_domain::{ServerEnrollReq}; use tokio::sync::Mutex; #[derive(Clone)] pub struct AgentService(Arc); impl std::ops::Deref for AgentService { type Target = Arc; fn deref(&self) -> &Self::Target { &self.0 } } impl Default for AgentService { fn default() -> Self { Self(Arc::new(DefaultAgentService::default())) } } #[derive(Default)] struct DefaultAgentService { server: Arc>, leases: Arc>>, } #[async_trait] pub trait AgentServiceTrait { async fn enroll(&self, agent_name: &str, server: &str, lease: &str) -> anyhow::Result<()>; } #[async_trait] impl AgentServiceTrait for DefaultAgentService { async fn enroll(&self, agent_name: &str, server: &str, lease: &str) -> anyhow::Result<()> { let mut cur_server = self.server.lock().await; let mut leases = self.leases.lock().await; let client = reqwest::Client::new(); let req = client .post(format!("{server}/agent/enroll")) .json(&ServerEnrollReq { lease: lease.into(), agent_name: agent_name.into(), }) .build()?; let resp = client.execute(req).await?; if !resp.status().is_success() { if let Ok(text) = resp.text().await { anyhow::bail!( "could not enroll agent: {} at server: {}, error: {}", agent_name, server, text ) } anyhow::bail!( "could not enroll agent: {} at server: {}", agent_name, server ) } *cur_server = server.to_string(); leases.push(lease.to_string()); Ok(()) } }