Skip to content

Commit

Permalink
fix: pytmbot exited with code 0
Browse files Browse the repository at this point in the history
  • Loading branch information
orenlab committed Dec 28, 2024
1 parent 5891dfe commit 8ba4e20
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 65 deletions.
4 changes: 1 addition & 3 deletions pytmbot/pytmbot_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,7 @@ def start_webhook_server(self) -> None:
)

server = WebhookServer(self.bot, **webhook_config)

import asyncio
asyncio.run(server.start())
server.start()

except ImportError as err:
bot_logger.exception(f"Failed to import FastAPI: {err}")
Expand Down
76 changes: 14 additions & 62 deletions pytmbot/webhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,8 @@
import uvicorn
from fastapi import FastAPI, HTTPException, Request, Depends, Header
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import Response
from telebot import TeleBot
from telebot.apihelper import ApiTelegramException
from typing_extensions import override

from pytmbot.exceptions import PyTMBotError
from pytmbot.globals import settings
Expand All @@ -32,19 +28,11 @@ def __init__(self, bot: TeleBot, url: str, port: int, secret_token: str = None)
self.port = port
self.secret_token = secret_token

async def setup_webhook(self, webhook_path: str) -> None:
"""
Configures the webhook for the bot.
Args:
webhook_path (str): The path component of the webhook URL
Raises:
PyTMBotError: If webhook configuration fails
"""
def setup_webhook(self, webhook_path: str) -> None:
"""Configures the webhook for the bot."""
try:
# Remove any existing webhook first
await self.remove_webhook()
self.remove_webhook()

webhook_url = f"https://{self.url}:{self.port}{webhook_path}"
cert_path = settings.webhook_config.cert[0].get_secret_value() or None
Expand All @@ -54,25 +42,19 @@ async def setup_webhook(self, webhook_path: str) -> None:
self.bot.set_webhook(
url=webhook_url,
timeout=20,
allowed_updates=['message', 'edited_message', 'inline_query', 'callback_query', ],
allowed_updates=['message', 'edited_message', 'inline_query', 'callback_query'],
drop_pending_updates=True,
certificate=cert_path,
secret_token=self.secret_token
)
bot_logger.info("Webhook successfully configured")

except ApiTelegramException as e:
error_msg = f"Failed to set webhook: {sanitize_exception(e)}"
bot_logger.error(error_msg)
raise PyTMBotError(error_msg) from e

async def remove_webhook(self) -> None:
"""
Removes the existing webhook configuration.
Raises:
PyTMBotError: If webhook removal fails
"""
def remove_webhook(self) -> None:
"""Removes the existing webhook configuration."""
try:
self.bot.remove_webhook()
bot_logger.debug("Existing webhook removed")
Expand All @@ -82,26 +64,6 @@ async def remove_webhook(self) -> None:
raise PyTMBotError(error_msg) from e


class SecurityHeadersMiddleware(BaseHTTPMiddleware):
"""Middleware for adding security headers."""

def __init__(self, app: FastAPI) -> None:
super().__init__(app)
self.security_headers = {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"Strict-Transport-Security": "max-age=31536000; includeSubDomains",
"X-XSS-Protection": "1; mode=block",
"Content-Security-Policy": "default-src 'self'"
}

@override
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
response = await call_next(request)
response.headers.update(self.security_headers)
return response


class RateLimit:
def __init__(self, limit: int, period: int, ban_threshold: int = 50) -> None:
self.limit = limit
Expand Down Expand Up @@ -177,14 +139,14 @@ def __init__(self, bot: TeleBot, token: str, host: str, port: int) -> None:

def _create_app(self) -> FastAPI:
@asynccontextmanager
async def lifespan():
def lifespan():
bot_logger.info("Initializing webhook server...")
try:
# Configure webhook during startup
await self.webhook_manager.setup_webhook(self.webhook_path)
self.webhook_manager.setup_webhook(self.webhook_path)
yield
# Cleanup webhook during shutdown
await self.webhook_manager.remove_webhook()
self.webhook_manager.remove_webhook()
except Exception as e:
bot_logger.error(f"Webhook lifecycle error: {sanitize_exception(e)}")
raise
Expand All @@ -199,16 +161,6 @@ async def lifespan():
lifespan=lifespan
)

app.add_middleware(SecurityHeadersMiddleware)
app.add_middleware(
CORSMiddleware,
allow_origins=[],
allow_credentials=False,
allow_methods=["POST"],
allow_headers=["*"],
max_age=3600,
)

self._setup_routes(app)
return app

Expand All @@ -225,7 +177,7 @@ def _get_update_type(update: UpdateModel) -> str:

def _setup_routes(self, app: FastAPI) -> None:
@app.exception_handler(404)
async def not_found_handler(request: Request, exc: HTTPException) -> JSONResponse:
def not_found_handler(request: Request, exc: HTTPException) -> JSONResponse:
client_ip = request.client.host
if self.rate_limiter_404.is_rate_limited(client_ip):
return JSONResponse(
Expand All @@ -237,7 +189,7 @@ async def not_found_handler(request: Request, exc: HTTPException) -> JSONRespons
content={"detail": "Not found"}
)

async def verify_telegram_ip(
def verify_telegram_ip(
request: Request,
x_forwarded_for: Annotated[str | None, Header()] = None
) -> str:
Expand All @@ -252,7 +204,7 @@ async def verify_telegram_ip(
return client_ip

@app.post(self.webhook_path)
async def process_webhook(
def process_webhook(
update: UpdateModel,
client_ip: Annotated[str, Depends(verify_telegram_ip)],
x_telegram_bot_api_secret_token: Annotated[str | None, Header()]
Expand Down Expand Up @@ -299,7 +251,7 @@ async def process_webhook(
bot_logger.error(f"Failed to process update: {str(e)}")
raise HTTPException(status_code=500, detail="Internal server error")

async def start(self) -> None:
def start(self) -> None:
"""
Starts the webhook server asynchronously.
Expand Down Expand Up @@ -336,7 +288,7 @@ async def start(self) -> None:

try:
server = uvicorn.Server(uvicorn.Config(**uvicorn_config))
await server.serve()
server.serve()
except Exception as e:
error_msg = f"Failed to start webhook server: {sanitize_exception(e)}"
bot_logger.error(error_msg)
Expand Down

0 comments on commit 8ba4e20

Please sign in to comment.