import asyncio import signal from aiohttp import web from loguru import logger from restreamer.broadcaster import ChannelBroadcaster from restreamer.channel_worker import ChannelWorker from restreamer.config import ChannelConfig, Settings from restreamer.http_server import create_app from restreamer.resolver import StreamResolver class RestreamerManager: def __init__(self, settings: Settings, channels: list[ChannelConfig], resolver: StreamResolver) -> None: self._settings = settings self._channels = channels self._resolver = resolver self._broadcasters = {channel.id: ChannelBroadcaster(channel.id) for channel in channels} self._workers = [ ChannelWorker(channel, resolver, self._broadcasters[channel.id]) for channel in channels ] async def run(self) -> None: base_url = self._settings.public_base_url or f"http://{self._settings.http_host}:{self._settings.http_port}" app = create_app(self._channels, self._broadcasters, base_url) runner = web.AppRunner(app) await runner.setup() site = web.TCPSite(runner, self._settings.http_host, self._settings.http_port) await site.start() logger.info("HTTP server listening on {}:{}", self._settings.http_host, self._settings.http_port) logger.info("Playlist available at {}/playlist.m3u", base_url) worker_tasks = [asyncio.create_task(worker.run()) for worker in self._workers] stop_event = asyncio.Event() loop = asyncio.get_running_loop() for sig in (signal.SIGINT, signal.SIGTERM): loop.add_signal_handler(sig, stop_event.set) await stop_event.wait() logger.info("Shutting down") for worker in self._workers: worker.stop() await asyncio.gather(*worker_tasks, return_exceptions=True) await runner.cleanup()