1use std::sync::Arc;
2
3use async_trait::async_trait;
4
5use crate::{
6 api::api_ext::ApiExt,
7 event::{
8 BotEvent, TypedEvent,
9 message::{GroupSenderInfo, PrivateSenderInfo, SenderSex},
10 },
11 message::{self, segments::Segment},
12};
13
14use super::context::BotContext;
15
16#[async_trait]
17pub trait FromEvent {
19 async fn from_event(context: BotContext, event: BotEvent) -> Option<Self>
20 where
21 Self: Sized;
22}
23
24pub struct State<S> {
27 pub state: Arc<S>,
28}
29
30#[async_trait]
31impl<S> FromEvent for State<S>
32where
33 S: 'static + Send + Sync,
34{
35 async fn from_event(context: BotContext, _: BotEvent) -> Option<Self> {
36 let state = context.state.get::<S>()?;
37 Some(Self { state })
38 }
39}
40
41pub struct MessageBody {
43 pub message: message::Message,
44}
45
46#[async_trait]
47impl FromEvent for MessageBody {
48 async fn from_event(_: BotContext, event: BotEvent) -> Option<MessageBody> {
49 match event.event {
50 crate::event::TypedEvent::Message(ref msg) => Some(Self {
51 message: msg.message.clone(),
52 }),
53 _ => None,
54 }
55 }
56}
57
58unsafe impl Send for MessageBody {}
59unsafe impl Sync for MessageBody {}
60
61pub struct BasicSenderInfo {
62 pub user_id: Option<i64>,
63 pub nickname: Option<String>,
64 pub sex: Option<SenderSex>,
65 pub age: Option<i32>,
66}
67
68impl From<PrivateSenderInfo> for BasicSenderInfo {
69 fn from(info: PrivateSenderInfo) -> Self {
70 Self {
71 user_id: info.user_id,
72 nickname: info.nickname,
73 sex: info.sex,
74 age: info.age,
75 }
76 }
77}
78
79impl From<GroupSenderInfo> for BasicSenderInfo {
80 fn from(info: GroupSenderInfo) -> Self {
81 Self {
82 user_id: info.user_id,
83 nickname: info.nickname,
84 sex: info.sex,
85 age: info.age,
86 }
87 }
88}
89
90pub struct Sender {
91 pub info: BasicSenderInfo,
92}
93
94#[async_trait]
95impl FromEvent for Sender {
96 async fn from_event(_: BotContext, event: BotEvent) -> Option<Self> {
97 match event.event {
98 TypedEvent::Message(ref msg) => {
99 let info = match &msg.info {
100 crate::event::message::TypedMessageInfo::Private(info) => {
101 info.sender.clone().into()
102 }
103 crate::event::message::TypedMessageInfo::Group(info) => {
104 info.sender.clone().into()
105 }
106 };
107 Some(Self { info })
108 }
109 _ => None,
110 }
111 }
112}
113
114unsafe impl Send for Sender {}
115unsafe impl Sync for Sender {}
116
117pub struct At {
118 pub user_id: String,
119}
120
121#[async_trait]
122impl FromEvent for At {
123 async fn from_event(_: BotContext, event: BotEvent) -> Option<Self> {
124 if let TypedEvent::Message(ref msg) = event.event {
125 msg.message.iter().find_map(|seg| match seg {
126 Segment::At(at) => Some(Self {
127 user_id: at.qq.clone(),
128 }),
129 _ => None,
130 })
131 } else {
132 None
133 }
134 }
135}
136
137unsafe impl Send for At {}
138unsafe impl Sync for At {}
139
140pub struct GroupId {
141 pub group_id: i64,
142}
143
144#[async_trait]
145impl FromEvent for GroupId {
146 async fn from_event(_: BotContext, event: BotEvent) -> Option<Self>
147 where
148 Self: Sized,
149 {
150 if let TypedEvent::Message(ref msg) = event.event {
151 match &msg.info {
152 crate::event::message::TypedMessageInfo::Group(info) => Some(Self {
153 group_id: info.group_id,
154 }),
155 _ => None,
156 }
157 } else {
158 None
159 }
160 }
161}
162
163unsafe impl Send for GroupId {}
164unsafe impl Sync for GroupId {}
165
166pub struct SenderId {
167 pub user_id: i64,
168}
169
170#[async_trait]
171impl FromEvent for SenderId {
172 async fn from_event(context: BotContext, event: BotEvent) -> Option<Self>
173 where
174 Self: Sized,
175 {
176 let sender_info = Sender::from_event(context, event).await?;
177 Some(Self {
178 user_id: sender_info.info.user_id?,
179 })
180 }
181}
182
183unsafe impl Send for SenderId {}
184unsafe impl Sync for SenderId {}
185
186pub struct MatchGroupId<const ID: i64>;
187
188#[async_trait]
189impl<const ID: i64> FromEvent for MatchGroupId<ID> {
190 async fn from_event(context: BotContext, event: BotEvent) -> Option<Self>
191 where
192 Self: Sized,
193 {
194 let group_id = GroupId::from_event(context, event).await?.group_id;
195 if group_id == ID { Some(Self) } else { None }
196 }
197}
198
199unsafe impl<const ID: i64> Send for MatchGroupId<ID> {}
200unsafe impl<const ID: i64> Sync for MatchGroupId<ID> {}
201
202pub struct Reply {
203 pub reply: message::Message,
204}
205
206#[async_trait]
207impl FromEvent for Reply {
208 async fn from_event(context: BotContext, event: BotEvent) -> Option<Self>
209 where
210 Self: Sized,
211 {
212 if let TypedEvent::Message(ref msg) = event.event {
213 for segment in msg.message.iter() {
214 if let Segment::Reply(reply) = segment {
215 let id = reply.id.parse::<i64>().ok()?;
216 let message = context
217 .get_message(id)
218 .await
219 .map(|msg| msg.message.clone())
220 .ok()?;
221 return Some(Self { reply: message });
222 }
223 }
224 }
225 None
226 }
227}
228
229#[async_trait]
230impl<T> FromEvent for Option<T>
231where
232 T: FromEvent,
233{
234 async fn from_event(context: BotContext, event: BotEvent) -> Option<Self>
235 where
236 Self: Sized,
237 {
238 Some(T::from_event(context, event).await)
239 }
240}
241
242#[macro_export]
258macro_rules! match_one {
259 ($name:ident,$($variant:ident : $matcher:ty),*) => {
260 pub enum $name {
261 $(
262 $variant($matcher),
263 )*
264 }
265
266 #[async_trait::async_trait]
267 impl $crate::base::extract::FromEvent for $name {
268 async fn from_event(context: $crate::base::context::BotContext, event: $crate::event::BotEvent) -> Option<Self> {
269 $(
270 if let Some(matcher) = <$matcher>::from_event(context.clone(), event.clone()).await {
271 return Some(Self::$variant(matcher));
272 }
273 )*
274 None
275 }
276 }
277 };
278}