From ff104c4c188a8b21293fc0cf6a7438b3553e6b55 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 1 Oct 2014 09:30:17 +0200 Subject: [PATCH] caclient: improve webui, rewrite status notifications --- src/api/api_caclient.c | 5 ++-- src/descrambler/caclient.c | 37 +++++++++++++++++++++++++++ src/descrambler/caclient.h | 11 ++++++++ src/descrambler/capmt.c | 42 +++++++++++-------------------- src/descrambler/cwc.c | 37 +++++++++------------------ src/webui/static/app/caclient.js | 13 ++++++++++ src/webui/static/app/ext.css | 16 ++++++++++++ src/webui/static/app/idnode.js | 40 ++++++++++++++++------------- src/webui/static/icons/accept.png | 1 + src/webui/static/icons/stop.png | 1 + 10 files changed, 132 insertions(+), 71 deletions(-) create mode 120000 src/webui/static/icons/accept.png create mode 120000 src/webui/static/icons/stop.png diff --git a/src/api/api_caclient.c b/src/api/api_caclient.c index e186ec2a..dc30cc85 100644 --- a/src/api/api_caclient.c +++ b/src/api/api_caclient.c @@ -36,8 +36,9 @@ api_caclient_list l = htsmsg_create_list(); TAILQ_FOREACH(cac, &caclients, cac_link) { e = htsmsg_create_map(); - htsmsg_add_str(e, "key", idnode_uuid_as_str(&cac->cac_id)); - htsmsg_add_str(e, "val", idnode_get_title(&cac->cac_id)); + htsmsg_add_str(e, "uuid", idnode_uuid_as_str(&cac->cac_id)); + htsmsg_add_str(e, "title", idnode_get_title(&cac->cac_id)); + htsmsg_add_str(e, "status", caclient_get_status(cac)); htsmsg_add_msg(l, NULL, e); } *resp = htsmsg_create_map(); diff --git a/src/descrambler/caclient.c b/src/descrambler/caclient.c index 759e4543..30882453 100644 --- a/src/descrambler/caclient.c +++ b/src/descrambler/caclient.c @@ -211,6 +211,15 @@ caclient_class_class_set(void *o, const void *v) return 0; } +static const void * +caclient_class_status_get(void *o) +{ + caclient_t *cac = o; + static const char *ret; + ret = caclient_get_status(cac); + return &ret; +} + const idclass_t caclient_class = { .ic_class = "caclient", @@ -256,6 +265,13 @@ const idclass_t caclient_class = .name = "Comment", .off = offsetof(caclient_t, cac_comment), }, + { + .type = PT_STR, + .id = "status", + .name = "Status", + .get = caclient_class_status_get, + .opts = PO_RDONLY | PO_HIDDEN | PO_NOSAVE, + }, { } } }; @@ -286,6 +302,27 @@ caclient_caid_update(struct mpegts_mux *mux, uint16_t caid, uint16_t pid, int va pthread_mutex_unlock(&caclients_mutex); } +void +caclient_set_status(caclient_t *cac, caclient_status_t status) +{ + if (cac->cac_status != status) { + cac->cac_status = status; + idnode_notify_simple(&cac->cac_id); + } +} + +const char * +caclient_get_status(caclient_t *cac) +{ + switch (cac->cac_status) { + case CACLIENT_STATUS_NONE: return "caclientNone"; + case CACLIENT_STATUS_READY: return "caclientReady"; + case CACLIENT_STATUS_CONNECTED: return "caclientConnected"; + case CACLIENT_STATUS_DISCONNECTED: return "caclientDisconnected"; + default: return "caclientUnknown"; + } +} + /* * Initialize */ diff --git a/src/descrambler/caclient.h b/src/descrambler/caclient.h index 0e26b78f..1bb0ed2a 100644 --- a/src/descrambler/caclient.h +++ b/src/descrambler/caclient.h @@ -34,6 +34,13 @@ extern struct caclient_entry_queue caclients; extern const idclass_t *caclient_classes[]; +typedef enum caclient_status { + CACLIENT_STATUS_NONE, + CACLIENT_STATUS_READY, + CACLIENT_STATUS_CONNECTED, + CACLIENT_STATUS_DISCONNECTED +} caclient_status_t; + typedef struct caclient { idnode_t cac_id; TAILQ_ENTRY(caclient) cac_link; @@ -43,6 +50,7 @@ typedef struct caclient { int cac_enabled; char *cac_name; char *cac_comment; + int cac_status; void (*cac_free)(struct caclient *cac); void (*cac_start)(struct caclient *cac, struct service *t); @@ -59,6 +67,9 @@ void caclient_start( struct service *t ); void caclient_caid_update(struct mpegts_mux *mux, uint16_t caid, uint16_t pid, int valid); +void caclient_set_status(caclient_t *cac, caclient_status_t status); +const char *caclient_get_status(caclient_t *cac); + void caclient_init(void); void caclient_done(void); diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index 289b97b9..0f3033e4 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -44,7 +44,6 @@ #include "tcp.h" #include "tvhpoll.h" -#include "notify.h" #include "subscriptions.h" #include "tvhcsa.h" #if ENABLE_LINUXDVB @@ -262,7 +261,6 @@ typedef struct capmt { /* thread flags */ int capmt_connected; - int capmt_enabled; int capmt_running; int capmt_reconfigure; @@ -424,22 +422,6 @@ capmt_pid_flush(capmt_t *capmt) } } -/** - * - */ -static void -capmt_set_connected(capmt_t *capmt, int c) -{ - htsmsg_t *m; - if (c == capmt->capmt_connected) - return; - m = htsmsg_create_map(); - capmt->capmt_connected = c; - htsmsg_add_str(m, "uuid", idnode_uuid_as_str(&capmt->cac_id)); - htsmsg_add_u32(m, "connected", capmt->capmt_connected); - notify_by_msg("caclient_status", m); -} - /* * */ @@ -585,7 +567,9 @@ capmt_write_msg(capmt_t *capmt, int adapter, int sid, const uint8_t *buf, size_t // opening socket and sending if (capmt->capmt_sock[i] < 0) { fd = capmt_connect(capmt, i); - capmt_set_connected(capmt, fd >= 0 ? 2 : 0); + caclient_set_status((caclient_t *)capmt, + fd >= 0 ? CACLIENT_STATUS_CONNECTED : + CACLIENT_STATUS_READY); if (fd >= 0) capmt_notify_server(capmt, NULL, 1); } @@ -1401,14 +1385,15 @@ capmt_thread(void *aux) memset(&capmt->capmt_demuxes, 0, sizeof(capmt->capmt_demuxes)); /* Accessible */ - if (capmt->capmt_sockfile && !access(capmt->capmt_sockfile, R_OK | W_OK)) - capmt_set_connected(capmt, 1); + if (capmt->capmt_sockfile && capmt->capmt_oscam != CAPMT_OSCAM_TCP && + !access(capmt->capmt_sockfile, R_OK | W_OK)) + caclient_set_status((caclient_t *)capmt, CACLIENT_STATUS_NONE); else - capmt_set_connected(capmt, 0); + caclient_set_status((caclient_t *)capmt, CACLIENT_STATUS_READY); pthread_mutex_lock(&capmt->capmt_mutex); - while(capmt->capmt_running && capmt->capmt_enabled == 0) + while(capmt->capmt_running && capmt->cac_enabled == 0) pthread_cond_wait(&capmt->capmt_cond, &capmt->capmt_mutex); pthread_mutex_unlock(&capmt->capmt_mutex); @@ -1419,7 +1404,7 @@ capmt_thread(void *aux) capmt_connect(capmt, 0); if (capmt->capmt_sock[0] >= 0) { - capmt_set_connected(capmt, 2); + caclient_set_status((caclient_t *)capmt, CACLIENT_STATUS_CONNECTED); #if CONFIG_LINUXDVB if (capmt_oscam_new(capmt)) { handle_single(capmt); @@ -1465,7 +1450,7 @@ capmt_thread(void *aux) #endif } - capmt_set_connected(capmt, 0); + caclient_set_status((caclient_t *)capmt, CACLIENT_STATUS_DISCONNECTED); /* close opened sockets */ for (i = 0; i < MAX_SOCKETS; i++) @@ -1741,7 +1726,7 @@ capmt_enumerate_services(capmt_t *capmt, int force) // closing socket (oscam handle this as event and stop decrypting) tvhlog(LOG_DEBUG, "capmt", "%s: no subscribed services, closing socket, fd=%d", __FUNCTION__, capmt->capmt_sock[0]); if (capmt->capmt_sock[0] >= 0) - capmt_set_connected(capmt, 1); + caclient_set_status((caclient_t *)capmt, CACLIENT_STATUS_READY); capmt_socket_close(capmt, 0); } else if (force || (res_srv_count != all_srv_count)) { @@ -1917,8 +1902,10 @@ capmt_conf_changed(caclient_t *cac) pthread_t tid; if (capmt->cac_enabled) { - if (capmt->capmt_sockfile == NULL || capmt->capmt_sockfile[0] == '\0') + if (capmt->capmt_sockfile == NULL || capmt->capmt_sockfile[0] == '\0') { + caclient_set_status(cac, CACLIENT_STATUS_NONE); return; + } if (!capmt->capmt_running) { capmt->capmt_running = 1; tvhthread_create(&capmt->capmt_tid, NULL, capmt_thread, capmt); @@ -1938,6 +1925,7 @@ capmt_conf_changed(caclient_t *cac) pthread_mutex_unlock(&capmt->capmt_mutex); tvh_write(capmt->capmt_pipe.wr, "", 1); pthread_join(tid, NULL); + caclient_set_status(cac, CACLIENT_STATUS_NONE); } } diff --git a/src/descrambler/cwc.c b/src/descrambler/cwc.c index bdfd0262..f273354b 100755 --- a/src/descrambler/cwc.c +++ b/src/descrambler/cwc.c @@ -35,7 +35,6 @@ #include "tvheadend.h" #include "tcp.h" #include "caclient.h" -#include "notify.h" #include "atomic.h" #include "subscriptions.h" #include "service.h" @@ -206,7 +205,6 @@ typedef struct cwc { caclient_t; int cwc_fd; - int cwc_connected; int cwc_retry_delay; @@ -269,7 +267,6 @@ typedef struct cwc { const char *cwc_errtxt; - int cwc_enabled; int cwc_running; int cwc_reconfigure; } cwc_t; @@ -545,19 +542,6 @@ cwc_send_ka(cwc_t *cwc) cwc_send_msg(cwc, buf, 3, 0, 0, 0, 0); } -/** - * - */ -static void -cwc_comet_status_update(cwc_t *cwc) -{ - htsmsg_t *m = htsmsg_create_map(); - - htsmsg_add_str(m, "uuid", idnode_uuid_as_str(&cwc->cac_id)); - htsmsg_add_u32(m, "connected", !!cwc->cwc_connected); - notify_by_msg("caclient_status", m); -} - /** * Handle reply to card data request */ @@ -590,8 +574,7 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len) return -1; } - cwc->cwc_connected = 1; - cwc_comet_status_update(cwc); + caclient_set_status((caclient_t *)cwc, CACLIENT_STATUS_CONNECTED); struct cs_card_data *pcard; pcard = calloc(1, sizeof(struct cs_card_data)); pcard->cwc_caid = (msg[4] << 8) | msg[5]; @@ -938,8 +921,7 @@ cwc_running_reply(cwc_t *cwc, uint8_t msgtype, uint8_t *msg, int len) tvhlog(LOG_INFO, "cwc", "Invalid card data reply (provider list)"); return -1; } - cwc->cwc_connected = 1; - cwc_comet_status_update(cwc); + caclient_set_status((caclient_t *)cwc, CACLIENT_STATUS_CONNECTED); struct cs_card_data *pcard; pcard = calloc(1, sizeof(struct cs_card_data)); pcard->cwc_caid = caid; @@ -974,7 +956,7 @@ cwc_running_reply(cwc_t *cwc, uint8_t msgtype, uint8_t *msg, int len) static int cwc_must_break(cwc_t *cwc) { - return !cwc->cwc_running || !cwc->cwc_enabled || cwc->cwc_reconfigure; + return !cwc->cwc_running || !cwc->cac_enabled || cwc->cwc_reconfigure; } /** @@ -1192,6 +1174,8 @@ cwc_thread(void *aux) pthread_mutex_lock(&cwc->cwc_mutex); while(cwc->cwc_running) { + + caclient_set_status((caclient_t *)cwc, CACLIENT_STATUS_READY); snprintf(hostname, sizeof(hostname), "%s", cwc->cwc_hostname); port = cwc->cwc_port; @@ -1226,16 +1210,16 @@ cwc_thread(void *aux) cwc->cwc_fd = -1; close(fd); - cwc->cwc_connected = 0; - cwc_comet_status_update(cwc); tvhlog(LOG_INFO, "cwc", "Disconnected from %s:%i", cwc->cwc_hostname, cwc->cwc_port); } if(cwc->cwc_running == 0) continue; if(attempts == 1) continue; // Retry immediately - d = 3; + caclient_set_status((caclient_t *)cwc, CACLIENT_STATUS_DISCONNECTED); + + d = 3; ts.tv_sec = time(NULL) + d; ts.tv_nsec = 0; @@ -2199,8 +2183,10 @@ cwc_conf_changed(caclient_t *cac) cwc->cwc_password ? crypt_md5(cwc->cwc_password, "$1$abcdefgh$") : NULL; if (cac->cac_enabled) { - if (cwc->cwc_hostname == NULL || cwc->cwc_hostname[0] == '\0') + if (cwc->cwc_hostname == NULL || cwc->cwc_hostname[0] == '\0') { + caclient_set_status(cac, CACLIENT_STATUS_NONE); return; + } if (!cwc->cwc_running) { cwc->cwc_running = 1; tvhthread_create(&cwc->cwc_tid, NULL, cwc_thread, cwc); @@ -2222,6 +2208,7 @@ cwc_conf_changed(caclient_t *cac) pthread_mutex_unlock(&cwc->cwc_mutex); pthread_kill(tid, SIGTERM); pthread_join(tid, NULL); + caclient_set_status(cac, CACLIENT_STATUS_NONE); } } diff --git a/src/webui/static/app/caclient.js b/src/webui/static/app/caclient.js index 15224d3a..ffb0a59e 100644 --- a/src/webui/static/app/caclient.js +++ b/src/webui/static/app/caclient.js @@ -11,6 +11,14 @@ tvheadend.caclient_builders = new Ext.data.JsonStore({ }); tvheadend.caclient = function(panel, index) { + var actions = new Ext.ux.grid.RowActions({ + id: 'status', + header: '', + width: 45, + actions: [ { iconIndex: 'status' } ], + destroy: function() { } + }); + var list = 'enabled,name,username,password,hostname,mode,camdfilename,' + 'port,deskey,emm,emmex,comment'; @@ -22,6 +30,9 @@ tvheadend.caclient = function(panel, index) { titleP: 'CAs', titleC: 'Client Name', iconCls: 'key', + key: 'uuid', + val: 'title', + fields: ['uuid', 'title', 'status'], tabIndex: index, list: { url: 'api/caclient/list', params: { } }, edit: { params: { list: list } }, @@ -40,6 +51,8 @@ tvheadend.caclient = function(panel, index) { }, del: true, move: true, + lcol: [actions], + plugins: [actions], help: function() { new tvheadend.help('Conditional Access Client', 'config_caclient.html'); }, diff --git a/src/webui/static/app/ext.css b/src/webui/static/app/ext.css index a20bbf0b..debe2ffc 100644 --- a/src/webui/static/app/ext.css +++ b/src/webui/static/app/ext.css @@ -322,6 +322,22 @@ background-image: url(../icons/film_edit.png) !important; } +.caclientNone { + background-image: url(../icons/stop.png) !important; +} + +.caclientReady { + background-image: url(../icons/accept.png) !important; +} + +.caclientConnected { + background-image: url(../icons/tick.png) !important; +} + +.caclientDisconnected { + background-image: url(../icons/exclamation.png) !important; +} + .x-linked { display: inline-block; background-image: url(../icons/linked.gif) !important; diff --git a/src/webui/static/app/idnode.js b/src/webui/static/app/idnode.js index 90fe4132..6104e9c3 100644 --- a/src/webui/static/app/idnode.js +++ b/src/webui/static/app/idnode.js @@ -1447,6 +1447,7 @@ tvheadend.idnode_form_grid = function(panel, conf) if (conf.builder) conf.builder(conf); + var columns = []; var buttons = []; var abuttons = {}; var plugins = conf.plugins || []; @@ -1464,12 +1465,13 @@ tvheadend.idnode_form_grid = function(panel, conf) 'class': conf.clazz }, autoLoad: true, - id: 'key', + id: conf.key || 'key', totalProperty: 'total', - fields: ['key','val'], + fields: conf.fields || ['key','val'], remoteSort: false, pruneModifiedRecords: true, - sortInfo: conf.move ? null : { field: 'val', direction: 'ASC' } + sortInfo: conf.move ? conf.sort : + (conf.sort || { field: conf.val || 'val', direction: 'ASC' }) }); store.on('load', function(records) { @@ -1486,16 +1488,23 @@ tvheadend.idnode_form_grid = function(panel, conf) select.selectFirstRow(); }); + /* Left-hand columns (do copy, no reference!) */ + if (conf.lcol) + for (i = 0; i < conf.lcol.length; i++) + columns.push(conf.lcol[i]); + + columns.push({ + width: 300, + id: conf.val || 'val', + header: conf.titleC, + sortable: conf.move ? false : true, + dataIndex: conf.val || 'val' + }); + /* Model */ var model = new Ext.grid.ColumnModel({ defaultSortable: conf.move ? false : true, - columns: [{ - width: 300, - id: 'val', - header: conf.titleC, - sortable: conf.move ? false : true, - dataIndex: 'val' - }] + columns: columns, }); /* Selection */ @@ -1587,13 +1596,11 @@ tvheadend.idnode_form_grid = function(panel, conf) text: 'Move Up', disabled: true, handler: function() { - var r = select.getSelections(); - if (r && r.length > 0) { - var uuid = r[0].id; + if (current) { tvheadend.Ajax({ url: 'api/idnode/moveup', params: { - uuid: uuid + uuid: current.uuid }, success: function(d) { @@ -1610,13 +1617,12 @@ tvheadend.idnode_form_grid = function(panel, conf) text: 'Move Down', disabled: true, handler: function() { - var r = select.getSelections(); - if (r && r.length > 0) { + if (current) { var uuid = r[0].id; tvheadend.Ajax({ url: 'api/idnode/movedown', params: { - uuid: uuid + uuid: current.uuid }, success: function(d) { diff --git a/src/webui/static/icons/accept.png b/src/webui/static/icons/accept.png new file mode 120000 index 00000000..89ffa3b0 --- /dev/null +++ b/src/webui/static/icons/accept.png @@ -0,0 +1 @@ +../../../../vendor/famfamsilk/accept.png \ No newline at end of file diff --git a/src/webui/static/icons/stop.png b/src/webui/static/icons/stop.png new file mode 120000 index 00000000..1a2fb193 --- /dev/null +++ b/src/webui/static/icons/stop.png @@ -0,0 +1 @@ +../../../../vendor/famfamsilk/stop.png \ No newline at end of file