rust_anticaptcha/core/captcha_interface.rs
1use std::time::Duration;
2
3use serde_json::{json, Value};
4use tokio::time::sleep;
5
6use super::enums::{EnpPostfix, GetResultStatus, TaskTypeTrait};
7use super::request_interface::RequestInterface;
8use super::structs::{CreateTaskRequest, ResultTaskRequest};
9
10/// Structure-interface stored captcha-solving methods
11/// and main logic for captcha service communication
12pub struct CaptchaInterface {
13 pub api_key: String, // service API key
14
15 callbackUrl: String, // optional web address where we can send the results of
16 // captcha task processing
17 sleep_time: u8, // sleep time between requests for task result receive
18 max_attempts: u8, // number of max retries for task result receive
19
20 task_payload: Value,
21 request_interface: RequestInterface,
22}
23impl CaptchaInterface {
24 /// New `CaptchaInterface` instance creation and setting API key value
25 pub fn new(api_key: String) -> Self {
26 CaptchaInterface {
27 api_key,
28 sleep_time: 10,
29 max_attempts: 5,
30 callbackUrl: String::new(),
31 task_payload: json!({}),
32 request_interface: RequestInterface::new(),
33 }
34 }
35
36 /// Method set new sleep time for client
37 ///
38 /// # Examples
39 ///
40 /// ```
41 /// use rust_anticaptcha::image_captcha::ImageCaptcha;
42 ///
43 /// let mut image_to_text_client = ImageCaptcha::new("API_KEY".to_string());
44 /// image_to_text_client.captcha_interface.set_sleep_time(3);
45 /// ```
46 ///
47 pub fn set_sleep_time(&mut self, sleep_time: u8) {
48 self.sleep_time = sleep_time;
49 }
50
51 /// Method set new max_attempts for client
52 ///
53 /// # Examples
54 ///
55 /// ```
56 /// use rust_anticaptcha::image_captcha::ImageCaptcha;
57 ///
58 /// let mut image_to_text_client = ImageCaptcha::new("API_KEY".to_string());
59 /// image_to_text_client.captcha_interface.set_max_attempts(9);
60 /// ```
61 ///
62 pub fn set_max_attempts(&mut self, max_attempts: u8) {
63 self.max_attempts = max_attempts;
64 }
65
66 /// Method set new callback URL for client
67 ///
68 /// # Examples
69 ///
70 /// ```
71 /// use rust_anticaptcha::image_captcha::ImageCaptcha;
72 ///
73 /// let mut image_to_text_client = ImageCaptcha::new("API_KEY".to_string());
74 /// image_to_text_client.captcha_interface.set_callback_url(&"some-url".to_string());
75 /// ```
76 ///
77 pub fn set_callback_url(&mut self, callbackUrl: &String) {
78 self.callbackUrl = callbackUrl.to_string();
79 }
80
81 /// Method starts processing captcha
82 ///
83 /// # Arguments
84 /// `captcha_type` - One of image captcha types from `TaskTypeTrait`
85 /// `captcha_properties` - JSON with keys/values for `task` key in payload
86 ///
87 pub async fn solve_captcha<CaptchaType: TaskTypeTrait>(
88 &mut self,
89 captcha_type: CaptchaType,
90 captcha_properties: &Value,
91 ) -> Value {
92 // fill task payload with params
93 self.task_payload = captcha_properties.clone();
94 self.task_payload["type"] = Value::String(captcha_type.as_string());
95
96 let task_id = match self.create_task().await {
97 Ok(task_id) => task_id,
98 Err(error_response) => return error_response,
99 };
100
101 sleep(Duration::from_secs(self.sleep_time as u64)).await;
102
103 self.get_task_result(task_id).await
104 }
105
106 /// Method create task for captcha processing
107 /// If task not created - return server response JSON value
108 ///
109 /// # Notes
110 /// Read more here:
111 ///
112 /// <https://anti-captcha.com/apidoc/methods/createTask>
113 ///
114 async fn create_task(&self) -> Result<String, Value> {
115 let create_task_payload = CreateTaskRequest::new(
116 self.api_key.clone(),
117 self.task_payload.clone(),
118 self.callbackUrl.clone(),
119 );
120 let task_result = self
121 .request_interface
122 .send_create_task_request(&create_task_payload, &EnpPostfix::createTask)
123 .await
124 .unwrap_or_else(|error| {
125 json!({
126 "errorId": 1.to_string(),
127 "errorDescription": error
128 })
129 });
130
131 if task_result["errorId"] == 0 {
132 Ok(task_result["taskId"].to_string())
133 } else {
134 Err(task_result)
135 }
136 }
137
138 /// Method wait and get task result
139 ///
140 /// # Notes
141 /// Read more here:
142 ///
143 /// <https://anti-captcha.com/apidoc/methods/getTaskResult>
144 ///
145 async fn get_task_result(&self, task_id: String) -> Value {
146 let mut attempt: u8 = 0;
147
148 let get_result_payload = ResultTaskRequest {
149 clientKey: self.api_key.clone(),
150 taskId: task_id.clone(),
151 };
152
153 loop {
154 attempt += 1;
155
156 let task_result = self
157 .request_interface
158 .send_get_result_request(&get_result_payload, &EnpPostfix::getTaskResult)
159 .await
160 .unwrap_or_else(|error| {
161 json!({
162 "errorId": 1.to_string(),
163 "taskId": task_id.to_string(),
164 "errorDescription": error
165 })
166 });
167
168 if task_result["errorId"] == 0 {
169 if task_result["status"] == GetResultStatus::ready.to_string() {
170 return task_result;
171 }
172 } else {
173 return task_result;
174 }
175
176 if attempt > self.max_attempts {
177 return task_result;
178 }
179
180 sleep(Duration::from_secs(self.sleep_time as u64)).await;
181 }
182 }
183}