Fix for getting the ip addresses resulting in an an error (#755)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Sun, 9 Jul 2023 00:06:10 +0000 (02:06 +0200)
committerGitHub <noreply@github.com>
Sun, 9 Jul 2023 00:06:10 +0000 (02:06 +0200)
music_assistant/server/controllers/streams.py
music_assistant/server/controllers/webserver.py
music_assistant/server/helpers/util.py
pyproject.toml
requirements_all.txt

index ce301b0d72570107d8f2680879bc701402096cf4..3ed32531f9600403cbe561e69081513601eb1deb 100644 (file)
@@ -18,7 +18,11 @@ import shortuuid
 from aiohttp import web
 
 from music_assistant.common.helpers.util import get_ip, select_free_port
-from music_assistant.common.models.config_entries import ConfigEntry, ConfigValueType
+from music_assistant.common.models.config_entries import (
+    ConfigEntry,
+    ConfigValueOption,
+    ConfigValueType,
+)
 from music_assistant.common.models.enums import ConfigEntryType, ContentType
 from music_assistant.common.models.errors import MediaNotFoundError, QueueEmpty
 from music_assistant.common.models.media_items import AudioFormat
@@ -33,6 +37,7 @@ from music_assistant.constants import (
     CONF_EQ_TREBLE,
     CONF_OUTPUT_CHANNELS,
     CONF_OUTPUT_CODEC,
+    CONF_PUBLISH_IP,
 )
 from music_assistant.server.helpers.audio import (
     check_audio_support,
@@ -41,6 +46,7 @@ from music_assistant.server.helpers.audio import (
     get_stream_details,
 )
 from music_assistant.server.helpers.process import AsyncProcess
+from music_assistant.server.helpers.util import get_ips
 from music_assistant.server.helpers.webserver import Webserver
 from music_assistant.server.models.core_controller import CoreController
 
@@ -279,6 +285,7 @@ class StreamsController(CoreController):
     ) -> tuple[ConfigEntry, ...]:
         """Return all Config Entries for this core module (if any)."""
         default_ip = await get_ip()
+        all_ips = await get_ips()
         default_port = await select_free_port(8096, 9200)
         return (
             ConfigEntry(
@@ -291,12 +298,11 @@ class StreamsController(CoreController):
                 "on the given IP and TCP port by players on the local network.",
             ),
             ConfigEntry(
-                key=CONF_BIND_IP,
+                key=CONF_PUBLISH_IP,
                 type=ConfigEntryType.STRING,
                 default_value=default_ip,
-                label="Bind to IP/interface",
-                description="Start the streamserver on this specific interface. \n"
-                "This IP address is communicated to players where to find this server. "
+                label="Published IP address",
+                description="This IP address is communicated to players where to find this server. "
                 "Override the default in advanced scenarios, such as multi NIC configurations. \n"
                 "Make sure that this server can be reached "
                 "on the given IP and TCP port by players on the local network. \n"
@@ -304,6 +310,18 @@ class StreamsController(CoreController):
                 "not be adjusted in regular setups.",
                 advanced=True,
             ),
+            ConfigEntry(
+                key=CONF_BIND_IP,
+                type=ConfigEntryType.STRING,
+                default_value="0.0.0.0",
+                options=(ConfigValueOption(x, x) for x in {"0.0.0.0", *all_ips}),
+                label="Bind to IP/interface",
+                description="Start the stream server on this specific interface. \n"
+                "Use 0.0.0.0 to bind to all interfaces, which is the default. \n"
+                "This is an advanced setting that should normally "
+                "not be adjusted in regular setups.",
+                advanced=True,
+            ),
         )
 
     async def setup(self, config: CoreConfig) -> None:
@@ -323,9 +341,9 @@ class StreamsController(CoreController):
         )
         # start the webserver
         self.publish_port = config.get_value(CONF_BIND_PORT)
-        self.publish_ip = config.get_value(CONF_BIND_IP)
+        self.publish_ip = config.get_value(CONF_PUBLISH_IP)
         await self._server.setup(
-            bind_ip=self.publish_ip,
+            bind_ip=config.get_value(CONF_BIND_IP),
             bind_port=self.publish_port,
             base_url=f"http://{self.publish_ip}:{self.publish_port}",
             static_routes=[
index a7c2a1e33295f1005ba280ad185b2bcf7834874a..2892533a0507362937c2064c73c20387fd67e767 100644 (file)
@@ -28,7 +28,7 @@ from music_assistant.common.models.api import (
     MessageType,
     SuccessResultMessage,
 )
-from music_assistant.common.models.config_entries import ConfigEntry
+from music_assistant.common.models.config_entries import ConfigEntry, ConfigValueOption
 from music_assistant.common.models.enums import ConfigEntryType
 from music_assistant.common.models.errors import InvalidCommand
 from music_assistant.common.models.event import MassEvent
@@ -119,6 +119,7 @@ class WebserverController(CoreController):
         # HA supervisor not present: user is responsible for securing the webserver
         # we give the tools to do so by presenting config options
         default_ip = await get_ip()
+        all_ips = await get_ips()
         default_port = await select_free_port(8095, 9200)
         default_base_url = f"http://{default_ip}:{default_port}"
         return (
@@ -142,6 +143,7 @@ class WebserverController(CoreController):
                 key=CONF_BIND_IP,
                 type=ConfigEntryType.STRING,
                 default_value="0.0.0.0",
+                options=(ConfigValueOption(x, x) for x in {"0.0.0.0", *all_ips}),
                 label="Bind to IP/interface",
                 description="Start the (web)server on this specific interface. \n"
                 "Use 0.0.0.0 to bind to all interfaces. \n"
index c4299544d45e4d8f0763f0162195f252346d1134..b02e2bafa23a6c77c03daaa29cf90f23c75b3a38 100644 (file)
@@ -5,7 +5,6 @@ import asyncio
 import importlib
 import logging
 import platform
-import socket
 import tempfile
 import urllib.error
 import urllib.parse
@@ -15,6 +14,7 @@ from importlib.metadata import PackageNotFoundError
 from importlib.metadata import version as pkg_version
 from typing import TYPE_CHECKING
 
+import ifaddr
 import memory_tempfile
 
 if TYPE_CHECKING:
@@ -54,17 +54,19 @@ async def get_package_version(pkg_name: str) -> str:
         return "0.0.0"
 
 
-async def get_ips(include_ipv6: bool = False) -> set[str]:
+async def get_ips(include_ipv6: bool = False, ignore_loopback: bool = True) -> set[str]:
     """Return all IP-adresses of all network interfaces."""
 
     def call() -> set[str]:
         result: set[str] = set()
-        for item in socket.getaddrinfo(socket.gethostname(), None):
-            protocol, *_, (ip, *_) = item
-            if protocol == socket.AddressFamily.AF_INET or (
-                include_ipv6 and protocol == socket.AddressFamily.AF_INET6
-            ):
-                result.add(ip)
+        adapters = ifaddr.get_adapters()
+        for adapter in adapters:
+            for ip in adapter.ips:
+                if ip.is_IPv6 and not include_ipv6:
+                    continue
+                if ip.ip == "127.0.0.1" and ignore_loopback:
+                    continue
+                result.add(ip.ip)
         return result
 
     return await asyncio.to_thread(call)
index e10d4c581c7e590e155754173abd6bd775d52f70..a33a9d196f38944ae301214b44b3b013a1c31fb6 100644 (file)
@@ -44,7 +44,8 @@ server = [
   "orjson==3.9.1",
   "shortuuid==1.0.11",
   "zeroconf==0.70.0",
-  "cryptography==41.0.1"
+  "cryptography==41.0.1",
+  "ifaddr==0.2.0"
 ]
 test = [
   "black==23.3.0",
index beae317166f75b7d53ab70c2350a93e2b5389e88..60dc2370a080fc04e560cad9ce8731582243a751 100644 (file)
@@ -16,6 +16,7 @@ faust-cchardet>=2.1.18
 git+https://github.com/gieljnssns/python-radios.git@main
 git+https://github.com/jozefKruszynski/python-tidal.git@refs/heads/album-type-with-fix
 git+https://github.com/pytube/pytube.git@refs/pull/1680/head
+ifaddr==0.2.0
 mashumaro==3.7
 memory-tempfile==2.2.3
 music-assistant-frontend==2.0.1