1use simploxide_api_types::{
4 AddressSettings, AutoAccept, CIDeleteMode, ChatListQuery, ChatPeerType, ConnectionPlan,
5 Contact, CreatedConnLink, GroupInfo, GroupMember, GroupMemberRole, GroupProfile, JsonObject,
6 LocalProfile, MsgContent, NewUser, PaginationByTime, PendingContactConnection, Preferences,
7 Profile, User,
8 client_api::{ClientApi, ClientApiError as _, UndocumentedResponse},
9 commands::{
10 ApiAddContact, ApiConnectPlan, ApiGetChats, ApiNewGroup, ApiNewPublicGroup,
11 ApiSetActiveUser, ApiSetProfileAddress, ApiSetUserAutoAcceptMemberContacts,
12 },
13 responses::{
14 AcceptingContactRequestResponse, ApiChatsResponse, ApiDeleteChatResponse,
15 ApiNewPublicGroupResponse, ApiUpdateChatItemResponse, ApiUpdateProfileResponse,
16 CancelFileResponse, ChatItemReactionResponse, ChatItemsDeletedResponse, CmdOkResponse,
17 ConnectResponse, ConnectionPlanResponse, ContactPrefsUpdatedResponse,
18 ContactRequestRejectedResponse, GroupCreatedResponse, GroupLinkCreatedResponse,
19 GroupLinkDeletedResponse, GroupUpdatedResponse, LeftMemberUserResponse,
20 MemberAcceptedResponse, MembersBlockedForAllUserResponse, MembersRoleUserResponse,
21 SentGroupInvitationResponse, UserAcceptedGroupSentResponse, UserDeletedMembersResponse,
22 UserProfileUpdatedResponse,
23 },
24};
25
26use std::sync::Arc;
27
28use crate::{
29 ext::{
30 AcceptFileBuilder, AddGroupRelaysResponse, ClientApiExt as _, DeleteMode,
31 GetGroupRelaysResponse, GroupLinkResult, Reaction,
32 },
33 id::{
34 ChatId, ContactId, ContactRequestId, FileId, GroupId, MemberId, MessageId, RelayId, UserId,
35 },
36 messages::{MessageBuilder, MessageLike, MulticastBuilder},
37 preferences,
38 preview::ImagePreview,
39};
40
41#[derive(Clone)]
43pub struct Bot<C> {
44 client: C,
45 user_id: i64,
46}
47
48impl<C> Bot<C> {
49 pub fn client(&self) -> &C {
50 &self.client
51 }
52
53 pub fn user_id(&self) -> UserId {
54 UserId(self.user_id)
55 }
56}
57
58impl<C: ClientApi> Bot<C> {
59 pub async fn init(client: C, settings: BotSettings) -> Result<Self, C::Error> {
60 let avatar = if let Some(preview) = settings.avatar {
61 Some(preview.resolve().await)
62 } else {
63 None
64 };
65
66 let mut users = client.users().await?;
67
68 match users.iter_mut().find_map(|info| {
69 (info.user.profile.display_name == settings.display_name).then_some(&mut info.user)
70 }) {
71 Some(user) => {
72 if !user.active_user {
73 client
74 .api_set_active_user(ApiSetActiveUser::new(user.user_id))
75 .await?;
76 }
77
78 let bot = Bot {
79 client,
80 user_id: user.user_id,
81 };
82
83 bot.setup_auto_accept(settings.auto_accept, user.profile.contact_link.is_some())
84 .await?;
85
86 let mut profile = match settings.profile_settings {
87 Some(BotProfileSettings::Preferences(preferences)) => {
88 let mut current_profile = extract_profile(&mut user.profile);
89 current_profile.preferences = Some(preferences);
90 current_profile
91 }
92 Some(BotProfileSettings::FullProfile(profile)) => profile,
93 None => Self::default_profile(settings.display_name),
94 };
95 profile.image = avatar;
96 bot.client.api_update_profile(user.user_id, profile).await?;
97
98 Ok(bot)
99 }
100 None => {
101 let mut bot_profile = match settings.profile_settings {
102 Some(BotProfileSettings::Preferences(preferences)) => {
103 let mut profile = Self::default_profile(settings.display_name.clone());
104 profile.preferences = Some(preferences);
105 profile
106 }
107 Some(BotProfileSettings::FullProfile(profile)) => profile,
108 None => Self::default_profile(settings.display_name.clone()),
109 };
110 bot_profile.image = avatar;
111
112 let response = client
113 .new_user(NewUser {
114 profile: Some(bot_profile),
115 past_timestamp: false,
116 user_chat_relay: false,
117 undocumented: Default::default(),
118 })
119 .await?;
120
121 let bot = Bot {
122 client,
123 user_id: response.user.user_id,
124 };
125
126 bot.setup_auto_accept(settings.auto_accept, false).await?;
127
128 Ok(bot)
129 }
130 }
131 }
132
133 async fn setup_auto_accept(
134 &self,
135 auto_accept: Option<String>,
136 has_existing_address: bool,
137 ) -> Result<(), C::Error> {
138 if let Some(welcome_message) = auto_accept {
139 if !has_existing_address {
140 self.get_or_create_address().await?;
141 self.publish_address().await?;
142 }
143
144 self.configure_address(AddressSettings {
145 business_address: false,
146 auto_accept: Some(AutoAccept {
147 accept_incognito: false,
148 undocumented: Default::default(),
149 }),
150 auto_reply: (!welcome_message.is_empty())
151 .then(|| MsgContent::make_text(welcome_message)),
152 undocumented: Default::default(),
153 })
154 .await?;
155 } else if has_existing_address {
156 self.configure_address(AddressSettings {
157 business_address: false,
158 auto_accept: None,
159 auto_reply: None,
160 undocumented: Default::default(),
161 })
162 .await?;
163
164 self.hide_address().await?;
165 }
166
167 Ok(())
168 }
169
170 pub fn wrap_client<W, F>(self, wrap: F) -> Bot<W>
176 where
177 W: ClientApi,
178 F: FnOnce(C) -> W,
179 {
180 let new_client = wrap(self.client);
181
182 Bot {
183 client: new_client,
184 user_id: self.user_id,
185 }
186 }
187
188 pub fn default_profile(name: impl Into<String>) -> Profile {
190 Profile {
191 display_name: name.into(),
192 full_name: String::default(),
193 short_descr: None,
194 image: None,
195 contact_link: None,
196 preferences: Some(Preferences {
197 timed_messages: preferences::timed_messages::NO,
198 full_delete: preferences::YES,
199 reactions: preferences::NO,
200 voice: preferences::NO,
201 files: preferences::NO,
202 calls: preferences::NO,
203 sessions: preferences::NO,
204 commands: None,
205 undocumented: Default::default(),
206 }),
207 peer_type: Some(ChatPeerType::Bot),
208 undocumented: serde_json::Value::Null,
209 }
210 }
211
212 pub async fn info(&self) -> Result<Arc<User>, C::Error> {
214 let response = self.client.show_active_user().await?;
215 Ok(Arc::new(response.user.clone()))
216 }
217
218 pub async fn initiate_connection(
230 &self,
231 link: impl Into<String>,
232 ) -> Result<UndocumentedResponse<ConnectResponse>, C::Error> {
233 self.client.initiate_connection(link).await
234 }
235
236 pub async fn check_connection_plan(
239 &self,
240 link: impl Into<String>,
241 ) -> Result<Arc<ConnectionPlanResponse>, C::Error> {
242 self.client
243 .api_connect_plan(ApiConnectPlan {
244 user_id: self.user_id,
245 connection_link: Some(link.into()),
246 resolve_known: false,
247 link_owner_sig: None,
248 })
249 .await
250 }
251
252 pub async fn initiate_connection_if<F: FnOnce(&ConnectionPlan) -> bool>(
266 &self,
267 link: impl Into<String>,
268 predicate: F,
269 ) -> Result<Connection, C::Error> {
270 let link = link.into();
271 let plan_resp = self.check_connection_plan(link.clone()).await?;
272
273 if !predicate(&plan_resp.connection_plan) {
274 return Ok(Connection::Rejected(plan_resp));
275 }
276
277 self.initiate_connection(link)
278 .await
279 .map(Connection::Initiated)
280 }
281
282 pub async fn create_invitation_link(
287 &self,
288 ) -> Result<(String, Arc<PendingContactConnection>), C::Error> {
289 let response = self
290 .client
291 .api_add_contact(ApiAddContact::new(self.user_id))
292 .await?;
293
294 let link = extract_address(&response.conn_link_invitation);
295 let pcc = Arc::new(response.connection.clone());
296
297 Ok((link, pcc))
298 }
299
300 pub async fn create_address(&self) -> Result<String, C::Error> {
301 let response = self.client.api_create_my_address(self.user_id).await?;
302 Ok(extract_address(&response.conn_link_contact))
303 }
304
305 pub async fn address(&self) -> Result<String, C::Error> {
308 let response = self.client.api_show_my_address(self.user_id).await?;
309 Ok(extract_address(&response.contact_link.conn_link_contact))
310 }
311
312 pub async fn get_or_create_address(&self) -> Result<String, C::Error> {
313 match self.address().await {
314 Ok(address) => Ok(address),
315 Err(e)
316 if e.bad_response()
317 .and_then(|e| {
318 e.chat_error().and_then(|e| {
319 e.error_store().map(|e| e.is_user_contact_link_not_found())
320 })
321 })
322 .unwrap_or(false) =>
323 {
324 self.create_address().await
325 }
326 Err(e) => Err(e),
327 }
328 }
329
330 pub async fn configure_address(&self, settings: AddressSettings) -> Result<(), C::Error> {
331 self.client
332 .api_set_address_settings(self.user_id, settings)
333 .await
334 .map(drop)
335 }
336
337 pub async fn publish_address(&self) -> Result<Arc<UserProfileUpdatedResponse>, C::Error> {
339 self.client
340 .api_set_profile_address(ApiSetProfileAddress {
341 user_id: self.user_id,
342 enable: true,
343 })
344 .await
345 }
346
347 pub async fn hide_address(&self) -> Result<Arc<UserProfileUpdatedResponse>, C::Error> {
349 self.client
350 .api_set_profile_address(ApiSetProfileAddress {
351 user_id: self.user_id,
352 enable: false,
353 })
354 .await
355 }
356
357 pub async fn delete_address(&self) -> Result<(), C::Error> {
358 self.client.api_delete_my_address(self.user_id).await?;
359 Ok(())
360 }
361
362 pub async fn update_profile<F>(&self, updater: F) -> Result<ApiUpdateProfileResponse, C::Error>
364 where
365 F: 'static + Send + FnOnce(&mut Profile),
366 {
367 let mut response = self.client.show_active_user().await?;
368 let response = Arc::get_mut(&mut response).unwrap();
369
370 let mut profile = extract_profile(&mut response.user.profile);
371 updater(&mut profile);
372
373 self.client.api_update_profile(self.user_id, profile).await
374 }
375
376 pub async fn set_display_name(
377 &self,
378 name: impl Into<String>,
379 ) -> Result<ApiUpdateProfileResponse, C::Error> {
380 let name = name.into();
381 self.update_profile(move |profile| profile.display_name = name)
382 .await
383 }
384
385 pub async fn set_full_name(
386 &self,
387 full_name: impl Into<String>,
388 ) -> Result<ApiUpdateProfileResponse, C::Error> {
389 let full_name = full_name.into();
390 self.update_profile(move |profile| profile.full_name = full_name)
391 .await
392 }
393
394 pub async fn set_bio(
395 &self,
396 bio: impl Into<String>,
397 ) -> Result<ApiUpdateProfileResponse, C::Error> {
398 let bio = bio.into();
399 self.update_profile(move |profile| profile.short_descr = Some(bio))
400 .await
401 }
402
403 pub async fn set_avatar(
405 &self,
406 avatar: ImagePreview,
407 ) -> Result<ApiUpdateProfileResponse, C::Error> {
408 let image = avatar.resolve().await;
409 self.update_profile(move |profile| profile.image = Some(image))
410 .await
411 }
412
413 pub async fn set_peer_type(
415 &self,
416 peer_type: ChatPeerType,
417 ) -> Result<ApiUpdateProfileResponse, C::Error> {
418 self.update_profile(move |profile| profile.peer_type = Some(peer_type))
419 .await
420 }
421
422 pub async fn set_preferences(
424 &self,
425 preferences: Preferences,
426 ) -> Result<ApiUpdateProfileResponse, C::Error> {
427 self.update_profile(move |profile| profile.preferences = Some(preferences))
428 .await
429 }
430
431 pub async fn update_preferences<F>(
433 &self,
434 updater: F,
435 ) -> Result<ApiUpdateProfileResponse, C::Error>
436 where
437 F: 'static + Send + FnOnce(&mut Preferences),
438 {
439 let mut response = self.client.show_active_user().await?;
440 let response = Arc::get_mut(&mut response).unwrap();
441
442 let mut profile = extract_profile(&mut response.user.profile);
443 let mut preferences = extract_preferences(&mut profile.preferences);
444 updater(&mut preferences);
445 profile.preferences = Some(preferences);
446
447 self.client.api_update_profile(self.user_id, profile).await
448 }
449
450 pub async fn set_contact_preferences<CID: Into<ContactId>>(
452 &self,
453 contact_id: CID,
454 preferences: Preferences,
455 ) -> Result<Arc<ContactPrefsUpdatedResponse>, C::Error> {
456 self.client
457 .api_set_contact_prefs(contact_id.into().0, preferences)
458 .await
459 }
460
461 pub async fn tweak_preferences_for_contact<CID: Into<ContactId>, F>(
464 &self,
465 contact_id: CID,
466 updater: F,
467 ) -> Result<Arc<ContactPrefsUpdatedResponse>, C::Error>
468 where
469 F: 'static + Send + FnOnce(&mut Preferences),
470 {
471 let mut response = self.client.show_active_user().await?;
472 let response = Arc::get_mut(&mut response).unwrap();
473
474 let mut preferences = extract_preferences(&mut response.user.profile.preferences);
475 updater(&mut preferences);
476
477 self.client
478 .api_set_contact_prefs(contact_id.into().0, preferences)
479 .await
480 }
481
482 pub async fn contacts(&self) -> Result<Vec<Contact>, C::Error> {
484 self.client.contacts(self.user_id()).await
485 }
486
487 pub async fn groups(&self) -> Result<Vec<GroupInfo>, C::Error> {
489 self.client.groups(self.user_id()).await
490 }
491
492 pub async fn accept_contact<CRID: Into<ContactRequestId>>(
494 &self,
495 contact_request_id: CRID,
496 ) -> Result<Arc<AcceptingContactRequestResponse>, <C as ClientApi>::Error> {
497 self.client.accept_contact(contact_request_id).await
498 }
499
500 pub async fn reject_contact<CRID: Into<ContactRequestId>>(
502 &self,
503 contact_request_id: CRID,
504 ) -> Result<Arc<ContactRequestRejectedResponse>, <C as ClientApi>::Error> {
505 self.client.reject_contact(contact_request_id).await
506 }
507
508 pub fn send_msg<CID: Into<ChatId>, M: MessageLike>(
510 &self,
511 chat_id: CID,
512 msg: M,
513 ) -> MessageBuilder<'_, C, M::Kind> {
514 self.client.send_message(chat_id.into(), msg)
515 }
516
517 pub fn multicast<I, M>(&self, chat_ids: I, msg: M) -> MulticastBuilder<'_, I, C, M::Kind>
519 where
520 I: IntoIterator<Item = ChatId>,
521 M: MessageLike,
522 {
523 self.client.multicast_message(chat_ids, msg)
524 }
525
526 pub async fn chat_ids(&self) -> Result<impl Iterator<Item = ChatId>, C::Error> {
528 self.chat_ids_with(|_| true).await
529 }
530
531 pub async fn chat_ids_with<F>(
533 &self,
534 f: F,
535 ) -> Result<impl 'static + Send + Iterator<Item = ChatId>, C::Error>
536 where
537 F: 'static + Send + FnMut(&ChatId) -> bool,
538 {
539 let (contacts, groups) = futures::future::try_join(self.contacts(), self.groups()).await?;
540
541 Ok(contacts
542 .into_iter()
543 .map(ChatId::from)
544 .chain(groups.into_iter().map(ChatId::from))
545 .filter(f))
546 }
547
548 pub async fn prepare_broadcast<M: MessageLike>(
557 &self,
558 msg: M,
559 ) -> Result<
560 MulticastBuilder<'_, impl 'static + Send + Iterator<Item = ChatId>, C, M::Kind>,
561 C::Error,
562 > {
563 self.prepare_broadcast_with(msg, |_| true).await
564 }
565
566 pub async fn prepare_broadcast_with<M, F>(
576 &self,
577 msg: M,
578 f: F,
579 ) -> Result<
580 MulticastBuilder<'_, impl 'static + Send + Iterator<Item = ChatId>, C, M::Kind>,
581 C::Error,
582 >
583 where
584 F: 'static + Send + FnMut(&ChatId) -> bool,
585 M: MessageLike,
586 {
587 let ids = self.chat_ids_with(f).await?;
588 let (msg, kind) = msg.into_builder_parts();
589
590 Ok(MulticastBuilder {
591 client: self.client(),
592 chat_ids: ids,
593 ttl: None,
594 msg,
595 kind,
596 })
597 }
598
599 pub async fn update_msg<CID: Into<ChatId>, MID: Into<MessageId>>(
600 &self,
601 chat_id: CID,
602 message_id: MID,
603 new_content: MsgContent,
604 ) -> Result<ApiUpdateChatItemResponse, C::Error> {
605 self.client
606 .update_message(chat_id, message_id, new_content)
607 .await
608 }
609
610 pub async fn delete_msg<CID: Into<ChatId>, MID: Into<MessageId>>(
611 &self,
612 chat_id: CID,
613 message_id: MID,
614 mode: CIDeleteMode,
615 ) -> Result<Arc<ChatItemsDeletedResponse>, C::Error> {
616 self.client.delete_message(chat_id, message_id, mode).await
617 }
618
619 pub async fn batch_delete_msgs<CID: Into<ChatId>, I: IntoIterator<Item = MessageId>>(
620 &self,
621 chat_id: CID,
622 message_ids: I,
623 mode: CIDeleteMode,
624 ) -> Result<Arc<ChatItemsDeletedResponse>, C::Error> {
625 self.client
626 .batch_delete_messages(chat_id, message_ids, mode)
627 .await
628 }
629
630 pub async fn batch_msg_reactions<
632 CID: Into<ChatId>,
633 MID: Into<MessageId>,
634 I: IntoIterator<Item = Reaction>,
635 >(
636 &self,
637 chat_id: CID,
638 message_id: MID,
639 reactions: I,
640 ) -> Vec<Result<Arc<ChatItemReactionResponse>, C::Error>> {
641 self.client
642 .batch_message_reactions(chat_id, message_id, reactions)
643 .await
644 }
645
646 pub async fn update_msg_reaction<CID: Into<ChatId>, MID: Into<MessageId>>(
647 &self,
648 chat_id: CID,
649 message_id: MID,
650 reaction: Reaction,
651 ) -> Vec<Result<Arc<ChatItemReactionResponse>, C::Error>> {
652 self.client
653 .update_message_reaction(chat_id, message_id, reaction)
654 .await
655 }
656
657 pub fn accept_file<FID: Into<FileId>>(&self, file_id: FID) -> AcceptFileBuilder<'_, C> {
659 self.client.accept_file(file_id)
660 }
661
662 pub async fn reject_file<FID: Into<FileId>>(
663 &self,
664 file_id: FID,
665 ) -> Result<CancelFileResponse, C::Error> {
666 self.client.reject_file(file_id).await
667 }
668
669 pub async fn delete_chat<CID: Into<ChatId>>(
670 &self,
671 chat_id: CID,
672 mode: DeleteMode,
673 ) -> Result<ApiDeleteChatResponse, C::Error> {
674 self.client.delete_chat(chat_id, mode).await
675 }
676
677 pub async fn create_group(
679 &self,
680 profile: GroupProfile,
681 ) -> Result<Arc<GroupCreatedResponse>, C::Error> {
682 self.client
683 .api_new_group(ApiNewGroup::new(self.user_id, profile))
684 .await
685 }
686
687 pub async fn create_public_group<I: IntoIterator<Item = RelayId>>(
690 &self,
691 relay_ids: I,
692 profile: GroupProfile,
693 ) -> Result<ApiNewPublicGroupResponse, C::Error> {
694 self.client
695 .api_new_public_group(ApiNewPublicGroup::new(
696 self.user_id,
697 relay_ids.into_iter().map(|id| id.0).collect(),
698 profile,
699 ))
700 .await
701 }
702
703 pub async fn set_auto_accept_member_contacts(
705 &self,
706 on: bool,
707 ) -> Result<Arc<CmdOkResponse>, C::Error> {
708 self.client
709 .api_set_user_auto_accept_member_contacts(ApiSetUserAutoAcceptMemberContacts {
710 user_id: self.user_id,
711 on_off: on,
712 })
713 .await
714 }
715
716 pub async fn add_member<GID: Into<GroupId>, CID: Into<ContactId>>(
718 &self,
719 group_id: GID,
720 contact_id: CID,
721 role: GroupMemberRole,
722 ) -> Result<Arc<SentGroupInvitationResponse>, C::Error> {
723 self.client.add_member(group_id, contact_id, role).await
724 }
725
726 pub async fn join_group<GID: Into<GroupId>>(
728 &self,
729 group_id: GID,
730 ) -> Result<Arc<UserAcceptedGroupSentResponse>, C::Error> {
731 self.client.join_group(group_id).await
732 }
733
734 pub async fn accept_member<GID: Into<GroupId>, MID: Into<MemberId>>(
736 &self,
737 group_id: GID,
738 member_id: MID,
739 role: GroupMemberRole,
740 ) -> Result<Arc<MemberAcceptedResponse>, C::Error> {
741 self.client.accept_member(group_id, member_id, role).await
742 }
743
744 pub async fn set_members_role<GID: Into<GroupId>, I: IntoIterator<Item = MemberId>>(
745 &self,
746 group_id: GID,
747 member_ids: I,
748 role: GroupMemberRole,
749 ) -> Result<Arc<MembersRoleUserResponse>, C::Error> {
750 self.client
751 .set_members_role(group_id, member_ids, role)
752 .await
753 }
754
755 pub async fn set_member_role<GID: Into<GroupId>, MID: Into<MemberId>>(
756 &self,
757 group_id: GID,
758 member_id: MID,
759 role: GroupMemberRole,
760 ) -> Result<Arc<MembersRoleUserResponse>, C::Error> {
761 self.client.set_member_role(group_id, member_id, role).await
762 }
763
764 pub async fn block_members_for_all<GID: Into<GroupId>, I: IntoIterator<Item = MemberId>>(
766 &self,
767 group_id: GID,
768 member_ids: I,
769 ) -> Result<Arc<MembersBlockedForAllUserResponse>, C::Error> {
770 self.client
771 .block_members_for_all(group_id, member_ids)
772 .await
773 }
774
775 pub async fn unblock_members_for_all<GID: Into<GroupId>, I: IntoIterator<Item = MemberId>>(
777 &self,
778 group_id: GID,
779 member_ids: I,
780 ) -> Result<Arc<MembersBlockedForAllUserResponse>, C::Error> {
781 self.client
782 .unblock_members_for_all(group_id, member_ids)
783 .await
784 }
785
786 pub async fn block_member_for_all<GID: Into<GroupId>, MID: Into<MemberId>>(
788 &self,
789 group_id: GID,
790 member_id: MID,
791 ) -> Result<Arc<MembersBlockedForAllUserResponse>, C::Error> {
792 self.client.block_member_for_all(group_id, member_id).await
793 }
794
795 pub async fn unblock_member_for_all<GID: Into<GroupId>, MID: Into<MemberId>>(
797 &self,
798 group_id: GID,
799 member_id: MID,
800 ) -> Result<Arc<MembersBlockedForAllUserResponse>, C::Error> {
801 self.client
802 .unblock_member_for_all(group_id, member_id)
803 .await
804 }
805
806 pub async fn remove_members<GID: Into<GroupId>, I: IntoIterator<Item = MemberId>>(
808 &self,
809 group_id: GID,
810 member_ids: I,
811 ) -> Result<Arc<UserDeletedMembersResponse>, C::Error> {
812 self.client.remove_members(group_id, member_ids).await
813 }
814
815 pub async fn remove_members_with_messages<
817 GID: Into<GroupId>,
818 I: IntoIterator<Item = MemberId>,
819 >(
820 &self,
821 group_id: GID,
822 member_ids: I,
823 ) -> Result<Arc<UserDeletedMembersResponse>, C::Error> {
824 self.client
825 .remove_members_with_messages(group_id, member_ids)
826 .await
827 }
828
829 pub async fn remove_member<GID: Into<GroupId>, MID: Into<MemberId>>(
831 &self,
832 group_id: GID,
833 member_id: MID,
834 ) -> Result<Arc<UserDeletedMembersResponse>, C::Error> {
835 self.client.remove_member(group_id, member_id).await
836 }
837
838 pub async fn remove_member_with_messages<GID: Into<GroupId>, MID: Into<MemberId>>(
840 &self,
841 group_id: GID,
842 member_id: MID,
843 ) -> Result<Arc<UserDeletedMembersResponse>, C::Error> {
844 self.client
845 .remove_member_with_messages(group_id, member_id)
846 .await
847 }
848
849 pub async fn leave_group<GID: Into<GroupId>>(
850 &self,
851 group_id: GID,
852 ) -> Result<Arc<LeftMemberUserResponse>, C::Error> {
853 self.client.leave_group(group_id).await
854 }
855
856 pub async fn list_members<GID: Into<GroupId>>(
857 &self,
858 group_id: GID,
859 ) -> Result<Vec<GroupMember>, C::Error> {
860 self.client.list_members(group_id).await
861 }
862
863 pub async fn moderate_messages<GID: Into<GroupId>, I: IntoIterator<Item = MessageId>>(
865 &self,
866 group_id: GID,
867 message_ids: I,
868 ) -> Result<Arc<ChatItemsDeletedResponse>, C::Error> {
869 self.client.moderate_messages(group_id, message_ids).await
870 }
871
872 pub async fn moderate_message<GID: Into<GroupId>, MID: Into<MessageId>>(
874 &self,
875 group_id: GID,
876 message_id: MID,
877 ) -> Result<Arc<ChatItemsDeletedResponse>, C::Error> {
878 self.client.moderate_message(group_id, message_id).await
879 }
880
881 pub async fn update_group_profile<GID: Into<GroupId>>(
882 &self,
883 group_id: GID,
884 profile: GroupProfile,
885 ) -> Result<Arc<GroupUpdatedResponse>, C::Error> {
886 self.client.update_group_profile(group_id, profile).await
887 }
888
889 pub async fn set_group_custom_data<GID: Into<GroupId>>(
891 &self,
892 group_id: GID,
893 data: Option<JsonObject>,
894 ) -> Result<Arc<CmdOkResponse>, C::Error> {
895 self.client.set_group_custom_data(group_id, data).await
896 }
897
898 pub async fn set_contact_custom_data<CID: Into<ContactId>>(
900 &self,
901 contact_id: CID,
902 data: Option<JsonObject>,
903 ) -> Result<Arc<CmdOkResponse>, C::Error> {
904 self.client.set_contact_custom_data(contact_id, data).await
905 }
906
907 pub async fn create_group_link<GID: Into<GroupId>>(
908 &self,
909 group_id: GID,
910 role: GroupMemberRole,
911 ) -> Result<Arc<GroupLinkCreatedResponse>, C::Error> {
912 self.client.create_group_link(group_id, role).await
913 }
914
915 pub async fn set_group_link_role<GID: Into<GroupId>>(
917 &self,
918 group_id: GID,
919 role: GroupMemberRole,
920 ) -> GroupLinkResult<C> {
921 self.client.set_group_link_role(group_id, role).await
922 }
923
924 pub async fn delete_group_link<GID: Into<GroupId>>(
925 &self,
926 group_id: GID,
927 ) -> Result<Arc<GroupLinkDeletedResponse>, C::Error> {
928 self.client.delete_group_link(group_id).await
929 }
930
931 pub async fn get_group_link<GID: Into<GroupId>>(&self, group_id: GID) -> GroupLinkResult<C> {
932 self.client.get_group_link(group_id).await
933 }
934
935 pub async fn get_group_relays<GID: Into<GroupId>>(
936 &self,
937 group_id: GID,
938 ) -> GetGroupRelaysResponse<C> {
939 self.client.get_group_relays(group_id).await
940 }
941
942 pub async fn add_group_relays<GID: Into<GroupId>, I: IntoIterator<Item = RelayId>>(
943 &self,
944 group_id: GID,
945 relay_ids: I,
946 ) -> AddGroupRelaysResponse<C> {
947 self.client.add_group_relays(group_id, relay_ids).await
948 }
949
950 pub async fn add_group_relay<GID: Into<GroupId>, RID: Into<RelayId>>(
951 &self,
952 group_id: GID,
953 relay_id: RID,
954 ) -> AddGroupRelaysResponse<C> {
955 self.client.add_group_relay(group_id, relay_id).await
956 }
957
958 pub async fn get_chats(
961 &self,
962 pagination: PaginationByTime,
963 query: ChatListQuery,
964 ) -> Result<Arc<ApiChatsResponse>, C::Error> {
965 self.client
966 .api_get_chats(ApiGetChats::new(self.user_id, pagination, query))
967 .await
968 }
969}
970
971#[cfg(feature = "xftp")]
972impl<C: crate::xftp::XftpExt> Bot<C> {
973 pub fn download_file<FID: Into<FileId>>(
974 &self,
975 file_id: FID,
976 ) -> crate::xftp::DownloadFileBuilder<'_, C> {
977 self.client.download_file(file_id)
978 }
979}
980
981#[cfg(feature = "websocket")]
982impl crate::ws::Bot {
983 pub fn shutdown(self) -> impl Future<Output = ()> {
984 self.client.disconnect()
985 }
986}
987
988#[cfg(feature = "ffi")]
989impl crate::ffi::Bot {
990 pub fn shutdown(self) -> impl Future<Output = ()> {
991 self.client.disconnect()
992 }
993}
994
995#[derive(Debug, Clone)]
997pub struct BotSettings {
998 pub display_name: String,
999 pub auto_accept: Option<String>,
1002 pub profile_settings: Option<BotProfileSettings>,
1003 pub avatar: Option<ImagePreview>,
1004}
1005
1006impl BotSettings {
1007 pub fn new(name: impl Into<String>) -> Self {
1008 Self {
1009 display_name: name.into(),
1010 auto_accept: None,
1011 profile_settings: None,
1012 avatar: None,
1013 }
1014 }
1015
1016 pub fn with_avatar(mut self, avatar: ImagePreview) -> Self {
1017 self.avatar = Some(avatar);
1018 self
1019 }
1020
1021 pub fn auto_accept(mut self) -> Self {
1023 self.auto_accept = Some(String::default());
1024 self
1025 }
1026
1027 pub fn auto_accept_with(mut self, welcome_message: impl Into<String>) -> Self {
1029 self.auto_accept = Some(welcome_message.into());
1030 self
1031 }
1032
1033 pub fn with_profile_settings(mut self, settings: BotProfileSettings) -> Self {
1034 self.profile_settings = Some(settings);
1035 self
1036 }
1037}
1038
1039#[derive(Debug, Clone)]
1040pub enum BotProfileSettings {
1041 Preferences(Preferences),
1043 FullProfile(Profile),
1045}
1046
1047pub enum Connection {
1048 Initiated(UndocumentedResponse<ConnectResponse>),
1049 Rejected(Arc<ConnectionPlanResponse>),
1050}
1051
1052impl Connection {
1053 pub fn rejected(&self) -> Option<&ConnectionPlan> {
1054 if let Self::Rejected(resp) = self {
1055 Some(&resp.connection_plan)
1056 } else {
1057 None
1058 }
1059 }
1060
1061 pub fn initiated(&self) -> Option<&UndocumentedResponse<ConnectResponse>> {
1062 if let Self::Initiated(resp) = self {
1063 Some(resp)
1064 } else {
1065 None
1066 }
1067 }
1068
1069 pub fn is_rejected(&self) -> bool {
1070 self.rejected().is_some()
1071 }
1072
1073 pub fn is_initiated(&self) -> bool {
1074 self.initiated().is_some()
1075 }
1076}
1077
1078fn extract_address(link: &CreatedConnLink) -> String {
1079 link.conn_short_link
1080 .clone()
1081 .unwrap_or_else(|| link.conn_full_link.clone())
1082}
1083
1084fn extract_profile(local: &mut LocalProfile) -> Profile {
1085 Profile {
1086 display_name: std::mem::take(&mut local.display_name),
1087 full_name: std::mem::take(&mut local.full_name),
1088 short_descr: local.short_descr.take(),
1089 image: local.image.take(),
1090 contact_link: local.contact_link.take(),
1091 preferences: local.preferences.take(),
1092 peer_type: local.peer_type.take(),
1093 undocumented: std::mem::take(&mut local.undocumented),
1094 }
1095}
1096
1097fn extract_preferences(preferences: &mut Option<Preferences>) -> Preferences {
1098 match preferences.as_mut() {
1099 Some(prefs) => Preferences {
1100 timed_messages: prefs.timed_messages.take(),
1101 full_delete: prefs.full_delete.take(),
1102 reactions: prefs.reactions.take(),
1103 voice: prefs.voice.take(),
1104 files: prefs.files.take(),
1105 calls: prefs.calls.take(),
1106 sessions: prefs.sessions.take(),
1107 commands: prefs.commands.take(),
1108 undocumented: std::mem::take(&mut prefs.undocumented),
1109 },
1110 None => Preferences {
1111 timed_messages: None,
1112 full_delete: None,
1113 reactions: None,
1114 voice: None,
1115 files: None,
1116 calls: None,
1117 sessions: None,
1118 commands: None,
1119 undocumented: Default::default(),
1120 },
1121 }
1122}