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