mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-02-23 21:01:17 +00:00
- Add pyproject.toml with uv and ruff configuration - Pin Python version to 3.13 via .python-version - Add Makefile commands: lint, format, fix - Apply ruff formatting to entire codebase - Remove unused imports (base64 in yookassa/simple_subscription) - Update .gitignore for new config files
119 lines
4.2 KiB
Python
119 lines
4.2 KiB
Python
import asyncio
|
|
import json
|
|
import logging
|
|
from typing import Any
|
|
|
|
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: bool | None = 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 сервер корректно остановлен')
|