feat: create backend skeleton

This commit is contained in:
h
2026-05-29 16:11:41 +02:00
parent e08d26dd10
commit 62aac0bf32
37 changed files with 1591 additions and 3 deletions
+98
View File
@@ -0,0 +1,98 @@
import asyncio
import contextlib
import json
from pathlib import Path
import asyncpg
import uvloop
from dependencies.container import container
from userbot.modules import PyroClient
from utils.env import env
from utils.logging import logger, setup_logging
setup_logging()
_UPSERT_ACCOUNT = """
INSERT INTO accounts
(tg_user_id, label, phone, session_name, is_active, raw, updated_at)
VALUES ($1, $2, $3, $4, TRUE, $5::jsonb, now())
ON CONFLICT (tg_user_id) DO UPDATE SET
label = EXCLUDED.label,
phone = EXCLUDED.phone,
session_name = EXCLUDED.session_name,
is_active = TRUE,
raw = EXCLUDED.raw,
updated_at = now()
"""
def _discover_sessions(sessions_dir: Path) -> list[Path]:
sessions_dir.mkdir(parents=True, exist_ok=True)
return sorted(sessions_dir.glob("*.session"))
async def _sync_account(
pool: asyncpg.Pool, client: PyroClient, session_name: str
) -> None:
me = client.me
if not me:
return
raw = json.dumps(
{
"id": me.id,
"first_name": me.first_name,
"last_name": me.last_name,
"username": me.username,
"phone_number": me.phone_number,
}
)
label = " ".join(filter(None, [me.first_name, me.last_name])) or me.username
await pool.execute(
_UPSERT_ACCOUNT, me.id, label, me.phone_number, session_name, raw
)
logger.info(f"[green]Account synced:[/] {label} ({me.id})")
async def runner() -> None:
pool = await container.get(asyncpg.Pool)
sessions_dir = Path(env.tg.sessions_dir)
session_files = _discover_sessions(sessions_dir)
if not session_files:
logger.warning(
f"[yellow]No .session files in {sessions_dir}/. "
f"Log in first, then restart userbot.[/]"
)
clients: list[PyroClient] = []
try:
for session_path in session_files:
session_name = session_path.stem
client = PyroClient(session_name, workdir=str(sessions_dir))
await client.start()
clients.append(client)
logger.info(
f"[green]Client started:[/] "
f"{client.me.full_name if client.me else 'unknown'} "
f"{client.me.id if client.me else 'unknown'}"
)
await _sync_account(pool, client, session_name)
if clients:
logger.info("[green]Userbot running. Idle (no handlers until phase 3).[/]")
await asyncio.Event().wait()
finally:
for client in clients:
with contextlib.suppress(Exception):
await client.stop()
await container.close()
def main() -> None:
uvloop.install()
logger.info("Starting userbot...")
with contextlib.suppress(KeyboardInterrupt):
asyncio.run(runner())
logger.info("[red]Userbot stopped.[/]")