1pub mod api;
39pub mod model;
40pub mod utils;
41
42use serde_json::{Value, json};
43
44use crate::{
45 api::user::User,
46 model::{
47 misc::{Log, LoginData, PreRegisterInfo, RegisterInfo, UserLite, UserVipInfo},
48 user::AtUser,
49 },
50 utils::{ResponseResult, error::Error, get, post},
51};
52
53pub struct FishPi;
55
56impl FishPi {
57 pub async fn login(data: &LoginData) -> Result<User, Error> {
63 let url = "api/getKey".to_string();
64
65 let data_json = data.to_value()?;
66
67 let rsp = post(&url, Some(data_json)).await?;
68
69 if rsp.get("code").and_then(|c| c.as_i64()).unwrap_or(-1) != 0 {
70 return Err(Error::Api(
71 rsp["msg"].as_str().unwrap_or("API error").to_string(),
72 ));
73 }
74
75 let token = rsp["Key"].as_str().unwrap_or("").trim().to_string();
76
77 Ok(User::new(token))
78 }
79
80 pub async fn pre_register(data: &PreRegisterInfo) -> Result<ResponseResult, Error> {
86 let url = "register".to_string();
87
88 let data_json = serde_json::to_value(data)
89 .map_err(|e| Error::Parse(format!("Failed to serialize PreRegisterInfo: {}", e)))?;
90
91 let rsp = post(&url, Some(data_json)).await?;
92
93 ResponseResult::from_value(&rsp)
94 }
95
96 pub async fn verify(code: &str) -> Result<String, Error> {
102 let url = format!("verify?code={}", code);
103
104 let rsp = get(&url).await?;
105
106 if rsp.get("code").and_then(|c| c.as_i64()).unwrap_or(-1) != 0 {
107 return Err(Error::Api(
108 rsp["msg"].as_str().unwrap_or("API error").to_string(),
109 ));
110 }
111
112 Ok(rsp["userId"].as_str().unwrap_or("").to_string())
113 }
114
115 pub async fn register(data: &RegisterInfo) -> Result<ResponseResult, Error> {
121 let url = if let Some(r) = &data.r {
122 format!("register2?r={}", r)
123 } else {
124 "register2".to_string()
125 };
126
127 let data_json = serde_json::to_value(data)
128 .map_err(|e| Error::Parse(format!("Failed to serialize RegisterInfo: {}", e)))?;
129
130 let rsp = post(&url, Some(data_json)).await?;
131
132 if let Some(code) = rsp.get("code").and_then(|c| c.as_i64())
133 && code != 0
134 {
135 return Err(Error::Api(
136 rsp["msg"].as_str().unwrap_or("API error").to_string(),
137 ));
138 }
139
140 ResponseResult::from_value(&rsp)
141 }
142
143 pub async fn names(name: &str) -> Result<Vec<AtUser>, Error> {
149 let url = "users/names".to_string();
150
151 let data_json = json!({
152 "name": name,
153 });
154
155 let rsp = post(&url, Some(data_json)).await?;
156
157 if rsp.get("code").and_then(|c| c.as_i64()).unwrap_or(0) != 0 {
158 return Err(Error::Api(
159 rsp["msg"].as_str().unwrap_or("API error").to_string(),
160 ));
161 }
162
163 let at_users = rsp["data"]
164 .as_array()
165 .ok_or_else(|| Error::Api("Data is not an array".to_string()))?
166 .iter()
167 .map(AtUser::from_value)
168 .collect::<Result<Vec<AtUser>, _>>()?;
169
170 Ok(at_users)
171 }
172
173 pub async fn recent_register() -> Result<Vec<UserLite>, Error> {
177 let url = "api/user/recentReg".to_string();
178
179 let rsp = get(&url).await?;
180
181 let user_lites = rsp["data"]
182 .as_array()
183 .ok_or_else(|| Error::Api("Data is not an array".to_string()))?
184 .iter()
185 .map(UserLite::from_value)
186 .collect::<Result<Vec<UserLite>, _>>()?;
187
188 Ok(user_lites)
189 }
190
191 pub async fn vip_info(user_id: &str) -> Result<UserVipInfo, Error> {
197 let url = format!("api/membership/{}", user_id);
198
199 let rsp = get(&url).await?;
200
201 if rsp.get("code").and_then(|c| c.as_i64()).unwrap_or(0) != 0 {
202 return Err(Error::Api(
203 rsp["msg"].as_str().unwrap_or("API error").to_string(),
204 ));
205 }
206
207 let data_obj = rsp["data"]
208 .as_object()
209 .ok_or_else(|| Error::Api("Data is not an object".to_string()))?;
210
211 let config_json_str = data_obj
212 .get("configJson")
213 .and_then(|v| v.as_str())
214 .unwrap_or("null");
215 let mut data: Value = serde_json::from_str(config_json_str).unwrap_or_else(|_| json!({}));
216
217 if let Some(data_map) = data.as_object_mut() {
218 data_map.insert(
219 "state".to_string(),
220 data_obj.get("state").cloned().unwrap_or(Value::Null),
221 );
222 if data_obj.get("state").and_then(|v| v.as_i64()).unwrap_or(0) == 1 {
223 data_map.insert(
224 "oId".to_string(),
225 data_obj.get("oId").cloned().unwrap_or(Value::Null),
226 );
227 data_map.insert(
228 "userId".to_string(),
229 data_obj.get("userId").cloned().unwrap_or(Value::Null),
230 );
231 data_map.insert(
232 "lvCode".to_string(),
233 data_obj.get("lvCode").cloned().unwrap_or(Value::Null),
234 );
235 data_map.insert(
236 "expiresAt".to_string(),
237 data_obj.get("expiresAt").cloned().unwrap_or(Value::Null),
238 );
239 data_map.insert(
240 "createdAt".to_string(),
241 data_obj.get("createdAt").cloned().unwrap_or(Value::Null),
242 );
243 data_map.insert(
244 "updatedAt".to_string(),
245 data_obj.get("updatedAt").cloned().unwrap_or(Value::Null),
246 );
247 }
248 }
249
250 UserVipInfo::from_value(&data)
251 }
252
253 pub async fn log(page: u32, page_size: u32) -> Result<Vec<Log>, Error> {
260 let url = format!("logs/more?page={}&pageSize={}", page, page_size);
261
262 let rsp = get(&url).await?;
263
264 let logs = rsp["data"]
265 .as_array()
266 .ok_or_else(|| Error::Api("Data is not an array".to_string()))?
267 .iter()
268 .map(Log::from_value)
269 .collect::<Result<Vec<Log>, _>>()?;
270
271 Ok(logs)
272 }
273}