aboutsummaryrefslogtreecommitdiffstats
path: root/src/client.c
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2008-10-14 22:38:14 +0200
committerMax Kellermann <max@duempel.org>2008-10-14 22:38:14 +0200
commita3e3d2c9506d17b3e19e205535ec263ee75178c9 (patch)
tree3e93ea6ae33dba8a8f5e12e34629366dcdd7fdb7 /src/client.c
parent30c86d8ae64ae46ba3bcb1c63e867789feab6dc4 (diff)
downloadmpd-a3e3d2c9506d17b3e19e205535ec263ee75178c9.tar.gz
mpd-a3e3d2c9506d17b3e19e205535ec263ee75178c9.tar.xz
mpd-a3e3d2c9506d17b3e19e205535ec263ee75178c9.zip
command: added command "idle"
"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.
Diffstat (limited to 'src/client.c')
-rw-r--r--src/client.c83
1 files changed, 82 insertions, 1 deletions
diff --git a/src/client.c b/src/client.c
index e8f93b556..1dcec5af2 100644
--- a/src/client.c
+++ b/src/client.c
@@ -27,6 +27,7 @@
#include "ioops.h"
#include "main_notify.h"
#include "dlist.h"
+#include "idle.h"
#include "../config.h"
@@ -87,6 +88,13 @@ struct client {
size_t send_buf_used; /* bytes used this instance */
size_t send_buf_size; /* bytes usable this instance */
size_t send_buf_alloc; /* bytes actually allocated */
+
+ /** is this client waiting for an "idle" response? */
+ bool idle_waiting;
+
+ /** idle flags pending on this client, to be sent as soon as
+ the client enters "idle" */
+ unsigned idle_flags;
};
static LIST_HEAD(clients);
@@ -409,6 +417,9 @@ static int client_input_received(struct client *client, int bytesRead)
int ret;
char *buf_tail = &(client->buffer[client->bufferLength - 1]);
+ /* any input from the client makes it leave "idle" mode */
+ client->idle_waiting = false;
+
while (bytesRead > 0) {
client->bufferLength++;
bytesRead--;
@@ -635,7 +646,9 @@ void client_manager_expire(void)
if (client_is_expired(client)) {
DEBUG("client %i: expired\n", client->num);
client_close(client);
- } else if (time(NULL) - client->lastTime >
+ } else if (!client->idle_waiting && /* idle clients
+ never expire */
+ time(NULL) - client->lastTime >
client_timeout) {
DEBUG("client %i: timeout\n", client->num);
client_close(client);
@@ -807,3 +820,71 @@ mpd_fprintf void client_printf(struct client *client, const char *fmt, ...)
client_vprintf(client, fmt, args);
va_end(args);
}
+
+static const char *const idle_names[] = {
+ "database",
+ "stored_playlist",
+ "playlist",
+ "player",
+ "mixer",
+ "output",
+ "options",
+};
+
+/**
+ * Send "idle" response to this client.
+ */
+static void
+client_idle_notify(struct client *client)
+{
+ unsigned flags, i;
+
+ assert(client->idle_waiting);
+ assert(client->idle_flags != 0);
+
+ flags = client->idle_flags;
+ client->idle_flags = 0;
+ client->idle_waiting = false;
+
+ for (i = 0; i < sizeof(idle_names) / sizeof(idle_names[0]); ++i) {
+ assert(idle_names[i] != NULL);
+
+ if (flags & (1 << i))
+ client_printf(client, "changed: %s\n",
+ idle_names[i]);
+ }
+
+ client_puts(client, "OK\n");
+ client->lastTime = time(NULL);
+}
+
+void client_manager_idle_add(unsigned flags)
+{
+ struct client *client;
+
+ assert(flags != 0);
+
+ list_for_each_entry(client, &clients, siblings) {
+ if (client_is_expired(client))
+ continue;
+
+ client->idle_flags |= flags;
+ if (client->idle_waiting) {
+ client_idle_notify(client);
+ client_write_output(client);
+ }
+ }
+}
+
+bool client_idle_wait(struct client *client)
+{
+ assert(!client->idle_waiting);
+
+ client->idle_waiting = true;
+
+ if (client->idle_flags != 0) {
+ client_idle_notify(client);
+ return true;
+ } else
+ return false;
+}