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 =
45            self.get("https://api.live.bilibili.com/ip_service/v1/ip_service/get_ip_addr");
46
47        if let Some(ip) = ip {
48            req = req.query(&[("ip", ip)]);
49        }
50
51        req.send_bpi("查询 IP 地址归属地").await
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    const TEST_IP: &str = "8.8.8.8";
60
61    #[tokio::test]
62    async fn test_clientinfo_ip() -> Result<(), Box<BpiError>> {
63        let bpi = BpiClient::new();
64
65        let resp = bpi.clientinfo_ip(Some(TEST_IP)).await?;
66        if resp.code == 0 {
67            if let Some(data) = resp.data {
68                tracing::info!(
69                    "IP 地址: {}, 省份: {:?}, 城市: {:?}, ISP: {:?}",
70                    data.addr.unwrap_or_default(),
71                    data.province,
72                    data.city,
73                    data.isp
74                );
75            }
76        } else {
77            tracing::error!("请求失败: code={}, message={}", resp.code, resp.message);
78        }
79
80        Ok(())
81    }
82}