aboutsummaryrefslogtreecommitdiffstats
path: root/src/client.c
diff options
context:
space:
mode:
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;
+}