1use std::str::FromStr;
2
3use serde_json::Value;
4
5use crate::{impl_str_enum, utils::error::Error};
6
7#[derive(Clone, Debug)]
9#[repr(u8)]
10pub enum GestureType {
11 Rock = 0,
13 Scissors = 1,
15 Paper = 2,
17}
18
19#[derive(Clone, Debug)]
21pub enum RedPacketType {
22 Random,
24 Average,
26 Specify,
28 Heartbeat,
30 RockPaperScissors,
32}
33
34#[derive(Clone, Debug)]
36pub struct RedPacket {
37 pub r#type: RedPacketType,
39 pub money: u32,
41 pub count: u32,
43 pub msg: String,
45 pub recivers: Vec<String>,
47 pub gesture: Option<GestureType>,
49}
50
51#[derive(Clone, Debug)]
53#[allow(non_snake_case)]
54pub struct RedPacketGot {
55 pub userId: String,
57 pub userName: String,
59 pub avatar: String,
61 pub userMoney: u32,
63 pub time: String,
65}
66
67#[derive(Clone, Debug)]
69#[allow(non_snake_case)]
70pub struct RedPacketMessage {
71 pub msgType: String,
73 pub count: u32,
75 pub got: u32,
77 pub money: u32,
79 pub msg: String,
81 pub senderId: String,
83 pub GestureType: Option<GestureType>,
85 pub recivers: Vec<String>,
87 pub who: Vec<RedPacketGot>,
89}
90
91#[derive(Clone, Debug)]
93#[allow(non_snake_case)]
94pub struct RedPacketBase {
95 pub count: u32,
97 pub gesture: Option<GestureType>,
99 pub got: u32,
101 pub msg: String,
103 pub userName: String,
105 pub userAvatarURL: String,
107}
108
109#[derive(Clone, Debug)]
111pub struct RedPacketInfo {
112 pub info: RedPacketBase,
113 pub recivers: Vec<String>,
114 pub who: Vec<RedPacketGot>,
115}
116
117fn parse_string_list(data: &Value, primary_key: &str, fallback_key: &str) -> Vec<String> {
118 data.get(primary_key)
119 .or_else(|| data.get(fallback_key))
120 .and_then(|v| v.as_array())
121 .map(|arr| {
122 arr.iter()
123 .filter_map(|v| v.as_str().map(ToString::to_string))
124 .collect()
125 })
126 .unwrap_or_default()
127}
128
129fn parse_gesture(
130 data: &Value,
131 primary_key: &str,
132 fallback_key: &str,
133 err_ctx: &str,
134) -> Result<Option<GestureType>, Error> {
135 let gesture = data
136 .get(primary_key)
137 .and_then(|v| v.as_str())
138 .or_else(|| data.get(fallback_key).and_then(|v| v.as_str()));
139
140 match gesture {
141 Some(gesture_str) => GestureType::from_str(gesture_str)
142 .map(Some)
143 .map_err(|_| Error::Parse(format!("Invalid gesture in {}", err_ctx))),
144 None => Ok(None),
145 }
146}
147
148fn parse_who_list(data: &Value) -> Result<Vec<RedPacketGot>, Error> {
149 let Some(who_array) = data.get("who").and_then(|v| v.as_array()) else {
150 return Ok(Vec::new());
151 };
152
153 let mut got_list = Vec::with_capacity(who_array.len());
154 for item in who_array {
155 let user_money = item
156 .get("userMoney")
157 .or_else(|| item.get("money"))
158 .and_then(|v| {
159 v.as_u64()
160 .or_else(|| v.as_i64().and_then(|n| if n >= 0 { Some(n as u64) } else { None }))
161 .or_else(|| v.as_str().and_then(|s| s.parse::<u64>().ok()))
162 })
163 .unwrap_or(0) as u32;
164 got_list.push(RedPacketGot {
165 userId: item["userId"]
166 .as_str()
167 .ok_or_else(|| Error::Parse("Missing userId in who".to_string()))?
168 .to_string(),
169 userName: item["userName"]
170 .as_str()
171 .ok_or_else(|| Error::Parse("Missing userName in who".to_string()))?
172 .to_string(),
173 avatar: item["avatar"]
174 .as_str()
175 .ok_or_else(|| Error::Parse("Missing avatar in who".to_string()))?
176 .to_string(),
177 userMoney: user_money,
178 time: item["time"]
179 .as_str()
180 .ok_or_else(|| Error::Parse("Missing time in who".to_string()))?
181 .to_string(),
182 });
183 }
184
185 Ok(got_list)
186}
187
188#[derive(Clone, Debug)]
190#[allow(non_snake_case)]
191pub struct RedPacketStatusMsg {
192 pub oId: String,
193 pub count: u32,
194 pub got: u32,
195 pub whoGive: String,
196 pub whoGot: Vec<String>,
197 pub avatarURL20: String,
198 pub avatarURL48: String,
199 pub avatarURL210: String,
200}
201
202impl RedPacketStatusMsg {
203 pub fn from_value(data: &Value) -> Result<Self, Error> {
204 Ok(RedPacketStatusMsg {
205 oId: data["oId"]
206 .as_str()
207 .ok_or_else(|| Error::Parse("Missing oId in RedPacketStatusMsg".to_string()))?
208 .to_string(),
209 count: data["count"].as_u64().ok_or_else(|| {
210 Error::Parse("Missing or invalid count in RedPacketStatusMsg".to_string())
211 })? as u32,
212 got: data["got"].as_u64().ok_or_else(|| {
213 Error::Parse("Missing or invalid got in RedPacketStatusMsg".to_string())
214 })? as u32,
215 whoGive: data["whoGive"]
216 .as_str()
217 .ok_or_else(|| Error::Parse("Missing whoGive in RedPacketStatusMsg".to_string()))?
218 .to_string(),
219 whoGot: if let Some(who_got_array) = data["whoGot"].as_array() {
220 who_got_array
221 .iter()
222 .filter_map(|v| v.as_str().map(|s| s.to_string()))
223 .collect()
224 } else {
225 data["whoGot"]
226 .as_str()
227 .map(|s| vec![s.to_string()])
228 .unwrap_or_default()
229 },
230 avatarURL20: data["userAvatarURL20"]
231 .as_str()
232 .ok_or_else(|| {
233 Error::Parse("Missing userAvatarURL20 in RedPacketStatusMsg".to_string())
234 })?
235 .to_string(),
236 avatarURL48: data["userAvatarURL48"]
237 .as_str()
238 .ok_or_else(|| {
239 Error::Parse("Missing userAvatarURL48 in RedPacketStatusMsg".to_string())
240 })?
241 .to_string(),
242 avatarURL210: data["userAvatarURL210"]
243 .as_str()
244 .ok_or_else(|| {
245 Error::Parse("Missing userAvatarURL210 in RedPacketStatusMsg".to_string())
246 })?
247 .to_string(),
248 })
249 }
250}
251
252impl Default for RedPacket {
253 fn default() -> Self {
254 RedPacket {
255 r#type: RedPacketType::Random,
256 money: 32,
257 count: 1,
258 msg: "摸鱼者, 事竟成!".to_string(),
259 recivers: Vec::new(),
260 gesture: None,
261 }
262 }
263}
264
265impl RedPacket {
266 pub fn from_value(data: &Value) -> Result<Self, Error> {
267 Ok(RedPacket {
268 r#type: RedPacketType::from_str(
269 data["type"]
270 .as_str()
271 .ok_or_else(|| Error::Parse("Missing type in RedPacket".to_string()))?,
272 )
273 .map_err(|_| Error::Parse("Invalid type in RedPacket".to_string()))?,
274 money: data["money"]
275 .as_u64()
276 .ok_or_else(|| Error::Parse("Missing or invalid money in RedPacket".to_string()))?
277 as u32,
278 count: data["count"]
279 .as_u64()
280 .ok_or_else(|| Error::Parse("Missing or invalid count in RedPacket".to_string()))?
281 as u32,
282 msg: data["msg"]
283 .as_str()
284 .ok_or_else(|| Error::Parse("Missing msg in RedPacket".to_string()))?
285 .to_string(),
286 recivers: parse_string_list(data, "recivers", "receivers"),
287 gesture: parse_gesture(data, "gesture", "GestureType", "RedPacket")?,
288 })
289 }
290}
291
292impl RedPacketMessage {
293 pub fn from_value(data: &Value) -> Result<Self, Error> {
294 Ok(RedPacketMessage {
295 msgType: data["msgType"]
296 .as_str()
297 .ok_or_else(|| Error::Parse("Missing msgType in RedPacketMessage".to_string()))?
298 .to_string(),
299 count: data["count"].as_u64().ok_or_else(|| {
300 Error::Parse("Missing or invalid count in RedPacketMessage".to_string())
301 })? as u32,
302 got: data["got"].as_u64().ok_or_else(|| {
303 Error::Parse("Missing or invalid got in RedPacketMessage".to_string())
304 })? as u32,
305 money: data["money"].as_u64().ok_or_else(|| {
306 Error::Parse("Missing or invalid money in RedPacketMessage".to_string())
307 })? as u32,
308 msg: data["msg"]
309 .as_str()
310 .ok_or_else(|| Error::Parse("Missing msg in RedPacketMessage".to_string()))?
311 .to_string(),
312 senderId: data["senderId"]
313 .as_str()
314 .ok_or_else(|| Error::Parse("Missing senderId in RedPacketMessage".to_string()))?
315 .to_string(),
316 GestureType: parse_gesture(data, "gesture", "GestureType", "RedPacketMessage")?,
317 recivers: parse_string_list(data, "recivers", "receivers"),
318 who: parse_who_list(data)?,
319 })
320 }
321}
322
323impl RedPacketBase {
324 pub fn from_value(data: &Value) -> Result<Self, Error> {
325 Ok(RedPacketBase {
326 count: data["count"].as_u64().ok_or_else(|| {
327 Error::Parse("Missing or invalid count in RedPacketBase".to_string())
328 })? as u32,
329 gesture: parse_gesture(data, "gesture", "GestureType", "RedPacketBase")?,
330 got: data["got"].as_u64().ok_or_else(|| {
331 Error::Parse("Missing or invalid got in RedPacketBase".to_string())
332 })? as u32,
333 msg: data["msg"]
334 .as_str()
335 .ok_or_else(|| Error::Parse("Missing msg in RedPacketBase".to_string()))?
336 .to_string(),
337 userName: data["userName"]
338 .as_str()
339 .ok_or_else(|| Error::Parse("Missing userName in RedPacketBase".to_string()))?
340 .to_string(),
341 userAvatarURL: data["userAvatarURL"]
342 .as_str()
343 .ok_or_else(|| Error::Parse("Missing userAvatarURL in RedPacketBase".to_string()))?
344 .to_string(),
345 })
346 }
347}
348
349impl RedPacketInfo {
350 pub fn from_value(data: &Value) -> Result<Self, Error> {
351 let info_data = &data["info"];
352 let info = RedPacketBase::from_value(info_data)?;
353
354 let recivers = parse_string_list(data, "recivers", "receivers");
355 let who = parse_who_list(data)?;
356
357 Ok(RedPacketInfo {
358 info,
359 recivers,
360 who,
361 })
362 }
363}
364
365impl_str_enum!(GestureType {
366 Rock => "石头",
367 Scissors => "剪刀",
368 Paper => "布",
369});
370
371impl_str_enum!(RedPacketType {
372 Random => "random",
373 Average => "average",
374 Specify => "specify",
375 Heartbeat => "heartbeat",
376 RockPaperScissors => "rockPaperScissors",
377});