1use serde::{Deserialize, Serialize};
3
4use crate::{
5 prelude::{WalleError, WalleResult},
6 structs::Selft,
7 util::{GetSelf, PushToValueMap, ValueMap, ValueMapExt},
8};
9
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
12pub struct Action {
13 pub action: String,
14 pub params: ValueMap,
15 #[serde(rename = "self")]
16 pub selft: Option<Selft>,
17}
18
19pub trait ToAction: PushToValueMap {
20 fn ty(&self) -> &'static str;
21 fn selft(&self) -> Option<Selft> {
22 None
23 }
24 fn to_action(self) -> Action
25 where
26 Self: Sized,
27 {
28 Action {
29 action: self.ty().to_string(),
30 selft: self.selft(),
31 params: {
32 let mut map = ValueMap::new();
33 self.push_to(&mut map);
34 map
35 },
36 }
37 }
38}
39
40pub trait TryFromAction: Sized {
41 fn try_from_action_mut(action: &mut Action) -> WalleResult<Self>;
42 fn try_from_action(mut action: Action) -> WalleResult<Self> {
43 Self::try_from_action_mut(&mut action)
44 }
45}
46
47impl GetSelf for Action {
48 fn get_self(&self) -> Selft {
49 self.selft.clone().unwrap_or_default()
50 }
51}
52
53#[derive(Debug, Clone, PartialEq)]
55pub struct BaseAction<T> {
56 pub action: T,
57 pub selft: Option<Selft>,
58 pub extra: ValueMap,
59}
60
61impl<T> From<BaseAction<T>> for Action
62where
63 T: ToAction,
64{
65 fn from(mut action: BaseAction<T>) -> Self {
66 Self {
67 action: action.action.ty().to_string(),
68 selft: action.selft,
69 params: {
70 action.action.push_to(&mut action.extra);
71 action.extra
72 },
73 }
74 }
75}
76
77impl<T> From<(T, Selft)> for Action
78where
79 T: ToAction + Into<ValueMap>,
80{
81 fn from(v: (T, Selft)) -> Self {
82 Self {
83 action: v.0.ty().to_owned(),
84 params: v.0.into(),
85 selft: Some(v.1),
86 }
87 }
88}
89
90impl<T> TryFrom<Action> for BaseAction<T>
91where
92 T: TryFromAction,
93{
94 type Error = WalleError;
95 fn try_from(mut value: Action) -> Result<Self, Self::Error> {
96 Ok(Self {
97 action: T::try_from_action_mut(&mut value)?,
98 selft: value.selft,
99 extra: value.params,
100 })
101 }
102}
103
104use walle_macro::{
105 _PushToValueMap as PushToValueMap, _ToAction as ToAction, _TryFromAction as TryFromAction,
106 _TryFromValue as TryFromValue,
107};
108
109#[derive(Debug, Clone, PartialEq, Eq, TryFromValue, TryFromAction, ToAction, PushToValueMap)]
110pub struct GetLatestEvents {
111 pub limit: i64,
112 pub timeout: i64,
113}
114
115#[derive(Debug, Clone, PartialEq, Eq, TryFromValue, TryFromAction, ToAction, PushToValueMap)]
116pub struct DeleteMessage {
117 pub message_id: String,
118}
119
120macro_rules! action {
121 ($name: ident) => {
122 #[derive(Debug, Clone, PartialEq, Eq, TryFromValue, TryFromAction, ToAction, PushToValueMap)]
123 pub struct $name;
124 };
125 ($name: ident, $($f: ident: $fty: ty),*) => {
126 #[derive(Debug, Clone, PartialEq, Eq, TryFromValue, TryFromAction, ToAction, PushToValueMap)]
127 pub struct $name {
128 $(pub $f: $fty,)*
129 }
130 };
131}
132
133use crate::util::OneBotBytes;
134
135#[derive(Debug, Clone, PartialEq, Eq, TryFromValue, TryFromAction, ToAction, PushToValueMap)]
136pub struct GetUserInfo {
137 pub user_id: String,
138}
139action!(GetGroupInfo, group_id: String);
141action!(GetGroupList);
142action!(GetGroupMemberInfo, group_id: String, user_id: String);
143action!(GetGroupMemberList, group_id: String);
144action!(SetGroupName, group_id: String, group_name: String);
145action!(LeaveGroup, group_id: String);
146action!(GetGuildInfo, guild_id: String);
148action!(GetGuildList);
149action!(SetGuildName, guild_id: String, guild_name: String);
150action!(GetGuildMemberInfo, guild_id: String, user_id: String);
151action!(GetGuildMemberList, guild_id: String);
152action!(LeaveGuild, guild_id: String);
153action!(GetChannelInfo, guild_id: String, channel_id: String);
155action!(GetChannelList, guild_id: String, joined_only: bool);
156action!(
157 SetChannelName,
158 guild_id: String,
159 channel_id: String,
160 channel_name: String
161);
162action!(
163 GetChannelMemberInfo,
164 guild_id: String,
165 channel_id: String,
166 user_id: String
167);
168action!(GetChannelMemberList, guild_id: String, channel_id: String);
169action!(LeaveChannel, guild_id: String, channel_id: String);
170#[derive(Debug, Clone, PartialEq, TryFromValue, TryFromAction, ToAction, PushToValueMap)]
172pub struct SendMessage {
173 pub detail_type: String,
174 pub user_id: Option<String>,
175 pub group_id: Option<String>,
176 pub guild_id: Option<String>,
177 pub channel_id: Option<String>,
178 pub message: crate::segment::Segments,
179}
180
181#[derive(Debug, Clone, PartialEq, Eq, TryFromValue, TryFromAction, ToAction, PushToValueMap)]
182pub struct GetFile {
183 pub file_id: String,
184 pub ty: String,
185}
186
187#[derive(Debug, Clone, PartialEq, Eq, TryFromValue, TryFromAction, ToAction, PushToValueMap)]
188pub struct UploadFile {
189 pub ty: String,
190 pub name: String,
191 pub url: Option<String>,
192 pub headers: Option<std::collections::HashMap<String, String>>,
193 pub path: Option<String>,
194 pub data: Option<OneBotBytes>,
195 pub sha256: Option<String>,
196}
197
198#[derive(Debug, Clone, PartialEq, Eq)]
199pub enum UploadFileFragmented {
200 Prepare {
201 name: String,
202 total_size: i64,
203 },
204 Transfer {
205 file_id: String,
206 offset: i64,
207 data: OneBotBytes,
208 },
209 Finish {
210 file_id: String,
211 sha256: Option<String>,
212 },
213}
214
215impl TryFromAction for UploadFileFragmented {
216 fn try_from_action_mut(action: &mut Action) -> WalleResult<Self> {
217 if action.action != "upload_file_fragmented" {
218 Err(WalleError::DeclareNotMatch(
219 "upload_file_fragmented",
220 action.action.clone(),
221 ))
222 } else {
223 match action.params.remove_downcast::<String>("stage")?.as_str() {
224 "prepare" => Ok(Self::Prepare {
225 name: action.params.remove_downcast("name")?,
226 total_size: action.params.remove_downcast("total_size")?,
227 }),
228 "transfer" => Ok(Self::Transfer {
229 file_id: action.params.remove_downcast("file_id")?,
230 offset: action.params.remove_downcast("offset")?,
231 data: action.params.remove_downcast("data")?,
232 }),
233 "finish" => Ok(Self::Finish {
234 file_id: action.params.remove_downcast("file_id")?,
235 sha256: action.params.try_remove_downcast("sha256")?,
236 }),
237 x => Err(WalleError::DeclareNotMatch(
238 "prepare or transfer or finish",
239 x.to_string(),
240 )),
241 }
242 }
243 }
244}
245
246impl TryFrom<&mut ValueMap> for UploadFileFragmented {
247 type Error = WalleError;
248 fn try_from(map: &mut ValueMap) -> Result<Self, Self::Error> {
249 match map.remove_downcast::<String>("stage")?.as_str() {
250 "prepare" => Ok(Self::Prepare {
251 name: map.remove_downcast("name")?,
252 total_size: map.remove_downcast("total_size")?,
253 }),
254 "transfer" => Ok(Self::Transfer {
255 file_id: map.remove_downcast("file_id")?,
256 offset: map.remove_downcast("offset")?,
257 data: map.remove_downcast("data")?,
258 }),
259 "finish" => Ok(Self::Finish {
260 file_id: map.remove_downcast("file_id")?,
261 sha256: map.try_remove_downcast("sha256")?,
262 }),
263 x => Err(WalleError::DeclareNotMatch(
264 "prepare or transfer or finish",
265 x.to_string(),
266 )),
267 }
268 }
269}
270
271impl PushToValueMap for UploadFileFragmented {
272 fn push_to(self, map: &mut ValueMap) {
273 match self {
274 UploadFileFragmented::Prepare { name, total_size } => {
275 map.insert("stage".to_string(), "prepare".into());
276 map.insert("name".to_string(), name.into());
277 map.insert("total_size".to_string(), total_size.into());
278 }
279 UploadFileFragmented::Transfer {
280 file_id,
281 offset,
282 data,
283 } => {
284 map.insert("stage".to_string(), "transfer".into());
285 map.insert("file_id".to_string(), file_id.into());
286 map.insert("offset".to_string(), offset.into());
287 map.insert("data".to_string(), data.into());
288 }
289 UploadFileFragmented::Finish { file_id, sha256 } => {
290 map.insert("stage".to_string(), "finish".into());
291 map.insert("file_id".to_string(), file_id.into());
292 map.insert("sha256".to_string(), sha256.into());
293 }
294 }
295 }
296}
297
298impl ToAction for UploadFileFragmented {
299 fn ty(&self) -> &'static str {
300 "upload_file_fragmented"
301 }
302}
303
304impl From<UploadFileFragmented> for Action {
305 fn from(u: UploadFileFragmented) -> Self {
306 u.to_action()
307 }
308}
309
310#[derive(Debug, Clone, PartialEq, Eq)]
311pub enum GetFileFragmented {
312 Prepare {
313 file_id: String,
314 },
315 Transfer {
316 file_id: String,
317 offset: i64,
318 size: i64,
319 },
320}
321
322impl TryFromAction for GetFileFragmented {
323 fn try_from_action_mut(action: &mut Action) -> WalleResult<Self> {
324 if action.action != "get_file_fragmented" {
325 Err(WalleError::DeclareNotMatch(
326 "get_file_fragmented",
327 action.action.clone(),
328 ))
329 } else {
330 match action.params.remove_downcast::<String>("stage")?.as_str() {
331 "prepare" => Ok(Self::Prepare {
332 file_id: action.params.remove_downcast("file_id")?,
333 }),
334 "transfer" => Ok(Self::Transfer {
335 file_id: action.params.remove_downcast("file_id")?,
336 offset: action.params.remove_downcast("offset")?,
337 size: action.params.remove_downcast("size")?,
338 }),
339 x => Err(WalleError::DeclareNotMatch(
340 "prepare or transfer or finish",
341 x.to_string(),
342 )),
343 }
344 }
345 }
346}
347
348impl TryFrom<&mut ValueMap> for GetFileFragmented {
349 type Error = WalleError;
350 fn try_from(map: &mut ValueMap) -> WalleResult<Self> {
351 match map.remove_downcast::<String>("stage")?.as_str() {
352 "prepare" => Ok(Self::Prepare {
353 file_id: map.remove_downcast("file_id")?,
354 }),
355 "transfer" => Ok(Self::Transfer {
356 file_id: map.remove_downcast("file_id")?,
357 offset: map.remove_downcast("offset")?,
358 size: map.remove_downcast("size")?,
359 }),
360 x => Err(WalleError::DeclareNotMatch(
361 "prepare | transfer | finish",
362 x.to_string(),
363 )),
364 }
365 }
366}
367
368impl PushToValueMap for GetFileFragmented {
369 fn push_to(self, map: &mut ValueMap) {
370 match self {
371 Self::Prepare { file_id } => {
372 map.insert("stage".to_string(), "prepare".into());
373 map.insert("file_id".to_string(), file_id.into());
374 }
375 Self::Transfer {
376 file_id,
377 offset,
378 size,
379 } => {
380 map.insert("stage".to_string(), "transfer".into());
381 map.insert("file_id".to_string(), file_id.into());
382 map.insert("offset".to_string(), offset.into());
383 map.insert("size".to_string(), size.into());
384 }
385 }
386 }
387}
388
389impl ToAction for GetFileFragmented {
390 fn ty(&self) -> &'static str {
391 "get_file_fragmented"
392 }
393}
394
395impl From<GetFileFragmented> for Action {
396 fn from(g: GetFileFragmented) -> Self {
397 g.to_action()
398 }
399}
400
401#[test]
402fn action() {
403 use crate::{value_map, WalleResult};
404 let action = Action {
405 action: "upload_file".to_string(),
406 selft: None,
407 params: value_map! {
408 "type": "type",
409 "name": "name",
410 "extra": "test"
411 },
412 };
413 let uf: WalleResult<BaseAction<UploadFile>> = action.try_into();
414 println!("{:?}", uf);
415}