mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-19 19:32:10 +00:00
118 lines
4.2 KiB
Python
118 lines
4.2 KiB
Python
import asyncio
|
|
import json
|
|
import logging
|
|
from typing import Any, Dict, Optional
|
|
|
|
from aiohttp import web
|
|
|
|
from app.config import settings
|
|
from app.database.database import AsyncSessionLocal
|
|
from app.external.heleket import HeleketService
|
|
from app.services.payment_service import PaymentService
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class HeleketWebhookHandler:
|
|
def __init__(self, payment_service: PaymentService) -> None:
|
|
self.payment_service = payment_service
|
|
self.service = HeleketService()
|
|
|
|
async def handle(self, request: web.Request) -> web.Response:
|
|
if not settings.is_heleket_enabled():
|
|
logger.warning("Получен Heleket webhook, но сервис отключен")
|
|
return web.json_response({"status": "error", "reason": "disabled"}, status=503)
|
|
|
|
try:
|
|
payload: Dict[str, Any] = await request.json()
|
|
except json.JSONDecodeError:
|
|
logger.error("Некорректный JSON Heleket webhook")
|
|
return web.json_response({"status": "error", "reason": "invalid_json"}, status=400)
|
|
|
|
if not self.service.verify_webhook_signature(payload):
|
|
return web.json_response({"status": "error", "reason": "invalid_signature"}, status=401)
|
|
|
|
processed: Optional[bool] = None
|
|
async with AsyncSessionLocal() as db:
|
|
try:
|
|
processed = await self.payment_service.process_heleket_webhook(db, payload)
|
|
await db.commit()
|
|
except Exception as e:
|
|
logger.error(f"Ошибка обработки Heleket webhook: {e}")
|
|
await db.rollback()
|
|
return web.json_response({"status": "error", "reason": "internal_error"}, status=500)
|
|
|
|
if processed:
|
|
return web.json_response({"status": "ok"}, status=200)
|
|
|
|
return web.json_response({"status": "error", "reason": "not_processed"}, status=400)
|
|
|
|
async def health_check(self, _: web.Request) -> web.Response:
|
|
return web.json_response(
|
|
{
|
|
"status": "ok",
|
|
"service": "heleket_webhook",
|
|
"enabled": settings.is_heleket_enabled(),
|
|
"path": settings.HELEKET_WEBHOOK_PATH,
|
|
}
|
|
)
|
|
|
|
async def options_handler(self, _: web.Request) -> web.Response:
|
|
return web.Response(
|
|
status=200,
|
|
headers={
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
|
|
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
},
|
|
)
|
|
|
|
|
|
def create_heleket_app(payment_service: PaymentService) -> web.Application:
|
|
handler = HeleketWebhookHandler(payment_service)
|
|
app = web.Application()
|
|
app.router.add_post(settings.HELEKET_WEBHOOK_PATH, handler.handle)
|
|
app.router.add_get("/heleket/health", handler.health_check)
|
|
app.router.add_get("/health", handler.health_check)
|
|
app.router.add_options(settings.HELEKET_WEBHOOK_PATH, handler.options_handler)
|
|
return app
|
|
|
|
|
|
async def start_heleket_webhook_server(payment_service: PaymentService) -> None:
|
|
if not settings.is_heleket_enabled():
|
|
logger.info("Heleket отключен, webhook сервер не запускается")
|
|
return
|
|
|
|
app = create_heleket_app(payment_service)
|
|
runner = web.AppRunner(app)
|
|
await runner.setup()
|
|
|
|
site = web.TCPSite(
|
|
runner,
|
|
host=settings.HELEKET_WEBHOOK_HOST,
|
|
port=settings.HELEKET_WEBHOOK_PORT,
|
|
)
|
|
|
|
try:
|
|
await site.start()
|
|
logger.info(
|
|
"Heleket webhook сервер запущен на %s:%s",
|
|
settings.HELEKET_WEBHOOK_HOST,
|
|
settings.HELEKET_WEBHOOK_PORT,
|
|
)
|
|
logger.info(
|
|
"Heleket webhook URL: http://%s:%s%s",
|
|
settings.HELEKET_WEBHOOK_HOST,
|
|
settings.HELEKET_WEBHOOK_PORT,
|
|
settings.HELEKET_WEBHOOK_PATH,
|
|
)
|
|
|
|
while True:
|
|
await asyncio.sleep(1)
|
|
except asyncio.CancelledError:
|
|
logger.info("Heleket webhook сервер остановлен по запросу")
|
|
finally:
|
|
await site.stop()
|
|
await runner.cleanup()
|
|
logger.info("Heleket webhook сервер корректно остановлен")
|