1use crate::ctx::Ctx;
5use crate::extract::{Extracted, FromContext, Reject};
6use async_trait::async_trait;
7use nagisa_types::event::{Event, Meta, Notice, Request};
8use nagisa_types::id::{Peer, Uin};
9
10#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
13pub enum EventKind {
14 Message,
15 MemberJoin,
16 MemberLeave,
17 Mute,
18 WholeMute,
19 AdminChange,
20 GroupNameChange,
21 Honor,
22 GroupCardChange,
23 Recall,
24 Reaction,
25 EssenceChange,
26 LuckyKing,
27 Nudge,
28 FriendAdd,
29 GroupFileUpload,
30 FriendFileUpload,
31 PeerPin,
32 GroupDismiss,
33 GroupTitleChange,
34 InputStatus,
35 ProfileLike,
36 GrayTip,
37 PokeRecall,
38 OnlineFile,
39 FlashFile,
40 FriendRequest,
41 GroupJoinRequest,
42 GroupInvitedJoin,
43 GroupInvite,
44 Connect,
45 Disconnect,
46 Ready,
47 Heartbeat,
48 BotOnline,
49 BotOffline,
50 Raw,
51}
52
53impl EventKind {
54 pub fn of(event: &Event) -> Option<EventKind> {
56 use EventKind as K;
57 Some(match event {
58 Event::Message(_) => K::Message,
59 Event::Notice(n) => match n {
60 Notice::Recall { .. } => K::Recall,
61 Notice::MemberIncrease { .. } => K::MemberJoin,
62 Notice::MemberDecrease { .. } => K::MemberLeave,
63 Notice::AdminChange { .. } => K::AdminChange,
64 Notice::Mute { .. } => K::Mute,
65 Notice::WholeMute { .. } => K::WholeMute,
66 Notice::GroupNameChange { .. } => K::GroupNameChange,
67 Notice::Honor { .. } => K::Honor,
68 Notice::GroupCardChange { .. } => K::GroupCardChange,
69 Notice::FriendNudge { .. } | Notice::GroupNudge { .. } => K::Nudge,
70 Notice::Reaction { .. } => K::Reaction,
71 Notice::EssenceChange { .. } => K::EssenceChange,
72 Notice::GroupFileUpload { .. } => K::GroupFileUpload,
73 Notice::FriendFileUpload { .. } => K::FriendFileUpload,
74 Notice::FriendAdd { .. } => K::FriendAdd,
75 Notice::PeerPinChange { .. } => K::PeerPin,
76 Notice::BotOffline { .. } => K::BotOffline,
77 Notice::LuckyKing { .. } => K::LuckyKing,
78 Notice::GroupDismiss { .. } => K::GroupDismiss,
79 Notice::GroupTitleChange { .. } => K::GroupTitleChange,
80 Notice::InputStatus { .. } => K::InputStatus,
81 Notice::ProfileLike { .. } => K::ProfileLike,
82 Notice::GrayTip { .. } => K::GrayTip,
83 Notice::PokeRecall { .. } => K::PokeRecall,
84 Notice::OnlineFile { .. } => K::OnlineFile,
85 Notice::FlashFile { .. } => K::FlashFile,
86 Notice::Other { .. } => return None,
87 _ => return None,
88 },
89 Event::Request(r) => match r {
90 Request::Friend { .. } => K::FriendRequest,
91 Request::GroupJoin { .. } => K::GroupJoinRequest,
92 Request::GroupInvitedJoin { .. } => K::GroupInvitedJoin,
93 Request::GroupInvite { .. } => K::GroupInvite,
94 _ => return None,
95 },
96 Event::Meta(m) => match m {
97 Meta::Connect => K::Connect,
98 Meta::Disconnect { .. } => K::Disconnect,
99 Meta::Ready { .. } => K::Ready,
100 Meta::Heartbeat { .. } => K::Heartbeat,
101 Meta::BotOnline { .. } => K::BotOnline,
102 Meta::BotOffline => K::BotOffline,
103 _ => return None,
104 },
105 Event::Raw(_) => K::Raw,
106 _ => K::Raw,
107 })
108 }
109}
110
111pub struct MemberJoin {
118 pub group: Uin,
119 pub user: Uin,
120 pub operator: Option<Uin>,
121 pub invitor: Option<Uin>,
122}
123#[async_trait]
124impl FromContext for MemberJoin {
125 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
126 match ctx.event().as_ref() {
127 Event::Notice(Notice::MemberIncrease { group, user, operator, invitor }) => {
128 Ok(MemberJoin { group: *group, user: *user, operator: *operator, invitor: *invitor })
129 }
130 _ => Err(Reject::Skip),
131 }
132 }
133}
134
135pub struct MemberLeave {
137 pub group: Uin,
138 pub user: Uin,
139 pub operator: Option<Uin>,
140 pub reason: nagisa_types::event::MemberDecreaseReason,
141}
142#[async_trait]
143impl FromContext for MemberLeave {
144 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
145 match ctx.event().as_ref() {
146 Event::Notice(Notice::MemberDecrease { group, user, operator, reason }) => {
147 Ok(MemberLeave { group: *group, user: *user, operator: *operator, reason: *reason })
148 }
149 _ => Err(Reject::Skip),
150 }
151 }
152}
153
154pub struct Mute {
156 pub group: Uin,
157 pub user: Uin,
158 pub operator: Uin,
159 pub duration: i32,
160}
161#[async_trait]
162impl FromContext for Mute {
163 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
164 match ctx.event().as_ref() {
165 Event::Notice(Notice::Mute { group, user, operator, duration }) => {
166 Ok(Mute { group: *group, user: *user, operator: *operator, duration: *duration })
167 }
168 _ => Err(Reject::Skip),
169 }
170 }
171}
172
173pub struct Recall {
178 pub peer: Peer,
179 pub id: nagisa_types::id::MessageId,
180 pub sender: Uin,
181 pub operator: Uin,
182 pub suffix: Option<String>,
183}
184#[async_trait]
185impl FromContext for Recall {
186 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
187 match ctx.event().as_ref() {
188 Event::Notice(Notice::Recall { peer, id, sender, operator, suffix }) => {
189 Ok(Recall { peer: *peer, id: id.clone(), sender: *sender, operator: *operator, suffix: suffix.clone() })
190 }
191 _ => Err(Reject::Skip),
192 }
193 }
194}
195
196pub struct Nudge {
199 pub peer: Peer,
200 pub sender: Uin,
201 pub receiver: Uin,
202}
203#[async_trait]
204impl FromContext for Nudge {
205 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
206 let self_id = ctx.bot().self_id();
207 match ctx.event().as_ref() {
208 Event::Notice(Notice::FriendNudge { user, is_self_send, .. }) => {
209 if *is_self_send {
210 return Err(Reject::Skip);
211 }
212 Ok(Nudge { peer: Peer::friend(*user), sender: *user, receiver: self_id })
214 }
215 Event::Notice(Notice::GroupNudge { group, sender, receiver, .. }) => {
216 if *sender == self_id {
217 return Err(Reject::Skip);
218 }
219 Ok(Nudge { peer: Peer::group(*group), sender: *sender, receiver: *receiver })
220 }
221 _ => Err(Reject::Skip),
222 }
223 }
224}
225
226pub struct FriendAdd {
228 pub user: Uin,
229}
230#[async_trait]
231impl FromContext for FriendAdd {
232 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
233 match ctx.event().as_ref() {
234 Event::Notice(Notice::FriendAdd { user }) => Ok(FriendAdd { user: *user }),
235 _ => Err(Reject::Skip),
236 }
237 }
238}
239
240pub struct FriendRequest {
242 pub initiator: Uin,
243 pub comment: String,
244 pub token: nagisa_types::event::RequestToken,
245}
246#[async_trait]
247impl FromContext for FriendRequest {
248 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
249 match ctx.event().as_ref() {
250 Event::Request(Request::Friend { initiator, comment, token, .. }) => {
251 Ok(FriendRequest { initiator: *initiator, comment: comment.clone(), token: token.clone() })
252 }
253 _ => Err(Reject::Skip),
254 }
255 }
256}
257
258pub struct GroupJoinRequest {
260 pub group: Uin,
261 pub initiator: Uin,
262 pub comment: String,
263 pub token: nagisa_types::event::RequestToken,
264}
265#[async_trait]
266impl FromContext for GroupJoinRequest {
267 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
268 match ctx.event().as_ref() {
269 Event::Request(Request::GroupJoin { group, initiator, comment, token, .. }) => Ok(GroupJoinRequest {
270 group: *group,
271 initiator: *initiator,
272 comment: comment.clone(),
273 token: token.clone(),
274 }),
275 _ => Err(Reject::Skip),
276 }
277 }
278}
279
280pub struct AdminChange {
283 pub group: Uin,
284 pub user: Uin,
285 pub operator: Option<Uin>,
286 pub is_set: bool,
287}
288#[async_trait]
289impl FromContext for AdminChange {
290 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
291 match ctx.event().as_ref() {
292 Event::Notice(Notice::AdminChange { group, user, operator, is_set }) => {
293 Ok(AdminChange { group: *group, user: *user, operator: *operator, is_set: *is_set })
294 }
295 _ => Err(Reject::Skip),
296 }
297 }
298}
299
300pub struct GroupCardChange {
303 pub group: Uin,
304 pub user: Uin,
305 pub old_card: String,
306 pub new_card: String,
307}
308#[async_trait]
309impl FromContext for GroupCardChange {
310 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
311 match ctx.event().as_ref() {
312 Event::Notice(Notice::GroupCardChange { group, user, old_card, new_card }) => Ok(GroupCardChange {
313 group: *group,
314 user: *user,
315 old_card: old_card.clone(),
316 new_card: new_card.clone(),
317 }),
318 _ => Err(Reject::Skip),
319 }
320 }
321}
322
323pub struct Honor {
325 pub group: Uin,
326 pub user: Uin,
327 pub honor: nagisa_types::event::HonorKind,
328}
329#[async_trait]
330impl FromContext for Honor {
331 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
332 match ctx.event().as_ref() {
333 Event::Notice(Notice::Honor { group, user, honor }) => {
334 Ok(Honor { group: *group, user: *user, honor: *honor })
335 }
336 _ => Err(Reject::Skip),
337 }
338 }
339}
340
341pub struct LuckyKing {
343 pub group: Uin,
344 pub user: Uin,
345 pub target: Uin,
346}
347#[async_trait]
348impl FromContext for LuckyKing {
349 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
350 match ctx.event().as_ref() {
351 Event::Notice(Notice::LuckyKing { group, user, target }) => {
352 Ok(LuckyKing { group: *group, user: *user, target: *target })
353 }
354 _ => Err(Reject::Skip),
355 }
356 }
357}
358
359pub struct Connect;
367#[async_trait]
368impl FromContext for Connect {
369 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
370 match ctx.event().as_ref() {
371 Event::Meta(Meta::Connect) => Ok(Connect),
372 _ => Err(Reject::Skip),
373 }
374 }
375}
376
377pub struct Disconnect {
379 pub reason: Option<String>,
380}
381#[async_trait]
382impl FromContext for Disconnect {
383 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
384 match ctx.event().as_ref() {
385 Event::Meta(Meta::Disconnect { reason }) => Ok(Disconnect { reason: reason.clone() }),
386 _ => Err(Reject::Skip),
387 }
388 }
389}
390
391pub struct Ready {
394 pub self_id: Uin,
395 pub nickname: String,
396}
397#[async_trait]
398impl FromContext for Ready {
399 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
400 match ctx.event().as_ref() {
401 Event::Meta(Meta::Ready { self_id, nickname }) => {
402 Ok(Ready { self_id: *self_id, nickname: nickname.clone() })
403 }
404 _ => Err(Reject::Skip),
405 }
406 }
407}
408
409pub struct BotOnline {
411 pub reason: Option<String>,
412}
413#[async_trait]
414impl FromContext for BotOnline {
415 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
416 match ctx.event().as_ref() {
417 Event::Meta(Meta::BotOnline { reason }) => Ok(BotOnline { reason: reason.clone() }),
418 _ => Err(Reject::Skip),
419 }
420 }
421}
422
423pub struct BotOffline;
425#[async_trait]
426impl FromContext for BotOffline {
427 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
428 match ctx.event().as_ref() {
429 Event::Meta(Meta::BotOffline) => Ok(BotOffline),
430 _ => Err(Reject::Skip),
431 }
432 }
433}
434
435pub struct Heartbeat {
437 pub interval: i64,
438 pub online: bool,
439 pub good: bool,
440}
441#[async_trait]
442impl FromContext for Heartbeat {
443 async fn from_context(ctx: &Ctx) -> Extracted<Self> {
444 match ctx.event().as_ref() {
445 Event::Meta(Meta::Heartbeat { interval, status }) => {
446 Ok(Heartbeat { interval: *interval, online: status.online, good: status.good })
447 }
448 _ => Err(Reject::Skip),
449 }
450 }
451}