From bf72af8734350c0b81612240ee14595542553c34 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Thu, 9 Mar 2023 16:57:22 +0100 Subject: [PATCH] fix race condition at startup --- MANIFEST.in | 6 +++ music_assistant/server/controllers/config.py | 7 +-- .../server/providers/airplay/bin/__init__.py | 1 - .../server/providers/frontend/__init__.py | 1 - .../server/providers/slimproto/__init__.py | 2 +- music_assistant/server/server.py | 49 +++++++++---------- pyproject.toml | 6 +-- 7 files changed, 37 insertions(+), 35 deletions(-) create mode 100644 MANIFEST.in delete mode 100644 music_assistant/server/providers/airplay/bin/__init__.py diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..a65d1e21 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,6 @@ +include *.txt +include README.rst +include LICENSE.md +graft music_assistant +recursive-exclude * *.py[co] +recursive-exclude * *.DS_Store diff --git a/music_assistant/server/controllers/config.py b/music_assistant/server/controllers/config.py index 3c9184d6..b0c5d50a 100644 --- a/music_assistant/server/controllers/config.py +++ b/music_assistant/server/controllers/config.py @@ -164,7 +164,7 @@ class ConfigController: raise KeyError(f"No config found for provider id {instance_id}") @api_command("config/providers/set") - def set_provider_config(self, config: ProviderConfig) -> None: + def set_provider_config(self, config: ProviderConfig, skip_reload=False) -> None: """Create or update ProviderConfig.""" # encrypt any password values for val in config.values.values(): @@ -179,8 +179,9 @@ class ConfigController: return self.set(conf_key, config_dict) # (re)load provider - updated_config = self.get_provider_config(config.instance_id) - self.mass.create_task(self.mass.load_provider(updated_config)) + if not skip_reload: + updated_config = self.get_provider_config(config.instance_id) + self.mass.create_task(self.mass.load_provider(updated_config)) @api_command("config/providers/create") def create_provider_config(self, provider_domain: str) -> ProviderConfig: diff --git a/music_assistant/server/providers/airplay/bin/__init__.py b/music_assistant/server/providers/airplay/bin/__init__.py deleted file mode 100644 index 92538754..00000000 --- a/music_assistant/server/providers/airplay/bin/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Music Assistant: The music library manager in python.""" diff --git a/music_assistant/server/providers/frontend/__init__.py b/music_assistant/server/providers/frontend/__init__.py index abb8a486..7a78a46b 100644 --- a/music_assistant/server/providers/frontend/__init__.py +++ b/music_assistant/server/providers/frontend/__init__.py @@ -22,7 +22,6 @@ class Frontend(PluginProvider): filepath = os.path.join(frontend_dir, filename) handler = partial(self.serve_static, filepath) self.mass.webapp.router.add_get(f"/{filename}", handler) - print(filename) # add assets subdir as static self.mass.webapp.router.add_static( diff --git a/music_assistant/server/providers/slimproto/__init__.py b/music_assistant/server/providers/slimproto/__init__.py index b726c732..0e3e08cd 100644 --- a/music_assistant/server/providers/slimproto/__init__.py +++ b/music_assistant/server/providers/slimproto/__init__.py @@ -112,7 +112,7 @@ class SlimprotoProvider(PlayerProvider): if hasattr(self, "_socket_servers"): for _server in self._socket_servers: _server.close() - self._socket_servers = None + self._socket_servers = None async def _create_client( self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter diff --git a/music_assistant/server/server.py b/music_assistant/server/server.py index 38125049..53e1828e 100644 --- a/music_assistant/server/server.py +++ b/music_assistant/server/server.py @@ -394,31 +394,30 @@ class MusicAssistant: """Load providers from config.""" # load all available providers from manifest files await self.__load_available_providers() - loaded_providers = set() - async with asyncio.TaskGroup() as tg: - # we loop twice to solve any dependencies - for allow_depends_on in (False, True): - # load all configured (and enabled) providers - for prov_conf in self.config.get_provider_configs(): - prov_manifest = self._available_providers[prov_conf.domain] - if prov_manifest.depends_on and not allow_depends_on: - continue - if prov_conf.instance_id in loaded_providers: - continue - loaded_providers.add(prov_conf.domain) - loaded_providers.add(prov_conf.instance_id) - tg.create_task(self.load_provider(prov_conf)) - # create default config for any 'load_by_default' providers (e.g. URL provider) - # NOTE: this will auto load any not yet existing providers - for prov_manifest in self._available_providers.values(): - if prov_manifest.domain in loaded_providers: - continue - if not prov_manifest.load_by_default: - continue - if prov_manifest.depends_on and not allow_depends_on: - continue - default_conf = self.config.create_provider_config(prov_manifest.domain) - self.config.set_provider_config(default_conf) + + # create default config for any 'load_by_default' providers (e.g. URL provider) + # we must do this first to resolve any dependencies + # NOTE: this will auto load any not yet existing providers + provider_configs = self.config.get_provider_configs() + for prov_manifest in self._available_providers.values(): + if not prov_manifest.load_by_default: + continue + existing = any(x for x in provider_configs if x.domain == prov_manifest.domain) + if existing: + continue + default_conf = self.config.create_provider_config(prov_manifest.domain) + # skip_reload to prevent race condition + self.config.set_provider_config(default_conf, skip_reload=True) + + # load all configured (and enabled) providers + for allow_depends_on in (False, True): + for prov_conf in self.config.get_provider_configs(): + prov_manifest = self._available_providers[prov_conf.domain] + if prov_manifest.depends_on and not allow_depends_on: + continue + if prov_conf.instance_id in self._providers: + continue + await self.load_provider(prov_conf) async def __load_available_providers(self) -> None: """Preload all available provider manifest files.""" diff --git a/pyproject.toml b/pyproject.toml index 1e02493f..56bad92e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,13 +96,11 @@ asyncio_mode = "auto" [tool.setuptools] platforms = ["any"] zip-safe = false +packages = ["music_assistant"] include-package-data = true [tool.setuptools.package-data] -"*" = ["*.*"] - -[tool.setuptools.packages.find] -where = ["."] +music_assistant = ["py.typed"] [tool.ruff] fix = true -- 2.34.1