Skip to main content

capmonstercloud_client/requests/
prosopo.rs

1use serde::Serialize;
2
3use super::{require_non_empty, CaptchaRequest};
4use crate::error::Result;
5use crate::proxy::ProxyInfo;
6use crate::timeouts::GetResultTimeouts;
7
8/// Prosopo Procaptcha (`ProsopoTask`), token based.
9#[derive(Debug, Clone, Serialize)]
10pub struct ProsopoTaskRequest {
11    /// Full URL of the captcha page.
12    #[serde(rename = "websiteURL")]
13    pub website_url: String,
14    /// The `siteKey` found on the page, e.g. `5EZU3LG31uzq1Mwi8inwqxmfvFDpj7VzwDnZwj4Q3syyxBwV`.
15    #[serde(rename = "websiteKey")]
16    pub website_key: String,
17    #[serde(flatten, skip_serializing_if = "Option::is_none")]
18    pub proxy: Option<ProxyInfo>,
19    /// Browser User-Agent (use a current Windows one).
20    #[serde(rename = "userAgent", skip_serializing_if = "Option::is_none")]
21    pub user_agent: Option<String>,
22}
23
24impl ProsopoTaskRequest {
25    pub fn new(website_url: impl Into<String>, website_key: impl Into<String>) -> Self {
26        Self {
27            website_url: website_url.into(),
28            website_key: website_key.into(),
29            proxy: None,
30            user_agent: None,
31        }
32    }
33
34    pub fn with_proxy(mut self, proxy: ProxyInfo) -> Self {
35        self.proxy = Some(proxy);
36        self
37    }
38
39    pub fn with_user_agent(mut self, value: impl Into<String>) -> Self {
40        self.user_agent = Some(value.into());
41        self
42    }
43}
44
45impl CaptchaRequest for ProsopoTaskRequest {
46    const TASK_TYPE: &'static str = "ProsopoTask";
47
48    fn timeouts(&self) -> GetResultTimeouts {
49        GetResultTimeouts::secs(1.0, 10.0, 3.0, 180.0)
50    }
51
52    fn validate(&self) -> Result<()> {
53        require_non_empty("websiteURL", &self.website_url)?;
54        require_non_empty("websiteKey", &self.website_key)?;
55        Ok(())
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use crate::proxy::ProxyType;
63    use serde_json::json;
64
65    #[test]
66    fn minimal_task() {
67        let task = ProsopoTaskRequest::new("https://example.com", "KEY")
68            .to_task()
69            .unwrap();
70        assert_eq!(
71            task,
72            json!({"type": "ProsopoTask", "websiteURL": "https://example.com", "websiteKey": "KEY"})
73        );
74    }
75
76    #[test]
77    fn full_task() {
78        let task = ProsopoTaskRequest::new("https://example.com", "KEY")
79            .with_proxy(ProxyInfo::new(ProxyType::Https, "h", 3128).with_auth("u", "p"))
80            .with_user_agent("UA")
81            .to_task()
82            .unwrap();
83        assert_eq!(
84            task,
85            json!({"type": "ProsopoTask", "websiteURL": "https://example.com", "websiteKey": "KEY",
86                   "userAgent": "UA", "proxyType": "https", "proxyAddress": "h", "proxyPort": 3128,
87                   "proxyLogin": "u", "proxyPassword": "p"})
88        );
89    }
90
91    #[test]
92    fn empty_required_strings_are_rejected() {
93        let err = ProsopoTaskRequest::new("", "KEY").to_task().unwrap_err();
94        assert!(matches!(err, crate::error::Error::Validation(ref m) if m.contains("websiteURL")));
95        let err = ProsopoTaskRequest::new("https://example.com", "")
96            .to_task()
97            .unwrap_err();
98        assert!(matches!(err, crate::error::Error::Validation(ref m) if m.contains("websiteKey")));
99    }
100}