forked from retoor/devplacepy
refactor: split bot.py into mixins (ref.md 3.3)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import random
|
||||
from datetime import datetime
|
||||
|
||||
from devplacepy.services.bot.config import SEARCH_TERMS
|
||||
from devplacepy.services.bot.handles import make_handle
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BotAuthMixin:
|
||||
def _generate_handle(self) -> str:
|
||||
return make_handle(SEARCH_TERMS.get(self.state.persona, []))
|
||||
|
||||
def _next_handle(self) -> str:
|
||||
while self.state.handle_candidates:
|
||||
candidate = self.state.handle_candidates.pop(0)
|
||||
if candidate:
|
||||
return candidate
|
||||
return self._generate_handle()
|
||||
|
||||
async def _ensure_auth(self) -> bool:
|
||||
b = self.b
|
||||
if not self.state.username:
|
||||
if not self.state.handle_candidates:
|
||||
self.state.handle_candidates = (
|
||||
await self._generate(
|
||||
self.llm.generate_handle_candidates, self.state.persona
|
||||
)
|
||||
or []
|
||||
)
|
||||
self.state.username = self._next_handle()
|
||||
self.state.account_api_key = ""
|
||||
self.state.email = self.faker.email()
|
||||
self.state.password = self.faker.password(length=random.randint(12, 18))
|
||||
self.state.started_at = datetime.now().isoformat()
|
||||
self._log(f"Identity: {self.state.username} / {self.state.email}")
|
||||
|
||||
curl = await b.url()
|
||||
if "/feed" in curl:
|
||||
return True
|
||||
|
||||
await b.goto(f"{self.base_url}/auth/login")
|
||||
curl = await b.url()
|
||||
if "/feed" in curl:
|
||||
return True
|
||||
|
||||
if await b.fill("#email", self.state.email):
|
||||
await b._idle(0.2, 0.5)
|
||||
await b.fill("#password", self.state.password)
|
||||
await b._idle(0.3, 0.8)
|
||||
await b.click(".auth-submit")
|
||||
await asyncio.sleep(2)
|
||||
curl = await b.url()
|
||||
if "/feed" in curl:
|
||||
self._log("Logged in")
|
||||
return True
|
||||
|
||||
self._log("Login failed, registering")
|
||||
for attempt in range(4):
|
||||
await b.goto(f"{self.base_url}/auth/signup")
|
||||
if not await b.fill("#username", self.state.username):
|
||||
return False
|
||||
await b._idle(0.2, 0.5)
|
||||
await b.fill("#email", self.state.email)
|
||||
await b._idle(0.2, 0.5)
|
||||
await b.fill("#password", self.state.password)
|
||||
await b._idle(0.2, 0.5)
|
||||
await b.fill("#confirm_password", self.state.password)
|
||||
await b._idle(0.5, 1.0)
|
||||
await b.click(".auth-submit")
|
||||
await asyncio.sleep(2)
|
||||
curl = await b.url()
|
||||
if "/feed" in curl:
|
||||
self._log(f"Registered as {self.state.username}")
|
||||
return True
|
||||
if attempt >= 2:
|
||||
base = self._next_handle()
|
||||
self.state.username = f"{base}{random.randint(10, 9999)}"[:20]
|
||||
else:
|
||||
self.state.username = self._next_handle()
|
||||
self.state.account_api_key = ""
|
||||
self.state.email = self.faker.email()
|
||||
self._log(f"Signup failed, retrying as {self.state.username}")
|
||||
return False
|
||||
|
||||
async def _fetch_account_api_key(self) -> str:
|
||||
if not self.state.username:
|
||||
return ""
|
||||
try:
|
||||
key = await self.b.page.evaluate(
|
||||
"""async (username) => {
|
||||
const resp = await fetch(`/profile/${username}`, {
|
||||
headers: {Accept: 'application/json'},
|
||||
});
|
||||
if (!resp.ok) return '';
|
||||
const data = await resp.json();
|
||||
return data.api_key || '';
|
||||
}""",
|
||||
self.state.username,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug("fetch account api key failed: %s", e)
|
||||
return ""
|
||||
return (key or "").strip()
|
||||
|
||||
async def _adopt_account_api_key(self) -> bool:
|
||||
for attempt in range(5):
|
||||
key = await self._fetch_account_api_key()
|
||||
if key:
|
||||
if key != self.state.account_api_key:
|
||||
self.state.account_api_key = key
|
||||
self._save()
|
||||
self._log("Adopted account API key for gateway calls")
|
||||
self.llm.api_key = key
|
||||
return True
|
||||
if attempt < 4:
|
||||
await asyncio.sleep(2)
|
||||
self._log("Account API key unavailable after retries")
|
||||
return False
|
||||
Reference in New Issue
Block a user