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 self.bind("ipinfo.io".to_string(), 80);
84
85 let mut stream = match self.connect().await {
86 ProxyResult::Ok(s) => s,
87 ProxyResult::Err(_) => return None,
88 };
89
90 let _ = stream.write_all(b"GET / HTTP/1.0\r\nHost: ipinfo.io\r\n\r\n").await;
91
92 let mut buf = Vec::new();
93 let _ = stream.read_to_end(&mut buf).await;
94
95 let data = match String::from_utf8(buf) {
96 Ok(s) => s,
97 Err(_) => String::new(),
98 };
99
100 let split_data = data.split("\n").collect::<Vec<&str>>();
101 let mut pretty_data = String::new();
102
103 for (i, item) in split_data.iter().enumerate() {
105 if i < 7 {
106 continue;
107 }
108
109 pretty_data.push_str(*item);
110 }
111
112 let ip_info: IpInfo = match serde_json::from_str(&pretty_data) {
113 Ok(info) => info,
114 Err(_) => return None,
115 };
116
117 Some(ip_info)
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use crate::{Proxy, ProxyChecker, ProxyType};
124
125 #[tokio::test]
126 async fn test_proxy_check() {
127 let proxy = Proxy::new("98.175.31.222:4145", ProxyType::Socks5);
128
129 if proxy.check_proxy().await {
130 println!("Доступен");
131 } else {
132 println!("Недоступен");
133 }
134 }
135
136 #[tokio::test]
137 async fn test_get_ip_info() {
138 let proxy = Proxy::new("98.175.31.222:4145", ProxyType::Socks5);
139 println!("Информация об IP: {:?}", proxy.get_ip_info().await);
140 }
141}