Skip to main content

bpi_rs/clientinfo/
ip.rs

1//! IP 地址归属地查询 API
2//!
3//! [参考文档](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/clientinfo/ip.md)
4
5use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
6use serde::{ Deserialize, Serialize };
7
8// ==========================
9// 数据结构
10// ==========================
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct IpInfo {
14    /// 国家
15    pub country: Option<String>,
16    /// 省份
17    pub province: Option<String>,
18    /// 城市
19    pub city: Option<String>,
20    /// ISP 运营商
21    pub isp: Option<String>,
22    /// IP 地址
23    pub addr: Option<String>,
24}
25
26// ==========================
27// API 封装
28// ==========================
29
30impl BpiClient {
31    /// 查询 IP 地址归属地
32    ///
33    /// 查询指定 IP 地址的地理位置信息,包括国家、省份、城市和 ISP 运营商。
34    /// 如果不提供 IP 参数,将返回请求方 IP 的地理信息。
35    ///
36    /// # 参数
37    /// | 名称 | 类型 | 说明 |
38    /// | ---- | ---- | ---- |
39    /// | `ip` | `Option<&str>` | IPv4 或 IPv6 地址,可选。如果留空,返回请求方 IP 信息 |
40    ///
41    /// # 文档
42    /// [IP 地址归属地查询](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/clientinfo/ip.md)
43    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}