]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
idnode: several improvements to the auto-updating features.
authorAdam Sutton <dev@adamsutton.me.uk>
Wed, 10 Jul 2013 11:10:53 +0000 (12:10 +0100)
committerAdam Sutton <dev@adamsutton.me.uk>
Wed, 10 Jul 2013 11:10:53 +0000 (12:10 +0100)
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.

src/idnode.c
src/idnode.h
src/input/mpegts/mpegts_input.c
src/input/mpegts/mpegts_mux.c
src/webui/extjs.c
src/webui/static/app/idnode.js

index 995d0f7a18c5c4f36c2e62955bde80a6f89f1f51..10be0a5dc1e8dda1c265f833b5124994343d66de 100644 (file)
@@ -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);
   }
   
index 6197ee6e5f50cb937c8b158b469ce2790689993d..27df992505538cd9c13470226bcb32577543af7f 100644 (file)
@@ -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);
index a575a23183b0e2fccaad56ecc871751863b4e271..7054bf7a6d389a14760c58748ef55c313f9f6459 100644 (file)
@@ -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,
     },
     {}
   }
index 0758619e0fa2af00a160b7d5512636950af5fc21..a2e73435feef7a1b9d057be124bf93458c3f7720 100644 (file)
@@ -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);
 }
 
 /* **************************************************************************
index 42c3ad3a4ec7916070e7c03c553805d85956ba82..8baa545277c3b1821c60c338ee30aa6ca4998e7a 100644 (file)
@@ -2170,91 +2170,110 @@ 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();
+
+  /* Children */
   } 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);
-      }
-    }
+    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;
   }
 
-  pthread_mutex_unlock(&global_lock);
-
   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);
 }
 
 
index 46d3fb0554e100cc1e656429cc0cdb8b9c089fad..6615ee8a48ec11e29384ed377c420464f4e360c1 100644 (file)
@@ -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'
     },