feat(tenacity): Stable Message Queue (#238)
This commit is contained in:
parent
b22ed65d00
commit
891684d29a
27
src/claim.py
27
src/claim.py
|
@ -11,9 +11,11 @@ import sys
|
|||
from dataclasses import dataclass, field
|
||||
from typing import List
|
||||
|
||||
import hcaptcha_challenger as solver
|
||||
import importlib_metadata
|
||||
from hcaptcha_challenger import install
|
||||
from hcaptcha_challenger.agents import Malenia
|
||||
from loguru import logger
|
||||
from playwright.async_api import BrowserContext, async_playwright, TimeoutError
|
||||
from playwright.async_api import BrowserContext, async_playwright
|
||||
|
||||
from epic_games import (
|
||||
EpicPlayer,
|
||||
|
@ -23,7 +25,6 @@ from epic_games import (
|
|||
get_promotions,
|
||||
get_order_history,
|
||||
)
|
||||
import importlib_metadata
|
||||
|
||||
self_supervised = True
|
||||
|
||||
|
@ -118,19 +119,9 @@ class ISurrender:
|
|||
single_promotions.append(p)
|
||||
|
||||
if single_promotions:
|
||||
for _ in range(3):
|
||||
try:
|
||||
if await epic.claim_weekly_games(page, single_promotions):
|
||||
break
|
||||
except TimeoutError:
|
||||
continue
|
||||
await epic.claim_weekly_games(page, single_promotions)
|
||||
if bundle_promotions:
|
||||
for _ in range(3):
|
||||
try:
|
||||
if await epic.claim_bundle_games(page, bundle_promotions):
|
||||
break
|
||||
except TimeoutError:
|
||||
continue
|
||||
await epic.claim_bundle_games(page, bundle_promotions)
|
||||
|
||||
@logger.catch
|
||||
async def stash(self):
|
||||
|
@ -139,11 +130,10 @@ class ISurrender:
|
|||
|
||||
logger.info(
|
||||
"run",
|
||||
image="20231105",
|
||||
image="20231121",
|
||||
version=importlib_metadata.version("hcaptcha-challenger"),
|
||||
role="EpicPlayer",
|
||||
headless=self.headless,
|
||||
self_supervised=self_supervised,
|
||||
)
|
||||
|
||||
async with async_playwright() as p:
|
||||
|
@ -155,8 +145,9 @@ class ISurrender:
|
|||
locale=self.locale,
|
||||
args=["--hide-crash-restore-bubble"],
|
||||
)
|
||||
await Malenia.apply_stealth(context)
|
||||
if not await self.prelude_with_context(context):
|
||||
solver.install(upgrade=True, clip=self_supervised)
|
||||
install(upgrade=True, clip=True)
|
||||
await self.claim_epic_games(context)
|
||||
await context.close()
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ from typing import List, Dict, Literal
|
|||
import httpx
|
||||
from loguru import logger
|
||||
from playwright.async_api import BrowserContext, expect, TimeoutError, Page, FrameLocator, Locator
|
||||
from tenacity import *
|
||||
|
||||
from epic_games.player import EpicPlayer
|
||||
from utils import from_dict_to_model, AgentG
|
||||
|
@ -87,6 +88,12 @@ class CommonHandler:
|
|||
return True
|
||||
|
||||
@staticmethod
|
||||
@retry(
|
||||
retry=retry_if_exception_type(TimeoutError),
|
||||
wait=wait_fixed(0.5),
|
||||
stop=stop_after_attempt(15),
|
||||
reraise=True,
|
||||
)
|
||||
async def insert_challenge(
|
||||
solver: AgentG,
|
||||
page: Page,
|
||||
|
@ -95,18 +102,19 @@ class CommonHandler:
|
|||
recur_url: str,
|
||||
is_uk: bool,
|
||||
):
|
||||
for _ in range(15):
|
||||
# {{< if fall in challenge >}}
|
||||
match await solver(window="free", recur_url=recur_url):
|
||||
case solver.status.CHALLENGE_BACKCALL | solver.status.CHALLENGE_RETRY:
|
||||
await wpc.locator("//a[@class='talon_close_button']").click()
|
||||
await page.wait_for_timeout(1000)
|
||||
if is_uk:
|
||||
await CommonHandler.uk_confirm_order(wpc)
|
||||
await payment_btn.click(delay=200)
|
||||
case solver.status.CHALLENGE_SUCCESS:
|
||||
await page.wait_for_url(recur_url)
|
||||
break
|
||||
response = await solver.execute(window="free")
|
||||
logger.debug("task done", sattus=f"{solver.status.CHALLENGE_SUCCESS}")
|
||||
|
||||
match response:
|
||||
case solver.status.CHALLENGE_BACKCALL | solver.status.CHALLENGE_RETRY:
|
||||
await wpc.locator("//a[@class='talon_close_button']").click()
|
||||
await page.wait_for_timeout(1000)
|
||||
if is_uk:
|
||||
await CommonHandler.uk_confirm_order(wpc)
|
||||
await payment_btn.click(delay=200)
|
||||
case solver.status.CHALLENGE_SUCCESS:
|
||||
await page.wait_for_url(recur_url)
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
async def empty_cart(page: Page, wait_rerender: int = 30) -> bool | None:
|
||||
|
@ -272,6 +280,12 @@ class EpicGames:
|
|||
logger.success("flush_token", path=self.player.ctx_cookie_path)
|
||||
return cookies
|
||||
|
||||
@retry(
|
||||
retry=retry_if_exception_type(TimeoutError),
|
||||
wait=wait_fixed(0.5),
|
||||
stop=(stop_after_delay(360) | stop_after_attempt(3)),
|
||||
reraise=True,
|
||||
)
|
||||
async def claim_weekly_games(self, page: Page, promotions: List[Game]):
|
||||
in_cart_nums = 0
|
||||
|
||||
|
@ -326,6 +340,12 @@ class EpicGames:
|
|||
|
||||
return True
|
||||
|
||||
@retry(
|
||||
retry=retry_if_exception_type(TimeoutError),
|
||||
wait=wait_fixed(0.5),
|
||||
stop=(stop_after_delay(360) | stop_after_attempt(3)),
|
||||
reraise=True,
|
||||
)
|
||||
async def claim_bundle_games(self, page: Page, promotions: List[Game]):
|
||||
for promotion in promotions:
|
||||
logger.info("claim_bundle_games", action="go to store", url=promotion.url)
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
# Author : QIN2DIM
|
||||
# GitHub : https://github.com/QIN2DIM
|
||||
# Description:
|
||||
import asyncio
|
||||
from dataclasses import dataclass
|
||||
|
||||
from hcaptcha_challenger.agents import AgentT
|
||||
from playwright.async_api import Page
|
||||
from tenacity import *
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -29,3 +31,38 @@ class AgentG(AgentT):
|
|||
frame_challenge = frame_purchase.frame_locator(self.HOOK_CHALLENGE)
|
||||
|
||||
return frame_challenge
|
||||
|
||||
@retry(
|
||||
retry=retry_if_exception_type(asyncio.QueueEmpty),
|
||||
wait=wait_fixed(0.5),
|
||||
stop=(stop_after_delay(30) | stop_after_attempt(60)),
|
||||
reraise=True,
|
||||
)
|
||||
async def _reset_state(self) -> bool | None:
|
||||
self.cr = None
|
||||
self.qr = self.qr_queue.get_nowait()
|
||||
|
||||
if not self.qr_queue.empty():
|
||||
for _ in range(self.qr_queue.qsize()):
|
||||
self.qr = self.qr_queue.get_nowait()
|
||||
|
||||
return True
|
||||
|
||||
@retry(
|
||||
retry=retry_if_exception_type(asyncio.QueueEmpty),
|
||||
wait=wait_fixed(0.5),
|
||||
stop=(stop_after_delay(30) | stop_after_attempt(60)),
|
||||
reraise=True,
|
||||
)
|
||||
async def _is_success(self):
|
||||
self.cr = self.cr_queue.get_nowait()
|
||||
|
||||
if not self.cr_queue.empty():
|
||||
for _ in range(self.cr_queue.qsize()):
|
||||
self.cr = self.cr_queue.get_nowait()
|
||||
|
||||
# Match: Timeout / Loss
|
||||
if not self.cr or not self.cr.is_pass:
|
||||
return self.status.CHALLENGE_RETRY
|
||||
if self.cr.is_pass:
|
||||
return self.status.CHALLENGE_SUCCESS
|
||||
|
|
Loading…
Reference in New Issue