Skip to main content

agent_relay/
client.rs

1//! HTTP client for connecting to a remote relay server.
2
3use crate::hub;
4use crate::{AgentRegistration, Message};
5
6pub struct RemoteRelay {
7    base_url: String,
8}
9
10impl RemoteRelay {
11    pub fn new(server_url: &str) -> Self {
12        let base_url = server_url.trim_end_matches('/').to_string();
13        Self { base_url }
14    }
15
16    pub fn health(&self) -> Result<String, String> {
17        let resp = ureq::get(&format!("{}/health", self.base_url))
18            .call()
19            .map_err(|e| format!("Connection failed: {}", e))?;
20        resp.into_string().map_err(|e| format!("Read error: {}", e))
21    }
22
23    pub fn register(
24        &self,
25        agent_id: &str,
26        session_id: &str,
27        pid: u32,
28    ) -> Result<AgentRegistration, String> {
29        let resp = ureq::post(&format!("{}/agents/register", self.base_url))
30            .send_json(serde_json::json!({
31                "session_id": session_id,
32                "agent_id": agent_id,
33                "pid": pid,
34            }))
35            .map_err(|e| format!("Request failed: {}", e))?;
36
37        let body: AgentRegistration = resp
38            .into_json()
39            .map_err(|e| format!("Parse error: {}", e))?;
40        Ok(body)
41    }
42
43    pub fn unregister(&self, session_id: &str) -> Result<(), String> {
44        ureq::post(&format!("{}/agents/unregister", self.base_url))
45            .send_json(serde_json::json!({"session_id": session_id}))
46            .map_err(|e| format!("Request failed: {}", e))?;
47        Ok(())
48    }
49
50    pub fn agents(&self) -> Result<Vec<AgentRegistration>, String> {
51        let resp = ureq::get(&format!("{}/agents", self.base_url))
52            .call()
53            .map_err(|e| format!("Request failed: {}", e))?;
54
55        let body: Vec<AgentRegistration> = resp
56            .into_json()
57            .map_err(|e| format!("Parse error: {}", e))?;
58        Ok(body)
59    }
60
61    pub fn send(
62        &self,
63        from_session: &str,
64        from_agent: &str,
65        to_session: Option<&str>,
66        content: &str,
67    ) -> Result<Message, String> {
68        self.send_scoped(from_session, from_agent, to_session, content, None, None)
69    }
70
71    pub fn send_scoped(
72        &self,
73        from_session: &str,
74        from_agent: &str,
75        to_session: Option<&str>,
76        content: &str,
77        team_id: Option<&str>,
78        channel: Option<&str>,
79    ) -> Result<Message, String> {
80        let resp = ureq::post(&format!("{}/messages/send", self.base_url))
81            .send_json(serde_json::json!({
82                "from_session": from_session,
83                "from_agent": from_agent,
84                "to_session": to_session,
85                "content": content,
86                "team_id": team_id,
87                "channel": channel,
88            }))
89            .map_err(|e| format!("Request failed: {}", e))?;
90
91        let body: Message = resp
92            .into_json()
93            .map_err(|e| format!("Parse error: {}", e))?;
94        Ok(body)
95    }
96
97    pub fn inbox(&self, session_id: &str, limit: usize) -> Result<Vec<Message>, String> {
98        self.inbox_scoped(session_id, limit, None, None)
99    }
100
101    pub fn inbox_scoped(
102        &self,
103        session_id: &str,
104        limit: usize,
105        team: Option<&str>,
106        channel: Option<&str>,
107    ) -> Result<Vec<Message>, String> {
108        let mut url = format!(
109            "{}/messages/inbox?session={}&limit={}",
110            self.base_url, session_id, limit
111        );
112        if let Some(t) = team {
113            url.push_str(&format!("&team={}", t));
114        }
115        if let Some(c) = channel {
116            url.push_str(&format!("&channel={}", c));
117        }
118        let resp = ureq::get(&url)
119            .call()
120            .map_err(|e| format!("Request failed: {}", e))?;
121
122        let body: Vec<Message> = resp
123            .into_json()
124            .map_err(|e| format!("Parse error: {}", e))?;
125        Ok(body)
126    }
127
128    pub fn unread_count(&self, session_id: &str) -> Result<u64, String> {
129        let resp = ureq::get(&format!(
130            "{}/messages/unread?session={}",
131            self.base_url, session_id
132        ))
133        .call()
134        .map_err(|e| format!("Request failed: {}", e))?;
135
136        let body: serde_json::Value = resp
137            .into_json()
138            .map_err(|e| format!("Parse error: {}", e))?;
139        Ok(body["count"].as_u64().unwrap_or(0))
140    }
141
142    // ── Auth ──
143
144    /// Sign up for a new account. Returns (user_id, api_key).
145    pub fn signup(&self, email: &str, name: &str) -> Result<(String, String), String> {
146        let resp = ureq::post(&format!("{}/auth/signup", self.base_url))
147            .send_json(serde_json::json!({ "email": email, "name": name }))
148            .map_err(|e| format!("Request failed: {}", e))?;
149
150        let body: serde_json::Value = resp
151            .into_json()
152            .map_err(|e| format!("Parse error: {}", e))?;
153
154        let user_id = body["user"]["id"]
155            .as_str()
156            .ok_or("Missing user.id in response")?
157            .to_string();
158        let api_key = body["api_key"]
159            .as_str()
160            .ok_or("Missing api_key in response")?
161            .to_string();
162
163        Ok((user_id, api_key))
164    }
165
166    /// Log in with an existing email. Returns a new api_key.
167    pub fn login(&self, email: &str) -> Result<String, String> {
168        let resp = ureq::post(&format!("{}/auth/login", self.base_url))
169            .send_json(serde_json::json!({ "email": email }))
170            .map_err(|e| format!("Request failed: {}", e))?;
171
172        let body: serde_json::Value = resp
173            .into_json()
174            .map_err(|e| format!("Parse error: {}", e))?;
175
176        body["api_key"]
177            .as_str()
178            .map(|s| s.to_string())
179            .ok_or("Missing api_key in response".to_string())
180    }
181
182    // ── Teams ──
183
184    pub fn create_team(&self, api_key: &str, name: &str) -> Result<hub::Team, String> {
185        let resp = ureq::post(&format!("{}/teams", self.base_url))
186            .set("Authorization", &format!("Bearer {}", api_key))
187            .send_json(serde_json::json!({ "name": name }))
188            .map_err(|e| format!("Request failed: {}", e))?;
189
190        resp.into_json().map_err(|e| format!("Parse error: {}", e))
191    }
192
193    pub fn list_teams(&self, api_key: &str) -> Result<Vec<hub::Team>, String> {
194        let resp = ureq::get(&format!("{}/teams", self.base_url))
195            .set("Authorization", &format!("Bearer {}", api_key))
196            .call()
197            .map_err(|e| format!("Request failed: {}", e))?;
198
199        resp.into_json().map_err(|e| format!("Parse error: {}", e))
200    }
201
202    pub fn invite(
203        &self,
204        api_key: &str,
205        team_id: &str,
206        email: Option<&str>,
207    ) -> Result<String, String> {
208        let resp = ureq::post(&format!("{}/teams/{}/invite", self.base_url, team_id))
209            .set("Authorization", &format!("Bearer {}", api_key))
210            .send_json(serde_json::json!({ "email": email }))
211            .map_err(|e| format!("Request failed: {}", e))?;
212
213        let body: serde_json::Value = resp
214            .into_json()
215            .map_err(|e| format!("Parse error: {}", e))?;
216
217        body["token"]
218            .as_str()
219            .map(|s| s.to_string())
220            .ok_or("Missing token in response".to_string())
221    }
222
223    pub fn join_team(&self, api_key: &str, token: &str) -> Result<(), String> {
224        ureq::post(&format!("{}/teams/join", self.base_url))
225            .set("Authorization", &format!("Bearer {}", api_key))
226            .send_json(serde_json::json!({ "token": token }))
227            .map_err(|e| format!("Request failed: {}", e))?;
228        Ok(())
229    }
230
231    pub fn list_members(
232        &self,
233        api_key: &str,
234        team_id: &str,
235    ) -> Result<Vec<hub::TeamMember>, String> {
236        let resp = ureq::get(&format!("{}/teams/{}/members", self.base_url, team_id))
237            .set("Authorization", &format!("Bearer {}", api_key))
238            .call()
239            .map_err(|e| format!("Request failed: {}", e))?;
240
241        resp.into_json().map_err(|e| format!("Parse error: {}", e))
242    }
243
244    pub fn kick_member(
245        &self,
246        api_key: &str,
247        team_id: &str,
248        user_id: &str,
249    ) -> Result<(), String> {
250        ureq::post(&format!("{}/teams/{}/kick", self.base_url, team_id))
251            .set("Authorization", &format!("Bearer {}", api_key))
252            .send_json(serde_json::json!({ "user_id": user_id }))
253            .map_err(|e| format!("Request failed: {}", e))?;
254        Ok(())
255    }
256
257    // ── Channels ──
258
259    pub fn create_channel(
260        &self,
261        api_key: &str,
262        team_id: &str,
263        name: &str,
264    ) -> Result<hub::Channel, String> {
265        let resp = ureq::post(&format!(
266            "{}/teams/{}/channels",
267            self.base_url, team_id
268        ))
269        .set("Authorization", &format!("Bearer {}", api_key))
270        .send_json(serde_json::json!({ "name": name }))
271        .map_err(|e| format!("Request failed: {}", e))?;
272
273        resp.into_json().map_err(|e| format!("Parse error: {}", e))
274    }
275
276    pub fn list_channels(
277        &self,
278        api_key: &str,
279        team_id: &str,
280    ) -> Result<Vec<hub::Channel>, String> {
281        let resp = ureq::get(&format!(
282            "{}/teams/{}/channels",
283            self.base_url, team_id
284        ))
285        .set("Authorization", &format!("Bearer {}", api_key))
286        .call()
287        .map_err(|e| format!("Request failed: {}", e))?;
288
289        resp.into_json().map_err(|e| format!("Parse error: {}", e))
290    }
291}