diff options
author | Max Kellermann <max@duempel.org> | 2008-10-14 22:38:14 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2008-10-14 22:38:14 +0200 |
commit | a3e3d2c9506d17b3e19e205535ec263ee75178c9 (patch) | |
tree | 3e93ea6ae33dba8a8f5e12e34629366dcdd7fdb7 /src/client.c | |
parent | 30c86d8ae64ae46ba3bcb1c63e867789feab6dc4 (diff) | |
download | mpd-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.c | 83 |
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; +} |