feat(tenacity): Stable Message Queue (#238)

This commit is contained in:
QIN2DIM 2023-11-21 21:13:44 +08:00 committed by GitHub
parent b22ed65d00
commit 891684d29a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 30 deletions

View File

@ -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()

View File

@ -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)

View File

@ -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