1use 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 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 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 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 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}