idnode: several improvements to the auto-updating features.
This can now be disabled via tick-box at bottom of the grid and no data is actually sent in the update, just which nodes have been updated. There is still an inefficiency in that a bunch of nodes being updated could result in loads of reloads, but that could be improved with a bit of client side buffering/delay.
This commit is contained in:
parent
c587fd3fdc
commit
bfd8cffdc2
6 changed files with 164 additions and 183 deletions
54
src/idnode.c
54
src/idnode.c
|
@ -290,6 +290,7 @@ idnode_get_u32
|
|||
ptr = ((void*)self) + p->off;
|
||||
switch (p->type) {
|
||||
case PT_INT:
|
||||
case PT_BOOL:
|
||||
*u32 = *(int*)ptr;
|
||||
return 0;
|
||||
case PT_U16:
|
||||
|
@ -401,6 +402,7 @@ idnode_cmp_sort
|
|||
case PT_INT:
|
||||
case PT_U16:
|
||||
case PT_U32:
|
||||
case PT_BOOL:
|
||||
{
|
||||
uint32_t u32a = 0, u32b = 0;
|
||||
idnode_get_u32(ina, sort->key, &u32a);
|
||||
|
@ -412,7 +414,6 @@ idnode_cmp_sort
|
|||
}
|
||||
break;
|
||||
case PT_DBL:
|
||||
case PT_BOOL:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
|
@ -577,18 +578,15 @@ int
|
|||
idnode_write0 ( idnode_t *self, htsmsg_t *c, int optmask, int dosave )
|
||||
{
|
||||
int save = 0;
|
||||
void (*savefn)(idnode_t*) = NULL;
|
||||
const idclass_t *idc = self->in_class;
|
||||
for (; idc; idc = idc->ic_super)
|
||||
for (; idc; idc = idc->ic_super) {
|
||||
save |= prop_write_values(self, idc->ic_properties, c, optmask, NULL);
|
||||
if (save) {
|
||||
if (dosave) {
|
||||
for(; idc != NULL; idc = idc->ic_super) {
|
||||
if(idc->ic_save != NULL) {
|
||||
idc->ic_save(self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!savefn && idc->ic_save)
|
||||
savefn = idc->ic_save;
|
||||
}
|
||||
if (save && dosave) {
|
||||
if (savefn) savefn(self);
|
||||
idnode_notify(self, NULL, 0);
|
||||
}
|
||||
return save;
|
||||
|
@ -721,17 +719,20 @@ void
|
|||
idnode_notify
|
||||
(idnode_t *in, const char *chn, int force)
|
||||
{
|
||||
const char *uuid = idnode_uuid_as_str(in);
|
||||
|
||||
/* Forced */
|
||||
if (chn || force) {
|
||||
htsmsg_t *m = idnode_serialize0(in, 0);
|
||||
notify_by_msg(chn ?: "idnodeParamsChanged", m);
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "uuid", uuid);
|
||||
notify_by_msg(chn ?: "idnodeUpdated", m);
|
||||
|
||||
/* Rate-limited */
|
||||
} else {
|
||||
pthread_mutex_lock(&idnode_mutex);
|
||||
if (!idnode_queue)
|
||||
idnode_queue = htsmsg_create_map();
|
||||
htsmsg_set_u32(idnode_queue, idnode_uuid_as_str(in), 1);
|
||||
htsmsg_set_u32(idnode_queue, uuid, 1);
|
||||
pthread_cond_signal(&idnode_cond);
|
||||
pthread_mutex_unlock(&idnode_mutex);
|
||||
}
|
||||
|
@ -743,6 +744,15 @@ idnode_notify_simple (void *in)
|
|||
idnode_notify(in, NULL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
idnode_notify_title_changed (void *in)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "uuid", idnode_uuid_as_str(in));
|
||||
htsmsg_add_str(m, "text", idnode_get_title(in));
|
||||
notify_by_msg("idnodeUpdated", m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Thread for handling notifications
|
||||
*/
|
||||
|
@ -771,20 +781,20 @@ idnode_thread ( void *p )
|
|||
|
||||
HTSMSG_FOREACH(f, q) {
|
||||
node = idnode_find(f->hmf_name, NULL);
|
||||
if (node) {
|
||||
m = idnode_serialize0(node, 0);
|
||||
if (m)
|
||||
notify_by_msg("idnodeUpdated", m);
|
||||
} else {
|
||||
m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "uuid", f->hmf_name);
|
||||
m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "uuid", f->hmf_name);
|
||||
if (node)
|
||||
notify_by_msg("idnodeUpdated", m);
|
||||
else
|
||||
notify_by_msg("idnodeDeleted", m);
|
||||
}
|
||||
}
|
||||
|
||||
/* Finished */
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
htsmsg_destroy(q);
|
||||
|
||||
/* Wait */
|
||||
usleep(500000);
|
||||
pthread_mutex_lock(&idnode_mutex);
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,7 @@ idnode_set_t *idnode_find_all(const idclass_t *idc);
|
|||
void idnode_notify
|
||||
(idnode_t *in, const char *chn, int force);
|
||||
void idnode_notify_simple (void *in);
|
||||
void idnode_notify_title_changed (void *in);
|
||||
|
||||
htsmsg_t *idclass_serialize0 (const idclass_t *idc, int optmask);
|
||||
htsmsg_t *idnode_serialize0 (idnode_t *self, int optmask);
|
||||
|
|
|
@ -54,7 +54,7 @@ const idclass_t mpegts_input_class =
|
|||
.id = "displayname",
|
||||
.name = "Name",
|
||||
.off = offsetof(mpegts_input_t, mi_displayname),
|
||||
.notify = idnode_notify_simple,
|
||||
.notify = idnode_notify_title_changed,
|
||||
},
|
||||
{}
|
||||
}
|
||||
|
|
|
@ -452,6 +452,7 @@ mpegts_mux_initial_scan_done ( mpegts_mux_t *mm )
|
|||
/* Save */
|
||||
mm->mm_initial_scan_done = 1;
|
||||
mm->mm_config_save(mm);
|
||||
idnode_updated(&mm->mm_id);
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
|
|
|
@ -2170,90 +2170,109 @@ extjs_tvhlog(http_connection_t *hc, const char *remain, void *opaque)
|
|||
}
|
||||
|
||||
static int
|
||||
extjs_idnode
|
||||
(http_connection_t *hc, const char *remain, void *opaque)
|
||||
extjs_idnode_tree
|
||||
( http_connection_t *hc, const char *uuid, const char *root,
|
||||
idnode_set_t *(*rootfn)(void), htsmsg_t **out )
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
int isroot = 0;
|
||||
htsmsg_t *out = NULL;
|
||||
int isroot;
|
||||
idnode_t *node = NULL;
|
||||
const char *uuid = http_arg_get(&hc->hc_req_args, "uuid");
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
#if 0
|
||||
const char *root = http_arg_get(&hc->hc_req_args, "root");
|
||||
if (uuid == NULL)
|
||||
uuid = http_arg_get(&hc->hc_req_args, "node");
|
||||
if (!strcmp(uuid, "root")) {
|
||||
isroot = 1;
|
||||
uuid = root;
|
||||
}
|
||||
if (op == NULL)
|
||||
op = "get";
|
||||
|
||||
if(uuid == NULL)
|
||||
/* Validate */
|
||||
if (!uuid)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
isroot = !strcmp("root", uuid);
|
||||
if (isroot && !(root || rootfn))
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
#endif
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if(http_access_verify(hc, ACCESS_ADMIN)) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_UNAUTHORIZED;
|
||||
if (!isroot || root) {
|
||||
if (!(node = idnode_find(isroot ? root : uuid, NULL))) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
node = idnode_find(uuid, NULL);
|
||||
#endif
|
||||
*out = htsmsg_create_list();
|
||||
|
||||
if (!strcmp(op, "get")) {
|
||||
out = htsmsg_create_list();
|
||||
/* Root node */
|
||||
if (isroot && node) {
|
||||
htsmsg_t *m = idnode_serialize(node);
|
||||
htsmsg_add_u32(m, "leaf", idnode_is_leaf(node));
|
||||
htsmsg_add_msg(out, NULL, m);
|
||||
htsmsg_add_msg(*out, NULL, m);
|
||||
|
||||
/* Children */
|
||||
} else {
|
||||
idnode_set_t *v = node ? idnode_get_childs(node) : rootfn();
|
||||
if (v) {
|
||||
int i;
|
||||
for(i = 0; i < v->is_count; i++) {
|
||||
htsmsg_t *m = idnode_serialize(v->is_array[i]);
|
||||
htsmsg_add_u32(m, "leaf", idnode_is_leaf(v->is_array[i]));
|
||||
htsmsg_add_msg(*out, NULL, m);
|
||||
}
|
||||
idnode_set_free(v);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
extjs_idnode0
|
||||
(http_connection_t *hc, const char *remain, void *opaque,
|
||||
idnode_set_t *(*rootfn)(void))
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
htsmsg_t *out = NULL;
|
||||
idnode_t *node = NULL;
|
||||
const char *uuid, *root, *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
|
||||
if (!op) return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
/* Get details */
|
||||
if (!strcmp(op, "get")) {
|
||||
if (!(uuid = http_arg_get(&hc->hc_req_args, "uuid")))
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
pthread_mutex_lock(&global_lock);
|
||||
if (!(node = idnode_find(uuid, NULL))) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_t *m = idnode_serialize(node);
|
||||
htsmsg_add_u32(m, "leaf", idnode_is_leaf(node));
|
||||
htsmsg_add_msg(out, "nodes", m);
|
||||
|
||||
/* Update */
|
||||
} else if (!strcmp(op, "save")) {
|
||||
const char *s;
|
||||
htsmsg_t *conf;
|
||||
htsmsg_field_t *f;
|
||||
htsmsg_t *conf, *nodes;
|
||||
if ((s = http_arg_get(&hc->hc_req_args, "nodes"))) {
|
||||
printf("s = %s\n", s);
|
||||
htsmsg_t *nodes = htsmsg_json_deserialize(s);
|
||||
htsmsg_field_t *f;
|
||||
if (nodes) {
|
||||
if ((nodes = htsmsg_json_deserialize(s))) {
|
||||
pthread_mutex_lock(&global_lock);
|
||||
HTSMSG_FOREACH(f, nodes) {
|
||||
if (!(conf = htsmsg_get_map_by_field(f))) continue;
|
||||
if (!(uuid = htsmsg_get_str(conf, "uuid"))) continue;
|
||||
if (!(node = idnode_find(uuid, NULL))) continue;
|
||||
idnode_update(node, conf);
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
htsmsg_destroy(nodes);
|
||||
}
|
||||
} else if ((s = http_arg_get(&hc->hc_req_args, "conf"))) {
|
||||
if ((conf = htsmsg_json_deserialize(s))) {
|
||||
idnode_update(node, conf);
|
||||
htsmsg_destroy(conf);
|
||||
}
|
||||
}
|
||||
out = htsmsg_create_map();
|
||||
} else if (!strcmp(op, "childs")) {
|
||||
out = htsmsg_create_list();
|
||||
if (isroot) {
|
||||
htsmsg_t *m = idnode_serialize(node);
|
||||
htsmsg_add_u32(m, "leaf", idnode_is_leaf(node));
|
||||
htsmsg_add_msg(out, NULL, m);
|
||||
} else {
|
||||
idnode_set_t *v;
|
||||
if ((v = idnode_get_childs(node))) {
|
||||
int i;
|
||||
for(i = 0; i < v->is_count; i++) {
|
||||
htsmsg_t *m = idnode_serialize(v->is_array[i]);
|
||||
htsmsg_add_u32(m, "leaf", idnode_is_leaf(v->is_array[i]));
|
||||
htsmsg_add_msg(out, NULL, m);
|
||||
}
|
||||
idnode_set_free(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
/* Children */
|
||||
} else if (!strcmp(op, "childs")) {
|
||||
int e;
|
||||
uuid = http_arg_get(&hc->hc_req_args, "uuid");
|
||||
root = http_arg_get(&hc->hc_req_args, "root");
|
||||
if ((e = extjs_idnode_tree(hc, uuid, root, rootfn, &out)))
|
||||
return e;
|
||||
}
|
||||
|
||||
if (!out)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
@ -2264,53 +2283,11 @@ printf("s = %s\n", s);
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_get_idnode(http_connection_t *hc, const char *remain, void *opaque,
|
||||
idnode_set_t *(*rootfn)(void))
|
||||
extjs_idnode
|
||||
(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
const char *s = http_arg_get(&hc->hc_req_args, "node");
|
||||
htsmsg_t *out = NULL;
|
||||
|
||||
if(s == NULL)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if(http_access_verify(hc, ACCESS_ADMIN)) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_UNAUTHORIZED;
|
||||
}
|
||||
|
||||
out = htsmsg_create_list();
|
||||
idnode_set_t *v;
|
||||
|
||||
if(!strcmp(s, "root")) {
|
||||
v = rootfn();
|
||||
} else {
|
||||
v = idnode_get_childs(idnode_find(s, NULL));
|
||||
}
|
||||
|
||||
if(v != NULL) {
|
||||
int i;
|
||||
for(i = 0; i < v->is_count; i++) {
|
||||
htsmsg_t *m = idnode_serialize(v->is_array[i]);
|
||||
htsmsg_add_u32(m, "leaf", idnode_is_leaf(v->is_array[i]));
|
||||
htsmsg_add_msg(out, NULL, m);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
if (v) idnode_set_free(v);
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
return extjs_idnode0(hc, remain, opaque, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2319,7 +2296,7 @@ extjs_get_idnode(http_connection_t *hc, const char *remain, void *opaque,
|
|||
static int
|
||||
extjs_tvadapters(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
return extjs_get_idnode(hc, remain, opaque, &linuxdvb_root);
|
||||
return extjs_idnode0(hc, remain, opaque, &linuxdvb_root);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -152,16 +152,17 @@ tvheadend.idnode_editor = function(item, conf)
|
|||
|
||||
/* Buttons */
|
||||
var saveBtn = new Ext.Button({
|
||||
text : 'Save',
|
||||
text : 'Save',
|
||||
handler : function() {
|
||||
var node = panel.getForm().getFieldValues();
|
||||
node.uuid = item.uuid;
|
||||
var params = {
|
||||
uuid: item.uuid,
|
||||
op : 'save',
|
||||
conf: Ext.util.JSON.encode(panel.getForm().getFieldValues())
|
||||
op : 'save',
|
||||
nodes : Ext.util.JSON.encode([node])
|
||||
};
|
||||
Ext.Ajax.request({
|
||||
url : 'api/idnode',
|
||||
params : params,
|
||||
url : 'api/idnode',
|
||||
params : params,
|
||||
success : function(d) {
|
||||
}
|
||||
});
|
||||
|
@ -177,7 +178,7 @@ tvheadend.idnode_editor = function(item, conf)
|
|||
labelWidth : 200,
|
||||
autoWidth : true,
|
||||
autoHeight : !conf.fixedHeight,
|
||||
width : 600,
|
||||
width : 600,
|
||||
//defaults: {width: 330},
|
||||
defaultType : 'textfield',
|
||||
buttonAlign : 'left',
|
||||
|
@ -564,6 +565,14 @@ tvheadend.idnode_grid = function(panel, conf)
|
|||
}
|
||||
|
||||
/* Grid Panel */
|
||||
var auto = new Ext.form.Checkbox({
|
||||
checked : true,
|
||||
listeners : {
|
||||
check : function ( s, c ) {
|
||||
if (c) store.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
var grid = new Ext.grid.EditorGridPanel({
|
||||
stripeRows : true,
|
||||
title : conf.titleP,
|
||||
|
@ -582,35 +591,21 @@ tvheadend.idnode_grid = function(panel, conf)
|
|||
pageSize : 50,
|
||||
displayInfo : true,
|
||||
displayMsg : conf.titleP + ' {0} - {1} of {2}',
|
||||
emptyMsg : 'No ' + conf.titleP.toLowerCase() + ' to display'
|
||||
emptyMsg : 'No ' + conf.titleP.toLowerCase() + ' to display',
|
||||
items : [ '-', 'Auto-refresh', auto ]
|
||||
})
|
||||
});
|
||||
panel.add(grid);
|
||||
|
||||
/* Add comet listeners */
|
||||
if (conf.comet) {
|
||||
tvheadend.comet.on(conf.comet, function(o) {
|
||||
var fs = [];
|
||||
var d = {};
|
||||
for ( i = 0; i < o.params.length; i++)
|
||||
if (o.params[i].id) {
|
||||
fs.push(o.params[i].id);
|
||||
d[o.params[i].id] = o.params[i].value;
|
||||
}
|
||||
var rec = Ext.data.Record.create(fs);
|
||||
rec = new rec(d, o.id);
|
||||
store.add(rec);
|
||||
});
|
||||
}
|
||||
tvheadend.comet.on('idnodeParamsChanged', function(o) {
|
||||
var r = store.getById(o.id);
|
||||
if (r) {
|
||||
for ( i = 0; i < o.params.length; i++)
|
||||
if (o.params[i].id)
|
||||
r.set(o.params[i].id, o.params[i].value);
|
||||
r.commit();
|
||||
}
|
||||
});
|
||||
var update = function(o) {
|
||||
if (auto.getValue())
|
||||
store.reload();
|
||||
};
|
||||
if (conf.comet)
|
||||
tvheadend.comet.on(conf.comet, update);
|
||||
tvheadend.comet.on('idnodeUpdated', update);
|
||||
tvheadend.comet.on('idnodeDeleted', update);
|
||||
}
|
||||
|
||||
/* Request data */
|
||||
|
@ -633,20 +628,22 @@ tvheadend.idnode_grid = function(panel, conf)
|
|||
tvheadend.idnode_tree = function (conf)
|
||||
{
|
||||
var current = null;
|
||||
|
||||
var params = conf.params || {};
|
||||
params.op = 'childs';
|
||||
var loader = new Ext.tree.TreeLoader({
|
||||
dataUrl : conf.url,
|
||||
baseParams : conf.params,
|
||||
dataUrl : conf.url,
|
||||
baseParams : params,
|
||||
preloadChildren : conf.preload,
|
||||
nodeParameter : 'uuid'
|
||||
});
|
||||
|
||||
var tree = new Ext.tree.TreePanel({
|
||||
loader : loader,
|
||||
flex : 1,
|
||||
border : false,
|
||||
root : new Ext.tree.AsyncTreeNode({
|
||||
id : conf.root || 'root',
|
||||
text : conf.title || ''
|
||||
loader : loader,
|
||||
flex : 1,
|
||||
border : false,
|
||||
root : new Ext.tree.AsyncTreeNode({
|
||||
id : conf.root || 'root',
|
||||
text : conf.title || ''
|
||||
}),
|
||||
listeners : {
|
||||
click: function(n) {
|
||||
|
@ -662,27 +659,22 @@ tvheadend.idnode_tree = function (conf)
|
|||
}
|
||||
});
|
||||
|
||||
tvheadend.comet.on('idnodeNameChanged', function(o) {
|
||||
var n = tree.getNodeById(o.id);
|
||||
if(n) {
|
||||
n.setText(o.text);
|
||||
// TODO: top-level reload
|
||||
tvheadend.comet.on('idnodeUpdated', function(o) {
|
||||
var n = tree.getNodeById(o.uuid);
|
||||
if (n) {
|
||||
if (o.text) n.setText(o.text);
|
||||
loader.load(n);
|
||||
}
|
||||
});
|
||||
|
||||
tvheadend.comet.on('idnodeParamsChanged', function(o) {
|
||||
var n = tree.getNodeById(o.id);
|
||||
if(n) {
|
||||
n.attributes.params = o.params;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var panel = new Ext.Panel({
|
||||
title : conf.title || '',
|
||||
layout : 'hbox',
|
||||
flex : 1,
|
||||
padding : 5,
|
||||
border : false,
|
||||
title : conf.title || '',
|
||||
layout : 'hbox',
|
||||
flex : 1,
|
||||
padding : 5,
|
||||
border : false,
|
||||
layoutConfig : {
|
||||
align : 'stretch'
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue