use crate::contact::group::Group;
use crate::error::{AtriError, AtriResult};
use crate::message::at::At;
use crate::message::meta::Anonymous;
use crate::message::MessageChain;
use crate::{Client, GroupMemberInfo};
use atri_ffi::contact::{FFIMember, MemberUnion};
use atri_ffi::ManagedCloneable;
use ricq::structs::MessageReceipt;
use ricq::RQError;
use std::mem::ManuallyDrop;
use std::sync::Arc;
use std::time::Duration;
#[derive(Clone)]
pub enum Member {
Named(NamedMember),
Anonymous(AnonymousMember),
}
impl Member {
pub fn id(&self) -> i64 {
match self {
Self::Named(named) => named.id(),
Self::Anonymous(_) => AnonymousMember::ID,
}
}
pub fn group(&self) -> &Group {
match self {
Self::Named(named) => named.group(),
Self::Anonymous(ano) => ano.group(),
}
}
pub async fn send_message(&self, chain: MessageChain) -> AtriResult<MessageReceipt> {
match self {
Self::Named(named) => named.send_message(chain).await,
Self::Anonymous(..) => Err(AtriError::Protocol(RQError::Other(
"Send message to anonymous member is not supported".into(),
))),
}
}
pub fn into_ffi(self) -> FFIMember {
match self {
Self::Named(named) => {
let ma = ManagedCloneable::from_value(named);
FFIMember {
is_named: true,
inner: MemberUnion {
named: ManuallyDrop::new(ma),
},
}
}
Self::Anonymous(ano) => {
let ma = ManagedCloneable::from_value(ano);
FFIMember {
is_named: false,
inner: MemberUnion {
anonymous: ManuallyDrop::new(ma),
},
}
}
}
}
pub fn from_ffi(ffi: FFIMember) -> Self {
unsafe {
if ffi.is_named {
let named: NamedMember = ManuallyDrop::into_inner(ffi.inner.named).into_value();
Self::Named(named)
} else {
let ano: AnonymousMember =
ManuallyDrop::into_inner(ffi.inner.anonymous).into_value();
Self::Anonymous(ano)
}
}
}
}
#[derive(Clone)]
pub struct NamedMember(Arc<imp::NamedMember>);
impl NamedMember {
pub fn id(&self) -> i64 {
self.0.info.uin
}
pub fn nickname(&self) -> &str {
&self.0.info.nickname
}
pub fn card_name(&self) -> &str {
&self.0.info.card_name
}
pub fn group(&self) -> &Group {
&self.0.group
}
pub fn client(&self) -> &Client {
self.group().client()
}
pub async fn mute(&self, duration: Duration) -> AtriResult<()> {
self.group()
.client()
.request_client()
.group_mute(self.group().id(), self.id(), duration)
.await
.map_err(AtriError::from)
}
pub async fn kick<S: AsRef<str>>(&self, msg: Option<S>, block: bool) -> AtriResult<()> {
let msg = msg.as_ref().map(AsRef::<str>::as_ref).unwrap_or("");
self.group()
.client()
.request_client()
.group_kick(self.group().id(), vec![self.id()], msg, block)
.await
.map_err(AtriError::from)
}
pub async fn change_card_name<S: ToString>(&self, new: S) -> AtriResult<()> {
self.group()
.client()
.request_client()
.edit_group_member_card(self.group().id(), self.id(), new.to_string())
.await
.map_err(AtriError::from)
}
pub async fn send_message(&self, chain: MessageChain) -> AtriResult<MessageReceipt> {
let client = self.group().client();
let receipt = if let Some(f) = client.find_friend(self.id()) {
f.send_message(chain).await?
} else {
client
.request_client()
.send_group_temp_message(self.group().id(), self.id(), chain.into())
.await?
};
Ok(receipt)
}
pub fn at(&self) -> At {
At {
target: self.id(),
display: self.card_name().into(),
}
}
pub(crate) fn from(group: Group, info: GroupMemberInfo) -> Self {
let inner = imp::NamedMember { group, info };
Self(inner.into())
}
}
#[derive(Clone)]
pub struct AnonymousMember(Arc<imp::AnonymousMember>);
impl AnonymousMember {
pub(crate) fn from(group: Group, info: Anonymous) -> Self {
let inner = imp::AnonymousMember { group, info };
Self(inner.into())
}
}
impl AnonymousMember {
pub const ID: i64 = 80000000;
pub fn id(&self) -> &[u8] {
&self.0.info.anon_id
}
pub fn nick(&self) -> &str {
&self.0.info.nick
}
pub fn group(&self) -> &Group {
&self.0.group
}
pub fn bot(&self) -> &Client {
self.group().client()
}
}
mod imp {
use crate::contact::group::Group;
use crate::message::meta::Anonymous;
use crate::GroupMemberInfo;
pub struct NamedMember {
pub group: Group,
pub info: GroupMemberInfo,
}
pub struct AnonymousMember {
pub group: Group,
pub info: Anonymous,
}
}