From 85a8827ae758a1f4607d7dcfe858fca70c253973 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Fri, 5 Jul 2024 12:18:45 +0200 Subject: [PATCH] Reload Snapcast provider when connection to the server gets lost (#1447) --- music_assistant/server/controllers/config.py | 6 ++++- .../server/providers/snapcast/__init__.py | 26 +++++++------------ 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/music_assistant/server/controllers/config.py b/music_assistant/server/controllers/config.py index e504ee30..b378a091 100644 --- a/music_assistant/server/controllers/config.py +++ b/music_assistant/server/controllers/config.py @@ -313,7 +313,11 @@ class ConfigController: @api_command("config/providers/reload") async def reload_provider(self, instance_id: str) -> None: """Reload provider.""" - config = await self.get_provider_config(instance_id) + try: + config = await self.get_provider_config(instance_id) + except KeyError: + # Edge case: Provider was removed before we could reload it + return await self._load_provider_config(config) @api_command("config/players") diff --git a/music_assistant/server/providers/snapcast/__init__.py b/music_assistant/server/providers/snapcast/__init__.py index 73ec3d3e..95d3b23f 100644 --- a/music_assistant/server/providers/snapcast/__init__.py +++ b/music_assistant/server/providers/snapcast/__init__.py @@ -229,7 +229,6 @@ class SnapCastProvider(PlayerProvider): _snapserver_runner: asyncio.Task | None _snapserver_started: asyncio.Event | None _ids_map: bidict # ma_id / snapclient_id - _builtin_server_retry: int def _get_snapclient_id(self, player_id: str) -> str: search_dict = self._ids_map @@ -283,7 +282,6 @@ class SnapCastProvider(PlayerProvider): self._snapcast_stream_dryout_ms = self.config.get_value(CONF_SERVER_DRYOUT_MS) self._stream_tasks = {} self._ids_map = bidict({}) - self._builtin_server_retry = 0 if self._use_builtin_server: await self._start_builtin_server() @@ -302,8 +300,8 @@ class SnapCastProvider(PlayerProvider): "Started connection to Snapserver %s", f"{self._snapcast_server_host}:{self._snapcast_server_control_port}", ) - if self._use_builtin_server: - self._snapserver.set_on_disconnect_callback(self._restart_builtin_server) + # register callback for when the connection gets lost to the snapserver + self._snapserver.set_on_disconnect_callback(self._handle_disconnect) except OSError as err: msg = "Unable to start the Snapserver connection ?" @@ -670,17 +668,6 @@ class SnapCastProvider(PlayerProvider): # where we try to connect too soon self.mass.loop.call_later(2, self._snapserver_started.set) - async def _restart_builtin_server(self) -> None: - """Restart the built-in Snapserver.""" - if self._use_builtin_server and self._builtin_server_retry > 1: - self.logger.info("Restarting, built-in Snapserver.") - await self._stop_builtin_server() - await asyncio.sleep(10) # prevent race conditions when reloading - await self._start_builtin_server() - else: - self._builtin_server_retry += 1 - self.logger.debug("Increase snapcast retry count") - async def _stop_builtin_server(self) -> None: """Stop the built-in Snapserver.""" self.logger.info("Stopping, built-in Snapserver") @@ -691,7 +678,14 @@ class SnapCastProvider(PlayerProvider): async def _start_builtin_server(self) -> None: """Start the built-in Snapserver.""" if self._use_builtin_server: - self._builtin_server_retry = 0 self._snapserver_started = asyncio.Event() self._snapserver_runner = asyncio.create_task(self._builtin_server_runner()) await asyncio.wait_for(self._snapserver_started.wait(), 10) + + def _handle_disconnect(self, exc: Exception) -> None: + """Handle disconnect callback from snapserver.""" + self.logger.info( + "Connection to SnapServer lost, reason: %s. Reloading provider in 5 seconds.", str(exc) + ) + # schedule a reload of the provider + self.mass.call_later(5, self.mass.config.reload_provider(self.instance_id)) -- 2.34.1