Damyan Ivanov [Sun, 21 Nov 2021 08:44:35 +0000 (08:44 +0000)]
rework idling again, walking around Net::Async::MPD interface
thing is, that the ->noidle() call places readers on the mpd handle,
because it uses ->send(). this interferes with the expected protocol
flow like this:
idle() is called, a reader/parser is queued by ->send()
when noidle is called, it calls send(), which queues another reader/parser
MPD sees the 'noidle' command and responds with plain 'OK', which is
consumed by the readers queued by idle(). this by itself causes a crash
because the is no "result" and ->{changes} is invoked on undefined value
it the undef deref is fixed, the protocol still hangs, because of the
extra readers queued, which consumes the reply of the next command
issued (e.g. 'playlist')
the other thing that doesn't work is the link check in mpd-feeder. on
timer, it wants to break out of 'idle' waiting just to be sure that the
connection is alive. this also causes dereferencing of an undefined
value and protocol lock up.
so, instead, the idle/noidle is implemented half under-the-table.
idle is implemented via ordinary send(), and broken by a crude call to
mpd->{mpd_handle}->write(), breaking API. this serves two purposes.
first, the readers queued by send() see toe 'OK' resulting from noidle
and return empty result, which is handled by Feeder without crashing.
second, sending a low-level 'noidle' command via the connection handle
avoids queuing extra reader which would cause protocol hang.
the result is that periodic connection checks (leaving and re-entering
idle) work, idle events (which put MPD out of idle mode) are handled
outside of 'idleness' as they should be, asynchronous signals
(TERM, INT, etc.) work as expected outside of 'idleness'. happy camping
all around!
Damyan Ivanov [Thu, 18 Nov 2021 06:17:19 +0000 (06:17 +0000)]
periodically break out of idle mode to see if the connection to MPD is intact
it may be hanging if for example the local system was suspended. in
this situation mpd would detect the missing peer (us) when e.g. reporting
idle changes and close the tcp socket. later, the local system resumes
and the local tcp connection is still open and waiting for an idle result
forever
Damyan Ivanov [Thu, 11 Nov 2021 20:06:45 +0000 (20:06 +0000)]
fix two instances of hanging open statements
when a cursor is exhausted with while (sth->fetch) {...} there is no
problem. Single row fetches, however need an explicit sth->finish or
the cursor remains open. this is not a big problem, but it is annoying
to see the warnings when the statement is reused (due to caching) or the
connection is shut down
Damyan Ivanov [Thu, 11 Nov 2021 14:43:57 +0000 (14:43 +0000)]
re-exec on SIGHUP, picking up configuration file changes
my first approach was to just re-read the config, but could not make
the idle/playlist loop behave. it gets stuck with responses getting
lost and eventually is disconnected my MPD due to timeout
re-exec works, but there is a (very small) chance of missing a database
update between disconnection and re-connection to MPD.