use serde::{Deserialize, Serialize};
use crate::error::{KanaError, Result};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DaimonConfig {
pub endpoint: String,
pub api_key: Option<String>,
}
impl Default for DaimonConfig {
fn default() -> Self {
Self {
endpoint: "http://localhost:8090".into(),
api_key: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HooshConfig {
pub endpoint: String,
}
impl Default for HooshConfig {
fn default() -> Self {
Self {
endpoint: "http://localhost:8088".into(),
}
}
}
pub struct DaimonClient {
config: DaimonConfig,
client: reqwest::Client,
}
impl DaimonClient {
pub fn new(config: DaimonConfig) -> Result<Self> {
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(30))
.build()
.map_err(|e| KanaError::InvalidParameter {
reason: format!("failed to build HTTP client: {e}"),
})?;
Ok(Self { config, client })
}
pub async fn register_agent(&self) -> Result<String> {
let body = serde_json::json!({
"name": "kana",
"capabilities": ["quantum_state", "operators", "entanglement", "circuits"],
});
let mut req = self
.client
.post(format!("{}/v1/agents/register", self.config.endpoint))
.json(&body);
if let Some(ref key) = self.config.api_key {
req = req.header("Authorization", format!("Bearer {key}"));
}
let resp = req.send().await.map_err(|e| KanaError::InvalidParameter {
reason: format!("registration request failed: {e}"),
})?;
if !resp.status().is_success() {
return Err(KanaError::InvalidParameter {
reason: format!("registration failed with status {}", resp.status()),
});
}
let data: serde_json::Value =
resp.json().await.map_err(|e| KanaError::InvalidParameter {
reason: format!("invalid registration response: {e}"),
})?;
data["agent_id"]
.as_str()
.map(String::from)
.ok_or_else(|| KanaError::InvalidParameter {
reason: "registration response missing 'agent_id' field".into(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let c = DaimonConfig::default();
assert_eq!(c.endpoint, "http://localhost:8090");
assert!(c.api_key.is_none());
}
#[test]
fn test_hoosh_default() {
let c = HooshConfig::default();
assert_eq!(c.endpoint, "http://localhost:8088");
}
#[test]
fn test_daimon_client_new() {
let config = DaimonConfig::default();
let client = DaimonClient::new(config);
assert!(client.is_ok());
}
#[test]
fn test_daimon_config_with_api_key() {
let c = DaimonConfig {
endpoint: "https://custom.host:9090".into(),
api_key: Some("test-key".into()),
};
assert_eq!(c.api_key.as_deref(), Some("test-key"));
}
#[test]
fn test_daimon_config_serde_roundtrip() {
let c = DaimonConfig {
endpoint: "http://example.com".into(),
api_key: Some("key123".into()),
};
let json = serde_json::to_string(&c).unwrap();
let back: DaimonConfig = serde_json::from_str(&json).unwrap();
assert_eq!(back.endpoint, c.endpoint);
assert_eq!(back.api_key, c.api_key);
}
#[test]
fn test_hoosh_config_serde_roundtrip() {
let c = HooshConfig::default();
let json = serde_json::to_string(&c).unwrap();
let back: HooshConfig = serde_json::from_str(&json).unwrap();
assert_eq!(back.endpoint, c.endpoint);
}
}