1use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
6use serde::{ Deserialize, Serialize };
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct IpInfo {
14 pub country: Option<String>,
16 pub province: Option<String>,
18 pub city: Option<String>,
20 pub isp: Option<String>,
22 pub addr: Option<String>,
24}
25
26impl BpiClient {
31 pub async fn clientinfo_ip(&self, ip: Option<&str>) -> Result<BpiResponse<IpInfo>, BpiError> {
44 let mut req = self.get(
45 "https://api.live.bilibili.com/ip_service/v1/ip_service/get_ip_addr"
46 );
47
48 if let Some(ip) = ip {
49 req = req.query(&[("ip", ip)]);
50 }
51
52 req.send_bpi("查询 IP 地址归属地").await
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 const TEST_IP: &str = "8.8.8.8";
61
62 #[tokio::test]
63 async fn test_clientinfo_ip() -> Result<(), Box<BpiError>> {
64 let bpi = BpiClient::new();
65
66 let resp = bpi.clientinfo_ip(Some(TEST_IP)).await?;
67 if resp.code == 0 {
68 if let Some(data) = resp.data {
69 tracing::info!(
70 "IP 地址: {}, 省份: {:?}, 城市: {:?}, ISP: {:?}",
71 data.addr.unwrap_or_default(),
72 data.province,
73 data.city,
74 data.isp
75 );
76 }
77 } else {
78 tracing::error!("请求失败: code={}, message={}", resp.code, resp.message);
79 }
80
81 Ok(())
82 }
83}