33import logging
44from typing import Union , Optional
55from urllib import parse
6- from urllib .parse import urljoin
76
87import aiohttp
98
10- from .enum import SaveFormatsEnm
11- from .const import ASYNC_RETRIES , BASE_REQUEST_URL , GET_RESULT_POSTFIX , CREATE_TASK_POSTFIX
9+ from .enum import SaveFormatsEnm , ResponseStatusEnm , EndpointPostfixEnm
10+ from .const import REQUEST_URL , ASYNC_RETRIES , VALID_STATUS_CODES , GET_BALANCE_POSTFIX
1211from .utils import attempts_generator
13- from .serializer import CreateTaskResponseSer
12+ from .serializer import CaptchaResponseSer
1413from .captcha_instrument import CaptchaInstrument
1514
1615__all__ = ("AIOCaptchaInstrument" ,)
@@ -24,21 +23,70 @@ class AIOCaptchaInstrument(CaptchaInstrument):
2423 def __init__ (self , captcha_params : "CaptchaParams" ):
2524 super ().__init__ ()
2625 self .captcha_params = captcha_params
26+ self .created_task_data = CaptchaResponseSer
2727
2828 async def processing_captcha (self ) -> dict :
29- # added task params to payload
30- self .captcha_params .create_task_payload .task .update (self .captcha_params .task_params )
29+ self .created_task_data = CaptchaResponseSer (** await self .__create_task ())
3130
32- created_task = await self ._create_task ()
31+ # if task created and already ready - return result
32+ if self .created_task_data .errorId == 0 and self .created_task_data .status == ResponseStatusEnm .Processing .value :
33+ return (await self .__get_result ()).to_dict ()
34+ return self .created_task_data .to_dict ()
3335
34- if created_task .errorId == 0 :
35- self .captcha_params .get_result_params .taskId = created_task .taskId
36- else :
37- return created_task .to_dict ()
36+ async def __create_task (self , url_postfix : str = EndpointPostfixEnm .CREATE_TASK .value ) -> dict :
37+ """
38+ Function send the ASYNC request to service and wait for result
39+ """
40+ async with aiohttp .ClientSession () as session :
41+ try :
42+ async with session .post (
43+ parse .urljoin (self .captcha_params .request_url , url_postfix ),
44+ json = self .captcha_params .create_task_payload .to_dict (),
45+ ) as resp :
46+ if resp .status in VALID_STATUS_CODES :
47+ return await resp .json ()
48+ else :
49+ raise ValueError (resp .reason )
50+ except Exception as error :
51+ logging .exception (error )
52+ raise
3853
54+ async def __get_result (self , url_postfix : str = EndpointPostfixEnm .GET_TASK_RESULT .value ) -> CaptchaResponseSer :
55+ """
56+ Function send the ASYNC request to service and wait for result
57+ """
58+ # initial waiting
3959 await asyncio .sleep (self .captcha_params .sleep_time )
4060
41- return await self ._get_result ()
61+ self .captcha_params .get_result_params .taskId = self .created_task_data .taskId
62+ attempts = attempts_generator ()
63+ async with aiohttp .ClientSession () as session :
64+ for _ in attempts :
65+ try :
66+ async with session .post (
67+ parse .urljoin (self .captcha_params .request_url , url_postfix ),
68+ json = self .captcha_params .get_result_params .to_dict (),
69+ ) as resp :
70+ if resp .status in VALID_STATUS_CODES :
71+ result_data = CaptchaResponseSer (** await resp .json ())
72+ if result_data .status in (ResponseStatusEnm .Ready , ResponseStatusEnm .Failed ):
73+ # if captcha ready\failed or have unknown status - return exist data
74+ return result_data
75+ else :
76+ raise ValueError (resp .reason )
77+ except Exception as error :
78+ logging .exception (error )
79+ raise
80+
81+ # if captcha just created or in processing now - wait
82+ await asyncio .sleep (self .captcha_params .sleep_time )
83+
84+ # default response if server is silent
85+ self .result .errorId = 1
86+ self .result .errorCode = self .CAPTCHA_UNSOLVABLE
87+ self .result .errorDescription = "Captcha not recognized"
88+ self .result .taskId = self .created_task_data .taskId
89+ self .result .status = ResponseStatusEnm .Failed
4290
4391 async def processing_image_captcha (
4492 self ,
@@ -94,49 +142,22 @@ async def __body_file_processing(
94142 self .captcha_params .create_task_payload .task .update ({"body" : base64 .b64encode (content ).decode ("utf-8" )})
95143 except Exception as error :
96144 self .result .errorId = 12
97- self .result .errorCode = self .NO_CAPTCHA_ERR
145+ self .result .errorCode = self .CAPTCHA_UNSOLVABLE
98146 self .result .errorDescription = str (error )
99147
100148 else :
101149 self .result .errorId = 12
102- self .result .errorCode = self .NO_CAPTCHA_ERR
103-
104- async def _url_read (self , url : str , ** kwargs ) -> bytes :
105- """
106- Async method read bytes from link
107- """
108- async with aiohttp .ClientSession () as session :
109- async for attempt in ASYNC_RETRIES :
110- with attempt :
111- async with session .get (url = url , ** kwargs ) as resp :
112- return await resp .content .read ()
113-
114- async def _create_task (self , url_postfix : str = CREATE_TASK_POSTFIX ) -> CreateTaskResponseSer :
115- """
116- Function send SYNC request to service and wait for result
117- """
118- async with aiohttp .ClientSession () as session :
119- try :
120- async with session .post (
121- parse .urljoin (BASE_REQUEST_URL , url_postfix ), json = self .captcha_params .create_task_payload .to_dict ()
122- ) as resp :
123- if resp .status == 200 :
124- return CreateTaskResponseSer (** await resp .json ())
125- else :
126- raise ValueError (resp .reason )
127- except Exception as error :
128- logging .exception (error )
129- raise
150+ self .result .errorCode = self .CAPTCHA_UNSOLVABLE
130151
131152 @staticmethod
132- async def send_post_request (payload : Optional [dict ] = None , url_postfix : str = CREATE_TASK_POSTFIX ) -> dict :
153+ async def send_post_request (payload : Optional [dict ] = None , url_postfix : str = GET_BALANCE_POSTFIX ) -> dict :
133154 """
134155 Function send ASYNC request to service and wait for result
135156 """
136157
137158 async with aiohttp .ClientSession () as session :
138159 try :
139- async with session .post (parse .urljoin (BASE_REQUEST_URL , url_postfix ), json = payload ) as resp :
160+ async with session .post (parse .urljoin (REQUEST_URL , url_postfix ), json = payload ) as resp :
140161 if resp .status == 200 :
141162 return await resp .json ()
142163 else :
@@ -145,24 +166,13 @@ async def send_post_request(payload: Optional[dict] = None, url_postfix: str = C
145166 logging .exception (error )
146167 raise
147168
148- async def _get_result (self , url_response : str = GET_RESULT_POSTFIX ) -> dict :
149- attempts = attempts_generator ()
150- # Send request for status of captcha solution.
169+ @staticmethod
170+ async def _url_read (url : str , ** kwargs ) -> bytes :
171+ """
172+ Async method read bytes from link
173+ """
151174 async with aiohttp .ClientSession () as session :
152- for _ in attempts :
153- async with session .post (
154- url = urljoin (BASE_REQUEST_URL , url_response ), json = self .captcha_params .get_result_params .to_dict ()
155- ) as resp :
156- json_result = await resp .json ()
157- # if there is no error, check CAPTCHA status
158- if json_result ["errorId" ] == 0 :
159- # If not yet resolved, wait
160- if json_result ["status" ] == "processing" :
161- await asyncio .sleep (self .captcha_params .sleep_time )
162- # otherwise return response
163- else :
164- json_result .update ({"taskId" : self .captcha_params .get_result_params .taskId })
165- return json_result
166- else :
167- json_result .update ({"taskId" : self .captcha_params .get_result_params .taskId })
168- return json_result
175+ async for attempt in ASYNC_RETRIES :
176+ with attempt :
177+ async with session .get (url = url , ** kwargs ) as resp :
178+ return await resp .content .read ()
0 commit comments