command: allow clients to subscribe to specific idle events
The client may provide the names of idle events as arguments to the "idle" command to inform MPD that it is only interested in these events.
This commit is contained in:
parent
976d5045c6
commit
0bad84066b
29
src/client.c
29
src/client.c
|
@ -91,6 +91,9 @@ struct client {
|
||||||
/** idle flags pending on this client, to be sent as soon as
|
/** idle flags pending on this client, to be sent as soon as
|
||||||
the client enters "idle" */
|
the client enters "idle" */
|
||||||
unsigned idle_flags;
|
unsigned idle_flags;
|
||||||
|
|
||||||
|
/** idle flags that the client wants to receive */
|
||||||
|
unsigned idle_subscriptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
static LIST_HEAD(clients);
|
static LIST_HEAD(clients);
|
||||||
|
@ -766,16 +769,6 @@ mpd_fprintf void client_printf(struct client *client, const char *fmt, ...)
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *const idle_names[] = {
|
|
||||||
"database",
|
|
||||||
"stored_playlist",
|
|
||||||
"playlist",
|
|
||||||
"player",
|
|
||||||
"mixer",
|
|
||||||
"output",
|
|
||||||
"options",
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send "idle" response to this client.
|
* Send "idle" response to this client.
|
||||||
*/
|
*/
|
||||||
|
@ -783,6 +776,7 @@ static void
|
||||||
client_idle_notify(struct client *client)
|
client_idle_notify(struct client *client)
|
||||||
{
|
{
|
||||||
unsigned flags, i;
|
unsigned flags, i;
|
||||||
|
const char *const* idle_names;
|
||||||
|
|
||||||
assert(client->idle_waiting);
|
assert(client->idle_waiting);
|
||||||
assert(client->idle_flags != 0);
|
assert(client->idle_flags != 0);
|
||||||
|
@ -791,10 +785,9 @@ client_idle_notify(struct client *client)
|
||||||
client->idle_flags = 0;
|
client->idle_flags = 0;
|
||||||
client->idle_waiting = false;
|
client->idle_waiting = false;
|
||||||
|
|
||||||
for (i = 0; i < sizeof(idle_names) / sizeof(idle_names[0]); ++i) {
|
idle_names = idle_get_names();
|
||||||
assert(idle_names[i] != NULL);
|
for (i = 0; idle_names[i]; ++i) {
|
||||||
|
if (flags & (1 << i) & client->idle_subscriptions)
|
||||||
if (flags & (1 << i))
|
|
||||||
client_printf(client, "changed: %s\n",
|
client_printf(client, "changed: %s\n",
|
||||||
idle_names[i]);
|
idle_names[i]);
|
||||||
}
|
}
|
||||||
|
@ -814,20 +807,22 @@ void client_manager_idle_add(unsigned flags)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
client->idle_flags |= flags;
|
client->idle_flags |= flags;
|
||||||
if (client->idle_waiting) {
|
if (client->idle_waiting
|
||||||
|
&& (client->idle_flags & client->idle_subscriptions)) {
|
||||||
client_idle_notify(client);
|
client_idle_notify(client);
|
||||||
client_write_output(client);
|
client_write_output(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool client_idle_wait(struct client *client)
|
bool client_idle_wait(struct client *client, unsigned flags)
|
||||||
{
|
{
|
||||||
assert(!client->idle_waiting);
|
assert(!client->idle_waiting);
|
||||||
|
|
||||||
client->idle_waiting = true;
|
client->idle_waiting = true;
|
||||||
|
client->idle_subscriptions = flags;
|
||||||
|
|
||||||
if (client->idle_flags != 0) {
|
if (client->idle_flags & client->idle_subscriptions) {
|
||||||
client_idle_notify(client);
|
client_idle_notify(client);
|
||||||
return true;
|
return true;
|
||||||
} else
|
} else
|
||||||
|
|
|
@ -78,6 +78,6 @@ void client_manager_idle_add(unsigned flags);
|
||||||
* sent immediately and "true" is returned". If no, it puts the
|
* sent immediately and "true" is returned". If no, it puts the
|
||||||
* client into waiting mode and returns false.
|
* client into waiting mode and returns false.
|
||||||
*/
|
*/
|
||||||
bool client_idle_wait(struct client *client);
|
bool client_idle_wait(struct client *client, unsigned flags);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "tag_print.h"
|
#include "tag_print.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "os_compat.h"
|
#include "os_compat.h"
|
||||||
|
#include "idle.h"
|
||||||
|
|
||||||
#define COMMAND_STATUS_VOLUME "volume"
|
#define COMMAND_STATUS_VOLUME "volume"
|
||||||
#define COMMAND_STATUS_STATE "state"
|
#define COMMAND_STATUS_STATE "state"
|
||||||
|
@ -1253,8 +1254,28 @@ static enum command_return
|
||||||
handle_idle(struct client *client,
|
handle_idle(struct client *client,
|
||||||
mpd_unused int argc, mpd_unused char *argv[])
|
mpd_unused int argc, mpd_unused char *argv[])
|
||||||
{
|
{
|
||||||
|
unsigned flags = 0, j;
|
||||||
|
int i;
|
||||||
|
const char *const* idle_names;
|
||||||
|
|
||||||
|
idle_names = idle_get_names();
|
||||||
|
for (i = 1; i < argc; ++i) {
|
||||||
|
if (!argv[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (j = 0; idle_names[j]; ++j) {
|
||||||
|
if (!strcasecmp(argv[i], idle_names[j])) {
|
||||||
|
flags |= (1 << j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No argument means that the client wants to receive everything */
|
||||||
|
if (flags == 0)
|
||||||
|
flags = ~0;
|
||||||
|
|
||||||
/* enable "idle" mode on this client */
|
/* enable "idle" mode on this client */
|
||||||
client_idle_wait(client);
|
client_idle_wait(client, flags);
|
||||||
|
|
||||||
/* return value is "1" so the caller won't print "OK" */
|
/* return value is "1" so the caller won't print "OK" */
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1280,7 +1301,7 @@ static const struct command commands[] = {
|
||||||
{ "disableoutput", PERMISSION_ADMIN, 1, 1, handle_disableoutput },
|
{ "disableoutput", PERMISSION_ADMIN, 1, 1, handle_disableoutput },
|
||||||
{ "enableoutput", PERMISSION_ADMIN, 1, 1, handle_enableoutput },
|
{ "enableoutput", PERMISSION_ADMIN, 1, 1, handle_enableoutput },
|
||||||
{ "find", PERMISSION_READ, 2, -1, handle_find },
|
{ "find", PERMISSION_READ, 2, -1, handle_find },
|
||||||
{ "idle", PERMISSION_READ, 0, 0, handle_idle },
|
{ "idle", PERMISSION_READ, 0, -1, handle_idle },
|
||||||
{ "kill", PERMISSION_ADMIN, -1, -1, handle_kill },
|
{ "kill", PERMISSION_ADMIN, -1, -1, handle_kill },
|
||||||
{ "list", PERMISSION_READ, 1, -1, handle_list },
|
{ "list", PERMISSION_READ, 1, -1, handle_list },
|
||||||
{ "listall", PERMISSION_READ, 0, 1, handle_listall },
|
{ "listall", PERMISSION_READ, 0, 1, handle_listall },
|
||||||
|
|
18
src/idle.c
18
src/idle.c
|
@ -30,6 +30,18 @@
|
||||||
static unsigned idle_flags;
|
static unsigned idle_flags;
|
||||||
static pthread_mutex_t idle_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t idle_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static const char *const idle_names[] = {
|
||||||
|
"database",
|
||||||
|
"stored_playlist",
|
||||||
|
"playlist",
|
||||||
|
"player",
|
||||||
|
"mixer",
|
||||||
|
"output",
|
||||||
|
"options",
|
||||||
|
"elapsed",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
idle_add(unsigned flags)
|
idle_add(unsigned flags)
|
||||||
{
|
{
|
||||||
|
@ -54,3 +66,9 @@ idle_get(void)
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char*const*
|
||||||
|
idle_get_names(void)
|
||||||
|
{
|
||||||
|
return idle_names;
|
||||||
|
}
|
||||||
|
|
|
@ -61,4 +61,10 @@ idle_add(unsigned flags);
|
||||||
unsigned
|
unsigned
|
||||||
idle_get(void);
|
idle_get(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get idle names
|
||||||
|
*/
|
||||||
|
const char*const*
|
||||||
|
idle_get_names(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue