use crate::*;
#[allow(unused_imports)]
use crate::{
InputMessage, InvocationError, PeerRef,
dialog::{Dialog, DialogIter, MessageIter},
inline_iter, media, participants, search, update,
};
use ferogram_tl_types::{Cursor, Deserializable};
impl Client {
pub async fn get_contacts(&self) -> Result<Vec<tl::enums::User>, InvocationError> {
let req = tl::functions::contacts::GetContacts { hash: 0 };
let body: Vec<u8> = self.rpc_call_raw(&req).await?;
let mut cur = Cursor::from_slice(&body);
match tl::enums::contacts::Contacts::deserialize(&mut cur)? {
tl::enums::contacts::Contacts::Contacts(c) => {
self.cache_users_slice(&c.users).await;
Ok(c.users)
}
tl::enums::contacts::Contacts::NotModified => Ok(vec![]),
}
}
pub async fn delete_contacts(&self, user_ids: &[i64]) -> Result<(), InvocationError> {
if user_ids.is_empty() {
return Ok(());
}
let cache: tokio::sync::RwLockReadGuard<'_, PeerCache> = self.inner.peer_cache.read().await;
let users: Vec<tl::enums::InputUser> = user_ids
.iter()
.map(|&id| {
let hash = cache.users.get(&id).copied().unwrap_or(0);
tl::enums::InputUser::InputUser(tl::types::InputUser {
user_id: id,
access_hash: hash,
})
})
.collect();
let req = tl::functions::contacts::DeleteContacts { id: users };
self.rpc_write(&req).await
}
pub async fn block(
&self,
peer: impl Into<PeerRef>,
block: bool,
) -> Result<(), InvocationError> {
let peer = peer.into().resolve(self).await?;
let input_peer = self.inner.peer_cache.read().await.peer_to_input(&peer)?;
if block {
let req = tl::functions::contacts::Block {
my_stories_from: false,
id: input_peer,
};
self.rpc_write(&req).await
} else {
let req = tl::functions::contacts::Unblock {
my_stories_from: false,
id: input_peer,
};
self.rpc_write(&req).await
}
}
pub async fn set_presence(&self, online: bool) -> Result<(), InvocationError> {
let req = tl::functions::account::UpdateStatus { offline: !online };
self.rpc_write(&req).await
}
pub async fn terminate_session(&self, hash: i64) -> Result<(), InvocationError> {
let req = tl::functions::account::ResetAuthorization { hash };
self.rpc_write(&req).await
}
pub async fn add_contact(
&self,
user_id: i64,
first_name: impl Into<String>,
last_name: impl Into<String>,
phone: impl Into<String>,
add_phone_privacy_exception: bool,
) -> Result<(), InvocationError> {
let hash = self
.inner
.peer_cache
.read()
.await
.users
.get(&user_id)
.copied()
.unwrap_or(0);
let req = tl::functions::contacts::AddContact {
add_phone_privacy_exception,
id: tl::enums::InputUser::InputUser(tl::types::InputUser {
user_id,
access_hash: hash,
}),
first_name: first_name.into(),
last_name: last_name.into(),
phone: phone.into(),
note: None,
};
self.rpc_write(&req).await
}
pub async fn import_contacts(
&self,
contacts: &[(&str, &str, &str)],
) -> Result<tl::types::contacts::ImportedContacts, InvocationError> {
use ferogram_tl_types::{Cursor, Deserializable};
let contacts_tl: Vec<tl::enums::InputContact> = contacts
.iter()
.enumerate()
.map(|(i, (phone, first, last))| {
tl::enums::InputContact::InputPhoneContact(tl::types::InputPhoneContact {
client_id: i as i64,
phone: phone.to_string(),
first_name: first.to_string(),
last_name: last.to_string(),
note: None,
})
})
.collect();
let req = tl::functions::contacts::ImportContacts {
contacts: contacts_tl,
};
let body = self.rpc_call_raw(&req).await?;
let mut cur = Cursor::from_slice(&body);
let tl::enums::contacts::ImportedContacts::ImportedContacts(result) =
tl::enums::contacts::ImportedContacts::deserialize(&mut cur)?;
self.cache_users_slice(&result.users).await;
Ok(result)
}
pub async fn get_blocked_users(
&self,
offset: i32,
limit: i32,
) -> Result<Vec<tl::enums::Peer>, InvocationError> {
let req = tl::functions::contacts::GetBlocked {
my_stories_from: false,
offset,
limit,
};
let body = self.rpc_call_raw(&req).await?;
let mut cur = Cursor::from_slice(&body);
let (blocked, chats, users) = match tl::enums::contacts::Blocked::deserialize(&mut cur)? {
tl::enums::contacts::Blocked::Blocked(b) => (b.blocked, b.chats, b.users),
tl::enums::contacts::Blocked::Slice(b) => (b.blocked, b.chats, b.users),
};
self.cache_users_slice(&users).await;
self.cache_chats_slice(&chats).await;
Ok(blocked
.into_iter()
.map(|b| match b {
tl::enums::PeerBlocked::PeerBlocked(pb) => pb.peer_id,
})
.collect())
}
pub async fn search_contacts(
&self,
query: impl Into<String>,
limit: i32,
) -> Result<Vec<tl::enums::Peer>, InvocationError> {
let req = tl::functions::contacts::Search {
q: query.into(),
limit,
bots: false,
broadcasts: false,
};
let body = self.rpc_call_raw(&req).await?;
let mut cur = Cursor::from_slice(&body);
let tl::enums::contacts::Found::Found(found) =
tl::enums::contacts::Found::deserialize(&mut cur)?;
self.cache_users_slice(&found.users).await;
self.cache_chats_slice(&found.chats).await;
let mut peers = found.my_results;
for p in found.results {
if !peers.contains(&p) {
peers.push(p);
}
}
Ok(peers)
}
pub async fn delete_profile_photos(
&self,
photo_ids: Vec<(i64, i64, Vec<u8>)>,
) -> Result<Vec<i64>, InvocationError> {
let id: Vec<tl::enums::InputPhoto> = photo_ids
.into_iter()
.map(|(id, access_hash, file_reference)| {
tl::enums::InputPhoto::InputPhoto(tl::types::InputPhoto {
id,
access_hash,
file_reference,
})
})
.collect();
let req = tl::functions::photos::DeletePhotos { id };
let body = self.rpc_call_raw(&req).await?;
let mut cur = Cursor::from_slice(&body);
let v = Vec::<i64>::deserialize(&mut cur)?;
Ok(v)
}
pub fn set_profile(&self, peer: impl Into<PeerRef>) -> crate::SetProfileBuilder {
crate::SetProfileBuilder::new(self.clone(), peer.into())
}
pub async fn get_authorizations(
&self,
) -> Result<Vec<tl::types::Authorization>, InvocationError> {
let req = tl::functions::account::GetAuthorizations {};
let body = self.rpc_call_raw(&req).await?;
let mut cur = Cursor::from_slice(&body);
let tl::enums::account::Authorizations::Authorizations(result) =
tl::enums::account::Authorizations::deserialize(&mut cur)?;
Ok(result
.authorizations
.into_iter()
.map(|x| {
let tl::enums::Authorization::Authorization(a) = x;
a
})
.collect())
}
pub async fn get_user_full(
&self,
user_id: i64,
) -> Result<tl::types::UserFull, InvocationError> {
let hash = self
.inner
.peer_cache
.read()
.await
.users
.get(&user_id)
.copied()
.unwrap_or(0);
let req = tl::functions::users::GetFullUser {
id: tl::enums::InputUser::InputUser(tl::types::InputUser {
user_id,
access_hash: hash,
}),
};
let body = self.rpc_call_raw(&req).await?;
let mut cur = Cursor::from_slice(&body);
let tl::enums::users::UserFull::UserFull(result) =
tl::enums::users::UserFull::deserialize(&mut cur)?;
self.cache_users_slice(&result.users).await;
self.cache_chats_slice(&result.chats).await;
let tl::enums::UserFull::UserFull(full_user) = result.full_user;
Ok(full_user)
}
pub async fn stats(
&self,
peer: impl Into<PeerRef>,
) -> Result<crate::ChannelStats, InvocationError> {
use ferogram_tl_types as tl;
let peer = peer.into().resolve(self).await?;
let input_peer = self.inner.peer_cache.read().await.peer_to_input(&peer)?;
let channel = match &input_peer {
tl::enums::InputPeer::Channel(c) => {
tl::enums::InputChannel::InputChannel(tl::types::InputChannel {
channel_id: c.channel_id,
access_hash: c.access_hash,
})
}
_ => {
return Err(InvocationError::Deserialize(
"stats: peer must be a channel or supergroup".into(),
));
}
};
let broadcast_req = tl::functions::stats::GetBroadcastStats {
dark: false,
channel: channel.clone(),
};
if let Ok(body) = self.rpc_call_raw(&broadcast_req).await {
let mut cur = Cursor::from_slice(&body);
if let Ok(s) = tl::enums::stats::BroadcastStats::deserialize(&mut cur) {
return Ok(crate::ChannelStats::Broadcast(s));
}
}
let meg_req = tl::functions::stats::GetMegagroupStats {
dark: false,
channel,
};
let body = self.rpc_call_raw(&meg_req).await?;
let mut cur = Cursor::from_slice(&body);
Ok(crate::ChannelStats::Megagroup(
tl::enums::stats::MegagroupStats::deserialize(&mut cur)?,
))
}
}