diff --git a/mopidy_mpd/__init__.py b/mopidy_mpd/__init__.py index 49f47e1..f2441dd 100644 --- a/mopidy_mpd/__init__.py +++ b/mopidy_mpd/__init__.py @@ -8,7 +8,6 @@ class Extension(ext.Extension): - dist_name = "Mopidy-MPD" ext_name = "mpd" version = __version__ diff --git a/mopidy_mpd/network.py b/mopidy_mpd/network.py index e8457b5..9b7b55c 100644 --- a/mopidy_mpd/network.py +++ b/mopidy_mpd/network.py @@ -15,6 +15,15 @@ CONTROL_CHARS = dict.fromkeys(range(32)) +def get_systemd_socket(): + """Attempt to get a socket from systemd.""" + fdnames = os.environ.get("LISTEN_FDNAMES", "").split(":") + if "mpd" not in fdnames: + return None + fd = fdnames.index("mpd") + 3 # 3 is the first systemd file handle + return socket.socket(fileno=fd) + + def get_unix_socket_path(socket_path): match = re.search("^unix:(.*)", socket_path) if not match: @@ -37,7 +46,7 @@ def get_socket_address(host, port): return (host, port) -class ShouldRetrySocketCall(Exception): +class ShouldRetrySocketCallError(Exception): """Indicate that attempted socket call should be retried""" @@ -122,6 +131,10 @@ def __init__( self.watcher = self.register_server_socket(self.server_socket.fileno()) def create_server_socket(self, host, port): + sock = get_systemd_socket() + if sock is not None: + return sock + socket_path = get_unix_socket_path(host) if socket_path is not None: # host is a path so use unix socket sock = create_unix_socket() @@ -157,7 +170,7 @@ def register_server_socket(self, fileno): def handle_connection(self, fd, flags): try: sock, addr = self.accept_connection() - except ShouldRetrySocketCall: + except ShouldRetrySocketCallError: return True if self.maximum_connections_exceeded(): @@ -174,7 +187,7 @@ def accept_connection(self): return sock, addr except OSError as e: if e.errno in (errno.EAGAIN, errno.EINTR): - raise ShouldRetrySocketCall + raise ShouldRetrySocketCallError raise def maximum_connections_exceeded(self): diff --git a/mopidy_mpd/protocol/current_playlist.py b/mopidy_mpd/protocol/current_playlist.py index 868f6ff..687f1e1 100644 --- a/mopidy_mpd/protocol/current_playlist.py +++ b/mopidy_mpd/protocol/current_playlist.py @@ -93,7 +93,7 @@ def delete(context, songrange): tl_tracks = context.core.tracklist.slice(start, end).get() if not tl_tracks: raise exceptions.MpdArgError("Bad song index", command="delete") - for (tlid, _) in tl_tracks: + for tlid, _ in tl_tracks: context.core.tracklist.remove({"tlid": [tlid]}) @@ -325,7 +325,7 @@ def plchangesposid(context, version): # XXX Naive implementation that returns all tracks as changed if int(version) != context.core.tracklist.get_version().get(): result = [] - for (position, (tlid, _)) in enumerate( + for position, (tlid, _) in enumerate( context.core.tracklist.get_tl_tracks().get() ): result.append(("cpos", position)) diff --git a/tests/dummy_audio.py b/tests/dummy_audio.py index 0e853fd..14acbbd 100644 --- a/tests/dummy_audio.py +++ b/tests/dummy_audio.py @@ -21,7 +21,8 @@ def __init__(self, config=None, mixer=None): self.state = audio.PlaybackState.STOPPED self._volume = 0 self._position = 0 - self._callback = None + self._source_setup_callback = None + self._about_to_finish_callback = None self._uri = None self._stream_changed = False self._live_stream = False @@ -58,6 +59,7 @@ def pause_playback(self): def prepare_change(self): self._uri = None + self._source_setup_callback = None return True def stop_playback(self): @@ -76,8 +78,11 @@ def set_metadata(self, track): def get_current_tags(self): return self._tags + def set_source_setup_callback(self, callback): + self._source_setup_callback = callback + def set_about_to_finish_callback(self, callback): - self._callback = callback + self._about_to_finish_callback = callback def enable_sync_handler(self): pass @@ -93,13 +98,13 @@ def _change_state(self, new_state): self._stream_changed = True self._uri = None - if self._uri is not None: - audio.AudioListener.send("position_changed", position=0) - if self._stream_changed: self._stream_changed = False audio.AudioListener.send("stream_changed", uri=self._uri) + if self._uri is not None: + audio.AudioListener.send("position_changed", position=0) + old_state, self.state = self.state, new_state audio.AudioListener.send( "state_changed", @@ -121,14 +126,22 @@ def trigger_fake_tags_changed(self, tags): self._tags.update(tags) audio.AudioListener.send("tags_changed", tags=self._tags.keys()) + def get_source_setup_callback(self): + # This needs to be called from outside the actor or we lock up. + def wrapper(): + if self._source_setup_callback: + self._source_setup_callback() + + return wrapper + def get_about_to_finish_callback(self): # This needs to be called from outside the actor or we lock up. def wrapper(): - if self._callback: + if self._about_to_finish_callback: self.prepare_change() - self._callback() + self._about_to_finish_callback() - if not self._uri or not self._callback: + if not self._uri or not self._about_to_finish_callback: self._tags = {} audio.AudioListener.send("reached_end_of_stream") else: diff --git a/tests/network/test_server.py b/tests/network/test_server.py index 467d979..112f485 100644 --- a/tests/network/test_server.py +++ b/tests/network/test_server.py @@ -250,7 +250,7 @@ def test_accept_connection_recoverable_error(self): for error in (errno.EAGAIN, errno.EINTR): sock.accept.side_effect = socket.error(error, "") - with self.assertRaises(network.ShouldRetrySocketCall): + with self.assertRaises(network.ShouldRetrySocketCallError): network.Server.accept_connection(self.mock) # FIXME decide if this should be allowed to propegate diff --git a/tests/protocol/test_regression.py b/tests/protocol/test_regression.py index aa4b63c..cee5f52 100644 --- a/tests/protocol/test_regression.py +++ b/tests/protocol/test_regression.py @@ -169,7 +169,6 @@ def test(self): class IssueGH113RegressionTest(protocol.BaseTestCase): - r""" The issue: https://github.com/mopidy/mopidy/issues/113