1use serde::Deserialize;
2use tokio::io::{AsyncReadExt, AsyncWriteExt};
3
4use crate::Proxy;
5use crate::result::ProxyResult;
6
7#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
9pub struct IpInfo {
10 pub ip: String,
11 pub hostname: String,
12 pub city: String,
13 pub region: String,
14 pub country: String,
15 pub loc: String,
16 pub org: String,
17 pub postal: String,
18 pub timezone: String,
19 pub readme: String,
20}
21
22pub trait ProxyChecker {
24 fn check_proxy(&self) -> impl std::future::Future<Output = bool> + Send;
42
43 fn get_ip_info(&self) -> impl std::future::Future<Output = Option<IpInfo>> + Send;
60}
61
62impl ProxyChecker for Proxy {
63 async fn check_proxy(&self) -> bool {
64 if !self.is_available().await {
65 return false;
66 }
67
68 let ip_info = match self.get_ip_info().await {
69 Some(info) => info,
70 None => return false,
71 };
72
73 if let Some(ip) = self.get_ip() {
74 if ip != ip_info.ip {
75 return false;
76 }
77 }
78
79 true
80 }
81
82 async fn get_ip_info(&self) -> Option<IpInfo> {
83 let mut stream = match self.connect("ipinfo.io", 80).await {
84 ProxyResult::Ok(s) => s,
85 ProxyResult::Err(_) => return None,
86 };
87
88 let _ = stream.write_all(b"GET / HTTP/1.0\r\nHost: ipinfo.io\r\n\r\n").await;
89
90 let mut buf = Vec::new();
91 let _ = stream.read_to_end(&mut buf).await;
92
93 let data = match String::from_utf8(buf) {
94 Ok(s) => s,
95 Err(_) => String::new(),
96 };
97
98 let split_data = data.split("\n").collect::<Vec<&str>>();
99 let mut pretty_data = String::new();
100
101 for (i, item) in split_data.iter().enumerate() {
103 if i < 7 {
104 continue;
105 }
106
107 pretty_data.push_str(*item);
108 }
109
110 let ip_info: IpInfo = match serde_json::from_str(&pretty_data) {
111 Ok(info) => info,
112 Err(_) => return None,
113 };
114
115 Some(ip_info)
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use crate::{Proxy, ProxyChecker, ProxyType};
122
123 #[tokio::test]
124 async fn test_proxy_check() {
125 let proxy = Proxy::new("98.175.31.222:4145", ProxyType::Socks5);
126
127 if proxy.check_proxy().await {
128 println!("Доступен");
129 } else {
130 println!("Недоступен");
131 }
132 }
133
134 #[tokio::test]
135 async fn test_get_ip_info() {
136 let proxy = Proxy::new("98.175.31.222:4145", ProxyType::Socks5);
137 println!("Информация об IP: {:?}", proxy.get_ip_info().await);
138 }
139}