From e4bdf0ed7df77744e4e049aa00d2f8a8c3874253 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 9 Jul 2023 02:06:10 +0200 Subject: [PATCH] Fix for getting the ip addresses resulting in an an error (#755) --- music_assistant/server/controllers/streams.py | 32 +++++++++++++++---- .../server/controllers/webserver.py | 4 ++- music_assistant/server/helpers/util.py | 18 ++++++----- pyproject.toml | 3 +- requirements_all.txt | 1 + 5 files changed, 41 insertions(+), 17 deletions(-) diff --git a/music_assistant/server/controllers/streams.py b/music_assistant/server/controllers/streams.py index ce301b0d..3ed32531 100644 --- a/music_assistant/server/controllers/streams.py +++ b/music_assistant/server/controllers/streams.py @@ -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=[ diff --git a/music_assistant/server/controllers/webserver.py b/music_assistant/server/controllers/webserver.py index a7c2a1e3..2892533a 100644 --- a/music_assistant/server/controllers/webserver.py +++ b/music_assistant/server/controllers/webserver.py @@ -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" diff --git a/music_assistant/server/helpers/util.py b/music_assistant/server/helpers/util.py index c4299544..b02e2baf 100644 --- a/music_assistant/server/helpers/util.py +++ b/music_assistant/server/helpers/util.py @@ -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) diff --git a/pyproject.toml b/pyproject.toml index e10d4c58..a33a9d19 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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", diff --git a/requirements_all.txt b/requirements_all.txt index beae3171..60dc2370 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -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 -- 2.34.1