use crate::ctx::Ctx;
use crate::extract::{Extracted, FromContext, Reject};
use async_trait::async_trait;
use nagisa_types::event::{Event, Meta, Notice, Request};
use nagisa_types::id::{Peer, Uin};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum EventKind {
Message,
MemberJoin, MemberLeave, Mute, WholeMute, AdminChange, GroupNameChange,
Honor, GroupCardChange, Recall, Reaction, EssenceChange, LuckyKing,
Nudge, FriendAdd, GroupFileUpload, FriendFileUpload, PeerPin,
GroupDismiss, GroupTitleChange, InputStatus, ProfileLike, GrayTip,
PokeRecall, OnlineFile, FlashFile,
FriendRequest, GroupJoinRequest, GroupInvitedJoin, GroupInvite,
Connect, Disconnect, Ready, Heartbeat, BotOnline, BotOffline,
Raw,
}
impl EventKind {
pub fn of(event: &Event) -> Option<EventKind> {
use EventKind as K;
Some(match event {
Event::Message(_) => K::Message,
Event::Notice(n) => match n {
Notice::Recall { .. } => K::Recall,
Notice::MemberIncrease { .. } => K::MemberJoin,
Notice::MemberDecrease { .. } => K::MemberLeave,
Notice::AdminChange { .. } => K::AdminChange,
Notice::Mute { .. } => K::Mute,
Notice::WholeMute { .. } => K::WholeMute,
Notice::GroupNameChange { .. } => K::GroupNameChange,
Notice::Honor { .. } => K::Honor,
Notice::GroupCardChange { .. } => K::GroupCardChange,
Notice::FriendNudge { .. } | Notice::GroupNudge { .. } => K::Nudge,
Notice::Reaction { .. } => K::Reaction,
Notice::EssenceChange { .. } => K::EssenceChange,
Notice::GroupFileUpload { .. } => K::GroupFileUpload,
Notice::FriendFileUpload { .. } => K::FriendFileUpload,
Notice::FriendAdd { .. } => K::FriendAdd,
Notice::PeerPinChange { .. } => K::PeerPin,
Notice::BotOffline { .. } => K::BotOffline,
Notice::LuckyKing { .. } => K::LuckyKing,
Notice::GroupDismiss { .. } => K::GroupDismiss,
Notice::GroupTitleChange { .. } => K::GroupTitleChange,
Notice::InputStatus { .. } => K::InputStatus,
Notice::ProfileLike { .. } => K::ProfileLike,
Notice::GrayTip { .. } => K::GrayTip,
Notice::PokeRecall { .. } => K::PokeRecall,
Notice::OnlineFile { .. } => K::OnlineFile,
Notice::FlashFile { .. } => K::FlashFile,
Notice::Other { .. } => return None,
_ => return None,
},
Event::Request(r) => match r {
Request::Friend { .. } => K::FriendRequest,
Request::GroupJoin { .. } => K::GroupJoinRequest,
Request::GroupInvitedJoin { .. } => K::GroupInvitedJoin,
Request::GroupInvite { .. } => K::GroupInvite,
_ => return None,
},
Event::Meta(m) => match m {
Meta::Connect => K::Connect,
Meta::Disconnect { .. } => K::Disconnect,
Meta::Ready { .. } => K::Ready,
Meta::Heartbeat { .. } => K::Heartbeat,
Meta::BotOnline { .. } => K::BotOnline,
Meta::BotOffline => K::BotOffline,
_ => return None,
},
Event::Raw(_) => K::Raw,
_ => K::Raw,
})
}
}
pub struct MemberJoin { pub group: Uin, pub user: Uin, pub operator: Option<Uin>, pub invitor: Option<Uin> }
#[async_trait]
impl FromContext for MemberJoin {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Notice(Notice::MemberIncrease { group, user, operator, invitor }) =>
Ok(MemberJoin { group: *group, user: *user, operator: *operator, invitor: *invitor }),
_ => Err(Reject::Skip),
}
}
}
pub struct MemberLeave {
pub group: Uin,
pub user: Uin,
pub operator: Option<Uin>,
pub reason: nagisa_types::event::MemberDecreaseReason,
}
#[async_trait]
impl FromContext for MemberLeave {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Notice(Notice::MemberDecrease { group, user, operator, reason }) =>
Ok(MemberLeave { group: *group, user: *user, operator: *operator, reason: *reason }),
_ => Err(Reject::Skip),
}
}
}
pub struct Mute { pub group: Uin, pub user: Uin, pub operator: Uin, pub duration: i32 }
#[async_trait]
impl FromContext for Mute {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Notice(Notice::Mute { group, user, operator, duration }) =>
Ok(Mute { group: *group, user: *user, operator: *operator, duration: *duration }),
_ => Err(Reject::Skip),
}
}
}
pub struct Recall {
pub peer: Peer,
pub id: nagisa_types::id::MessageId,
pub sender: Uin,
pub operator: Uin,
pub suffix: Option<String>,
}
#[async_trait]
impl FromContext for Recall {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Notice(Notice::Recall { peer, id, sender, operator, suffix }) =>
Ok(Recall { peer: *peer, id: id.clone(), sender: *sender, operator: *operator, suffix: suffix.clone() }),
_ => Err(Reject::Skip),
}
}
}
pub struct Nudge { pub peer: Peer, pub sender: Uin, pub receiver: Uin }
#[async_trait]
impl FromContext for Nudge {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
let self_id = ctx.bot().self_id();
match ctx.event().as_ref() {
Event::Notice(Notice::FriendNudge { user, is_self_send, .. }) => {
if *is_self_send {
return Err(Reject::Skip);
}
Ok(Nudge { peer: Peer::friend(*user), sender: *user, receiver: self_id })
}
Event::Notice(Notice::GroupNudge { group, sender, receiver, .. }) => {
if *sender == self_id {
return Err(Reject::Skip);
}
Ok(Nudge { peer: Peer::group(*group), sender: *sender, receiver: *receiver })
}
_ => Err(Reject::Skip),
}
}
}
pub struct FriendAdd { pub user: Uin }
#[async_trait]
impl FromContext for FriendAdd {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Notice(Notice::FriendAdd { user }) => Ok(FriendAdd { user: *user }),
_ => Err(Reject::Skip),
}
}
}
pub struct FriendRequest { pub initiator: Uin, pub comment: String, pub token: nagisa_types::event::RequestToken }
#[async_trait]
impl FromContext for FriendRequest {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Request(Request::Friend { initiator, comment, token, .. }) =>
Ok(FriendRequest { initiator: *initiator, comment: comment.clone(), token: token.clone() }),
_ => Err(Reject::Skip),
}
}
}
pub struct GroupJoinRequest { pub group: Uin, pub initiator: Uin, pub comment: String, pub token: nagisa_types::event::RequestToken }
#[async_trait]
impl FromContext for GroupJoinRequest {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Request(Request::GroupJoin { group, initiator, comment, token, .. }) =>
Ok(GroupJoinRequest { group: *group, initiator: *initiator, comment: comment.clone(), token: token.clone() }),
_ => Err(Reject::Skip),
}
}
}
pub struct AdminChange { pub group: Uin, pub user: Uin, pub operator: Option<Uin>, pub is_set: bool }
#[async_trait]
impl FromContext for AdminChange {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Notice(Notice::AdminChange { group, user, operator, is_set }) =>
Ok(AdminChange { group: *group, user: *user, operator: *operator, is_set: *is_set }),
_ => Err(Reject::Skip),
}
}
}
pub struct GroupCardChange { pub group: Uin, pub user: Uin, pub old_card: String, pub new_card: String }
#[async_trait]
impl FromContext for GroupCardChange {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Notice(Notice::GroupCardChange { group, user, old_card, new_card }) =>
Ok(GroupCardChange { group: *group, user: *user, old_card: old_card.clone(), new_card: new_card.clone() }),
_ => Err(Reject::Skip),
}
}
}
pub struct Honor { pub group: Uin, pub user: Uin, pub honor: nagisa_types::event::HonorKind }
#[async_trait]
impl FromContext for Honor {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Notice(Notice::Honor { group, user, honor }) =>
Ok(Honor { group: *group, user: *user, honor: *honor }),
_ => Err(Reject::Skip),
}
}
}
pub struct LuckyKing { pub group: Uin, pub user: Uin, pub target: Uin }
#[async_trait]
impl FromContext for LuckyKing {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Notice(Notice::LuckyKing { group, user, target }) =>
Ok(LuckyKing { group: *group, user: *user, target: *target }),
_ => Err(Reject::Skip),
}
}
}
pub struct Connect;
#[async_trait]
impl FromContext for Connect {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Meta(Meta::Connect) => Ok(Connect),
_ => Err(Reject::Skip),
}
}
}
pub struct Disconnect { pub reason: Option<String> }
#[async_trait]
impl FromContext for Disconnect {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Meta(Meta::Disconnect { reason }) => Ok(Disconnect { reason: reason.clone() }),
_ => Err(Reject::Skip),
}
}
}
pub struct Ready { pub self_id: Uin, pub nickname: String }
#[async_trait]
impl FromContext for Ready {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Meta(Meta::Ready { self_id, nickname }) => {
Ok(Ready { self_id: *self_id, nickname: nickname.clone() })
}
_ => Err(Reject::Skip),
}
}
}
pub struct BotOnline { pub reason: Option<String> }
#[async_trait]
impl FromContext for BotOnline {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Meta(Meta::BotOnline { reason }) => Ok(BotOnline { reason: reason.clone() }),
_ => Err(Reject::Skip),
}
}
}
pub struct BotOffline;
#[async_trait]
impl FromContext for BotOffline {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Meta(Meta::BotOffline) => Ok(BotOffline),
_ => Err(Reject::Skip),
}
}
}
pub struct Heartbeat { pub interval: i64, pub online: bool, pub good: bool }
#[async_trait]
impl FromContext for Heartbeat {
async fn from_context(ctx: &Ctx) -> Extracted<Self> {
match ctx.event().as_ref() {
Event::Meta(Meta::Heartbeat { interval, status }) =>
Ok(Heartbeat { interval: *interval, online: status.online, good: status.good }),
_ => Err(Reject::Skip),
}
}
}