feagi_agent/sdk/registration/
mod.rs1use crate::core::SdkError;
4use crate::sdk::base::TopologyCache;
5
6#[derive(Debug, Clone)]
8pub struct FeagiApiConfig {
9 host: String,
10 port: u16,
11 timeout: std::time::Duration,
12}
13
14impl FeagiApiConfig {
15 pub fn new(host: impl Into<String>, port: u16, timeout: std::time::Duration) -> Self {
17 Self {
18 host: host.into(),
19 port,
20 timeout,
21 }
22 }
23
24 fn base_url(&self) -> String {
25 format!("http://{}:{}", self.host, self.port)
26 }
27}
28
29#[derive(Debug, Clone, Copy)]
31pub struct DeviceRegistrationCounts {
32 pub input_units: usize,
33 pub output_units: usize,
34 pub feedbacks: usize,
35}
36
37#[derive(Debug, Clone)]
39pub struct AgentRegistrar {
40 config: FeagiApiConfig,
41 #[cfg(feature = "sdk-io")]
42 client: reqwest::Client,
43}
44
45impl AgentRegistrar {
46 pub fn new(config: FeagiApiConfig) -> Result<Self, SdkError> {
48 #[cfg(feature = "sdk-io")]
49 let client = reqwest::Client::builder()
50 .timeout(config.timeout)
51 .build()
52 .map_err(|e| SdkError::Other(format!("Registrar HTTP client init failed: {e}")))?;
53 Ok(Self {
54 config,
55 #[cfg(feature = "sdk-io")]
56 client,
57 })
58 }
59
60 pub fn topology_cache(&self) -> Result<TopologyCache, SdkError> {
62 TopologyCache::new(
63 self.config.host.clone(),
64 self.config.port,
65 self.config.timeout.as_secs_f64(),
66 )
67 }
68
69 #[cfg(feature = "sdk-io")]
71 pub async fn sync_device_registrations(
72 &self,
73 device_registrations: serde_json::Value,
74 agent_id: &str,
75 ) -> Result<DeviceRegistrationCounts, SdkError> {
76 let counts = count_device_registrations(&device_registrations)?;
77
78 let url = format!(
79 "{}/v1/agent/{}/device_registrations",
80 self.config.base_url(),
81 agent_id
82 );
83
84 let response = self
85 .client
86 .post(url)
87 .json(&serde_json::json!({
88 "device_registrations": device_registrations
89 }))
90 .send()
91 .await
92 .map_err(|e| SdkError::Other(format!("Device registration sync failed: {e}")))?;
93
94 response
95 .error_for_status()
96 .map_err(|e| SdkError::Other(format!("Device registration sync error: {e}")))?;
97
98 Ok(counts)
99 }
100}
101
102fn count_device_registrations(
103 device_registrations: &serde_json::Value,
104) -> Result<DeviceRegistrationCounts, SdkError> {
105 let input_units = device_registrations
106 .get("input_units_and_encoder_properties")
107 .and_then(|v| v.as_object())
108 .map(|m| m.len())
109 .ok_or_else(|| SdkError::Other("Device registrations missing input units".to_string()))?;
110 let output_units = device_registrations
111 .get("output_units_and_decoder_properties")
112 .and_then(|v| v.as_object())
113 .map(|m| m.len())
114 .ok_or_else(|| SdkError::Other("Device registrations missing output units".to_string()))?;
115 let feedbacks_value = device_registrations
116 .get("feedbacks")
117 .ok_or_else(|| SdkError::Other("Device registrations missing feedbacks".to_string()))?;
118 let feedbacks = if let Some(list) = feedbacks_value.as_array() {
119 list.len()
120 } else if let Some(obj) = feedbacks_value.as_object() {
121 obj.get("registered_feedbacks")
122 .and_then(|v| v.as_array())
123 .map(|v| v.len())
124 .ok_or_else(|| {
125 SdkError::Other(
126 "Device registrations feedbacks missing registered_feedbacks".to_string(),
127 )
128 })?
129 } else {
130 return Err(SdkError::Other(
131 "Device registrations feedbacks must be an array or object".to_string(),
132 ));
133 };
134
135 Ok(DeviceRegistrationCounts {
136 input_units,
137 output_units,
138 feedbacks,
139 })
140}