caclient: improve webui, rewrite status notifications

This commit is contained in:
Jaroslav Kysela 2014-10-01 09:30:17 +02:00
parent 7f89149674
commit ff104c4c18
10 changed files with 132 additions and 71 deletions

View file

@ -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();

View file

@ -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
*/

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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');
},

View file

@ -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;

View file

@ -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)
{

View file

@ -0,0 +1 @@
../../../../vendor/famfamsilk/accept.png

View file

@ -0,0 +1 @@
../../../../vendor/famfamsilk/stop.png