The list of commands is known at compile time. Instead of creating a
linked list on startup, we can just register all commands in a static
sorted array.
The command pointers which are passed around aren't being modified -
in fact, no command pointer must be modified once it has been added to
the commandList.
When adding a local file, clients have to use the "file" URI schema
described in RFC 1738 3.10. By adding this schema to "urlhandlers", a
client can detect whether this feature is available.
"idle" waits until something noteworthy happens on the server,
e.g. song change, playlist modified, database updated. This allows
clients to keep up to date without polling.
The documentation for directory_update_init() was incorrect: a job ID
must be positive, not non-negative. If the update queue is full and
no job was created, it makes more sense to return 0 instead of -1,
because it is more consistent with the return value of isUpdatingDB().
Remove clutter from directory.c. Everything which saves or loads
to/from the hard disk goes to directory_save.c, and code which sends
directory information to the client is moved into directory_print.c.
With commit 6dcd7fea (if I am not mistaken) the error returned when
you try to save to an existing playlist is wrong. Instead of
MPD_ACK_ERROR_EXIST, MPD_ACK_ERROR_NO_EXIST is returned. This is
obviously wrong and breaks gmpc.
Taming the directory.c monster, part II: move the database management
stuff to database. directory.c should only contain code which works
on directory objects.
The source directory.c mixes several libraries: directory object
management, database management and database update, resulting in a
1000+ line monster. Move the whole database update code to update.c.
This got broken when listHandlerFunc was removed. Since we no
longer need it and it's confusing, remove processCommandInternal
and just use process_command.
commands should really not behave differently if they're issued
inside a command list or not; so stop having special handler
functions to deal with them. "update" was the only command
that used this functionality and I changed that in the last
commit to serialize access.
Now the "update" command can be issued multiple times regardless
of whether the client is in list mode or not.
We serialize the update tasks to prevent updates from trampling
over each other and will spawn another update task
once the current one is finished updating and reaped.
Right now we cap the queue size to 32 which is probably enough (I
bet most people usually run update with no argument anyways);
but we can make it grow/shrink dynamically if needed. There'll
still be a hard-coded limit to prevent DoS attacks, though.
This only breaks "update" under list command mode and
no other commands. This can be done more optimally
without the extra heap allocation via xstrdup(); but is
uncommon enough to not matter.
Due to a merge error, I broke the function handleUpdate(). It did not
do anything for the global update, and it did not send a proper
response to the client. This patch fixes both bugs.
A lot of the preparation was needed (and done in previous
months) in making update thread-safe, but here it is.
This was the first thing I made work inside a thread when I
started mpd-uclinux many years ago, and also the last thing I've
done in mainline mpd to work inside a thread, go figure.
print_playlist_result() had an assert(0) at the end, in case there was
an invalid result value. With NDEBUG, this resulted in a function not
returning a value - add a dummy "return -1" at the end to keep gcc
quiet.
The function loadPlaylist() wants to report incremental errors to the
client, for this reason we cannot remove its protocol dependency right
now. Instead, make it use the client struct instead of the raw file
descriptor.
Don't pass the raw file descriptor around. This migration patch is
rather large, because all of the sources have inter dependencies - we
have to change all of them at the same time.
Pass the client struct to CommandHandlerFunction and
CommandListHandlerFunction. Most commands cannot take real advantage
of that yet, since most of them still work with the raw file
descriptor.
These two functions take a client struct instead of the file
descriptor. We will now begin passing the client struct around
instead of a raw file descriptor (which needed a linear lookup in the
client list to be useful).