From eed81f5bec3aef79295112f6c4eeaac3946cc417 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 30 Mar 2022 22:46:10 +0000 Subject: [PATCH] Feature: Added basic health reporting for sources --- admin/listmounts.xsl | 5 ++++- src/admin.c | 20 ++++++++++++++++++++ src/source.c | 28 ++++++++++++++++++++++++++++ src/source.h | 9 +++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/admin/listmounts.xsl b/admin/listmounts.xsl index 84677fd7..5f33c954 100644 --- a/admin/listmounts.xsl +++ b/admin/listmounts.xsl @@ -16,7 +16,10 @@

Mountpoint

- +
+
 
+ +

Listener(s)

diff --git a/src/admin.c b/src/admin.c index ebbc02f5..2ee9758a 100644 --- a/src/admin.c +++ b/src/admin.c @@ -530,6 +530,9 @@ xmlDocPtr admin_build_sourcelist(const char *mount, client_t *client, admin_form config_release_config(); if (source->running) { + const source_flags_t flags = source->flags; + xmlNodePtr flagsnode; + if (source->client) { snprintf(buf, sizeof(buf), "%lu", (unsigned long)(now - source->con->con_time)); @@ -541,6 +544,23 @@ xmlDocPtr admin_build_sourcelist(const char *mount, client_t *client, admin_form } xmlNewTextChild(srcnode, NULL, XMLSTR("content-type"), XMLSTR(source->format->contenttype)); + + switch (source_get_health(source)) { + case HEALTH_OK: + xmlNewTextChild(srcnode, NULL, XMLSTR("health"), XMLSTR("green")); + break; + case HEALTH_WARNING: + xmlNewTextChild(srcnode, NULL, XMLSTR("health"), XMLSTR("yellow")); + break; + case HEALTH_ERROR: + xmlNewTextChild(srcnode, NULL, XMLSTR("health"), XMLSTR("red")); + break; + } + flagsnode = xmlNewChild(srcnode, NULL, XMLSTR("flags"), NULL); + xmlSetProp(flagsnode, XMLSTR("comment"), XMLSTR("This is an experimental node. Do not use!")); + if (flags & SOURCE_FLAG_GOT_DATA) + xmlNewTextChild(flagsnode, NULL, XMLSTR("flag"), XMLSTR("got-data")); + } snprintf(buf, sizeof(buf), "%"PRIu64, source->dumpfile_written); diff --git a/src/source.c b/src/source.c index 01394264..c3b865f5 100644 --- a/src/source.c +++ b/src/source.c @@ -74,6 +74,17 @@ static int _free_client(void *key); static void _parse_audio_info (source_t *source, const char *s); static void source_shutdown (source_t *source); +static void source_set_flags(source_t *source, source_flags_t flags) +{ + /* check if we need to do anything at all */ + if ((source->flags & flags) == flags) + return; + + thread_mutex_lock(&source->lock); + source->flags |= flags; + thread_mutex_unlock(&source->lock); +} + /* Allocate a new source with the stated mountpoint, if one already * exists with that mountpoint in the global source tree then return * NULL. @@ -290,6 +301,7 @@ void source_clear_source (source_t *source) source->hidden = 0; source->shoutcast_compat = 0; source->last_stats_update = 0; + source->flags = 0; util_dict_free(source->audio_info); source->audio_info = NULL; @@ -537,6 +549,9 @@ static refbuf_t *get_next_buffer (source_t *source) break; } + if (refbuf) + source_set_flags(source, SOURCE_FLAG_GOT_DATA); + return refbuf; } @@ -1013,6 +1028,8 @@ static void source_apply_mount (ice_config_t *config, source_t *source, mount_pr avl_tree_rlock (source->client_tree); stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners); + source->flags &= ~SOURCE_FLAGS_CLEARABLE; + if (mountinfo) { source->max_listeners = mountinfo->max_listeners; @@ -1515,3 +1532,14 @@ void source_kill_dumpfile(source_t *source) stats_event(source->mount, "dumpfile_written", NULL); stats_event(source->mount, "dumpfile_start", NULL); } + +health_t source_get_health(source_t *source) +{ + const source_flags_t flags = source->flags; + health_t health = HEALTH_OK; + + if (!(flags & SOURCE_FLAG_GOT_DATA)) + health = health_atbest(health, HEALTH_ERROR); + + return health; +} diff --git a/src/source.h b/src/source.h index 2134d90a..64dc9b0d 100644 --- a/src/source.h +++ b/src/source.h @@ -15,6 +15,7 @@ #define __SOURCE_H__ #include +#include #include #include "common/thread/thread.h" @@ -27,6 +28,12 @@ #include "format.h" #include "playlist.h" +typedef uint_least32_t source_flags_t; + +#define SOURCE_FLAG_GOT_DATA ((source_flags_t)0x00000001U) + +#define SOURCE_FLAGS_CLEARABLE ((source_flags_t)0) + struct source_tag { mutex_t lock; client_t *client; @@ -43,6 +50,7 @@ struct source_tag { /* set to zero to request the source to shutdown without causing a global * shutdown */ int running; + source_flags_t flags; struct _format_plugin_tag *format; @@ -114,6 +122,7 @@ void source_recheck_mounts (int update_all); /* Writes a buffer of raw data to a dumpfile. returns true if the write was successful (and complete). */ bool source_write_dumpfile(source_t *source, const void *buffer, size_t len); void source_kill_dumpfile(source_t *source); +health_t source_get_health(source_t *source); extern mutex_t move_clients_mutex;