Refactor project structure and enhance Docker configuration
- Updated `.dockerignore` to exclude test and development artifacts, optimizing the Docker image size. - Refactored `main.py` to delegate execution to `duty_teller.run.main()`, simplifying the entry point. - Introduced a new `duty_teller` package to encapsulate core functionality, improving modularity and organization. - Enhanced `pyproject.toml` to define a script for running the application, streamlining the execution process. - Updated README documentation to reflect changes in project structure and usage instructions. - Improved Alembic environment configuration to utilize the new package structure for database migrations.
This commit is contained in:
86
main.py
86
main.py
@@ -1,88 +1,6 @@
|
||||
"""Single entry point: build Application, run HTTP server + polling. Migrations run in Docker entrypoint."""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import threading
|
||||
import urllib.request
|
||||
|
||||
import config
|
||||
from telegram.ext import ApplicationBuilder
|
||||
|
||||
from handlers import group_duty_pin, register_handlers
|
||||
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
level=logging.INFO,
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _set_default_menu_button_webapp() -> None:
|
||||
"""Set the bot's default menu button to Web App so Telegram sends tgWebAppData when users open the app from the menu."""
|
||||
if not (config.MINI_APP_BASE_URL and config.BOT_TOKEN):
|
||||
return
|
||||
menu_url = (config.MINI_APP_BASE_URL.rstrip("/") + "/app/").strip()
|
||||
if not menu_url.startswith("https://"):
|
||||
return
|
||||
payload = {
|
||||
"menu_button": {
|
||||
"type": "web_app",
|
||||
"text": "Календарь",
|
||||
"web_app": {"url": menu_url},
|
||||
}
|
||||
}
|
||||
req = urllib.request.Request(
|
||||
f"https://api.telegram.org/bot{config.BOT_TOKEN}/setChatMenuButton",
|
||||
data=json.dumps(payload).encode(),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=10) as resp:
|
||||
if resp.status == 200:
|
||||
logger.info("Default menu button set to Web App: %s", menu_url)
|
||||
else:
|
||||
logger.warning("setChatMenuButton returned %s", resp.status)
|
||||
except Exception as e:
|
||||
logger.warning("Could not set menu button: %s", e)
|
||||
|
||||
|
||||
def _run_uvicorn(web_app, port: int) -> None:
|
||||
"""Run uvicorn in a dedicated thread with its own event loop."""
|
||||
import uvicorn
|
||||
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
server = uvicorn.Server(
|
||||
uvicorn.Config(web_app, host="0.0.0.0", port=port, log_level="info"),
|
||||
)
|
||||
loop.run_until_complete(server.serve())
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# Menu button (Календарь) and inline Calendar button are disabled; users open the app by link if needed.
|
||||
# _set_default_menu_button_webapp()
|
||||
app = (
|
||||
ApplicationBuilder()
|
||||
.token(config.BOT_TOKEN)
|
||||
.post_init(group_duty_pin.restore_group_pin_jobs)
|
||||
.build()
|
||||
)
|
||||
register_handlers(app)
|
||||
|
||||
from api.app import app as web_app
|
||||
|
||||
t = threading.Thread(
|
||||
target=_run_uvicorn,
|
||||
args=(web_app, config.HTTP_PORT),
|
||||
daemon=True,
|
||||
)
|
||||
t.start()
|
||||
|
||||
logger.info("Bot starting (polling)... HTTP API on port %s", config.HTTP_PORT)
|
||||
app.run_polling(allowed_updates=["message", "my_chat_member"])
|
||||
"""Entry point: delegate to duty_teller.run.main(). Run with python main.py or duty-teller."""
|
||||
|
||||
from duty_teller.run import main
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user