1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-12-04 14:46:30 -05:00

Feature: Added JSON output for admin commands listclients, listmounts, streamlist, moveclients, and updatemetadata

This commit is contained in:
Philipp Schafft 2020-10-11 08:18:55 +00:00
parent 25f23c4192
commit 5e9feb611a
2 changed files with 45 additions and 10 deletions

View File

@ -74,6 +74,7 @@
#define METADATA_JSON_REQUEST "metadata.json"
#define LISTCLIENTS_RAW_REQUEST "listclients"
#define LISTCLIENTS_HTML_REQUEST "listclients.xsl"
#define LISTCLIENTS_JSON_REQUEST "listclients.json"
#define STATS_RAW_REQUEST "stats"
#define STATS_HTML_REQUEST "stats.xsl"
#define STATS_JSON_REQUEST "stats.json"
@ -82,11 +83,14 @@
#define QUEUE_RELOAD_JSON_REQUEST "reloadconfig.json"
#define LISTMOUNTS_RAW_REQUEST "listmounts"
#define LISTMOUNTS_HTML_REQUEST "listmounts.xsl"
#define LISTMOUNTS_JSON_REQUEST "listmounts.json"
#define STREAMLIST_RAW_REQUEST "streamlist"
#define STREAMLIST_HTML_REQUEST "streamlist.xsl"
#define STREAMLIST_JSON_REQUEST "streamlist.json"
#define STREAMLIST_PLAINTEXT_REQUEST "streamlist.txt"
#define MOVECLIENTS_RAW_REQUEST "moveclients"
#define MOVECLIENTS_HTML_REQUEST "moveclients.xsl"
#define MOVECLIENTS_JSON_REQUEST "moveclients.json"
#define KILLCLIENT_RAW_REQUEST "killclient"
#define KILLCLIENT_HTML_REQUEST "killclient.xsl"
#define KILLCLIENT_JSON_REQUEST "killclient.json"
@ -98,6 +102,7 @@
#define MANAGEAUTH_HTML_REQUEST "manageauth.xsl"
#define UPDATEMETADATA_RAW_REQUEST "updatemetadata"
#define UPDATEMETADATA_HTML_REQUEST "updatemetadata.xsl"
#define UPDATEMETADATA_JSON_REQUEST "updatemetadata.json"
#define SHOWLOG_RAW_REQUEST "showlog"
#define SHOWLOG_HTML_REQUEST "showlog.xsl"
#define SHOWLOG_JSON_REQUEST "showlog.json"
@ -146,6 +151,7 @@ static const admin_command_handler_t handlers[] = {
{ SHOUTCAST_METADATA_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_HTML, command_shoutcast_metadata, NULL},
{ LISTCLIENTS_RAW_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_RAW, command_show_listeners, NULL},
{ LISTCLIENTS_HTML_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_HTML, command_show_listeners, NULL},
{ LISTCLIENTS_JSON_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_JSON, command_show_listeners, NULL},
{ STATS_RAW_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_RAW, command_stats, NULL},
{ STATS_HTML_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_HTML, command_stats, NULL},
{ STATS_JSON_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_JSON, command_stats, NULL},
@ -155,11 +161,14 @@ static const admin_command_handler_t handlers[] = {
{ QUEUE_RELOAD_JSON_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_JSON, command_queue_reload, NULL},
{ LISTMOUNTS_RAW_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_RAW, command_list_mounts, NULL},
{ LISTMOUNTS_HTML_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, command_list_mounts, NULL},
{ LISTMOUNTS_JSON_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_JSON, command_list_mounts, NULL},
{ STREAMLIST_RAW_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_RAW, command_list_mounts, NULL},
{ STREAMLIST_PLAINTEXT_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_PLAINTEXT, command_list_mounts, NULL},
{ STREAMLIST_HTML_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, command_list_mounts, NULL},
{ STREAMLIST_JSON_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_JSON, command_list_mounts, NULL},
{ MOVECLIENTS_RAW_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_RAW, command_move_clients, NULL},
{ MOVECLIENTS_HTML_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_HTML, command_move_clients, NULL},
{ MOVECLIENTS_JSON_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_JSON, command_move_clients, NULL},
{ KILLCLIENT_RAW_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_RAW, command_kill_client, NULL},
{ KILLCLIENT_HTML_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_HTML, command_kill_client, NULL},
{ KILLCLIENT_JSON_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_JSON, command_kill_client, NULL},
@ -170,6 +179,7 @@ static const admin_command_handler_t handlers[] = {
{ MANAGEAUTH_HTML_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, command_manageauth, NULL},
{ UPDATEMETADATA_RAW_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_RAW, command_updatemetadata, NULL},
{ UPDATEMETADATA_HTML_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_HTML, command_updatemetadata, NULL},
{ UPDATEMETADATA_JSON_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_JSON, command_updatemetadata, NULL},
{ BUILDM3U_RAW_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_RAW, command_buildm3u, NULL},
{ SHOWLOG_RAW_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_RAW, command_show_log, NULL},
{ SHOWLOG_HTML_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, command_show_log, NULL},
@ -371,7 +381,7 @@ xmlNodePtr admin_build_rootnode(xmlDocPtr doc, const char *name)
/* build an XML doc containing information about currently running sources.
* If a mountpoint is passed then that source will not be added to the XML
* doc even if the source is running */
xmlDocPtr admin_build_sourcelist(const char *mount)
xmlDocPtr admin_build_sourcelist(const char *mount, client_t *client, admin_format_t format)
{
avl_node *node;
source_t *source;
@ -406,9 +416,12 @@ xmlDocPtr admin_build_sourcelist(const char *mount)
srcnode = xmlNewChild(xmlnode, NULL, XMLSTR("source"), NULL);
xmlSetProp(srcnode, XMLSTR("mount"), XMLSTR(source->mount));
xmlNewTextChild(srcnode, NULL, XMLSTR("fallback"),
(source->fallback_mount != NULL)?
XMLSTR(source->fallback_mount):XMLSTR(""));
if (source->fallback_mount) {
xmlNewTextChild(srcnode, NULL, XMLSTR("fallback"), XMLSTR(source->fallback_mount));
} else {
if (format == ADMIN_FORMAT_RAW && client->mode != OMODE_STRICT)
xmlNewTextChild(srcnode, NULL, XMLSTR("fallback"), XMLSTR(""));
}
snprintf(buf, sizeof(buf), "%lu", source->listeners);
xmlNewTextChild(srcnode, NULL, XMLSTR("listeners"), XMLSTR(buf));
@ -428,7 +441,11 @@ xmlDocPtr admin_build_sourcelist(const char *mount)
if (source->client) {
snprintf(buf, sizeof(buf), "%lu",
(unsigned long)(now - source->con->con_time));
xmlNewTextChild(srcnode, NULL, XMLSTR("Connected"), XMLSTR(buf));
if (format == ADMIN_FORMAT_RAW && client->mode != OMODE_STRICT) {
xmlNewTextChild(srcnode, NULL, XMLSTR("Connected"), XMLSTR(buf));
} else {
xmlNewTextChild(srcnode, NULL, XMLSTR("connected"), XMLSTR(buf));
}
}
xmlNewTextChild(srcnode, NULL, XMLSTR("content-type"),
XMLSTR(source->format->contenttype));
@ -741,7 +758,7 @@ static void command_move_clients(client_t *client,
}
ICECAST_LOG_DEBUG("Done optional check (%d)", parameters_passed);
if (!parameters_passed) {
xmlDocPtr doc = admin_build_sourcelist(source->mount);
xmlDocPtr doc = admin_build_sourcelist(source->mount, client, response);
if (idtext) {
xmlNodePtr root = xmlDocGetRootElement(doc);
@ -1100,7 +1117,7 @@ static void command_fallback(client_t *client,
if (client->mode == OMODE_STRICT) {
if (!(COMMAND_OPTIONAL(client, "fallback", fallback))) {
xmlDocPtr doc = admin_build_sourcelist(source->mount);
xmlDocPtr doc = admin_build_sourcelist(source->mount, client, response);
admin_send_response(doc, client, response, FALLBACK_HTML_REQUEST);
xmlFreeDoc(doc);
return;
@ -1273,7 +1290,7 @@ static void command_list_mounts(client_t *client, source_t *source, admin_format
} else {
xmlDocPtr doc;
avl_tree_rlock(global.source_tree);
doc = admin_build_sourcelist(NULL);
doc = admin_build_sourcelist(NULL, client, response);
avl_tree_unlock(global.source_tree);
admin_send_response(doc, client, response,

View File

@ -330,7 +330,7 @@ static void render_node_legacystats(json_renderer_t *renderer, xmlDocPtr doc, xm
};
static const char * number_keys_source[] = {
"audio_bitrate", "audio_channels", "audio_samplerate", "ice-bitrate", "listener_peak", "listeners", "slow_listeners",
"total_bytes_read", "total_bytes_sent", NULL
"total_bytes_read", "total_bytes_sent", "connected", NULL
};
static const char * boolean_keys_source[] = {
"public", NULL
@ -341,7 +341,7 @@ static void render_node_legacystats(json_renderer_t *renderer, xmlDocPtr doc, xm
if (node->type == XML_ELEMENT_NODE) {
const char *nodename = (const char *)node->name;
handled = 1;
if (strcmp(nodename, "icestats") == 0 || strcmp(nodename, "source") == 0) {
if (strcmp(nodename, "icestats") == 0 || strcmp(nodename, "source") == 0 || strcmp(nodename, "listener") == 0) {
int is_icestats = strcmp(nodename, "icestats") == 0;
struct nodelist nodelist;
size_t i;
@ -402,6 +402,24 @@ static void render_node_legacystats(json_renderer_t *renderer, xmlDocPtr doc, xm
json_renderer_end(renderer);
nodelist_unset(&nodelist, i);
} else if (strcmp((const char *)cur->name, "listener") == 0) {
size_t j;
json_renderer_write_key(renderer, (const char *)cur->name, JSON_RENDERER_FLAGS_NONE);
json_renderer_begin(renderer, JSON_ELEMENT_TYPE_ARRAY);
for (j = i; j < len; j++) {
xmlNodePtr subcur = nodelist_get(&nodelist, j);
if (subcur == NULL)
continue;
if (subcur->type == XML_ELEMENT_NODE && subcur->name && strcmp((const char *)cur->name, (const char *)subcur->name) == 0) {
nodelist_unset(&nodelist, j);
render_node_legacystats(renderer, doc, subcur, cur, cache);
}
}
json_renderer_end(renderer);
} else if (strcmp((const char *)cur->name, "metadata") == 0) {
size_t j;