Files
max2telegram/app/main.py
T
2026-06-12 01:10:44 +03:00

120 lines
3.6 KiB
Python

import asyncio
from collections.abc import Awaitable, Callable
from pathlib import Path
import structlog
from app.config import Settings
from app.logging_setup import setup_logging
from app.max_layer.client_holder import MaxClientHolder
from app.max_layer.listener import MaxListener
from app.max_layer.worker import MaxWorker
from app.queue.redis_queue import RedisQueue
from app.router.router import MessageRouter
from app.storage.database import create_engine, create_session_factory
from app.storage.repository import SqliteStorage
from app.telegram_layer.bot_holder import BotHolder
from app.telegram_layer.listener import TelegramListener
from app.telegram_layer.worker import TelegramWorker
from app.topic_locks import TopicLockRegistry
logger = structlog.get_logger(__name__)
SERVICE_RESTART_DELAY_SEC = 3.0
async def run_service(
name: str,
runner: Callable[[], Awaitable[None]],
) -> None:
while True:
try:
await runner()
logger.warning("service_stopped", service=name)
except asyncio.CancelledError:
logger.info("service_cancelled", service=name)
raise
except Exception:
logger.exception("service_failed", service=name)
await asyncio.sleep(SERVICE_RESTART_DELAY_SEC)
async def main() -> None:
settings = Settings()
setup_logging(settings.log_level)
Path(settings.sqlite_path).parent.mkdir(parents=True, exist_ok=True)
Path(settings.data_dir).mkdir(parents=True, exist_ok=True)
engine = create_engine(settings.database_url)
session_factory = create_session_factory(engine)
storage = SqliteStorage(session_factory)
await storage.init()
mappings = await storage.list_mappings()
sqlite_file = Path(settings.sqlite_path)
db_exists = sqlite_file.is_file()
db_size_bytes = sqlite_file.stat().st_size if db_exists else 0
logger.info(
"storage_ready",
sqlite_path=settings.sqlite_path,
database_url=settings.database_url,
db_file_exists=db_exists,
db_file_size_bytes=db_size_bytes,
mapping_count=len(mappings),
)
if len(mappings) == 0:
logger.info(
"storage_no_mappings",
reason="chat_mappings_table_empty",
effect="new_tg_forum_topic_will_be_created_for_each_max_chat",
hint="after_container_recreate_check_volume_mount_data_dir_and_sqlite_path",
sqlite_path=settings.sqlite_path,
)
legacy_db = Path.cwd() / "app" / "data" / "bridge.db"
if (
legacy_db.is_file()
and legacy_db.resolve() != sqlite_file.resolve()
):
logger.warning(
"sqlite_legacy_path_detected",
legacy_path=str(legacy_db.resolve()),
active_path=settings.sqlite_path,
hint="old_database_url_app/data/bridge_db_writes_outside_volume_use_data/bridge_db",
)
queue = RedisQueue(settings.redis_url)
await queue.connect()
topic_locks = TopicLockRegistry()
router = MessageRouter(
storage=storage,
queue=queue,
forum_channel_id=settings.tg_forum_channel_id,
topic_locks=topic_locks,
)
max_holder = MaxClientHolder()
bot_holder = BotHolder()
max_listener = MaxListener(settings, max_holder, router, storage)
tg_listener = TelegramListener(
settings, bot_holder, router, storage, max_holder
)
tg_worker = TelegramWorker(
settings, bot_holder, max_holder, queue, storage, topic_locks
)
max_worker = MaxWorker(settings, max_holder, bot_holder, queue, router, storage)
logger.info("max2telegram_starting")
await asyncio.gather(
run_service("max_listener", max_listener.run),
run_service("tg_listener", tg_listener.run),
run_service("tg_worker", tg_worker.run),
run_service("max_worker", max_worker.run),
)
if __name__ == "__main__":
asyncio.run(main())