120 lines
3.6 KiB
Python
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())
|