fix race condition at startup
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Thu, 9 Mar 2023 15:57:22 +0000 (16:57 +0100)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Thu, 9 Mar 2023 15:57:22 +0000 (16:57 +0100)
MANIFEST.in [new file with mode: 0644]
music_assistant/server/controllers/config.py
music_assistant/server/providers/airplay/bin/__init__.py [deleted file]
music_assistant/server/providers/frontend/__init__.py
music_assistant/server/providers/slimproto/__init__.py
music_assistant/server/server.py
pyproject.toml

diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644 (file)
index 0000000..a65d1e2
--- /dev/null
@@ -0,0 +1,6 @@
+include *.txt
+include README.rst
+include LICENSE.md
+graft music_assistant
+recursive-exclude * *.py[co]
+recursive-exclude * *.DS_Store
index 3c9184d64e82e7d223334332027f7b7bb73b6baf..b0c5d50a803e3aa034d1763ed98ca423dba7f1c9 100644 (file)
@@ -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 (file)
index 9253875..0000000
+++ /dev/null
@@ -1 +0,0 @@
-"""Music Assistant: The music library manager in python."""
index abb8a4869e9ac66ef7ae9c9880e0d4fd2bb41582..7a78a46bbe7ddfe4404d18d81527732bb307d388 100644 (file)
@@ -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(
index b726c732cf5a65c7587baf897537688d983ddd40..0e3e08cddd238cdae19fcd8fe8c4a6e193ccecb7 100644 (file)
@@ -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
index 3812504964b7f9cdd8762d86e05802564b3f0a51..53e1828e11e849ac07ed8968818c8bb19c9f9dde 100644 (file)
@@ -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."""
index 1e02493f571074e5de0e8468362caf7bce1a4a03..56bad92e13ce642803274bdfb032c759b242a8a9 100644 (file)
@@ -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