simploxide_api_types/client_api.rs
1use crate::{commands::*, responses::*, utils::CommandSyntax, *};
2use std::future::Future;
3use std::sync::Arc;
4
5/// A helper trait to handle different response wrappers
6pub trait ExtractResponse<'de, T>: Deserialize<'de> {
7 fn extract_response(self) -> Result<T, BadResponseError>;
8}
9
10pub trait ClientApiError: From<BadResponseError> + std::error::Error {
11 /// If current error is a bad response error return a reference to it
12 fn bad_response(&self) -> Option<&BadResponseError>;
13
14 /// If current error is a bad response error return a mut reference to it
15 fn bad_response_mut(&mut self) -> Option<&mut BadResponseError>;
16}
17
18pub trait ClientApi: Sync {
19 type ResponseShape<'de, T>: ExtractResponse<'de, T>
20 where
21 T: 'de + Deserialize<'de>;
22 type Error: ClientApiError;
23
24 fn send_raw(&self, command: String)
25 -> impl Future<Output = Result<String, Self::Error>> + Send;
26
27 fn send<C, R>(&self, cmd: C) -> impl Future<Output = Result<R, Self::Error>> + Send
28 where
29 C: Send + CommandSyntax,
30 R: for<'de> Deserialize<'de>,
31 {
32 async move {
33 let raw = self.send_raw(cmd.to_command_string()).await?;
34 let response_shape: Self::ResponseShape<'_, R> =
35 serde_json::from_str(&raw).map_err(BadResponseError::InvalidJson)?;
36 let response = response_shape.extract_response()?;
37 Ok(response)
38 }
39 }
40
41 /// ### Address commands
42 ///
43 /// Bots can use these commands to automatically check and create address when initialized
44 ///
45 /// ----
46 ///
47 /// Create bot address.
48 ///
49 /// *Network usage*: interactive.
50 ///
51 /// *Syntax:*
52 ///
53 /// ```
54 /// /_address <userId>
55 /// ```
56 fn api_create_my_address(
57 &self,
58 user_id: i64,
59 ) -> impl Future<Output = Result<Arc<UserContactLinkCreatedResponse>, Self::Error>> + Send {
60 async move {
61 let command = ApiCreateMyAddress { user_id };
62 let response: ApiCreateMyAddressResponse = self.send(command).await?;
63 Ok(response.into_inner())
64 }
65 }
66
67 /// ### Address commands
68 ///
69 /// Bots can use these commands to automatically check and create address when initialized
70 ///
71 /// ----
72 ///
73 /// Delete bot address.
74 ///
75 /// *Network usage*: background.
76 ///
77 /// *Syntax:*
78 ///
79 /// ```
80 /// /_delete_address <userId>
81 /// ```
82 fn api_delete_my_address(
83 &self,
84 user_id: i64,
85 ) -> impl Future<Output = Result<Arc<UserContactLinkDeletedResponse>, Self::Error>> + Send {
86 async move {
87 let command = ApiDeleteMyAddress { user_id };
88 let response: ApiDeleteMyAddressResponse = self.send(command).await?;
89 Ok(response.into_inner())
90 }
91 }
92
93 /// ### Address commands
94 ///
95 /// Bots can use these commands to automatically check and create address when initialized
96 ///
97 /// ----
98 ///
99 /// Get bot address and settings.
100 ///
101 /// *Network usage*: no.
102 ///
103 /// *Syntax:*
104 ///
105 /// ```
106 /// /_show_address <userId>
107 /// ```
108 fn api_show_my_address(
109 &self,
110 user_id: i64,
111 ) -> impl Future<Output = Result<Arc<UserContactLinkResponse>, Self::Error>> + Send {
112 async move {
113 let command = ApiShowMyAddress { user_id };
114 let response: ApiShowMyAddressResponse = self.send(command).await?;
115 Ok(response.into_inner())
116 }
117 }
118
119 /// ### Address commands
120 ///
121 /// Bots can use these commands to automatically check and create address when initialized
122 ///
123 /// ----
124 ///
125 /// Add address to bot profile.
126 ///
127 /// *Network usage*: interactive.
128 ///
129 /// *Syntax:*
130 ///
131 /// ```
132 /// /_profile_address <userId> on|off
133 /// ```
134 fn api_set_profile_address(
135 &self,
136 command: ApiSetProfileAddress,
137 ) -> impl Future<Output = Result<Arc<UserProfileUpdatedResponse>, Self::Error>> + Send {
138 async move {
139 let response: ApiSetProfileAddressResponse = self.send(command).await?;
140 Ok(response.into_inner())
141 }
142 }
143
144 /// ### Address commands
145 ///
146 /// Bots can use these commands to automatically check and create address when initialized
147 ///
148 /// ----
149 ///
150 /// Set bot address settings.
151 ///
152 /// *Network usage*: interactive.
153 ///
154 /// *Syntax:*
155 ///
156 /// ```
157 /// /_address_settings <userId> <json(settings)>
158 /// ```
159 fn api_set_address_settings(
160 &self,
161 user_id: i64,
162 settings: AddressSettings,
163 ) -> impl Future<Output = Result<Arc<UserContactLinkUpdatedResponse>, Self::Error>> + Send {
164 async move {
165 let command = ApiSetAddressSettings { user_id, settings };
166 let response: ApiSetAddressSettingsResponse = self.send(command).await?;
167 Ok(response.into_inner())
168 }
169 }
170
171 /// ### Message commands
172 ///
173 /// Commands to send, update, delete, moderate messages and set message reactions
174 ///
175 /// ----
176 ///
177 /// Send messages.
178 ///
179 /// *Network usage*: background.
180 ///
181 /// *Syntax:*
182 ///
183 /// ```
184 /// /_send <str(sendRef)>[ live=on][ ttl=<ttl>] json <json(composedMessages)>
185 /// ```
186 fn api_send_messages(
187 &self,
188 command: ApiSendMessages,
189 ) -> impl Future<Output = Result<Arc<NewChatItemsResponse>, Self::Error>> + Send {
190 async move {
191 let response: ApiSendMessagesResponse = self.send(command).await?;
192 Ok(response.into_inner())
193 }
194 }
195
196 /// ### Message commands
197 ///
198 /// Commands to send, update, delete, moderate messages and set message reactions
199 ///
200 /// ----
201 ///
202 /// Update message.
203 ///
204 /// *Network usage*: background.
205 ///
206 /// *Syntax:*
207 ///
208 /// ```
209 /// /_update item <str(chatRef)> <chatItemId>[ live=on] json <json(updatedMessage)>
210 /// ```
211 fn api_update_chat_item(
212 &self,
213 command: ApiUpdateChatItem,
214 ) -> impl Future<Output = Result<ApiUpdateChatItemResponse, Self::Error>> + Send {
215 async move {
216 let response: ApiUpdateChatItemResponse = self.send(command).await?;
217 Ok(response)
218 }
219 }
220
221 /// ### Message commands
222 ///
223 /// Commands to send, update, delete, moderate messages and set message reactions
224 ///
225 /// ----
226 ///
227 /// Delete message.
228 ///
229 /// *Network usage*: background.
230 ///
231 /// *Syntax:*
232 ///
233 /// ```
234 /// /_delete item <str(chatRef)> <chatItemIds[0]>[,<chatItemIds[1]>...] broadcast|internal|internalMark|history
235 /// ```
236 fn api_delete_chat_item(
237 &self,
238 chat_ref: ChatRef,
239 chat_item_ids: Vec<i64>,
240 delete_mode: CIDeleteMode,
241 ) -> impl Future<Output = Result<Arc<ChatItemsDeletedResponse>, Self::Error>> + Send {
242 async move {
243 let command = ApiDeleteChatItem {
244 chat_ref,
245 chat_item_ids,
246 delete_mode,
247 };
248 let response: ApiDeleteChatItemResponse = self.send(command).await?;
249 Ok(response.into_inner())
250 }
251 }
252
253 /// ### Message commands
254 ///
255 /// Commands to send, update, delete, moderate messages and set message reactions
256 ///
257 /// ----
258 ///
259 /// Moderate message. Requires Moderator role (and higher than message author's).
260 ///
261 /// *Network usage*: background.
262 ///
263 /// *Syntax:*
264 ///
265 /// ```
266 /// /_delete member item #<groupId> <chatItemIds[0]>[,<chatItemIds[1]>...]
267 /// ```
268 fn api_delete_member_chat_item(
269 &self,
270 group_id: i64,
271 chat_item_ids: Vec<i64>,
272 ) -> impl Future<Output = Result<Arc<ChatItemsDeletedResponse>, Self::Error>> + Send {
273 async move {
274 let command = ApiDeleteMemberChatItem {
275 group_id,
276 chat_item_ids,
277 };
278 let response: ApiDeleteMemberChatItemResponse = self.send(command).await?;
279 Ok(response.into_inner())
280 }
281 }
282
283 /// ### Message commands
284 ///
285 /// Commands to send, update, delete, moderate messages and set message reactions
286 ///
287 /// ----
288 ///
289 /// Add/remove message reaction.
290 ///
291 /// *Network usage*: background.
292 ///
293 /// *Syntax:*
294 ///
295 /// ```
296 /// /_reaction <str(chatRef)> <chatItemId> on|off <json(reaction)>
297 /// ```
298 fn api_chat_item_reaction(
299 &self,
300 command: ApiChatItemReaction,
301 ) -> impl Future<Output = Result<Arc<ChatItemReactionResponse>, Self::Error>> + Send {
302 async move {
303 let response: ApiChatItemReactionResponse = self.send(command).await?;
304 Ok(response.into_inner())
305 }
306 }
307
308 /// ### File commands
309 ///
310 /// Commands to receive and to cancel files. Files are sent as part of the message, there are no separate commands to send files.
311 ///
312 /// ----
313 ///
314 /// Receive file.
315 ///
316 /// *Network usage*: no.
317 ///
318 /// *Syntax:*
319 ///
320 /// ```
321 /// /freceive <fileId>[ approved_relays=on][ encrypt=on|off][ inline=on|off][ <filePath>]
322 /// ```
323 fn receive_file(
324 &self,
325 command: ReceiveFile,
326 ) -> impl Future<Output = Result<ReceiveFileResponse, Self::Error>> + Send {
327 async move {
328 let response: ReceiveFileResponse = self.send(command).await?;
329 Ok(response)
330 }
331 }
332
333 /// ### File commands
334 ///
335 /// Commands to receive and to cancel files. Files are sent as part of the message, there are no separate commands to send files.
336 ///
337 /// ----
338 ///
339 /// Cancel file.
340 ///
341 /// *Network usage*: background.
342 ///
343 /// *Syntax:*
344 ///
345 /// ```
346 /// /fcancel <fileId>
347 /// ```
348 fn cancel_file(
349 &self,
350 file_id: i64,
351 ) -> impl Future<Output = Result<CancelFileResponse, Self::Error>> + Send {
352 async move {
353 let command = CancelFile { file_id };
354 let response: CancelFileResponse = self.send(command).await?;
355 Ok(response)
356 }
357 }
358
359 /// ### Group commands
360 ///
361 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
362 ///
363 /// ----
364 ///
365 /// Add contact to group. Requires bot to have Admin role.
366 ///
367 /// *Network usage*: interactive.
368 ///
369 /// *Syntax:*
370 ///
371 /// ```
372 /// /_add #<groupId> <contactId> relay|observer|author|member|moderator|admin|owner
373 /// ```
374 fn api_add_member(
375 &self,
376 group_id: i64,
377 contact_id: i64,
378 member_role: GroupMemberRole,
379 ) -> impl Future<Output = Result<Arc<SentGroupInvitationResponse>, Self::Error>> + Send {
380 async move {
381 let command = ApiAddMember {
382 group_id,
383 contact_id,
384 member_role,
385 };
386 let response: ApiAddMemberResponse = self.send(command).await?;
387 Ok(response.into_inner())
388 }
389 }
390
391 /// ### Group commands
392 ///
393 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
394 ///
395 /// ----
396 ///
397 /// Join group.
398 ///
399 /// *Network usage*: interactive.
400 ///
401 /// *Syntax:*
402 ///
403 /// ```
404 /// /_join #<groupId>
405 /// ```
406 fn api_join_group(
407 &self,
408 group_id: i64,
409 ) -> impl Future<Output = Result<Arc<UserAcceptedGroupSentResponse>, Self::Error>> + Send {
410 async move {
411 let command = ApiJoinGroup { group_id };
412 let response: ApiJoinGroupResponse = self.send(command).await?;
413 Ok(response.into_inner())
414 }
415 }
416
417 /// ### Group commands
418 ///
419 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
420 ///
421 /// ----
422 ///
423 /// Accept group member. Requires Admin role.
424 ///
425 /// *Network usage*: background.
426 ///
427 /// *Syntax:*
428 ///
429 /// ```
430 /// /_accept member #<groupId> <groupMemberId> relay|observer|author|member|moderator|admin|owner
431 /// ```
432 fn api_accept_member(
433 &self,
434 group_id: i64,
435 group_member_id: i64,
436 member_role: GroupMemberRole,
437 ) -> impl Future<Output = Result<Arc<MemberAcceptedResponse>, Self::Error>> + Send {
438 async move {
439 let command = ApiAcceptMember {
440 group_id,
441 group_member_id,
442 member_role,
443 };
444 let response: ApiAcceptMemberResponse = self.send(command).await?;
445 Ok(response.into_inner())
446 }
447 }
448
449 /// ### Group commands
450 ///
451 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
452 ///
453 /// ----
454 ///
455 /// Set members role. Requires Admin role.
456 ///
457 /// *Network usage*: background.
458 ///
459 /// *Syntax:*
460 ///
461 /// ```
462 /// /_member role #<groupId> <groupMemberIds[0]>[,<groupMemberIds[1]>...] relay|observer|author|member|moderator|admin|owner
463 /// ```
464 fn api_members_role(
465 &self,
466 group_id: i64,
467 group_member_ids: Vec<i64>,
468 member_role: GroupMemberRole,
469 ) -> impl Future<Output = Result<Arc<MembersRoleUserResponse>, Self::Error>> + Send {
470 async move {
471 let command = ApiMembersRole {
472 group_id,
473 group_member_ids,
474 member_role,
475 };
476 let response: ApiMembersRoleResponse = self.send(command).await?;
477 Ok(response.into_inner())
478 }
479 }
480
481 /// ### Group commands
482 ///
483 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
484 ///
485 /// ----
486 ///
487 /// Block members. Requires Moderator role.
488 ///
489 /// *Network usage*: background.
490 ///
491 /// *Syntax:*
492 ///
493 /// ```
494 /// /_block #<groupId> <groupMemberIds[0]>[,<groupMemberIds[1]>...] blocked=on|off
495 /// ```
496 fn api_block_members_for_all(
497 &self,
498 command: ApiBlockMembersForAll,
499 ) -> impl Future<Output = Result<Arc<MembersBlockedForAllUserResponse>, Self::Error>> + Send
500 {
501 async move {
502 let response: ApiBlockMembersForAllResponse = self.send(command).await?;
503 Ok(response.into_inner())
504 }
505 }
506
507 /// ### Group commands
508 ///
509 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
510 ///
511 /// ----
512 ///
513 /// Remove members. Requires Admin role.
514 ///
515 /// *Network usage*: background.
516 ///
517 /// *Syntax:*
518 ///
519 /// ```
520 /// /_remove #<groupId> <groupMemberIds[0]>[,<groupMemberIds[1]>...][ messages=on]
521 /// ```
522 fn api_remove_members(
523 &self,
524 command: ApiRemoveMembers,
525 ) -> impl Future<Output = Result<Arc<UserDeletedMembersResponse>, Self::Error>> + Send {
526 async move {
527 let response: ApiRemoveMembersResponse = self.send(command).await?;
528 Ok(response.into_inner())
529 }
530 }
531
532 /// ### Group commands
533 ///
534 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
535 ///
536 /// ----
537 ///
538 /// Leave group.
539 ///
540 /// *Network usage*: background.
541 ///
542 /// *Syntax:*
543 ///
544 /// ```
545 /// /_leave #<groupId>
546 /// ```
547 fn api_leave_group(
548 &self,
549 group_id: i64,
550 ) -> impl Future<Output = Result<Arc<LeftMemberUserResponse>, Self::Error>> + Send {
551 async move {
552 let command = ApiLeaveGroup { group_id };
553 let response: ApiLeaveGroupResponse = self.send(command).await?;
554 Ok(response.into_inner())
555 }
556 }
557
558 /// ### Group commands
559 ///
560 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
561 ///
562 /// ----
563 ///
564 /// Get group members.
565 ///
566 /// *Network usage*: no.
567 ///
568 /// *Syntax:*
569 ///
570 /// ```
571 /// /_members #<groupId>
572 /// ```
573 fn api_list_members(
574 &self,
575 group_id: i64,
576 ) -> impl Future<Output = Result<Arc<GroupMembersResponse>, Self::Error>> + Send {
577 async move {
578 let command = ApiListMembers { group_id };
579 let response: ApiListMembersResponse = self.send(command).await?;
580 Ok(response.into_inner())
581 }
582 }
583
584 /// ### Group commands
585 ///
586 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
587 ///
588 /// ----
589 ///
590 /// Create group.
591 ///
592 /// *Network usage*: no.
593 ///
594 /// *Syntax:*
595 ///
596 /// ```
597 /// /_group <userId>[ incognito=on] <json(groupProfile)>
598 /// ```
599 fn api_new_group(
600 &self,
601 command: ApiNewGroup,
602 ) -> impl Future<Output = Result<Arc<GroupCreatedResponse>, Self::Error>> + Send {
603 async move {
604 let response: ApiNewGroupResponse = self.send(command).await?;
605 Ok(response.into_inner())
606 }
607 }
608
609 /// ### Group commands
610 ///
611 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
612 ///
613 /// ----
614 ///
615 /// Create public group.
616 ///
617 /// *Network usage*: interactive.
618 ///
619 /// *Syntax:*
620 ///
621 /// ```
622 /// /_public group <userId>[ incognito=on] <relayIds[0]>[,<relayIds[1]>...] <json(groupProfile)>
623 /// ```
624 fn api_new_public_group(
625 &self,
626 command: ApiNewPublicGroup,
627 ) -> impl Future<Output = Result<ApiNewPublicGroupResponse, Self::Error>> + Send {
628 async move {
629 let response: ApiNewPublicGroupResponse = self.send(command).await?;
630 Ok(response)
631 }
632 }
633
634 /// ### Group commands
635 ///
636 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
637 ///
638 /// ----
639 ///
640 /// Get group relays.
641 ///
642 /// *Network usage*: no.
643 ///
644 /// *Syntax:*
645 ///
646 /// ```
647 /// /_get relays #<groupId>
648 /// ```
649 fn api_get_group_relays(
650 &self,
651 group_id: i64,
652 ) -> impl Future<Output = Result<Arc<GroupRelaysResponse>, Self::Error>> + Send {
653 async move {
654 let command = ApiGetGroupRelays { group_id };
655 let response: ApiGetGroupRelaysResponse = self.send(command).await?;
656 Ok(response.into_inner())
657 }
658 }
659
660 /// ### Group commands
661 ///
662 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
663 ///
664 /// ----
665 ///
666 /// Add relays to group.
667 ///
668 /// *Network usage*: interactive.
669 ///
670 /// *Syntax:*
671 ///
672 /// ```
673 /// /_add relays #<groupId> <relayIds[0]>[,<relayIds[1]>...]
674 /// ```
675 fn api_add_group_relays(
676 &self,
677 group_id: i64,
678 relay_ids: Vec<i64>,
679 ) -> impl Future<Output = Result<ApiAddGroupRelaysResponse, Self::Error>> + Send {
680 async move {
681 let command = ApiAddGroupRelays {
682 group_id,
683 relay_ids,
684 };
685 let response: ApiAddGroupRelaysResponse = self.send(command).await?;
686 Ok(response)
687 }
688 }
689
690 /// ### Group commands
691 ///
692 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
693 ///
694 /// ----
695 ///
696 /// Clear relay rejection for a channel (relay operator).
697 ///
698 /// *Network usage*: background.
699 ///
700 /// *Syntax:*
701 ///
702 /// ```
703 /// /_relay allow #<groupId>
704 /// ```
705 fn api_allow_relay_group(
706 &self,
707 group_id: i64,
708 ) -> impl Future<Output = Result<Arc<RelayGroupAllowedResponse>, Self::Error>> + Send {
709 async move {
710 let command = ApiAllowRelayGroup { group_id };
711 let response: ApiAllowRelayGroupResponse = self.send(command).await?;
712 Ok(response.into_inner())
713 }
714 }
715
716 /// ### Group commands
717 ///
718 /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
719 ///
720 /// ----
721 ///
722 /// Update group profile.
723 ///
724 /// *Network usage*: background.
725 ///
726 /// *Syntax:*
727 ///
728 /// ```
729 /// /_group_profile #<groupId> <json(groupProfile)>
730 /// ```
731 fn api_update_group_profile(
732 &self,
733 group_id: i64,
734 group_profile: GroupProfile,
735 ) -> impl Future<Output = Result<Arc<GroupUpdatedResponse>, Self::Error>> + Send {
736 async move {
737 let command = ApiUpdateGroupProfile {
738 group_id,
739 group_profile,
740 };
741 let response: ApiUpdateGroupProfileResponse = self.send(command).await?;
742 Ok(response.into_inner())
743 }
744 }
745
746 /// ### Group link commands
747 ///
748 /// These commands can be used by bots that manage multiple public groups
749 ///
750 /// ----
751 ///
752 /// Create group link.
753 ///
754 /// *Network usage*: interactive.
755 ///
756 /// *Syntax:*
757 ///
758 /// ```
759 /// /_create link #<groupId> relay|observer|author|member|moderator|admin|owner
760 /// ```
761 fn api_create_group_link(
762 &self,
763 group_id: i64,
764 member_role: GroupMemberRole,
765 ) -> impl Future<Output = Result<Arc<GroupLinkCreatedResponse>, Self::Error>> + Send {
766 async move {
767 let command = ApiCreateGroupLink {
768 group_id,
769 member_role,
770 };
771 let response: ApiCreateGroupLinkResponse = self.send(command).await?;
772 Ok(response.into_inner())
773 }
774 }
775
776 /// ### Group link commands
777 ///
778 /// These commands can be used by bots that manage multiple public groups
779 ///
780 /// ----
781 ///
782 /// Set member role for group link.
783 ///
784 /// *Network usage*: no.
785 ///
786 /// *Syntax:*
787 ///
788 /// ```
789 /// /_set link role #<groupId> relay|observer|author|member|moderator|admin|owner
790 /// ```
791 fn api_group_link_member_role(
792 &self,
793 group_id: i64,
794 member_role: GroupMemberRole,
795 ) -> impl Future<Output = Result<Arc<GroupLinkResponse>, Self::Error>> + Send {
796 async move {
797 let command = ApiGroupLinkMemberRole {
798 group_id,
799 member_role,
800 };
801 let response: ApiGroupLinkMemberRoleResponse = self.send(command).await?;
802 Ok(response.into_inner())
803 }
804 }
805
806 /// ### Group link commands
807 ///
808 /// These commands can be used by bots that manage multiple public groups
809 ///
810 /// ----
811 ///
812 /// Delete group link.
813 ///
814 /// *Network usage*: background.
815 ///
816 /// *Syntax:*
817 ///
818 /// ```
819 /// /_delete link #<groupId>
820 /// ```
821 fn api_delete_group_link(
822 &self,
823 group_id: i64,
824 ) -> impl Future<Output = Result<Arc<GroupLinkDeletedResponse>, Self::Error>> + Send {
825 async move {
826 let command = ApiDeleteGroupLink { group_id };
827 let response: ApiDeleteGroupLinkResponse = self.send(command).await?;
828 Ok(response.into_inner())
829 }
830 }
831
832 /// ### Group link commands
833 ///
834 /// These commands can be used by bots that manage multiple public groups
835 ///
836 /// ----
837 ///
838 /// Get group link.
839 ///
840 /// *Network usage*: no.
841 ///
842 /// *Syntax:*
843 ///
844 /// ```
845 /// /_get link #<groupId>
846 /// ```
847 fn api_get_group_link(
848 &self,
849 group_id: i64,
850 ) -> impl Future<Output = Result<Arc<GroupLinkResponse>, Self::Error>> + Send {
851 async move {
852 let command = ApiGetGroupLink { group_id };
853 let response: ApiGetGroupLinkResponse = self.send(command).await?;
854 Ok(response.into_inner())
855 }
856 }
857
858 /// ### Connection commands
859 ///
860 /// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
861 ///
862 /// ----
863 ///
864 /// Create 1-time invitation link.
865 ///
866 /// *Network usage*: interactive.
867 ///
868 /// *Syntax:*
869 ///
870 /// ```
871 /// /_connect <userId>[ incognito=on]
872 /// ```
873 fn api_add_contact(
874 &self,
875 command: ApiAddContact,
876 ) -> impl Future<Output = Result<Arc<InvitationResponse>, Self::Error>> + Send {
877 async move {
878 let response: ApiAddContactResponse = self.send(command).await?;
879 Ok(response.into_inner())
880 }
881 }
882
883 /// ### Connection commands
884 ///
885 /// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
886 ///
887 /// ----
888 ///
889 /// Determine SimpleX link type and if the bot is already connected via this link.
890 ///
891 /// *Network usage*: interactive.
892 ///
893 /// *Syntax:*
894 ///
895 /// ```
896 /// /_connect plan <userId> <connectionLink>
897 /// ```
898 fn api_connect_plan(
899 &self,
900 command: ApiConnectPlan,
901 ) -> impl Future<Output = Result<Arc<ConnectionPlanResponse>, Self::Error>> + Send {
902 async move {
903 let response: ApiConnectPlanResponse = self.send(command).await?;
904 Ok(response.into_inner())
905 }
906 }
907
908 /// ### Connection commands
909 ///
910 /// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
911 ///
912 /// ----
913 ///
914 /// Connect via prepared SimpleX link. The link can be 1-time invitation link, contact address or group link.
915 ///
916 /// *Network usage*: interactive.
917 ///
918 /// *Syntax:*
919 ///
920 /// ```
921 /// /_connect <userId>[ <str(preparedLink_)>]
922 /// ```
923 fn api_connect(
924 &self,
925 command: ApiConnect,
926 ) -> impl Future<Output = Result<ApiConnectResponse, Self::Error>> + Send {
927 async move {
928 let response: ApiConnectResponse = self.send(command).await?;
929 Ok(response)
930 }
931 }
932
933 /// ### Connection commands
934 ///
935 /// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
936 ///
937 /// ----
938 ///
939 /// Connect via SimpleX link as string in the active user profile.
940 ///
941 /// *Network usage*: interactive.
942 ///
943 /// *Syntax:*
944 ///
945 /// ```
946 /// /connect[ <connLink_>]
947 /// ```
948 fn connect(
949 &self,
950 command: Connect,
951 ) -> impl Future<Output = Result<ConnectResponse, Self::Error>> + Send {
952 async move {
953 let response: ConnectResponse = self.send(command).await?;
954 Ok(response)
955 }
956 }
957
958 /// ### Connection commands
959 ///
960 /// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
961 ///
962 /// ----
963 ///
964 /// Accept contact request.
965 ///
966 /// *Network usage*: interactive.
967 ///
968 /// *Syntax:*
969 ///
970 /// ```
971 /// /_accept <contactReqId>
972 /// ```
973 fn api_accept_contact(
974 &self,
975 contact_req_id: i64,
976 ) -> impl Future<Output = Result<Arc<AcceptingContactRequestResponse>, Self::Error>> + Send
977 {
978 async move {
979 let command = ApiAcceptContact { contact_req_id };
980 let response: ApiAcceptContactResponse = self.send(command).await?;
981 Ok(response.into_inner())
982 }
983 }
984
985 /// ### Connection commands
986 ///
987 /// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
988 ///
989 /// ----
990 ///
991 /// Reject contact request. The user who sent the request is **not notified**.
992 ///
993 /// *Network usage*: no.
994 ///
995 /// *Syntax:*
996 ///
997 /// ```
998 /// /_reject <contactReqId>
999 /// ```
1000 fn api_reject_contact(
1001 &self,
1002 contact_req_id: i64,
1003 ) -> impl Future<Output = Result<Arc<ContactRequestRejectedResponse>, Self::Error>> + Send {
1004 async move {
1005 let command = ApiRejectContact { contact_req_id };
1006 let response: ApiRejectContactResponse = self.send(command).await?;
1007 Ok(response.into_inner())
1008 }
1009 }
1010
1011 /// ### Chat commands
1012 ///
1013 /// Commands to list and delete conversations.
1014 ///
1015 /// ----
1016 ///
1017 /// Get contacts.
1018 ///
1019 /// *Network usage*: no.
1020 ///
1021 /// *Syntax:*
1022 ///
1023 /// ```
1024 /// /_contacts <userId>
1025 /// ```
1026 fn api_list_contacts(
1027 &self,
1028 user_id: i64,
1029 ) -> impl Future<Output = Result<Arc<ContactsListResponse>, Self::Error>> + Send {
1030 async move {
1031 let command = ApiListContacts { user_id };
1032 let response: ApiListContactsResponse = self.send(command).await?;
1033 Ok(response.into_inner())
1034 }
1035 }
1036
1037 /// ### Chat commands
1038 ///
1039 /// Commands to list and delete conversations.
1040 ///
1041 /// ----
1042 ///
1043 /// Get groups.
1044 ///
1045 /// *Network usage*: no.
1046 ///
1047 /// *Syntax:*
1048 ///
1049 /// ```
1050 /// /_groups <userId>[ @<contactId_>][ <search>]
1051 /// ```
1052 fn api_list_groups(
1053 &self,
1054 command: ApiListGroups,
1055 ) -> impl Future<Output = Result<Arc<GroupsListResponse>, Self::Error>> + Send {
1056 async move {
1057 let response: ApiListGroupsResponse = self.send(command).await?;
1058 Ok(response.into_inner())
1059 }
1060 }
1061
1062 /// ### Chat commands
1063 ///
1064 /// Commands to list and delete conversations.
1065 ///
1066 /// ----
1067 ///
1068 /// Get chat previews. Supports time-based pagination — use this instead of APIListContacts / APIListGroups when scanning at scale (those load every record into memory and fail on large databases).
1069 ///
1070 /// *Network usage*: no.
1071 ///
1072 /// *Syntax:*
1073 ///
1074 /// ```
1075 /// /_get chats <userId>[ pcc=on] <str(pagination)> <json(query)>
1076 /// ```
1077 fn api_get_chats(
1078 &self,
1079 command: ApiGetChats,
1080 ) -> impl Future<Output = Result<Arc<ApiChatsResponse>, Self::Error>> + Send {
1081 async move {
1082 let response: ApiGetChatsResponse = self.send(command).await?;
1083 Ok(response.into_inner())
1084 }
1085 }
1086
1087 /// ### Chat commands
1088 ///
1089 /// Commands to list and delete conversations.
1090 ///
1091 /// ----
1092 ///
1093 /// Delete chat.
1094 ///
1095 /// *Network usage*: background.
1096 ///
1097 /// *Syntax:*
1098 ///
1099 /// ```
1100 /// /_delete <str(chatRef)> <str(chatDeleteMode)>
1101 /// ```
1102 fn api_delete_chat(
1103 &self,
1104 chat_ref: ChatRef,
1105 chat_delete_mode: ChatDeleteMode,
1106 ) -> impl Future<Output = Result<ApiDeleteChatResponse, Self::Error>> + Send {
1107 async move {
1108 let command = ApiDeleteChat {
1109 chat_ref,
1110 chat_delete_mode,
1111 };
1112 let response: ApiDeleteChatResponse = self.send(command).await?;
1113 Ok(response)
1114 }
1115 }
1116
1117 /// ### Chat commands
1118 ///
1119 /// Commands to list and delete conversations.
1120 ///
1121 /// ----
1122 ///
1123 /// Set group custom data.
1124 ///
1125 /// *Network usage*: no.
1126 ///
1127 /// *Syntax:*
1128 ///
1129 /// ```
1130 /// /_set custom #<groupId>[ <json(customData)>]
1131 /// ```
1132 fn api_set_group_custom_data(
1133 &self,
1134 command: ApiSetGroupCustomData,
1135 ) -> impl Future<Output = Result<Arc<CmdOkResponse>, Self::Error>> + Send {
1136 async move {
1137 let response: ApiSetGroupCustomDataResponse = self.send(command).await?;
1138 Ok(response.into_inner())
1139 }
1140 }
1141
1142 /// ### Chat commands
1143 ///
1144 /// Commands to list and delete conversations.
1145 ///
1146 /// ----
1147 ///
1148 /// Set contact custom data.
1149 ///
1150 /// *Network usage*: no.
1151 ///
1152 /// *Syntax:*
1153 ///
1154 /// ```
1155 /// /_set custom @<contactId>[ <json(customData)>]
1156 /// ```
1157 fn api_set_contact_custom_data(
1158 &self,
1159 command: ApiSetContactCustomData,
1160 ) -> impl Future<Output = Result<Arc<CmdOkResponse>, Self::Error>> + Send {
1161 async move {
1162 let response: ApiSetContactCustomDataResponse = self.send(command).await?;
1163 Ok(response.into_inner())
1164 }
1165 }
1166
1167 /// ### Chat commands
1168 ///
1169 /// Commands to list and delete conversations.
1170 ///
1171 /// ----
1172 ///
1173 /// Set auto-accept member contacts.
1174 ///
1175 /// *Network usage*: no.
1176 ///
1177 /// *Syntax:*
1178 ///
1179 /// ```
1180 /// /_set accept member contacts <userId> on|off
1181 /// ```
1182 fn api_set_user_auto_accept_member_contacts(
1183 &self,
1184 command: ApiSetUserAutoAcceptMemberContacts,
1185 ) -> impl Future<Output = Result<Arc<CmdOkResponse>, Self::Error>> + Send {
1186 async move {
1187 let response: ApiSetUserAutoAcceptMemberContactsResponse = self.send(command).await?;
1188 Ok(response.into_inner())
1189 }
1190 }
1191
1192 /// ### User profile commands
1193 ///
1194 /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1195 ///
1196 /// ----
1197 ///
1198 /// Get active user profile.
1199 ///
1200 /// *Network usage*: no.
1201 ///
1202 /// *Syntax:*
1203 ///
1204 /// ```
1205 /// /user
1206 /// ```
1207 fn show_active_user(
1208 &self,
1209 ) -> impl Future<Output = Result<Arc<ActiveUserResponse>, Self::Error>> + Send {
1210 async move {
1211 let command = ShowActiveUser {};
1212 let response: ShowActiveUserResponse = self.send(command).await?;
1213 Ok(response.into_inner())
1214 }
1215 }
1216
1217 /// ### User profile commands
1218 ///
1219 /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1220 ///
1221 /// ----
1222 ///
1223 /// Create new user profile.
1224 ///
1225 /// *Network usage*: no.
1226 ///
1227 /// *Syntax:*
1228 ///
1229 /// ```
1230 /// /_create user <json(newUser)>
1231 /// ```
1232 fn create_active_user(
1233 &self,
1234 new_user: NewUser,
1235 ) -> impl Future<Output = Result<Arc<ActiveUserResponse>, Self::Error>> + Send {
1236 async move {
1237 let command = CreateActiveUser { new_user };
1238 let response: CreateActiveUserResponse = self.send(command).await?;
1239 Ok(response.into_inner())
1240 }
1241 }
1242
1243 /// ### User profile commands
1244 ///
1245 /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1246 ///
1247 /// ----
1248 ///
1249 /// Get all user profiles.
1250 ///
1251 /// *Network usage*: no.
1252 ///
1253 /// *Syntax:*
1254 ///
1255 /// ```
1256 /// /users
1257 /// ```
1258 fn list_users(
1259 &self,
1260 ) -> impl Future<Output = Result<Arc<UsersListResponse>, Self::Error>> + Send {
1261 async move {
1262 let command = ListUsers {};
1263 let response: ListUsersResponse = self.send(command).await?;
1264 Ok(response.into_inner())
1265 }
1266 }
1267
1268 /// ### User profile commands
1269 ///
1270 /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1271 ///
1272 /// ----
1273 ///
1274 /// Set active user profile.
1275 ///
1276 /// *Network usage*: no.
1277 ///
1278 /// *Syntax:*
1279 ///
1280 /// ```
1281 /// /_user <userId>[ <json(viewPwd)>]
1282 /// ```
1283 fn api_set_active_user(
1284 &self,
1285 command: ApiSetActiveUser,
1286 ) -> impl Future<Output = Result<Arc<ActiveUserResponse>, Self::Error>> + Send {
1287 async move {
1288 let response: ApiSetActiveUserResponse = self.send(command).await?;
1289 Ok(response.into_inner())
1290 }
1291 }
1292
1293 /// ### User profile commands
1294 ///
1295 /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1296 ///
1297 /// ----
1298 ///
1299 /// Delete user profile.
1300 ///
1301 /// *Network usage*: background.
1302 ///
1303 /// *Syntax:*
1304 ///
1305 /// ```
1306 /// /_delete user <userId> del_smp=on|off[ <json(viewPwd)>]
1307 /// ```
1308 fn api_delete_user(
1309 &self,
1310 command: ApiDeleteUser,
1311 ) -> impl Future<Output = Result<Arc<CmdOkResponse>, Self::Error>> + Send {
1312 async move {
1313 let response: ApiDeleteUserResponse = self.send(command).await?;
1314 Ok(response.into_inner())
1315 }
1316 }
1317
1318 /// ### User profile commands
1319 ///
1320 /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1321 ///
1322 /// ----
1323 ///
1324 /// Update user profile.
1325 ///
1326 /// *Network usage*: background.
1327 ///
1328 /// *Syntax:*
1329 ///
1330 /// ```
1331 /// /_profile <userId> <json(profile)>
1332 /// ```
1333 fn api_update_profile(
1334 &self,
1335 user_id: i64,
1336 profile: Profile,
1337 ) -> impl Future<Output = Result<ApiUpdateProfileResponse, Self::Error>> + Send {
1338 async move {
1339 let command = ApiUpdateProfile { user_id, profile };
1340 let response: ApiUpdateProfileResponse = self.send(command).await?;
1341 Ok(response)
1342 }
1343 }
1344
1345 /// ### User profile commands
1346 ///
1347 /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1348 ///
1349 /// ----
1350 ///
1351 /// Configure chat preference overrides for the contact.
1352 ///
1353 /// *Network usage*: background.
1354 ///
1355 /// *Syntax:*
1356 ///
1357 /// ```
1358 /// /_set prefs @<contactId> <json(preferences)>
1359 /// ```
1360 fn api_set_contact_prefs(
1361 &self,
1362 contact_id: i64,
1363 preferences: Preferences,
1364 ) -> impl Future<Output = Result<Arc<ContactPrefsUpdatedResponse>, Self::Error>> + Send {
1365 async move {
1366 let command = ApiSetContactPrefs {
1367 contact_id,
1368 preferences,
1369 };
1370 let response: ApiSetContactPrefsResponse = self.send(command).await?;
1371 Ok(response.into_inner())
1372 }
1373 }
1374
1375 /// ### Chat management
1376 ///
1377 /// These commands should not be used with CLI-based bots
1378 ///
1379 /// ----
1380 ///
1381 /// Start chat controller.
1382 ///
1383 /// *Network usage*: no.
1384 ///
1385 /// *Syntax:*
1386 ///
1387 /// ```
1388 /// /_start
1389 /// ```
1390 fn start_chat(
1391 &self,
1392 command: StartChat,
1393 ) -> impl Future<Output = Result<StartChatResponse, Self::Error>> + Send {
1394 async move {
1395 let response: StartChatResponse = self.send(command).await?;
1396 Ok(response)
1397 }
1398 }
1399
1400 /// ### Chat management
1401 ///
1402 /// These commands should not be used with CLI-based bots
1403 ///
1404 /// ----
1405 ///
1406 /// Stop chat controller.
1407 ///
1408 /// *Network usage*: no.
1409 ///
1410 /// *Syntax:*
1411 ///
1412 /// ```
1413 /// /_stop
1414 /// ```
1415 fn api_stop_chat(
1416 &self,
1417 ) -> impl Future<Output = Result<Arc<ChatStoppedResponse>, Self::Error>> + Send {
1418 async move {
1419 let command = ApiStopChat {};
1420 let response: ApiStopChatResponse = self.send(command).await?;
1421 Ok(response.into_inner())
1422 }
1423 }
1424}
1425
1426/// Use this as [`ClientApi::ResponseShape`] to extract web socket responses
1427#[derive(Serialize, Deserialize)]
1428pub struct WebSocketResponseShape<T> {
1429 pub resp: WebSocketResponseShapeInner<T>,
1430}
1431
1432#[derive(Serialize, Deserialize)]
1433#[serde(untagged)]
1434pub enum WebSocketResponseShapeInner<T> {
1435 Response(T),
1436 Error(ChatCmdError),
1437 Undocumented(JsonObject),
1438}
1439
1440impl<'de, T: 'de + Deserialize<'de>> ExtractResponse<'de, T> for WebSocketResponseShape<T> {
1441 fn extract_response(self) -> Result<T, BadResponseError> {
1442 self.resp.extract_response()
1443 }
1444}
1445
1446impl<'de, T: 'de + Deserialize<'de>> ExtractResponse<'de, T> for WebSocketResponseShapeInner<T> {
1447 fn extract_response(self) -> Result<T, BadResponseError> {
1448 match self {
1449 Self::Response(resp) => Ok(resp),
1450 Self::Error(err) => Err(BadResponseError::ChatError(
1451 err.into_inner().chat_error.clone(),
1452 )),
1453 Self::Undocumented(json) => Err(BadResponseError::Undocumented(json)),
1454 }
1455 }
1456}
1457
1458/// Use this as [`ClientApi::ResponseShape`] to extract FFI responses
1459#[derive(Serialize, Deserialize)]
1460pub enum FfiResponseShape<T> {
1461 #[serde(rename = "result")]
1462 Result(T),
1463
1464 #[serde(rename = "error")]
1465 Error(Arc<ChatError>),
1466
1467 #[serde(untagged)]
1468 Undocumented(JsonObject),
1469}
1470
1471impl<'de, T: 'de + Deserialize<'de>> ExtractResponse<'de, T> for FfiResponseShape<T> {
1472 fn extract_response(self) -> Result<T, BadResponseError> {
1473 match self {
1474 Self::Result(resp) => Ok(resp),
1475 Self::Error(err) => Err(BadResponseError::ChatError(err)),
1476 Self::Undocumented(json) => Err(BadResponseError::Undocumented(json)),
1477 }
1478 }
1479}
1480
1481#[derive(Debug)]
1482pub enum BadResponseError {
1483 ChatError(Arc<ChatError>),
1484 InvalidJson(serde_json::Error),
1485 Undocumented(JsonObject),
1486}
1487
1488impl BadResponseError {
1489 pub fn chat_error(&self) -> Option<&ChatError> {
1490 if let Self::ChatError(error) = self {
1491 Some(error.as_ref())
1492 } else {
1493 None
1494 }
1495 }
1496
1497 pub fn invalid_json(&self) -> Option<&serde_json::Error> {
1498 if let Self::InvalidJson(error) = self {
1499 Some(error)
1500 } else {
1501 None
1502 }
1503 }
1504
1505 pub fn undocumented(&self) -> Option<&JsonObject> {
1506 if let Self::Undocumented(error) = self {
1507 Some(error)
1508 } else {
1509 None
1510 }
1511 }
1512}
1513
1514impl std::error::Error for BadResponseError {
1515 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1516 match self {
1517 Self::ChatError(error) => Some(error.as_ref()),
1518 Self::InvalidJson(error) => Some(error),
1519 Self::Undocumented(_) => None,
1520 }
1521 }
1522}
1523
1524impl std::fmt::Display for BadResponseError {
1525 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1526 match self {
1527 Self::ChatError(resp) => writeln!(f, "Bad response:\n{resp:#}"),
1528 Self::Undocumented(resp) => writeln!(f, "Unexpected response:\n{resp:#}"),
1529 Self::InvalidJson(err) => writeln!(f, "Invalid JSON:\n{err:#}"),
1530 }
1531 }
1532}
1533
1534pub enum UndocumentedResponse<T> {
1535 Documented(T),
1536 Undocumented(JsonObject),
1537}
1538
1539/// If you want to ~~suffer~~ handle undocumented responses you can use this extension trait
1540/// on client API return values which moves Undocumented from `Err` to `Ok` variant.
1541///
1542/// Example:
1543///
1544/// ```ignore
1545/// match client
1546/// .api_create_my_address(1)
1547/// .await
1548/// .allow_undocumented()?
1549/// {
1550/// UndocumentedResponse::Documented(resp) => {
1551/// // Process expected response...
1552/// }
1553/// UndocumentedResponse::Undocumented(resp) => {
1554/// // Do something with the unexpected response...
1555/// }
1556/// }
1557/// }
1558/// ```
1559pub trait AllowUndocumentedResponses<T, E> {
1560 fn allow_undocumented(self) -> Result<UndocumentedResponse<T>, E>;
1561}
1562
1563impl<T, E> AllowUndocumentedResponses<T, E> for Result<T, E>
1564where
1565 E: ClientApiError,
1566{
1567 fn allow_undocumented(self) -> Result<UndocumentedResponse<T>, E> {
1568 match self {
1569 Ok(resp) => Ok(UndocumentedResponse::Documented(resp)),
1570 Err(mut e) => match e.bad_response_mut() {
1571 Some(BadResponseError::Undocumented(btree_map)) => Ok(
1572 UndocumentedResponse::Undocumented(std::mem::take(btree_map)),
1573 ),
1574 _ => Err(e),
1575 },
1576 }
1577 }
1578}