1use crate::{PrismerClient, types::*};
2use serde_json::json;
3
4pub struct IMClient<'a> {
5 client: &'a PrismerClient,
6 token: Option<String>,
7}
8
9impl<'a> IMClient<'a> {
10 pub fn new(client: &'a PrismerClient) -> Self {
11 Self { client, token: None }
12 }
13
14 async fn im_request<T: serde::de::DeserializeOwned>(
18 &self,
19 method: reqwest::Method,
20 path: &str,
21 body: Option<serde_json::Value>,
22 ) -> Result<ApiResponse<T>, PrismerError> {
23 let body = if method == reqwest::Method::POST && path.contains("/messages") {
24 if let Some(mut b) = body {
25 if b.get("signature").is_none() {
27 let content = b.get("content").and_then(|v| v.as_str()).unwrap_or("");
28 let msg_type = b.get("type").and_then(|v| v.as_str()).unwrap_or("text");
29 if let Some((content_hash, signature, sender_did, timestamp)) =
30 self.client.sign_message(content, msg_type)
31 {
32 b["secVersion"] = json!(1);
33 b["senderDid"] = json!(sender_did);
34 b["contentHash"] = json!(content_hash);
35 b["signature"] = json!(signature);
36 b["signedAt"] = json!(timestamp);
37 }
38 }
39 Some(b)
40 } else {
41 None
42 }
43 } else {
44 body
45 };
46 self.client.request(method, path, body).await
47 }
48
49 pub async fn health(&self) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
51 self.im_request(reqwest::Method::GET, "/api/im/health", None).await
52 }
53
54 pub async fn register(&mut self, username: &str, display_name: &str, agent_type: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
56 let res: ApiResponse<serde_json::Value> = self.im_request(
57 reqwest::Method::POST,
58 "/api/im/register",
59 Some(json!({
60 "type": agent_type,
61 "username": username,
62 "displayName": display_name,
63 })),
64 ).await?;
65 if let Some(data) = &res.data {
66 if let Some(t) = data.get("token").and_then(|v| v.as_str()) {
67 self.token = Some(t.to_string());
68 }
69 }
70 Ok(res)
71 }
72
73 pub async fn discover(&self) -> Result<ApiResponse<Vec<serde_json::Value>>, PrismerError> {
75 self.im_request(reqwest::Method::GET, "/api/im/discover", None).await
76 }
77
78 pub async fn send_message(&self, user_id: &str, content: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
80 self.im_request(
81 reqwest::Method::POST,
82 &format!("/api/im/direct/{}/messages", user_id),
83 Some(json!({ "content": content })),
84 ).await
85 }
86
87 pub async fn send_message_with_options(&self, user_id: &str, content: &str, options: SendMessageOptions) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
89 let mut body = json!({ "content": content });
90 if let Some(t) = &options.msg_type {
91 body["type"] = json!(t);
92 }
93 if let Some(m) = &options.metadata {
94 body["metadata"] = m.clone();
95 }
96 if let Some(p) = &options.parent_id {
97 body["parentId"] = json!(p);
98 }
99 if let Some(q) = &options.quoted_message_id {
100 body["quotedMessageId"] = json!(q);
101 }
102 self.im_request(
103 reqwest::Method::POST,
104 &format!("/api/im/direct/{}/messages", user_id),
105 Some(body),
106 ).await
107 }
108
109 pub async fn create_group(&self, title: &str, members: &[&str], description: Option<&str>) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
113 let mut body = json!({ "title": title, "members": members });
114 if let Some(d) = description {
115 body["description"] = json!(d);
116 }
117 self.im_request(reqwest::Method::POST, "/api/im/groups", Some(body)).await
118 }
119
120 pub async fn list_groups(&self) -> Result<ApiResponse<Vec<serde_json::Value>>, PrismerError> {
122 self.im_request(reqwest::Method::GET, "/api/im/groups", None).await
123 }
124
125 pub async fn get_group(&self, group_id: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
127 self.im_request(reqwest::Method::GET, &format!("/api/im/groups/{}", group_id), None).await
128 }
129
130 pub async fn send_group_message(&self, group_id: &str, content: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
132 self.im_request(
133 reqwest::Method::POST,
134 &format!("/api/im/groups/{}/messages", group_id),
135 Some(json!({ "content": content })),
136 ).await
137 }
138
139 pub async fn send_group_message_with_options(&self, group_id: &str, content: &str, options: SendMessageOptions) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
141 let mut body = json!({ "content": content });
142 if let Some(t) = &options.msg_type {
143 body["type"] = json!(t);
144 }
145 if let Some(m) = &options.metadata {
146 body["metadata"] = m.clone();
147 }
148 if let Some(p) = &options.parent_id {
149 body["parentId"] = json!(p);
150 }
151 if let Some(q) = &options.quoted_message_id {
152 body["quotedMessageId"] = json!(q);
153 }
154 self.im_request(
155 reqwest::Method::POST,
156 &format!("/api/im/groups/{}/messages", group_id),
157 Some(body),
158 ).await
159 }
160
161 pub async fn get_group_messages(&self, group_id: &str, limit: Option<u32>, offset: Option<u32>) -> Result<ApiResponse<Vec<serde_json::Value>>, PrismerError> {
163 let mut query = String::new();
164 let mut sep = '?';
165 if let Some(l) = limit {
166 query.push_str(&format!("{}limit={}", sep, l));
167 sep = '&';
168 }
169 if let Some(o) = offset {
170 query.push_str(&format!("{}offset={}", sep, o));
171 }
172 self.im_request(reqwest::Method::GET, &format!("/api/im/groups/{}/messages{}", group_id, query), None).await
173 }
174
175 pub async fn add_group_member(&self, group_id: &str, user_id: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
177 self.im_request(
178 reqwest::Method::POST,
179 &format!("/api/im/groups/{}/members", group_id),
180 Some(json!({ "userId": user_id })),
181 ).await
182 }
183
184 pub async fn remove_group_member(&self, group_id: &str, user_id: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
186 self.im_request(
187 reqwest::Method::DELETE,
188 &format!("/api/im/groups/{}/members/{}", group_id, user_id),
189 None,
190 ).await
191 }
192
193 pub async fn send_conversation_message(&self, conversation_id: &str, content: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
197 self.im_request(
198 reqwest::Method::POST,
199 &format!("/api/im/messages/{}", conversation_id),
200 Some(json!({ "content": content })),
201 ).await
202 }
203
204 pub async fn send_conversation_message_with_options(&self, conversation_id: &str, content: &str, options: SendMessageOptions) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
206 let mut body = json!({ "content": content });
207 if let Some(t) = &options.msg_type {
208 body["type"] = json!(t);
209 }
210 if let Some(m) = &options.metadata {
211 body["metadata"] = m.clone();
212 }
213 if let Some(p) = &options.parent_id {
214 body["parentId"] = json!(p);
215 }
216 if let Some(q) = &options.quoted_message_id {
217 body["quotedMessageId"] = json!(q);
218 }
219 self.im_request(
220 reqwest::Method::POST,
221 &format!("/api/im/messages/{}", conversation_id),
222 Some(body),
223 ).await
224 }
225
226 pub async fn get_conversation_messages(&self, conversation_id: &str, limit: Option<u32>, offset: Option<u32>) -> Result<ApiResponse<Vec<serde_json::Value>>, PrismerError> {
228 let mut query = String::new();
229 let mut sep = '?';
230 if let Some(l) = limit {
231 query.push_str(&format!("{}limit={}", sep, l));
232 sep = '&';
233 }
234 if let Some(o) = offset {
235 query.push_str(&format!("{}offset={}", sep, o));
236 }
237 self.im_request(reqwest::Method::GET, &format!("/api/im/messages/{}{}", conversation_id, query), None).await
238 }
239
240 pub async fn edit_message(&self, conversation_id: &str, message_id: &str, content: &str, metadata: Option<serde_json::Value>) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
244 let mut body = json!({ "content": content });
245 if let Some(m) = metadata {
246 body["metadata"] = m;
247 }
248 self.im_request(
249 reqwest::Method::PATCH,
250 &format!("/api/im/messages/{}/{}", conversation_id, message_id),
251 Some(body),
252 ).await
253 }
254
255 pub async fn delete_message(&self, conversation_id: &str, message_id: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
257 self.im_request(
258 reqwest::Method::DELETE,
259 &format!("/api/im/messages/{}/{}", conversation_id, message_id),
260 None,
261 ).await
262 }
263
264 pub async fn react_message(
269 &self,
270 conversation_id: &str,
271 message_id: &str,
272 emoji: &str,
273 remove: bool,
274 ) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
275 let mut body = serde_json::json!({ "emoji": emoji });
276 if remove {
277 body["remove"] = serde_json::Value::Bool(true);
278 }
279 self.im_request(
280 reqwest::Method::POST,
281 &format!("/api/im/messages/{}/{}/reactions", conversation_id, message_id),
282 Some(body),
283 ).await
284 }
285
286 pub async fn conversations(&self) -> Result<ApiResponse<Vec<serde_json::Value>>, PrismerError> {
288 self.im_request(reqwest::Method::GET, "/api/im/conversations", None).await
289 }
290
291 pub async fn me(&self) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
293 self.im_request(reqwest::Method::GET, "/api/im/me", None).await
294 }
295
296 pub async fn contacts(&self) -> Result<ApiResponse<Vec<serde_json::Value>>, PrismerError> {
298 self.im_request(reqwest::Method::GET, "/api/im/contacts", None).await
299 }
300
301 pub async fn credits(&self) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
303 self.im_request(reqwest::Method::GET, "/api/im/credits", None).await
304 }
305
306 pub async fn transactions(&self, limit: u32) -> Result<ApiResponse<Vec<serde_json::Value>>, PrismerError> {
308 self.im_request(reqwest::Method::GET, &format!("/api/im/credits/transactions?limit={}", limit), None).await
309 }
310
311 pub async fn recall(&self, query: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
313 self.im_request(
314 reqwest::Method::POST,
315 "/api/im/recall",
316 Some(json!({ "query": query })),
317 ).await
318 }
319
320 pub async fn get_conversation_security(&self, conversation_id: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
324 self.im_request(
325 reqwest::Method::GET,
326 &format!("/api/im/conversations/{}/security", conversation_id),
327 None,
328 ).await
329 }
330
331 pub async fn set_conversation_security(
333 &self,
334 conversation_id: &str,
335 signing_policy: Option<&str>,
336 encryption_mode: Option<&str>,
337 ) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
338 let mut body = json!({});
339 if let Some(sp) = signing_policy { body["signingPolicy"] = json!(sp); }
340 if let Some(em) = encryption_mode { body["encryptionMode"] = json!(em); }
341 self.im_request(
342 reqwest::Method::PATCH,
343 &format!("/api/im/conversations/{}/security", conversation_id),
344 Some(body),
345 ).await
346 }
347
348 pub async fn upload_key(
350 &self,
351 conversation_id: &str,
352 public_key: &str,
353 algorithm: Option<&str>,
354 ) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
355 let mut body = json!({ "publicKey": public_key });
356 if let Some(a) = algorithm { body["algorithm"] = json!(a); }
357 self.im_request(
358 reqwest::Method::POST,
359 &format!("/api/im/conversations/{}/keys", conversation_id),
360 Some(body),
361 ).await
362 }
363
364 pub async fn get_keys(&self, conversation_id: &str) -> Result<ApiResponse<Vec<serde_json::Value>>, PrismerError> {
366 self.im_request(
367 reqwest::Method::GET,
368 &format!("/api/im/conversations/{}/keys", conversation_id),
369 None,
370 ).await
371 }
372
373 pub async fn revoke_key(&self, conversation_id: &str, key_user_id: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
375 self.im_request(
376 reqwest::Method::DELETE,
377 &format!("/api/im/conversations/{}/keys/{}", conversation_id, key_user_id),
378 None,
379 ).await
380 }
381
382 pub async fn send_friend_request(&self, user_id: &str, reason: Option<&str>) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
386 let mut body = json!({ "userId": user_id });
387 if let Some(r) = reason {
388 body["reason"] = json!(r);
389 }
390 self.im_request(
391 reqwest::Method::POST,
392 "/api/im/contacts/request",
393 Some(body),
394 ).await
395 }
396
397 pub async fn pending_requests_received(&self) -> Result<ApiResponse<Vec<serde_json::Value>>, PrismerError> {
399 self.im_request(
400 reqwest::Method::GET,
401 "/api/im/contacts/requests/received",
402 None,
403 ).await
404 }
405
406 pub async fn pending_requests_sent(&self) -> Result<ApiResponse<Vec<serde_json::Value>>, PrismerError> {
408 self.im_request(
409 reqwest::Method::GET,
410 "/api/im/contacts/requests/sent",
411 None,
412 ).await
413 }
414
415 pub async fn accept_friend_request(&self, request_id: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
417 self.im_request(
418 reqwest::Method::POST,
419 &format!("/api/im/contacts/requests/{}/accept", request_id),
420 Some(json!({})),
421 ).await
422 }
423
424 pub async fn reject_friend_request(&self, request_id: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
426 self.im_request(
427 reqwest::Method::POST,
428 &format!("/api/im/contacts/requests/{}/reject", request_id),
429 Some(json!({})),
430 ).await
431 }
432
433 pub async fn friends(&self) -> Result<ApiResponse<Vec<serde_json::Value>>, PrismerError> {
435 self.im_request(
436 reqwest::Method::GET,
437 "/api/im/contacts/friends",
438 None,
439 ).await
440 }
441
442 pub async fn remove_friend(&self, user_id: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
444 self.im_request(
445 reqwest::Method::DELETE,
446 &format!("/api/im/contacts/{}/remove", user_id),
447 None,
448 ).await
449 }
450
451 pub async fn set_friend_remark(&self, user_id: &str, remark: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
453 self.im_request(
454 reqwest::Method::PATCH,
455 &format!("/api/im/contacts/{}/remark", user_id),
456 Some(json!({ "remark": remark })),
457 ).await
458 }
459
460 pub async fn block_user(&self, user_id: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
462 self.im_request(
463 reqwest::Method::POST,
464 &format!("/api/im/contacts/{}/block", user_id),
465 Some(json!({})),
466 ).await
467 }
468
469 pub async fn unblock_user(&self, user_id: &str) -> Result<ApiResponse<serde_json::Value>, PrismerError> {
471 self.im_request(
472 reqwest::Method::DELETE,
473 &format!("/api/im/contacts/{}/block", user_id),
474 None,
475 ).await
476 }
477
478 pub async fn blocked_list(&self) -> Result<ApiResponse<Vec<serde_json::Value>>, PrismerError> {
480 self.im_request(
481 reqwest::Method::GET,
482 "/api/im/contacts/blocked",
483 None,
484 ).await
485 }
486}
487
488#[derive(Default)]
490pub struct SendMessageOptions {
491 pub msg_type: Option<String>,
492 pub metadata: Option<serde_json::Value>,
493 pub parent_id: Option<String>,
494 pub quoted_message_id: Option<String>,
495}