1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
pub mod friend_list;
pub mod group_list;
pub mod member_list;
pub mod message_from_id;
pub mod recall;
pub mod send_friend_message;
pub mod send_group_message;
use serde::Serialize;
use crate::Result;
pub trait Api: ApiRequest {
type Response: serde::de::DeserializeOwned;
fn process_response(value: serde_json::Value) -> Result<Self::Response>;
}
pub trait ApiRequest: Send {
fn command(&self) -> &'static str;
fn sub_command(&self) -> Option<&'static str>;
fn encode(&self, sync_id: i64) -> String;
}
#[derive(Serialize)]
struct ApiRequestData<T: Serialize> {
#[serde(rename = "syncId")]
sync_id: i64,
command: &'static str,
#[serde(rename = "subCommand")]
sub_command: Option<&'static str>,
content: T,
}
#[macro_export]
macro_rules! api {
(
command = $cmd:literal,
$req:path,
$rsp:path
) => {
$crate::api!(
command = $cmd,
subcommand = None,
field = "data",
$req,
$rsp
);
};
(
command = $cmd:literal,
subcommand = $sub_cmd:expr,
field = $field:tt,
$req:path,
$rsp:path
) => {
impl $crate::api::ApiRequest for $req {
fn command(&self) -> &'static str {
$cmd
}
fn sub_command(&self) -> Option<&'static str> {
$sub_cmd
}
fn encode(&self, sync_id: i64) -> String {
let request = $crate::api::ApiRequestData {
command: self.command(),
sub_command: self.sub_command(),
sync_id,
content: &self,
};
serde_json::to_string(&request).unwrap()
}
}
crate::api!(@def_resp field = $field);
impl $crate::api::Api for $req {
type Response = $rsp;
fn process_response(value: serde_json::Value) -> $crate::Result<Self::Response> {
debug!("process value {:?} as response", value);
let resp: ApiResponseData::<$rsp> = serde_json::from_value(value)?;
if resp.code != 0 {
return Err($crate::Error::Request {
code: resp.code,
msg: resp.msg,
});
}
Ok(resp.data)
}
}
};
(@def_resp field = "data") => {
#[derive(Deserialize)]
struct ApiResponseData<T> {
code: i32,
msg: String,
data: T,
}
};
(@def_resp field = "flatten") => {
#[derive(Deserialize)]
struct ApiResponseData<T> {
code: i32,
msg: String,
#[serde(flatten)]
data: T,
}
};
(@def_resp field = "default") => {
#[derive(Deserialize)]
struct ApiResponseData<T> {
code: i32,
msg: String,
#[serde(default)]
data: T,
}
}
}