From 5ea8ebbf647edd50441fea24db11b977702fa0c5 Mon Sep 17 00:00:00 2001 From: mokurin000 <1348292515a@gmail.com> Date: Wed, 30 Jul 2025 03:57:51 +0800 Subject: [PATCH] feat: preview user info --- Cargo.lock | 1 + Cargo.toml | 2 + sdgb-api/Cargo.toml | 2 +- .../title/model/get_user_preview_api/mod.rs | 70 +++++++++++++++++++ sdgb-api/src/title/model/mod.rs | 3 + sdgb-cli/Cargo.toml | 1 + sdgb-cli/src/commands.rs | 4 ++ sdgb-cli/src/main.rs | 26 ++++++- 8 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 sdgb-api/src/title/model/get_user_preview_api/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 7b76365..ed731e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1121,6 +1121,7 @@ dependencies = [ "nyquest-preset", "palc", "sdgb-api", + "serde_json", "snafu", "spdlog-rs", ] diff --git a/Cargo.toml b/Cargo.toml index d833bc9..4db59f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,9 @@ resolver = "3" [workspace.dependencies] sdgb-api = { path = "./sdgb-api" } + snafu = { version = "0.8.6", features = ["backtrace", "rust_1_81"] } +serde_json = "1.0.141" [profile.release] lto = true diff --git a/sdgb-api/Cargo.toml b/sdgb-api/Cargo.toml index ecb8351..31ec8f0 100644 --- a/sdgb-api/Cargo.toml +++ b/sdgb-api/Cargo.toml @@ -7,6 +7,7 @@ license = "GPL-3.0" [dependencies] snafu = { workspace = true } +serde_json = { workspace = true } digest = "0.10.7" hmac-sha256 = { version = "1.1.12", features = ["digest010", "traits010"] } @@ -20,7 +21,6 @@ nyquest = { version = "0.2.0", features = ["async", "json"] } # (de)serialization serde = { version = "1.0.219", features = ["derive"] } -serde_json = "1.0.141" flate2 = "1.1.2" cbc = "0.1.2" diff --git a/sdgb-api/src/title/model/get_user_preview_api/mod.rs b/sdgb-api/src/title/model/get_user_preview_api/mod.rs new file mode 100644 index 0000000..b74832a --- /dev/null +++ b/sdgb-api/src/title/model/get_user_preview_api/mod.rs @@ -0,0 +1,70 @@ +use std::fmt::Display; + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetUserPreviewApi { + pub user_id: u32, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetUserPreviewApiResp { + pub user_id: i64, + pub user_name: String, + pub is_login: bool, + pub last_rom_version: String, + pub last_data_version: String, + pub last_login_date: String, + pub last_play_date: String, + pub player_rating: i64, + pub nameplate_id: i64, + pub icon_id: i64, + pub trophy_id: i64, + pub is_net_member: i64, + pub is_inherit: bool, + pub total_awake: i64, + pub disp_rate: i64, + pub daily_bonus_date: String, + pub ban_state: i64, + // pub last_game_id: Value, + // pub head_phone_volume: Value, +} + +impl Display for GetUserPreviewApiResp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("ID: {}\n", self.user_id))?; + f.write_fmt(format_args!("昵称: {}\n", self.user_name))?; + f.write_fmt(format_args!("登录中: {}\n", self.is_login))?; + + f.write_fmt(format_args!("上次游戏版本: {}\n", self.last_rom_version))?; + f.write_fmt(format_args!("上次数据版本: {}\n", self.last_data_version))?; + + f.write_fmt(format_args!("DX Rating: {}\n", self.player_rating))?; + f.write_fmt(format_args!("牌子: {}\n", self.nameplate_id))?; + f.write_fmt(format_args!("图标: {}\n", self.icon_id))?; + f.write_fmt(format_args!("trophy: {}\n", self.trophy_id))?; + f.write_fmt(format_args!("Net成员: {}\n", self.is_net_member))?; + f.write_fmt(format_args!("继承账号: {}\n", self.is_inherit))?; + f.write_fmt(format_args!("总觉醒: {}\n", self.total_awake))?; + + f.write_fmt(format_args!( + "状态显示: {}\n", + match self.disp_rate { + 0 => "全部都显示", + 1 => "显示评级和段位", + 2 => "显示评级和阶级", + 3 => "显示段位和阶级", + 4 => "只显示评级", + 5 => "只显示段位", + 6 => "只显示阶级", + 7 => "全部都不显示", + _ => "未知", + } + ))?; + + f.write_fmt(format_args!("封禁状态: {}\n", self.ban_state))?; + Ok(()) + } +} diff --git a/sdgb-api/src/title/model/mod.rs b/sdgb-api/src/title/model/mod.rs index 9af5d52..ad6cdc0 100644 --- a/sdgb-api/src/title/model/mod.rs +++ b/sdgb-api/src/title/model/mod.rs @@ -2,3 +2,6 @@ use serde::Serialize; #[derive(Serialize)] pub struct Ping {} + +mod get_user_preview_api; +pub use get_user_preview_api::{GetUserPreviewApi, GetUserPreviewApiResp}; diff --git a/sdgb-cli/Cargo.toml b/sdgb-cli/Cargo.toml index c4d8c9f..b4aa4ea 100644 --- a/sdgb-cli/Cargo.toml +++ b/sdgb-cli/Cargo.toml @@ -8,6 +8,7 @@ description = "CLI tool for SDGB protocol" [dependencies] snafu = { workspace = true } sdgb-api = { workspace = true } +serde_json = { workspace = true } nyquest-preset = { version = "0.2.0", features = ["async"] } compio = { version = "0.15.0", default-features = false, features = [ diff --git a/sdgb-cli/src/commands.rs b/sdgb-cli/src/commands.rs index 2ce8f23..93dc30a 100644 --- a/sdgb-cli/src/commands.rs +++ b/sdgb-cli/src/commands.rs @@ -11,6 +11,10 @@ pub struct Cli { #[derive(Subcommand)] pub enum Commands { Ping, + Preview { + #[arg(short, long)] + user_id: u32, + }, /// Login with QRCode from wechat QRLogin { /// content of the qrcode, only the last 64 characters were used diff --git a/sdgb-cli/src/main.rs b/sdgb-cli/src/main.rs index 41b2f9a..ed69484 100644 --- a/sdgb-cli/src/main.rs +++ b/sdgb-cli/src/main.rs @@ -2,7 +2,11 @@ use nyquest_preset::nyquest::ClientBuilder; use palc::Parser; use sdgb_api::{ all_net::QRCode, - title::{MaiVersionExt, Sdgb1_40, Sdgb1_50, methods::APIMethod, model::Ping}, + title::{ + MaiVersionExt, Sdgb1_40, Sdgb1_50, + methods::APIMethod, + model::{GetUserPreviewApi, GetUserPreviewApiResp, Ping}, + }, }; use spdlog::{error, info}; @@ -18,8 +22,26 @@ async fn main() -> Result<(), Box> { let client = ClientBuilder::default().build_async().await?; match cmd.command { + commands::Commands::Preview { user_id } => { + let preview = Sdgb1_50::request( + &client, + APIMethod::GetUserPreviewApi, + user_id, + GetUserPreviewApi { user_id }, + ) + .await?; + + let preview: GetUserPreviewApiResp = serde_json::from_slice(&preview)?; + println!("{preview}"); + } commands::Commands::Ping => { - let decoded = Sdgb1_40::request(&client, APIMethod::Ping, "", Ping {}).await?; + let decoded = Sdgb1_40::request( + &client, + APIMethod::Ping, + "", + Ping {}, // note: must not be `Ping`, or serde_json serializes to nothing + ) + .await?; info!("sdgb 1.40 resp: {:?}", String::from_utf8_lossy(&decoded)); let decoded = Sdgb1_50::request(&client, APIMethod::Ping, "", Ping {}).await?; info!("sdgb 1.50 resp: {:?}", String::from_utf8_lossy(&decoded));