diff --git a/Makefile b/Makefile index 99c91a73..b25fb163 100644 --- a/Makefile +++ b/Makefile @@ -113,6 +113,7 @@ SRCS = src/version.c \ SRCS += \ src/api.c \ + src/api/api_status.c \ src/api/api_idnode.c \ src/api/api_input.c \ src/api/api_channel.c \ diff --git a/src/api.c b/src/api.c index b4d4ed52..dd9a164b 100644 --- a/src/api.c +++ b/src/api.c @@ -122,4 +122,5 @@ void api_init ( void ) api_channel_init(); api_epg_init(); api_epggrab_init(); + api_status_init(); } diff --git a/src/api.h b/src/api.h index d2a2778d..39e9df86 100644 --- a/src/api.h +++ b/src/api.h @@ -63,6 +63,7 @@ void api_channel_init ( void ); void api_mpegts_init ( void ); void api_epg_init ( void ); void api_epggrab_init ( void ); +void api_status_init ( void ); /* * IDnode diff --git a/src/api/api_input.c b/src/api/api_input.c index 9dbf7bd4..4152dbc6 100644 --- a/src/api/api_input.c +++ b/src/api/api_input.c @@ -26,36 +26,6 @@ #include "access.h" #include "api.h" -static int -api_input_status - ( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) -{ - int c = 0; - htsmsg_t *l, *e; - tvh_input_t *ti; - tvh_input_stream_t *st; - tvh_input_stream_list_t stl = { 0 }; - - TVH_INPUT_FOREACH(ti) - ti->ti_get_streams(ti, &stl); - - l = htsmsg_create_list(); - while ((st = LIST_FIRST(&stl))) { - e = tvh_input_stream_create_msg(st); - htsmsg_add_msg(l, NULL, e); - tvh_input_stream_destroy(st); - LIST_REMOVE(st, link); - free(st); - c++; - } - - *resp = htsmsg_create_map(); - htsmsg_add_msg(*resp, "entries", l); - htsmsg_add_u32(*resp, "totalCount", c); - - return 0; -} - static idnode_set_t * api_input_hw_tree ( void ) { @@ -69,7 +39,6 @@ api_input_hw_tree ( void ) void api_input_init ( void ) { static api_hook_t ah[] = { - { "input/status", ACCESS_ANONYMOUS, api_input_status, NULL }, { "hardware/tree", ACCESS_ADMIN, api_idnode_tree, api_input_hw_tree }, { NULL }, }; diff --git a/src/api/api_subscriptions.c b/src/api/api_status.c similarity index 53% rename from src/api/api_subscriptions.c rename to src/api/api_status.c index 1d0c4b1a..3104850b 100644 --- a/src/api/api_subscriptions.c +++ b/src/api/api_status.c @@ -24,9 +24,41 @@ #include "subscriptions.h" #include "access.h" #include "api.h" +#include "tcp.h" +#include "input.h" static int -api_subscription_list +api_status_inputs + ( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) +{ + int c = 0; + htsmsg_t *l, *e; + tvh_input_t *ti; + tvh_input_stream_t *st; + tvh_input_stream_list_t stl = { 0 }; + + TVH_INPUT_FOREACH(ti) + ti->ti_get_streams(ti, &stl); + + l = htsmsg_create_list(); + while ((st = LIST_FIRST(&stl))) { + e = tvh_input_stream_create_msg(st); + htsmsg_add_msg(l, NULL, e); + tvh_input_stream_destroy(st); + LIST_REMOVE(st, link); + free(st); + c++; + } + + *resp = htsmsg_create_map(); + htsmsg_add_msg(*resp, "entries", l); + htsmsg_add_u32(*resp, "totalCount", c); + + return 0; +} + +static int +api_status_subscriptions ( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) { int c; @@ -43,16 +75,27 @@ api_subscription_list *resp = htsmsg_create_map(); htsmsg_add_msg(*resp, "entries", l); - htsmsg_add_msg(*resp, "totalCount", c); + htsmsg_add_u32(*resp, "totalCount", c); return 0; } -void api_service_init ( void ) +static int +api_status_connections + ( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) +{ + pthread_mutex_lock(&global_lock); + *resp = tcp_server_connections(); + pthread_mutex_unlock(&global_lock); + return 0; +} + +void api_status_init ( void ) { - extern const idclass_t service_class; static api_hook_t ah[] = { - { "subscription/list", ACCESS_ANONYMOUS, api_subscribtion_list, NULL }, + { "status/connections", ACCESS_ADMIN, api_status_connections, NULL }, + { "status/subscriptions", ACCESS_ADMIN, api_status_subscriptions, NULL }, + { "status/inputs", ACCESS_ADMIN, api_status_inputs, NULL }, { NULL }, }; diff --git a/src/htsp_server.c b/src/htsp_server.c index 7116cc7a..a289c266 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -30,6 +30,7 @@ #include "plumbing/tsfix.h" #include "imagecache.h" #include "descrambler.h" +#include "notify.h" #if ENABLE_TIMESHIFT #include "timeshift.h" #endif @@ -1873,6 +1874,7 @@ htsp_authenticate(htsp_connection_t *htsp, htsmsg_t *m) htsp->htsp_logname, username); tvh_str_update(&htsp->htsp_username, username); htsp_update_logname(htsp); + notify_reload("connections"); } if(htsmsg_get_bin(m, "digest", &digest, &digestlen)) diff --git a/src/http.c b/src/http.c index 9aaf4cf0..0adc721f 100644 --- a/src/http.c +++ b/src/http.c @@ -33,6 +33,7 @@ #include "tcp.h" #include "http.h" #include "access.h" +#include "notify.h" static void *http_server; @@ -497,8 +498,9 @@ process_request(http_connection_t *hc, htsbuf_queue_t *spill) n = base64_decode(authbuf, argv[1], sizeof(authbuf) - 1); authbuf[n] = 0; if((n = http_tokenize((char *)authbuf, argv, 2, ':')) == 2) { - hc->hc_username = strdup(argv[0]); - hc->hc_password = strdup(argv[1]); + hc->hc_username = strdup(argv[0]); + hc->hc_password = strdup(argv[1]); + // No way to actually track this } } } diff --git a/src/tcp.c b/src/tcp.c index 051778da..0157ead9 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -397,8 +397,6 @@ typedef struct tcp_server_launch { static LIST_HEAD(, tcp_server_launch) tcp_server_launches = { 0 }; -static gtimer_t tcp_server_status_timer; - /** * */ @@ -438,6 +436,7 @@ tcp_server_start(void *aux) time(&tsl->started); pthread_mutex_lock(&global_lock); LIST_INSERT_HEAD(&tcp_server_launches, tsl, link); + notify_reload("connections"); pthread_mutex_unlock(&global_lock); tsl->ops.start(tsl->fd, &tsl->opaque, &tsl->peer, &tsl->self); @@ -445,6 +444,7 @@ tcp_server_start(void *aux) if (tsl->ops.stop) tsl->ops.stop(tsl->opaque); pthread_mutex_lock(&global_lock); LIST_REMOVE(tsl, link); + notify_reload("connections"); pthread_mutex_unlock(&global_lock); free(tsl); @@ -600,20 +600,19 @@ tcp_server_create /* * Connections status */ -static void -tcp_server_status_callback ( void *opaque ) +htsmsg_t * +tcp_server_connections ( void ) { tcp_server_launch_t *tsl; lock_assert(&global_lock); htsmsg_t *l, *e, *m; char buf[1024]; + int c = 0; - /* RE-arm */ - gtimer_arm(&tcp_server_status_timer, tcp_server_status_callback, NULL, 1); - /* Build list */ l = htsmsg_create_list(); LIST_FOREACH(tsl, &tcp_server_launches, link) { + c++; e = htsmsg_create_map(); tcp_get_ip_str((struct sockaddr*)&tsl->peer, buf, sizeof(buf)); htsmsg_add_str(e, "peer", buf); @@ -625,7 +624,8 @@ tcp_server_status_callback ( void *opaque ) /* Output */ m = htsmsg_create_map(); htsmsg_add_msg(m, "entries", l); - notify_by_msg("tcp_connections", m); + htsmsg_add_u32(m, "totalCount", c); + return m; } /** @@ -641,9 +641,4 @@ tcp_server_init(int opt_ipv6) tcp_server_poll = tvhpoll_create(10); tvhthread_create(&tid, NULL, tcp_server_loop, NULL, 1); - - /* Status timer */ - gtimer_arm(&tcp_server_status_timer, tcp_server_status_callback, NULL, 1); } - - diff --git a/src/tcp.h b/src/tcp.h index 8e329dc5..9b130066 100644 --- a/src/tcp.h +++ b/src/tcp.h @@ -59,4 +59,6 @@ int tcp_read_timeout(int fd, void *buf, size_t len, int timeout); char *tcp_get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen); +htsmsg_t *tcp_server_connections ( void ); + #endif /* TCP_H_ */ diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 1cd1b129..dad55836 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -44,7 +44,6 @@ #include "epggrab/private.h" #include "config2.h" #include "lang_codes.h" -#include "subscriptions.h" #include "imagecache.h" #include "timeshift.h" #include "tvhtime.h" @@ -1332,40 +1331,6 @@ extjs_dvrlist_failed(http_connection_t *hc, const char *remain, void *opaque) return extjs_dvrlist(hc, remain, opaque, is_dvr_entry_failed, dvr_sort_start_descending); } -/** - * - */ -static int -extjs_subscriptions(http_connection_t *hc, const char *remain, void *opaque) -{ - htsbuf_queue_t *hq = &hc->hc_reply; - htsmsg_t *out, *array; - th_subscription_t *s; - - pthread_mutex_lock(&global_lock); - - if(http_access_verify(hc, ACCESS_ADMIN)) { - pthread_mutex_unlock(&global_lock); - return HTTP_STATUS_UNAUTHORIZED; - } - - out = htsmsg_create_map(); - array = htsmsg_create_list(); - - LIST_FOREACH(s, &subscriptions, ths_global_link) - htsmsg_add_msg(array, NULL, subscription_create_msg(s)); - - pthread_mutex_unlock(&global_lock); - - htsmsg_add_msg(out, "entries", array); - - htsmsg_json_serialize(out, hq, 0); - htsmsg_destroy(out); - http_output_content(hc, "text/x-json; charset=UTF-8"); - return 0; -} - - /** * */ @@ -1795,7 +1760,6 @@ extjs_start(void) http_path_add("/dvrlist_finished", NULL, extjs_dvrlist_finished, ACCESS_WEB_INTERFACE); http_path_add("/dvrlist_failed", NULL, extjs_dvrlist_failed, ACCESS_WEB_INTERFACE); http_path_add("/dvr_containers", NULL, extjs_dvr_containers, ACCESS_WEB_INTERFACE); - http_path_add("/subscriptions", NULL, extjs_subscriptions, ACCESS_WEB_INTERFACE); http_path_add("/ecglist", NULL, extjs_ecglist, ACCESS_WEB_INTERFACE); http_path_add("/config", NULL, extjs_config, ACCESS_WEB_INTERFACE); http_path_add("/languages", NULL, extjs_languages, ACCESS_WEB_INTERFACE); diff --git a/src/webui/static/app/status.js b/src/webui/static/app/status.js index 8f2007ad..ff113370 100644 --- a/src/webui/static/app/status.js +++ b/src/webui/static/app/status.js @@ -31,7 +31,7 @@ tvheadend.status_subs = function() { type : 'date', dateFormat : 'U' /* unix time */ } ], - url : 'subscriptions', + url : 'api/status/subscriptions', autoLoad : true, id : 'id' }); @@ -131,7 +131,7 @@ tvheadend.status_subs = function() { loadMask : true, stripeRows : true, disableSelection : true, - title : 'Active subscriptions', + title : 'Subscriptions', iconCls : 'eye', store : tvheadend.subsStore, cm : subsCm, @@ -176,7 +176,7 @@ tvheadend.status_streams = function() { name : 'bps' }, ], - url : 'api/input/status', + url : 'api/status/inputs', autoLoad : true, id : 'uuid' }); @@ -272,16 +272,93 @@ tvheadend.status_streams = function() { return panel; } -tvheadend.status = function() { +/** + * + */ +tvheadend.status_conns = function() { - var panel = new Ext.Panel({ - border: false, - layout : 'vbox', - title : 'Status', + var store = new Ext.data.JsonStore({ + root : 'entries', + totalProperty : 'totalCount', + fields : [ { + name : 'id' + }, { + name : 'type' + }, { + name : 'peer' + }, { + name : 'user' + }, { + name : 'started', + type : 'date', + dateFormat : 'U' /* unix time */ + } ], + url : 'api/status/connections', + autoLoad : true, + id : 'id' + }); + + tvheadend.comet.on('connections', function(m) { + if (m.reload != null) store.reload(); + }); + + function renderDate(value) { + var dt = new Date(value); + return dt.format('Y-m-d H:i:s'); + } + + var cm = new Ext.grid.ColumnModel([{ + width : 50, + id : 'type', + header : "Type", + dataIndex : 'type' + }, { + width : 50, + id : 'peer', + header : "IP Address", + dataIndex : 'peer' + }, { + width : 50, + id : 'user', + header : "Username", + dataIndex : 'user' + }, { + width : 50, + id : 'started', + header : "Started", + dataIndex : 'started', + renderer : renderDate + } ]); + + var panel = new Ext.grid.GridPanel({ + border: false, + loadMask : true, + stripeRows : true, + disableSelection : true, + title : 'Connections', iconCls : 'eye', - items : [ new tvheadend.status_subs, new tvheadend.status_streams ] - }); + store : store, + cm : cm, + flex: 1, + viewConfig : { + forceFit : true + } + }); + return panel; +} +tvheadend.status = function() { + var panel = new Ext.TabPanel({ + title : 'Status', + autoScroll : true, + activeTab : 0, + iconCls : 'eye', + items : [ + new tvheadend.status_subs, + new tvheadend.status_streams, + new tvheadend.status_conns + ] + }); return panel; }