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}