pub mod api;
pub mod model;
pub mod utils;
use serde_json::{Value, json};
use crate::{
api::user::User,
model::{
misc::{Log, LoginData, PreRegisterInfo, RegisterInfo, UserLite, UserVipInfo},
user::AtUser,
},
utils::{ResponseResult, error::Error, get, post},
};
pub struct FishPi;
impl FishPi {
pub async fn login(data: &LoginData) -> Result<User, Error> {
let url = "api/getKey".to_string();
let data_json = data.to_value()?;
let rsp = post(&url, Some(data_json)).await?;
if rsp.get("code").and_then(|c| c.as_i64()).unwrap_or(-1) != 0 {
return Err(Error::Api(
rsp["msg"].as_str().unwrap_or("API error").to_string(),
));
}
let token = rsp["Key"].as_str().unwrap_or("").trim().to_string();
Ok(User::new(token))
}
pub async fn pre_register(data: &PreRegisterInfo) -> Result<ResponseResult, Error> {
let url = "register".to_string();
let data_json = serde_json::to_value(data)
.map_err(|e| Error::Parse(format!("Failed to serialize PreRegisterInfo: {}", e)))?;
let rsp = post(&url, Some(data_json)).await?;
ResponseResult::from_value(&rsp)
}
pub async fn verify(code: &str) -> Result<String, Error> {
let url = format!("verify?code={}", code);
let rsp = get(&url).await?;
if rsp.get("code").and_then(|c| c.as_i64()).unwrap_or(-1) != 0 {
return Err(Error::Api(
rsp["msg"].as_str().unwrap_or("API error").to_string(),
));
}
Ok(rsp["userId"].as_str().unwrap_or("").to_string())
}
pub async fn register(data: &RegisterInfo) -> Result<ResponseResult, Error> {
let url = if let Some(r) = &data.r {
format!("register2?r={}", r)
} else {
"register2".to_string()
};
let data_json = serde_json::to_value(data)
.map_err(|e| Error::Parse(format!("Failed to serialize RegisterInfo: {}", e)))?;
let rsp = post(&url, Some(data_json)).await?;
if let Some(code) = rsp.get("code").and_then(|c| c.as_i64())
&& code != 0
{
return Err(Error::Api(
rsp["msg"].as_str().unwrap_or("API error").to_string(),
));
}
ResponseResult::from_value(&rsp)
}
pub async fn names(name: &str) -> Result<Vec<AtUser>, Error> {
let url = "users/names".to_string();
let data_json = json!({
"name": name,
});
let rsp = post(&url, Some(data_json)).await?;
if rsp.get("code").and_then(|c| c.as_i64()).unwrap_or(0) != 0 {
return Err(Error::Api(
rsp["msg"].as_str().unwrap_or("API error").to_string(),
));
}
let at_users = rsp["data"]
.as_array()
.ok_or_else(|| Error::Api("Data is not an array".to_string()))?
.iter()
.map(AtUser::from_value)
.collect::<Result<Vec<AtUser>, _>>()?;
Ok(at_users)
}
pub async fn recent_register() -> Result<Vec<UserLite>, Error> {
let url = "api/user/recentReg".to_string();
let rsp = get(&url).await?;
let user_lites = rsp["data"]
.as_array()
.ok_or_else(|| Error::Api("Data is not an array".to_string()))?
.iter()
.map(UserLite::from_value)
.collect::<Result<Vec<UserLite>, _>>()?;
Ok(user_lites)
}
pub async fn vip_info(user_id: &str) -> Result<UserVipInfo, Error> {
let url = format!("api/membership/{}", user_id);
let rsp = get(&url).await?;
if rsp.get("code").and_then(|c| c.as_i64()).unwrap_or(0) != 0 {
return Err(Error::Api(
rsp["msg"].as_str().unwrap_or("API error").to_string(),
));
}
let data_obj = rsp["data"]
.as_object()
.ok_or_else(|| Error::Api("Data is not an object".to_string()))?;
let config_json_str = data_obj
.get("configJson")
.and_then(|v| v.as_str())
.unwrap_or("null");
let mut data: Value = serde_json::from_str(config_json_str).unwrap_or_else(|_| json!({}));
if let Some(data_map) = data.as_object_mut() {
data_map.insert(
"state".to_string(),
data_obj.get("state").cloned().unwrap_or(Value::Null),
);
if data_obj.get("state").and_then(|v| v.as_i64()).unwrap_or(0) == 1 {
data_map.insert(
"oId".to_string(),
data_obj.get("oId").cloned().unwrap_or(Value::Null),
);
data_map.insert(
"userId".to_string(),
data_obj.get("userId").cloned().unwrap_or(Value::Null),
);
data_map.insert(
"lvCode".to_string(),
data_obj.get("lvCode").cloned().unwrap_or(Value::Null),
);
data_map.insert(
"expiresAt".to_string(),
data_obj.get("expiresAt").cloned().unwrap_or(Value::Null),
);
data_map.insert(
"createdAt".to_string(),
data_obj.get("createdAt").cloned().unwrap_or(Value::Null),
);
data_map.insert(
"updatedAt".to_string(),
data_obj.get("updatedAt").cloned().unwrap_or(Value::Null),
);
}
}
UserVipInfo::from_value(&data)
}
pub async fn log(page: u32, page_size: u32) -> Result<Vec<Log>, Error> {
let url = format!("logs/more?page={}&pageSize={}", page, page_size);
let rsp = get(&url).await?;
let logs = rsp["data"]
.as_array()
.ok_or_else(|| Error::Api("Data is not an array".to_string()))?
.iter()
.map(Log::from_value)
.collect::<Result<Vec<Log>, _>>()?;
Ok(logs)
}
}