Merge branch 'feature/dvb-rewrite' of github.com:adamsutton/tvheadend into feature/dvb-rewrite
This commit is contained in:
commit
6924fbc032
22 changed files with 1176 additions and 1075 deletions
12
Makefile
12
Makefile
|
@ -109,6 +109,11 @@ SRCS = src/version.c \
|
|||
src/descrambler/descrambler.c \
|
||||
src/service_mapper.c \
|
||||
|
||||
SRCS += \
|
||||
src/api.c \
|
||||
src/api/api_idnode.c \
|
||||
src/api/api_mpegts.c \
|
||||
|
||||
SRCS += \
|
||||
src/parsers/parsers.c \
|
||||
src/parsers/bitstream.c \
|
||||
|
@ -132,10 +137,10 @@ SRCS += src/dvr/dvr_db.c \
|
|||
SRCS += src/webui/webui.c \
|
||||
src/webui/comet.c \
|
||||
src/webui/extjs.c \
|
||||
src/webui/extjs_dvb.c \
|
||||
src/webui/simpleui.c \
|
||||
src/webui/statedump.c \
|
||||
src/webui/html.c\
|
||||
src/webui/webui_api.c\
|
||||
|
||||
SRCS += src/muxer.c \
|
||||
src/muxer/muxer_pass.c \
|
||||
|
@ -203,11 +208,6 @@ SRCS-${CONFIG_TIMESHIFT} += \
|
|||
SRCS-${CONFIG_INOTIFY} += \
|
||||
src/dvr/dvr_inotify.c \
|
||||
|
||||
# V4L
|
||||
SRCS-${CONFIG_V4L} += \
|
||||
src/v4l.c \
|
||||
src/webui/extjs_v4l.c \
|
||||
|
||||
# Avahi
|
||||
SRCS-$(CONFIG_AVAHI) += src/avahi.c
|
||||
|
||||
|
|
120
src/api.c
Normal file
120
src/api.c
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* API - Common functions for control/query API
|
||||
*
|
||||
* Copyright (C) 2013 Adam Sutton
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "api.h"
|
||||
#include "access.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
typedef struct api_link {
|
||||
const api_hook_t *hook;
|
||||
RB_ENTRY(api_link) link;
|
||||
} api_link_t;
|
||||
|
||||
RB_HEAD(,api_link) api_hook_tree;
|
||||
|
||||
static int ah_cmp
|
||||
( api_link_t *a, api_link_t *b )
|
||||
{
|
||||
return strcmp(a->hook->ah_subsystem, b->hook->ah_subsystem);
|
||||
}
|
||||
|
||||
void
|
||||
api_register ( const api_hook_t *hook )
|
||||
{
|
||||
static api_link_t *t, *skel = NULL;
|
||||
if (!skel)
|
||||
skel = calloc(1, sizeof(api_link_t));
|
||||
skel->hook = hook;
|
||||
t = RB_INSERT_SORTED(&api_hook_tree, skel, link, ah_cmp);
|
||||
if (t)
|
||||
tvherror("api", "trying to re-register subsystem");
|
||||
else
|
||||
skel = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
api_register_all ( const api_hook_t *hooks )
|
||||
{
|
||||
while (hooks->ah_subsystem) {
|
||||
api_register(hooks);
|
||||
hooks++;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
api_exec ( const char *subsystem, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
api_hook_t h;
|
||||
api_link_t *ah, skel;
|
||||
const char *op;
|
||||
|
||||
/* Args and response must be set */
|
||||
if (!args || !resp)
|
||||
return EINVAL;
|
||||
|
||||
// Note: there is no locking while checking the hook tree, its assumed
|
||||
// this is all setup during init (if this changes the code will
|
||||
// need updating)
|
||||
h.ah_subsystem = subsystem;
|
||||
skel.hook = &h;
|
||||
ah = RB_FIND(&api_hook_tree, &skel, link, ah_cmp);
|
||||
|
||||
if (!ah) {
|
||||
tvhwarn("api", "failed to find subsystem [%s]", subsystem);
|
||||
return ENOSYS; // TODO: is this really the right error code?
|
||||
}
|
||||
|
||||
/* Extract method */
|
||||
op = htsmsg_get_str(args, "method");
|
||||
if (!op)
|
||||
op = htsmsg_get_str(args, "op");
|
||||
// Note: this is not required (so no final validation)
|
||||
|
||||
/* Execute */
|
||||
return ah->hook->ah_callback(ah->hook->ah_opaque, op, args, resp);
|
||||
}
|
||||
|
||||
static int
|
||||
api_serverinfo
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
*resp = htsmsg_create_map();
|
||||
htsmsg_add_str(*resp, "sw_version", tvheadend_version);
|
||||
htsmsg_add_u32(*resp, "api_version", TVH_API_VERSION);
|
||||
htsmsg_add_str(*resp, "name", "Tvheadend");
|
||||
if (tvheadend_webroot)
|
||||
htsmsg_add_str(*resp, "webroot", tvheadend_webroot);
|
||||
htsmsg_add_msg(*resp, "capabilities", tvheadend_capabilities_list(1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void api_init ( void )
|
||||
{
|
||||
static api_hook_t h[] = {
|
||||
{ "serverinfo", ACCESS_ANONYMOUS, api_serverinfo, NULL },
|
||||
{ NULL, 0, NULL, NULL }
|
||||
};
|
||||
api_register_all(h);
|
||||
|
||||
/* Subsystems */
|
||||
api_idnode_init();
|
||||
api_mpegts_init();
|
||||
}
|
87
src/api.h
Normal file
87
src/api.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* API - Common functions for control/query API
|
||||
*
|
||||
* Copyright (C) 2013 Adam Sutton
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TVH_API_H__
|
||||
#define __TVH_API_H__
|
||||
|
||||
#include "htsmsg.h"
|
||||
#include "idnode.h"
|
||||
#include "redblack.h"
|
||||
|
||||
#define TVH_API_VERSION 12
|
||||
|
||||
/*
|
||||
* Command hook
|
||||
*/
|
||||
|
||||
typedef int (*api_callback_t)
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp );
|
||||
|
||||
typedef struct api_hook
|
||||
{
|
||||
const char *ah_subsystem;
|
||||
int ah_access;
|
||||
api_callback_t ah_callback;
|
||||
void *ah_opaque;
|
||||
} api_hook_t;
|
||||
|
||||
/*
|
||||
* Regsiter handler
|
||||
*/
|
||||
void api_register ( const api_hook_t *hook );
|
||||
void api_register_all ( const api_hook_t *hooks );
|
||||
|
||||
/*
|
||||
* Execute
|
||||
*/
|
||||
int api_exec ( const char *subsystem, htsmsg_t *args, htsmsg_t **resp );
|
||||
|
||||
/*
|
||||
* Initialise
|
||||
*/
|
||||
void api_init ( void );
|
||||
void api_idnode_init ( void );
|
||||
void api_mpegts_init ( void );
|
||||
|
||||
/*
|
||||
* IDnode
|
||||
*/
|
||||
typedef struct api_idnode_grid_conf
|
||||
{
|
||||
int start;
|
||||
int limit;
|
||||
idnode_filter_t filter;
|
||||
idnode_sort_t sort;
|
||||
} api_idnode_grid_conf_t;
|
||||
|
||||
typedef void (*api_idnode_grid_callback_t)
|
||||
(idnode_set_t*, api_idnode_grid_conf_t*);
|
||||
typedef idnode_set_t *(*api_idnode_tree_callback_t)
|
||||
(void);
|
||||
|
||||
int api_idnode_grid
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp );
|
||||
|
||||
int api_idnode_class
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp );
|
||||
|
||||
int api_idnode_tree
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp );
|
||||
|
||||
#endif /* __TVH_API_H__ */
|
438
src/api/api_idnode.c
Normal file
438
src/api/api_idnode.c
Normal file
|
@ -0,0 +1,438 @@
|
|||
/*
|
||||
* API - idnode related API calls
|
||||
*
|
||||
* Copyright (C) 2013 Adam Sutton
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TVH_API_IDNODE_H__
|
||||
#define __TVH_API_IDNODE_H__
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "access.h"
|
||||
#include "idnode.h"
|
||||
#include "htsmsg.h"
|
||||
#include "api.h"
|
||||
|
||||
static struct strtab filtcmptab[] = {
|
||||
{ "gt", IC_GT },
|
||||
{ "lt", IC_LT },
|
||||
{ "eq", IC_EQ }
|
||||
};
|
||||
|
||||
static void
|
||||
api_idnode_grid_conf
|
||||
( htsmsg_t *args, api_idnode_grid_conf_t *conf )
|
||||
{
|
||||
htsmsg_field_t *f;
|
||||
htsmsg_t *filter, *e;
|
||||
const char *str;
|
||||
|
||||
/* Start */
|
||||
if ((str = htsmsg_get_str(args, "start")))
|
||||
conf->start = atoi(str);
|
||||
else
|
||||
conf->start = 0;
|
||||
|
||||
/* Limit */
|
||||
if ((str = htsmsg_get_str(args, "limit")))
|
||||
conf->limit = atoi(str);
|
||||
else
|
||||
conf->limit = 50;
|
||||
|
||||
/* Filter */
|
||||
if ((filter = htsmsg_get_list(args, "filter"))) {
|
||||
HTSMSG_FOREACH(f, filter) {
|
||||
const char *k, *t, *v;
|
||||
if (!(e = htsmsg_get_map_by_field(f))) continue;
|
||||
if (!(k = htsmsg_get_str(e, "field"))) continue;
|
||||
if (!(t = htsmsg_get_str(e, "type"))) continue;
|
||||
if (!strcmp(t, "string")) {
|
||||
if ((v = htsmsg_get_str(e, "value")))
|
||||
idnode_filter_add_str(&conf->filter, k, v, IC_RE);
|
||||
} else if (!strcmp(t, "numeric")) {
|
||||
uint32_t v;
|
||||
if (!htsmsg_get_u32(e, "value", &v)) {
|
||||
int t = str2val(htsmsg_get_str(e, "comparison") ?: "",
|
||||
filtcmptab);
|
||||
idnode_filter_add_num(&conf->filter, k, v, t == -1 ? IC_EQ : t);
|
||||
}
|
||||
} else if (!strcmp(t, "boolean")) {
|
||||
uint32_t v;
|
||||
if (!htsmsg_get_u32(e, "value", &v))
|
||||
idnode_filter_add_bool(&conf->filter, k, v, IC_EQ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort */
|
||||
if ((str = htsmsg_get_str(args, "sort"))) {
|
||||
conf->sort.key = str;
|
||||
if ((str = htsmsg_get_str(args, "dir")) && !strcmp(str, "DESC"))
|
||||
conf->sort.dir = IS_DSC;
|
||||
else
|
||||
conf->sort.dir = IS_ASC;
|
||||
} else
|
||||
conf->sort.key = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
api_idnode_grid
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
int i;
|
||||
htsmsg_t *list, *e;
|
||||
api_idnode_grid_conf_t conf = { 0 };
|
||||
idnode_set_t ins = { 0 };
|
||||
api_idnode_grid_callback_t cb = opaque;
|
||||
|
||||
/* Grid configuration */
|
||||
api_idnode_grid_conf(args, &conf);
|
||||
|
||||
/* Create list */
|
||||
pthread_mutex_lock(&global_lock);
|
||||
cb(&ins, &conf);
|
||||
|
||||
/* Sort */
|
||||
if (conf.sort.key)
|
||||
idnode_set_sort(&ins, &conf.sort);
|
||||
|
||||
/* Paginate */
|
||||
list = htsmsg_create_list();
|
||||
for (i = conf.start; i < ins.is_count && conf.limit != 0; i++) {
|
||||
e = htsmsg_create_map();
|
||||
htsmsg_add_str(e, "uuid", idnode_uuid_as_str(ins.is_array[i]));
|
||||
idnode_read0(ins.is_array[i], e, 0);
|
||||
htsmsg_add_msg(list, NULL, e);
|
||||
if (conf.limit > 0) conf.limit--;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
/* Output */
|
||||
*resp = htsmsg_create_map();
|
||||
htsmsg_add_msg(*resp, "entries", list);
|
||||
htsmsg_add_u32(*resp, "total", ins.is_count);
|
||||
|
||||
/* Cleanup */
|
||||
free(ins.is_array);
|
||||
idnode_filter_clear(&conf.filter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
api_idnode_load_by_class
|
||||
( const char *class, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
int i, _enum;
|
||||
const idclass_t *idc;
|
||||
idnode_set_t *is;
|
||||
idnode_t *in;
|
||||
htsmsg_t *l, *e;
|
||||
|
||||
// TODO: this only works if pass as integer
|
||||
_enum = htsmsg_get_bool_or_default(args, "enum", 0);
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
/* Find class */
|
||||
if (!(idc = idclass_find(class))) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
l = htsmsg_create_list();
|
||||
if ((is = idnode_find_all(idc))) {
|
||||
for (i = 0; i < is->is_count; i++) {
|
||||
in = is->is_array[i];
|
||||
|
||||
/* Name/UUID only */
|
||||
if (_enum) {
|
||||
e = htsmsg_create_map();
|
||||
htsmsg_add_str(e, "key", idnode_uuid_as_str(in));
|
||||
htsmsg_add_str(e, "val", idnode_get_title(in));
|
||||
|
||||
/* Full record */
|
||||
} else
|
||||
e = idnode_serialize(in);
|
||||
|
||||
if (e)
|
||||
htsmsg_add_msg(l, NULL, e);
|
||||
}
|
||||
}
|
||||
*resp = htsmsg_create_map();
|
||||
htsmsg_add_msg(*resp, "entries", l);
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
api_idnode_load
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
int err = 0;
|
||||
idnode_t *in;
|
||||
htsmsg_t *t, *l = NULL;
|
||||
htsmsg_field_t *f;
|
||||
const char *uuid, *class;
|
||||
|
||||
/* Class based */
|
||||
if ((class = htsmsg_get_str(args, "class")))
|
||||
return api_idnode_load_by_class(class, args, resp);
|
||||
|
||||
/* ID based */
|
||||
if (!(f = htsmsg_field_find(args, "uuid")))
|
||||
return EINVAL;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
/* Single */
|
||||
if (f->hmf_type == HMF_STR) {
|
||||
uuid = htsmsg_field_get_string(f);
|
||||
in = idnode_find(uuid, NULL);
|
||||
if (in) {
|
||||
l = htsmsg_create_list();
|
||||
htsmsg_add_msg(l, NULL, idnode_serialize(in));
|
||||
} else
|
||||
err = ENOENT;
|
||||
|
||||
/* Multiple */
|
||||
} else if (f->hmf_type == HMF_LIST) {
|
||||
t = htsmsg_get_list_by_field(f);
|
||||
l = htsmsg_create_list();
|
||||
HTSMSG_FOREACH(f, t) {
|
||||
if (!(uuid = htsmsg_field_get_string(f))) continue;
|
||||
if (!(in = idnode_find(uuid, NULL))) continue;
|
||||
htsmsg_add_msg(l, NULL, idnode_serialize(in));
|
||||
}
|
||||
|
||||
/* Invalid */
|
||||
} else {
|
||||
err = EINVAL;
|
||||
}
|
||||
|
||||
if (l) {
|
||||
*resp = htsmsg_create_map();
|
||||
htsmsg_add_msg(*resp, "entries", l);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
api_idnode_save
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
int err = EINVAL;
|
||||
idnode_t *in;
|
||||
htsmsg_t *conf, *l;
|
||||
htsmsg_field_t *f;
|
||||
const char *uuid;
|
||||
|
||||
if (!(f = htsmsg_field_find(args, "node")))
|
||||
return EINVAL;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
/* Single */
|
||||
if (f->hmf_type == HMF_MAP) {
|
||||
conf = htsmsg_get_map_by_field(f);
|
||||
if (!(uuid = htsmsg_get_str(conf, "uuid")))
|
||||
goto exit;
|
||||
if (!(in = idnode_find(uuid, NULL)))
|
||||
goto exit;
|
||||
idnode_update(in, conf);
|
||||
err = 0;
|
||||
|
||||
/* Multiple */
|
||||
} else if (f->hmf_type == HMF_LIST) {
|
||||
l = htsmsg_get_list_by_field(f);
|
||||
HTSMSG_FOREACH(f, l) {
|
||||
if (!(conf = htsmsg_get_map_by_field(f)))
|
||||
continue;
|
||||
if (!(uuid = htsmsg_get_str(conf, "uuid")))
|
||||
continue;
|
||||
if (!(in = idnode_find(uuid, NULL)))
|
||||
continue;
|
||||
idnode_update(in, conf);
|
||||
}
|
||||
err = 0;
|
||||
|
||||
/* Invalid */
|
||||
} else {
|
||||
err = EINVAL;
|
||||
}
|
||||
|
||||
// TODO: return updated UUIDs?
|
||||
|
||||
exit:
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
api_idnode_tree
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
const char *uuid;
|
||||
const char *root = NULL;
|
||||
int isroot;
|
||||
idnode_t *node = NULL;
|
||||
api_idnode_tree_callback_t rootfn = opaque;
|
||||
|
||||
/* UUID */
|
||||
if (!(uuid = htsmsg_get_str(args, "uuid")))
|
||||
return EINVAL;
|
||||
|
||||
/* Root UUID */
|
||||
if (!rootfn)
|
||||
root = htsmsg_get_str(args, "root");
|
||||
|
||||
/* Is root? */
|
||||
isroot = (strcmp("root", uuid) == 0);
|
||||
if (isroot && !(root || rootfn))
|
||||
return EINVAL;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if (!isroot || root) {
|
||||
if (!(node = idnode_find(isroot ? root : uuid, NULL))) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
*resp = 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(*resp, 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(*resp, NULL, m);
|
||||
}
|
||||
idnode_set_free(v);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
api_idnode_class
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
int err = EINVAL;
|
||||
const char *name;
|
||||
const idclass_t *idc;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
/* Lookup */
|
||||
if (!opaque) {
|
||||
if (!(name = htsmsg_get_str(args, "name")))
|
||||
goto exit;
|
||||
if (!(idc = idclass_find(name)))
|
||||
goto exit;
|
||||
|
||||
} else {
|
||||
idc = opaque;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
*resp = idclass_serialize(idc);
|
||||
|
||||
exit:
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
api_idnode_delete
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
int err = 0;
|
||||
idnode_t *in;
|
||||
htsmsg_t *l;
|
||||
htsmsg_field_t *f;
|
||||
const char *uuid;
|
||||
|
||||
/* ID based */
|
||||
if (!(f = htsmsg_field_find(args, "uuid")))
|
||||
return EINVAL;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
/* Single */
|
||||
if (f->hmf_type == HMF_STR) {
|
||||
uuid = htsmsg_field_get_string(f);
|
||||
in = idnode_find(uuid, NULL);
|
||||
if (in) {
|
||||
idnode_delete(in);
|
||||
} else
|
||||
err = ENOENT;
|
||||
|
||||
/* Multiple */
|
||||
} else if (f->hmf_type == HMF_LIST) {
|
||||
l = htsmsg_get_list_by_field(f);
|
||||
HTSMSG_FOREACH(f, l) {
|
||||
if (!(uuid = htsmsg_field_get_string(f))) continue;
|
||||
if (!(in = idnode_find(uuid, NULL))) continue;
|
||||
idnode_delete(in);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: should we return the UUIDs that are deleted?
|
||||
if (!err)
|
||||
*resp = htsmsg_create_map();
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void api_idnode_init ( void )
|
||||
{
|
||||
static api_hook_t ah[] = {
|
||||
{ "idnode/load", ACCESS_ANONYMOUS, api_idnode_load, NULL },
|
||||
{ "idnode/save", ACCESS_ADMIN, api_idnode_save, NULL },
|
||||
{ "idnode/tree", ACCESS_ANONYMOUS, api_idnode_tree, NULL },
|
||||
{ "idnode/class", ACCESS_ANONYMOUS, api_idnode_class, NULL },
|
||||
{ "idnode/delete", ACCESS_ADMIN, api_idnode_delete, NULL },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
api_register_all(ah);
|
||||
}
|
||||
|
||||
|
||||
#endif /* __TVH_API_IDNODE_H__ */
|
324
src/api/api_mpegts.c
Normal file
324
src/api/api_mpegts.c
Normal file
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
* tvheadend - API access to MPEGTS system
|
||||
*
|
||||
* Copyright (C) 2013 Adam Sutton
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "access.h"
|
||||
#include "htsmsg.h"
|
||||
#include "api.h"
|
||||
#include "input/mpegts.h"
|
||||
#if ENABLE_LINUXDVB
|
||||
#include "input/mpegts/linuxdvb.h"
|
||||
#include "input/mpegts/linuxdvb/linuxdvb_private.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Inputs
|
||||
*/
|
||||
static int
|
||||
api_mpegts_input_network_list
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
int i, err = EINVAL;
|
||||
const char *uuid;
|
||||
mpegts_input_t *mi;
|
||||
mpegts_network_t *mn;
|
||||
idnode_set_t *is;
|
||||
extern const idclass_t mpegts_input_class;
|
||||
|
||||
if (!(uuid = htsmsg_get_str(args, "uuid")))
|
||||
return EINVAL;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
mi = mpegts_input_find(uuid);
|
||||
if (!mi)
|
||||
goto exit;
|
||||
|
||||
htsmsg_t *l = htsmsg_create_list();
|
||||
if ((is = mi->mi_network_list(mi))) {
|
||||
for (i = 0; i < is->is_count; i++) {
|
||||
char buf[256];
|
||||
htsmsg_t *e = htsmsg_create_map();
|
||||
mn = (mpegts_network_t*)is->is_array[i];
|
||||
htsmsg_add_str(e, "key", idnode_uuid_as_str(is->is_array[i]));
|
||||
mn->mn_display_name(mn, buf, sizeof(buf));
|
||||
htsmsg_add_str(e, "val", buf);
|
||||
htsmsg_add_msg(l, NULL, e);
|
||||
}
|
||||
idnode_set_free(is);
|
||||
}
|
||||
err = 0;
|
||||
*resp = htsmsg_create_map();
|
||||
htsmsg_add_msg(*resp, "entries", l);
|
||||
|
||||
exit:
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Networks
|
||||
*/
|
||||
static void
|
||||
api_mpegts_network_grid
|
||||
( idnode_set_t *ins, api_idnode_grid_conf_t *conf )
|
||||
{
|
||||
mpegts_network_t *mn;
|
||||
|
||||
LIST_FOREACH(mn, &mpegts_network_all, mn_global_link) {
|
||||
idnode_set_add(ins, (idnode_t*)mn, &conf->filter);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
api_mpegts_network_builders
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
mpegts_network_builder_t *mnb;
|
||||
htsmsg_t *l, *e;
|
||||
|
||||
/* List of available builder classes */
|
||||
l = htsmsg_create_list();
|
||||
LIST_FOREACH(mnb, &mpegts_network_builders, link)
|
||||
if ((e = idclass_serialize(mnb->idc)))
|
||||
htsmsg_add_msg(l, NULL, e);
|
||||
|
||||
/* Output */
|
||||
*resp = htsmsg_create_map();
|
||||
htsmsg_add_msg(*resp, "entries", l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
api_mpegts_network_create
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
int err;
|
||||
const char *class;
|
||||
htsmsg_t *conf;
|
||||
mpegts_network_t *mn;
|
||||
|
||||
if (!(class = htsmsg_get_str(args, "class")))
|
||||
return -EINVAL;
|
||||
if (!(conf = htsmsg_get_map(args, "conf")))
|
||||
return -EINVAL;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
mn = mpegts_network_build(class, conf);
|
||||
if (mn) {
|
||||
err = 0;
|
||||
*resp = htsmsg_create_map();
|
||||
mn->mn_config_save(mn);
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
api_mpegts_network_muxclass
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
int err = EINVAL;
|
||||
const idclass_t *idc;
|
||||
mpegts_network_t *mn;
|
||||
const char *uuid;
|
||||
|
||||
if (!(uuid = htsmsg_get_str(args, "uuid")))
|
||||
return EINVAL;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if (!(mn = mpegts_network_find(uuid)))
|
||||
goto exit;
|
||||
|
||||
if (!(idc = mn->mn_mux_class(mn)))
|
||||
goto exit;
|
||||
|
||||
*resp = idclass_serialize(idc);
|
||||
err = 0;
|
||||
|
||||
exit:
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
api_mpegts_network_muxcreate
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
int err = EINVAL;
|
||||
mpegts_network_t *mn;
|
||||
mpegts_mux_t *mm;
|
||||
htsmsg_t *conf;
|
||||
const char *uuid;
|
||||
|
||||
if (!(uuid = htsmsg_get_str(args, "uuid")))
|
||||
return EINVAL;
|
||||
if (!(conf = htsmsg_get_map(args, "conf")))
|
||||
return EINVAL;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if (!(mn = mpegts_network_find(uuid)))
|
||||
goto exit;
|
||||
|
||||
if (!(mm = mn->mn_mux_create2(mn, conf)))
|
||||
goto exit;
|
||||
|
||||
mm->mm_config_save(mm);
|
||||
err = 0;
|
||||
|
||||
exit:
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Muxes
|
||||
*/
|
||||
static void
|
||||
api_mpegts_mux_grid
|
||||
( idnode_set_t *ins, api_idnode_grid_conf_t *conf )
|
||||
{
|
||||
mpegts_network_t *mn;
|
||||
mpegts_mux_t *mm;
|
||||
|
||||
LIST_FOREACH(mn, &mpegts_network_all, mn_global_link) {
|
||||
LIST_FOREACH(mm, &mn->mn_muxes, mm_network_link) {
|
||||
idnode_set_add(ins, (idnode_t*)mm, &conf->filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Services
|
||||
*/
|
||||
static void
|
||||
api_mpegts_service_grid
|
||||
( idnode_set_t *ins, api_idnode_grid_conf_t *conf )
|
||||
{
|
||||
mpegts_network_t *mn;
|
||||
mpegts_mux_t *mm;
|
||||
mpegts_service_t *ms;
|
||||
|
||||
LIST_FOREACH(mn, &mpegts_network_all, mn_global_link) {
|
||||
LIST_FOREACH(mm, &mn->mn_muxes, mm_network_link) {
|
||||
LIST_FOREACH(ms, &mm->mm_services, s_dvb_mux_link) {
|
||||
idnode_set_add(ins, (idnode_t*)ms, &conf->filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Satconfs
|
||||
*/
|
||||
#if ENABLE_LINUXDVB
|
||||
static void
|
||||
api_linuxdvb_satconf_grid
|
||||
( idnode_set_t *ins, api_idnode_grid_conf_t *conf )
|
||||
{
|
||||
mpegts_input_t *mi;
|
||||
extern const idclass_t linuxdvb_satconf_class;
|
||||
|
||||
LIST_FOREACH(mi, &mpegts_input_all, mi_global_link)
|
||||
if (idnode_is_instance((idnode_t*)mi, &linuxdvb_satconf_class))
|
||||
idnode_set_add(ins, (idnode_t*)mi, &conf->filter);
|
||||
}
|
||||
|
||||
static int
|
||||
api_linuxdvb_satconf_create
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
int err;
|
||||
htsmsg_t *conf;
|
||||
idnode_t *in;
|
||||
|
||||
if (!(conf = htsmsg_get_map(args, "conf")))
|
||||
return -EINVAL;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
in = (idnode_t*)linuxdvb_satconf_create0(NULL, conf);
|
||||
if (in) {
|
||||
err = 0;
|
||||
in->in_class->ic_save(in);
|
||||
*resp = htsmsg_create_map();
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Adapter list
|
||||
*
|
||||
* TODO: this will need reworking for mpegps etc...
|
||||
*/
|
||||
static idnode_set_t *
|
||||
api_tvadapter_tree ( void )
|
||||
{
|
||||
#if ENABLE_LINUXDVB
|
||||
return linuxdvb_root();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Init
|
||||
*/
|
||||
void
|
||||
api_mpegts_init ( void )
|
||||
{
|
||||
extern const idclass_t mpegts_network_class;
|
||||
extern const idclass_t mpegts_mux_class;
|
||||
extern const idclass_t mpegts_service_class;
|
||||
extern const idclass_t linuxdvb_satconf_class;
|
||||
|
||||
static api_hook_t ah[] = {
|
||||
{ "tvadapter/tree", ACCESS_ANONYMOUS, api_idnode_tree, api_tvadapter_tree },
|
||||
{ "mpegts/input/network_list", ACCESS_ANONYMOUS, api_mpegts_input_network_list, NULL },
|
||||
{ "mpegts/network/grid", ACCESS_ANONYMOUS, api_idnode_grid, api_mpegts_network_grid },
|
||||
{ "mpegts/network/class", ACCESS_ANONYMOUS, api_idnode_class, (void*)&mpegts_network_class },
|
||||
{ "mpegts/network/builders", ACCESS_ANONYMOUS, api_mpegts_network_builders, NULL },
|
||||
{ "mpegts/network/create", ACCESS_ANONYMOUS, api_mpegts_network_create, NULL },
|
||||
{ "mpegts/network/mux_class", ACCESS_ANONYMOUS, api_mpegts_network_muxclass, NULL },
|
||||
{ "mpegts/network/mux_create", ACCESS_ANONYMOUS, api_mpegts_network_muxcreate, NULL },
|
||||
{ "mpegts/mux/grid", ACCESS_ANONYMOUS, api_idnode_grid, api_mpegts_mux_grid },
|
||||
{ "mpegts/mux/class", ACCESS_ANONYMOUS, api_idnode_class, (void*)&mpegts_mux_class },
|
||||
{ "mpegts/service/grid", ACCESS_ANONYMOUS, api_idnode_grid, api_mpegts_service_grid },
|
||||
{ "mpegts/service/class", ACCESS_ANONYMOUS, api_idnode_class, (void*)&mpegts_service_class },
|
||||
#if ENABLE_LINUXDVB
|
||||
{ "linuxdvb/satconf/grid", ACCESS_ANONYMOUS, api_idnode_grid, api_linuxdvb_satconf_grid },
|
||||
{ "linuxdvb/satconf/class", ACCESS_ANONYMOUS, api_idnode_class, (void*)&linuxdvb_satconf_class },
|
||||
{ "linuxdvb/satconf/create", ACCESS_ANONYMOUS, api_linuxdvb_satconf_create, NULL },
|
||||
#endif
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
api_register_all(ah);
|
||||
}
|
17
src/idnode.c
17
src/idnode.c
|
@ -183,6 +183,23 @@ idnode_unlink(idnode_t *in)
|
|||
idnode_notify(in, NULL, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
idnode_delete(idnode_t *in)
|
||||
{
|
||||
lock_assert(&global_lock);
|
||||
const idclass_t *idc = in->in_class;
|
||||
while (idc) {
|
||||
if (idc->ic_delete) {
|
||||
idc->ic_delete(in);
|
||||
break;
|
||||
}
|
||||
idc = idc->ic_super;
|
||||
}
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
* Info
|
||||
* *************************************************************************/
|
||||
|
|
|
@ -52,6 +52,7 @@ typedef struct idclass {
|
|||
idnode_set_t *(*ic_get_childs)(idnode_t *self);
|
||||
const char *(*ic_get_title) (idnode_t *self);
|
||||
void (*ic_save) (idnode_t *self);
|
||||
void (*ic_delete) (idnode_t *self);
|
||||
} idclass_t;
|
||||
|
||||
/*
|
||||
|
@ -114,6 +115,7 @@ idnode_set_t *idnode_get_childs (idnode_t *in);
|
|||
const char *idnode_get_title (idnode_t *in);
|
||||
int idnode_is_leaf (idnode_t *in);
|
||||
int idnode_is_instance (idnode_t *in, const idclass_t *idc);
|
||||
void idnode_delete (idnode_t *in);
|
||||
|
||||
void *idnode_find (const char *uuid, const idclass_t *idc);
|
||||
idnode_set_t *idnode_find_all(const idclass_t *idc);
|
||||
|
|
|
@ -177,7 +177,6 @@ struct mpegts_network
|
|||
/*
|
||||
* Functions
|
||||
*/
|
||||
void (*mn_delete) (mpegts_network_t *mn);
|
||||
void (*mn_display_name) (mpegts_network_t*, char *buf, size_t len);
|
||||
void (*mn_config_save) (mpegts_network_t*);
|
||||
mpegts_mux_t* (*mn_create_mux)
|
||||
|
@ -472,9 +471,6 @@ extern const idclass_t mpegts_network_class;
|
|||
#define mpegts_network_find(u)\
|
||||
idnode_find(u, &mpegts_network_class)
|
||||
|
||||
#define mpegts_network_delete_by_uuid(u)\
|
||||
{ mpegts_network_t *mn = mpegts_network_find(u); if (mn && mn->mn_delete) mn->mn_delete(mn); }
|
||||
|
||||
void mpegts_network_delete ( mpegts_network_t *mn );
|
||||
|
||||
void mpegts_network_schedule_initial_scan
|
||||
|
|
|
@ -95,8 +95,7 @@ linuxdvb_frontend_class_network_enum(void *o)
|
|||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_t *p = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "type", "api");
|
||||
htsmsg_add_str(m, "uri", "mpegts/input");
|
||||
htsmsg_add_str(p, "op", "network_list");
|
||||
htsmsg_add_str(m, "uri", "mpegts/input/network_list");
|
||||
htsmsg_add_str(p, "uuid", idnode_uuid_as_str((idnode_t*)o));
|
||||
htsmsg_add_str(m, "event", "mpegts_network");
|
||||
htsmsg_add_msg(m, "params", p);
|
||||
|
|
|
@ -36,11 +36,25 @@
|
|||
|
||||
extern const idclass_t mpegts_network_class;
|
||||
|
||||
static void
|
||||
linuxdvb_network_class_delete ( idnode_t *in )
|
||||
{
|
||||
mpegts_network_t *mn = (mpegts_network_t*)in;
|
||||
|
||||
/* remove config */
|
||||
hts_settings_remove("input/linuxdvb/networks/%s",
|
||||
idnode_uuid_as_str(in));
|
||||
|
||||
/* Parent delete */
|
||||
mpegts_network_delete(mn);
|
||||
}
|
||||
|
||||
const idclass_t linuxdvb_network_class =
|
||||
{
|
||||
.ic_super = &mpegts_network_class,
|
||||
.ic_class = "linuxdvb_network",
|
||||
.ic_caption = "LinuxDVB Network",
|
||||
.ic_delete = linuxdvb_network_class_delete,
|
||||
.ic_properties = (const property_t[]){
|
||||
{}
|
||||
}
|
||||
|
@ -169,18 +183,6 @@ linuxdvb_network_mux_create2
|
|||
NULL, NULL, conf);
|
||||
}
|
||||
|
||||
static void
|
||||
linuxdvb_network_delete
|
||||
( mpegts_network_t *mn )
|
||||
{
|
||||
/* remove config */
|
||||
hts_settings_remove("input/linuxdvb/networks/%s",
|
||||
idnode_uuid_as_str(&mn->mn_id));
|
||||
|
||||
/* Parent delete */
|
||||
mpegts_network_delete(mn);
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Creation/Config
|
||||
* ***************************************************************************/
|
||||
|
@ -208,7 +210,6 @@ linuxdvb_network_create0
|
|||
ln->ln_type = FE_ATSC;
|
||||
|
||||
/* Callbacks */
|
||||
ln->mn_delete = linuxdvb_network_delete;
|
||||
ln->mn_create_mux = linuxdvb_network_create_mux;
|
||||
ln->mn_create_service = linuxdvb_network_create_service;
|
||||
ln->mn_config_save = linuxdvb_network_config_save;
|
||||
|
|
|
@ -77,9 +77,9 @@ linuxdvb_satconf_class_network_enum(void *o)
|
|||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_t *p = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "type", "api");
|
||||
htsmsg_add_str(m, "uri", "idnode");
|
||||
htsmsg_add_str(m, "uri", "idnode/load");
|
||||
htsmsg_add_str(m, "event", "mpegts_network");
|
||||
htsmsg_add_str(p, "op", "list");
|
||||
htsmsg_add_u32(p, "enum", 1);
|
||||
htsmsg_add_str(p, "class", linuxdvb_network_dvbs_class.ic_class);
|
||||
htsmsg_add_msg(m, "params", p);
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <arpa/inet.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "api.h"
|
||||
#include "tcp.h"
|
||||
#include "access.h"
|
||||
#include "http.h"
|
||||
|
@ -687,6 +688,8 @@ main(int argc, char **argv)
|
|||
/**
|
||||
* Initialize subsystems
|
||||
*/
|
||||
|
||||
api_init();
|
||||
|
||||
#if ENABLE_LIBAV
|
||||
libav_init();
|
||||
|
|
|
@ -1885,161 +1885,6 @@ extjs_tvhlog(http_connection_t *hc, const char *remain, void *opaque)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
extjs_idnode_tree
|
||||
( http_connection_t *hc, const char *uuid, const char *root,
|
||||
idnode_set_t *(*rootfn)(void), htsmsg_t **out )
|
||||
{
|
||||
int isroot;
|
||||
idnode_t *node = NULL;
|
||||
|
||||
/* Validate */
|
||||
if (!uuid)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
isroot = !strcmp("root", uuid);
|
||||
if (isroot && !(root || rootfn))
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if (!isroot || root) {
|
||||
if (!(node = idnode_find(isroot ? root : uuid, NULL))) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
*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);
|
||||
|
||||
/* 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);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
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_field_t *f;
|
||||
htsmsg_t *conf, *nodes;
|
||||
if ((s = http_arg_get(&hc->hc_req_args, "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);
|
||||
}
|
||||
}
|
||||
out = htsmsg_create_map();
|
||||
|
||||
/* List by class */
|
||||
} else if (!strcmp(op, "list")) {
|
||||
int i;
|
||||
const char *cls = http_arg_get(&hc->hc_req_args, "class");
|
||||
pthread_mutex_lock(&global_lock);
|
||||
const idclass_t *idc = idclass_find(cls);
|
||||
idnode_set_t *is = idnode_find_all(idc);
|
||||
out = htsmsg_create_map();
|
||||
if (is) {
|
||||
htsmsg_t *l = htsmsg_create_list();
|
||||
for (i = 0; i < is->is_count; i++) {
|
||||
idnode_t *in = is->is_array[i];
|
||||
htsmsg_t *e = htsmsg_create_map();
|
||||
htsmsg_add_str(e, "key", idnode_uuid_as_str(in));
|
||||
htsmsg_add_str(e, "val", idnode_get_title(in));
|
||||
htsmsg_add_msg(l, NULL, e);
|
||||
}
|
||||
idnode_set_free(is);
|
||||
htsmsg_add_msg(out, "entries", l);
|
||||
}
|
||||
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;
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
extjs_idnode
|
||||
(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
return extjs_idnode0(hc, remain, opaque, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_tvadapters(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
return extjs_idnode0(hc, remain, opaque, &linuxdvb_root);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Capability check
|
||||
*/
|
||||
|
@ -2221,13 +2066,8 @@ extjs_start(void)
|
|||
#endif
|
||||
http_path_add("/tvhlog", NULL, extjs_tvhlog, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/tvadapters",
|
||||
NULL, extjs_tvadapters, ACCESS_ADMIN);
|
||||
http_path_add("/api/idnode", NULL, extjs_idnode, ACCESS_ADMIN); // TODO: might want diff access for read/write`
|
||||
http_path_add("/api/service_mapping", NULL, extjs_service_mapping, ACCESS_ADMIN);
|
||||
|
||||
extjs_start_dvb();
|
||||
|
||||
#if ENABLE_V4L
|
||||
extjs_start_v4l();
|
||||
#endif
|
||||
|
|
|
@ -1,517 +0,0 @@
|
|||
/*
|
||||
* tvheadend, EXTJS based interface
|
||||
* Copyright (C) 2008 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "htsmsg.h"
|
||||
#include "htsmsg_json.h"
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "http.h"
|
||||
#include "webui.h"
|
||||
#include "access.h"
|
||||
#include "dtable.h"
|
||||
#include "channels.h"
|
||||
|
||||
#include "input.h"
|
||||
|
||||
extern const idclass_t mpegts_input_class;
|
||||
extern const idclass_t mpegts_network_class;
|
||||
extern const idclass_t mpegts_mux_class;
|
||||
extern const idclass_t mpegts_service_class;
|
||||
|
||||
typedef struct extjs_grid_conf
|
||||
{
|
||||
int start;
|
||||
int limit;
|
||||
idnode_filter_t filter;
|
||||
idnode_sort_t sort;
|
||||
} extjs_grid_conf_t;
|
||||
|
||||
static struct strtab extjs_filtcmp_tab[] = {
|
||||
{ "gt", IC_GT },
|
||||
{ "lt", IC_LT },
|
||||
{ "eq", IC_EQ }
|
||||
};
|
||||
|
||||
static void
|
||||
extjs_grid_conf
|
||||
( struct http_arg_list *args, extjs_grid_conf_t *conf )
|
||||
{
|
||||
const char *str;
|
||||
if ((str = http_arg_get(args, "start")))
|
||||
conf->start = atoi(str);
|
||||
else
|
||||
conf->start = 0;
|
||||
if ((str = http_arg_get(args, "limit")))
|
||||
conf->limit = atoi(str);
|
||||
else
|
||||
conf->limit = 50;
|
||||
if ((str = http_arg_get(args, "filter"))) {
|
||||
htsmsg_field_t *f;
|
||||
htsmsg_t *e, *t = htsmsg_json_deserialize(str);
|
||||
HTSMSG_FOREACH(f, t) {
|
||||
const char *k, *t, *v;
|
||||
if (!(e = htsmsg_get_map_by_field(f))) continue;
|
||||
if (!(k = htsmsg_get_str(e, "field"))) continue;
|
||||
if (!(t = htsmsg_get_str(e, "type"))) continue;
|
||||
if (!strcmp(t, "string")) {
|
||||
if ((v = htsmsg_get_str(e, "value")))
|
||||
idnode_filter_add_str(&conf->filter, k, v, IC_RE);
|
||||
} else if (!strcmp(t, "numeric")) {
|
||||
uint32_t v;
|
||||
if (!htsmsg_get_u32(e, "value", &v)) {
|
||||
int t = str2val(htsmsg_get_str(e, "comparison") ?: "",
|
||||
extjs_filtcmp_tab);
|
||||
idnode_filter_add_num(&conf->filter, k, v, t == -1 ? IC_EQ : t);
|
||||
}
|
||||
} else if (!strcmp(t, "boolean")) {
|
||||
uint32_t v;
|
||||
if (!htsmsg_get_u32(e, "value", &v))
|
||||
idnode_filter_add_bool(&conf->filter, k, v, IC_EQ);
|
||||
}
|
||||
}
|
||||
htsmsg_destroy(t);
|
||||
}
|
||||
if ((str = http_arg_get(args, "sort"))) {
|
||||
conf->sort.key = str;
|
||||
if ((str = http_arg_get(args, "dir")) && !strcmp(str, "DESC"))
|
||||
conf->sort.dir = IS_DSC;
|
||||
else
|
||||
conf->sort.dir = IS_ASC;
|
||||
} else
|
||||
conf->sort.key = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
extjs_idnode_grid
|
||||
(idnode_set_t *ins, extjs_grid_conf_t *conf, htsmsg_t *out)
|
||||
{
|
||||
int i;
|
||||
htsmsg_t *list = htsmsg_create_list();
|
||||
if (conf->sort.key)
|
||||
idnode_set_sort(ins, &conf->sort);
|
||||
for (i = conf->start; i < ins->is_count && conf->limit != 0; i++) {
|
||||
htsmsg_t *e = htsmsg_create_map();
|
||||
htsmsg_add_str(e, "uuid", idnode_uuid_as_str(ins->is_array[i]));
|
||||
idnode_read0(ins->is_array[i], e, 0);
|
||||
htsmsg_add_msg(list, NULL, e);
|
||||
if (conf->limit > 0) conf->limit--;
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
free(ins->is_array);
|
||||
idnode_filter_clear(&conf->filter);
|
||||
htsmsg_add_msg(out, "entries", list);
|
||||
htsmsg_add_u32(out, "total", ins->is_count);
|
||||
}
|
||||
|
||||
static int
|
||||
extjs_mpegts_service
|
||||
(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
//char buf[256];
|
||||
mpegts_network_t *mn;
|
||||
mpegts_mux_t *mm;
|
||||
mpegts_service_t *ms;
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
htsmsg_t *out = htsmsg_create_map();
|
||||
extjs_grid_conf_t conf = { 0 };
|
||||
|
||||
if (!strcmp(op, "list")) {
|
||||
idnode_set_t ins = { 0 };
|
||||
extjs_grid_conf(&hc->hc_req_args, &conf);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
LIST_FOREACH(mn, &mpegts_network_all, mn_global_link) {
|
||||
LIST_FOREACH(mm, &mn->mn_muxes, mm_network_link) {
|
||||
LIST_FOREACH(ms, &mm->mm_services, s_dvb_mux_link) {
|
||||
idnode_set_add(&ins, (idnode_t*)ms, &conf.filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
extjs_idnode_grid(&ins, &conf, out);
|
||||
} else if (!strcmp(op, "class")) {
|
||||
htsmsg_t *list = idclass_serialize(&mpegts_service_class);
|
||||
htsmsg_add_msg(out, "entries", list);
|
||||
}
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
htsmsg_destroy(out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
http_api_boilerplate
|
||||
(http_connection_t *hc, const char **op, htsmsg_t **args)
|
||||
{
|
||||
const char *s;
|
||||
*op = http_arg_get(&hc->hc_req_args, "op");
|
||||
s = http_arg_get(&hc->hc_req_args, "args");
|
||||
if (s)
|
||||
*args = htsmsg_json_deserialize(s);
|
||||
else
|
||||
*args = NULL;
|
||||
if (!*op && *args)
|
||||
*op = htsmsg_get_str(*args, "method"); // HTSP compat
|
||||
}
|
||||
|
||||
static int
|
||||
extjs_mpegts_mux
|
||||
(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
mpegts_network_t *mn;
|
||||
mpegts_mux_t *mm;
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
const char *op;
|
||||
htsmsg_t *args;
|
||||
htsmsg_t *out = htsmsg_create_map();
|
||||
extjs_grid_conf_t conf = { 0 };
|
||||
|
||||
http_api_boilerplate(hc, &op, &args);
|
||||
if (!op)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
if (!strcmp(op, "list")) {
|
||||
idnode_set_t ins = { 0 };
|
||||
extjs_grid_conf(&hc->hc_req_args, &conf);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
LIST_FOREACH(mn, &mpegts_network_all, mn_global_link) {
|
||||
LIST_FOREACH(mm, &mn->mn_muxes, mm_network_link) {
|
||||
idnode_set_add(&ins, (idnode_t*)mm, &conf.filter);
|
||||
}
|
||||
}
|
||||
extjs_idnode_grid(&ins, &conf, out);
|
||||
} else if (!strcmp(op, "class")) {
|
||||
htsmsg_t *list = idclass_serialize(&mpegts_mux_class);
|
||||
htsmsg_add_msg(out, "entries", list);
|
||||
} else if (!strcmp(op, "delete") && args) {
|
||||
htsmsg_field_t *f;
|
||||
htsmsg_t *uuids = htsmsg_get_list(args, "uuids");
|
||||
if (uuids) {
|
||||
pthread_mutex_lock(&global_lock);
|
||||
HTSMSG_FOREACH(f, uuids) {
|
||||
if (f->hmf_type == HMF_STR)
|
||||
mpegts_mux_delete_by_uuid(f->hmf_str);
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
}
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
htsmsg_destroy(out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
extjs_linuxdvb_satconf
|
||||
(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
struct linuxdvb_satconf;
|
||||
extern const idclass_t linuxdvb_satconf_class;
|
||||
extern struct linuxdvb_satconf *linuxdvb_satconf_create0(const char*, htsmsg_t*);
|
||||
mpegts_input_t *mi;
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
htsmsg_t *out = htsmsg_create_map();
|
||||
extjs_grid_conf_t conf = { 0 };
|
||||
|
||||
if (!strcmp(op, "list")) {
|
||||
idnode_set_t ins = { 0 };
|
||||
extjs_grid_conf(&hc->hc_req_args, &conf);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
LIST_FOREACH(mi, &mpegts_input_all, mi_global_link)
|
||||
if (idnode_is_instance((idnode_t*)mi, &linuxdvb_satconf_class))
|
||||
idnode_set_add(&ins, (idnode_t*)mi, &conf.filter);
|
||||
extjs_idnode_grid(&ins, &conf, out);
|
||||
} else if (!strcmp(op, "class")) {
|
||||
htsmsg_t *list = idclass_serialize(&linuxdvb_satconf_class);
|
||||
htsmsg_add_msg(out, "entries", list);
|
||||
} else if (!strcmp(op, "create")) {
|
||||
idnode_t *in;
|
||||
htsmsg_t *conf = NULL;
|
||||
const char *c;
|
||||
if ((c = http_arg_get(&hc->hc_req_args, "conf")))
|
||||
conf = htsmsg_json_deserialize(c);
|
||||
if (!conf)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
pthread_mutex_lock(&global_lock);
|
||||
in = (idnode_t*)linuxdvb_satconf_create0(NULL, conf);
|
||||
if (in) in->in_class->ic_save(in);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
htsmsg_destroy(out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
extjs_mpegts_network
|
||||
(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
mpegts_network_t *mn = NULL;
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
const char *op;
|
||||
htsmsg_t *args;
|
||||
htsmsg_t *out = htsmsg_create_map();
|
||||
extjs_grid_conf_t conf = { 0 };
|
||||
|
||||
http_api_boilerplate(hc, &op, &args);
|
||||
if (!op)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
if (!strcmp(op, "list")) {
|
||||
idnode_set_t ins = { 0 };
|
||||
extjs_grid_conf(&hc->hc_req_args, &conf);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
LIST_FOREACH(mn, &mpegts_network_all, mn_global_link) {
|
||||
idnode_set_add(&ins, (idnode_t*)mn, &conf.filter);
|
||||
}
|
||||
extjs_idnode_grid(&ins, &conf, out);
|
||||
} else if (!strcmp(op, "class")) {
|
||||
htsmsg_t *c = idclass_serialize(&mpegts_network_class);
|
||||
htsmsg_add_msg(out, "entries", c);
|
||||
} else if (!strcmp(op, "class_list")) {
|
||||
mpegts_network_builder_t *mnb;
|
||||
htsmsg_t *e, *c = htsmsg_create_list();
|
||||
LIST_FOREACH(mnb, &mpegts_network_builders, link)
|
||||
if ((e = idclass_serialize(mnb->idc)))
|
||||
htsmsg_add_msg(c, NULL, e);
|
||||
htsmsg_add_msg(out, "entries", c);
|
||||
} else if (!strcmp(op, "delete") && args) {
|
||||
htsmsg_field_t *f;
|
||||
htsmsg_t *uuids = htsmsg_get_list(args, "uuids");
|
||||
if (uuids) {
|
||||
pthread_mutex_lock(&global_lock);
|
||||
HTSMSG_FOREACH(f, uuids) {
|
||||
if (f->hmf_type == HMF_STR)
|
||||
mpegts_network_delete_by_uuid(f->hmf_str);
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
} else if (!strcmp(op, "create")) {
|
||||
htsmsg_t *conf = NULL;
|
||||
const char *s, *c;
|
||||
if (!(s = http_arg_get(&hc->hc_req_args, "conf")))
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
if (!(c = http_arg_get(&hc->hc_req_args, "class")))
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
if (!(conf = htsmsg_json_deserialize(s)))
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
pthread_mutex_lock(&global_lock);
|
||||
mn = mpegts_network_build(c, conf);
|
||||
if (mn) mn->mn_config_save(mn);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
} else if (!strcmp(op, "mux_class")) {
|
||||
const idclass_t *idc;
|
||||
const char *uuid = http_arg_get(&hc->hc_req_args, "uuid");
|
||||
pthread_mutex_lock(&global_lock);
|
||||
mn = (uuid ? mpegts_network_find(uuid) : NULL);
|
||||
if (!mn) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
if (!(idc = mn->mn_mux_class(mn))) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
htsmsg_t *c = idclass_serialize(idc);
|
||||
htsmsg_add_msg(out, "entries", c);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
} else if (!strcmp(op, "mux_create")) {
|
||||
mpegts_mux_t *mm;
|
||||
htsmsg_t *conf = NULL;
|
||||
const char *c;
|
||||
const char *uuid = http_arg_get(&hc->hc_req_args, "uuid");
|
||||
pthread_mutex_lock(&global_lock);
|
||||
mn = (uuid ? mpegts_network_find(uuid) : NULL);
|
||||
if (!mn) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
if ((c = http_arg_get(&hc->hc_req_args, "conf")))
|
||||
conf = htsmsg_json_deserialize(c);
|
||||
if (!conf) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
mm = mn->mn_mux_create2(mn, conf);
|
||||
if(mm) mm->mm_config_save(mm);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
if (!mm) return HTTP_STATUS_BAD_REQUEST; // TODO: error message
|
||||
} else {
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
htsmsg_destroy(out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
extjs_mpegts_input
|
||||
(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
mpegts_input_t *mi;
|
||||
mpegts_network_t *mn;
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
htsmsg_t *out = htsmsg_create_map();
|
||||
extjs_grid_conf_t conf = { 0 };
|
||||
|
||||
if (!op) return 404;
|
||||
|
||||
if (!strcmp(op, "list")) {
|
||||
idnode_set_t ins = { 0 };
|
||||
extjs_grid_conf(&hc->hc_req_args, &conf);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
LIST_FOREACH(mi, &mpegts_input_all, mi_global_link)
|
||||
idnode_set_add(&ins, (idnode_t*)mi, &conf.filter);
|
||||
extjs_idnode_grid(&ins, &conf, out);
|
||||
} else if (!strcmp(op, "class")) {
|
||||
htsmsg_t *list = idclass_serialize(&mpegts_input_class);
|
||||
htsmsg_add_msg(out, "entries", list);
|
||||
} else if (!strcmp(op, "network_list")) {
|
||||
const char *uuid = http_arg_get(&hc->hc_req_args, "uuid");
|
||||
if (!uuid) return HTTP_STATUS_BAD_REQUEST;
|
||||
pthread_mutex_lock(&global_lock);
|
||||
mi = mpegts_input_find(uuid);
|
||||
if (mi) {
|
||||
int i;
|
||||
idnode_set_t *is = mi->mi_network_list(mi);
|
||||
if (is) {
|
||||
htsmsg_t *l = htsmsg_create_list();
|
||||
for (i = 0; i < is->is_count; i++) {
|
||||
char buf[256];
|
||||
htsmsg_t *e = htsmsg_create_map();
|
||||
mn = (mpegts_network_t*)is->is_array[i];
|
||||
htsmsg_add_str(e, "key", idnode_uuid_as_str(is->is_array[i]));
|
||||
mn->mn_display_name(mn, buf, sizeof(buf));
|
||||
htsmsg_add_str(e, "val", buf);
|
||||
htsmsg_add_msg(l, NULL, e);
|
||||
}
|
||||
htsmsg_add_msg(out, "entries", l);
|
||||
idnode_set_free(is);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
#if 0
|
||||
} else if (!strcmp(op, "network_class")) {
|
||||
const char *uuid = http_arg_get(&hc->hc_req_args, "uuid");
|
||||
if (!uuid) return 404;
|
||||
pthread_mutex_lock(&global_lock);
|
||||
mpegts_input_t *mi = idnode_find(uuid, &mpegts_input_class);
|
||||
if (!mi) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return 404;
|
||||
}
|
||||
htsmsg_t *list= idclass_serialize(mi->mi_network_class(mi));
|
||||
htsmsg_add_msg(out, "entries", list);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
} else if (!strcmp(op, "network_create")) {
|
||||
const char *uuid = http_arg_get(&hc->hc_req_args, "uuid");
|
||||
const char *conf = http_arg_get(&hc->hc_req_args, "conf");
|
||||
if (!uuid || !conf) return 404;
|
||||
pthread_mutex_lock(&global_lock);
|
||||
mi = idnode_find(uuid, &mpegts_input_class);
|
||||
if (!mi) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return 404;
|
||||
}
|
||||
mn = mi->mi_network_create(mi, htsmsg_json_deserialize(conf));
|
||||
if (mn)
|
||||
mn->mn_config_save(mn);
|
||||
else {
|
||||
// TODO: Check for error
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
htsmsg_destroy(out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* DVB WEB user interface
|
||||
*/
|
||||
void
|
||||
extjs_start_dvb(void)
|
||||
{
|
||||
http_path_add("/api/mpegts/network",
|
||||
NULL, extjs_mpegts_network, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/api/mpegts/mux",
|
||||
NULL, extjs_mpegts_mux, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/api/mpegts/service",
|
||||
NULL, extjs_mpegts_service, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/api/mpegts/input",
|
||||
NULL, extjs_mpegts_input, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/api/linuxdvb/satconf",
|
||||
NULL, extjs_linuxdvb_satconf, ACCESS_WEB_INTERFACE);
|
||||
#if 0
|
||||
http_path_add("/dvb/locations",
|
||||
NULL, extjs_dvblocations, ACCESS_WEB_INTERFACE);
|
||||
|
||||
http_path_add("/dvb/adapter",
|
||||
NULL, extjs_dvbadapter, ACCESS_ADMIN);
|
||||
|
||||
|
||||
http_path_add("/dvb/muxes",
|
||||
NULL, extjs_dvbmuxes, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/dvb/services",
|
||||
NULL, extjs_dvbservices, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/dvb/lnbtypes",
|
||||
NULL, extjs_lnbtypes, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/dvb/satconf",
|
||||
NULL, extjs_dvbsatconf, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/dvb/feopts",
|
||||
NULL, extjs_dvb_feopts, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/dvb/addmux",
|
||||
NULL, extjs_dvb_addmux, ACCESS_ADMIN);
|
||||
http_path_add("/dvb/copymux",
|
||||
NULL, extjs_dvb_copymux, ACCESS_ADMIN);
|
||||
#endif
|
||||
|
||||
}
|
|
@ -1,295 +0,0 @@
|
|||
/*
|
||||
* tvheadend, EXTJS based interface
|
||||
* Copyright (C) 2008 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "htsmsg.h"
|
||||
#include "htsmsg_json.h"
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "http.h"
|
||||
#include "webui.h"
|
||||
#include "access.h"
|
||||
#include "channels.h"
|
||||
#include "psi.h"
|
||||
|
||||
#include "v4l.h"
|
||||
#include "serviceprobe.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
json_single_record(htsmsg_t *rec, const char *root)
|
||||
{
|
||||
htsmsg_t *out, *array;
|
||||
|
||||
out = htsmsg_create_map();
|
||||
array = htsmsg_create_list();
|
||||
|
||||
htsmsg_add_msg(array, NULL, rec);
|
||||
htsmsg_add_msg(out, root, array);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_v4ladapter(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
v4l_adapter_t *va;
|
||||
htsmsg_t *out, *array, *r;
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
const char *s;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if(remain == NULL) {
|
||||
/* Just list all adapters */
|
||||
|
||||
array = htsmsg_create_list();
|
||||
|
||||
TAILQ_FOREACH(va, &v4l_adapters, va_global_link)
|
||||
htsmsg_add_msg(array, NULL, v4l_adapter_build_msg(va));
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
out = htsmsg_create_map();
|
||||
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;
|
||||
}
|
||||
|
||||
if((va = v4l_adapter_find_by_identifier(remain)) == NULL) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return 404;
|
||||
}
|
||||
|
||||
if(!strcmp(op, "load")) {
|
||||
r = htsmsg_create_map();
|
||||
htsmsg_add_str(r, "id", va->va_identifier);
|
||||
htsmsg_add_str(r, "device", va->va_path ?: "No hardware attached");
|
||||
htsmsg_add_str(r, "name", va->va_displayname);
|
||||
htsmsg_add_u32(r, "logging", va->va_logging);
|
||||
|
||||
out = json_single_record(r, "v4ladapters");
|
||||
} else if(!strcmp(op, "save")) {
|
||||
|
||||
if((s = http_arg_get(&hc->hc_req_args, "name")) != NULL)
|
||||
v4l_adapter_set_displayname(va, s);
|
||||
|
||||
s = http_arg_get(&hc->hc_req_args, "logging");
|
||||
v4l_adapter_set_logging(va, !!s);
|
||||
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_add_u32(out, "success", 1);
|
||||
|
||||
} else {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
service_update_v4l(htsmsg_t *in)
|
||||
{
|
||||
htsmsg_field_t *f;
|
||||
htsmsg_t *c;
|
||||
service_t *t;
|
||||
uint32_t u32;
|
||||
const char *id;
|
||||
int save;
|
||||
|
||||
TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
|
||||
if((c = htsmsg_get_map_by_field(f)) == NULL ||
|
||||
(id = htsmsg_get_str(c, "id")) == NULL)
|
||||
continue;
|
||||
|
||||
if((t = service_find_by_identifier(id)) == NULL)
|
||||
continue;
|
||||
|
||||
save = 0;
|
||||
|
||||
if(!htsmsg_get_u32(c, "frequency", &u32)) {
|
||||
t->s_v4l_frequency = u32;
|
||||
save = 1;
|
||||
}
|
||||
if(save)
|
||||
t->s_config_save(t); // Save config
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
build_record_v4l(service_t *t)
|
||||
{
|
||||
htsmsg_t *r = htsmsg_create_map();
|
||||
|
||||
// htsmsg_add_str(r, "id", t->s_identifier); // XXX(dvbreorg)
|
||||
|
||||
htsmsg_add_str(r, "channelname", t->s_ch ? t->s_ch->ch_name : "");
|
||||
htsmsg_add_u32(r, "frequency", t->s_v4l_frequency);
|
||||
htsmsg_add_u32(r, "enabled", t->s_enabled);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
v4l_servicecmp(const void *A, const void *B)
|
||||
{
|
||||
service_t *a = *(service_t **)A;
|
||||
service_t *b = *(service_t **)B;
|
||||
|
||||
return (int)a->s_v4l_frequency - (int)b->s_v4l_frequency;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_v4lservices(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
v4l_adapter_t *va;
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
htsmsg_t *out, *in, *array;
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
const char *entries = http_arg_get(&hc->hc_req_args, "entries");
|
||||
service_t *t, **tvec;
|
||||
int count = 0, i = 0;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if((va = v4l_adapter_find_by_identifier(remain)) == NULL) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return 404;
|
||||
}
|
||||
|
||||
in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
|
||||
|
||||
if(!strcmp(op, "get")) {
|
||||
|
||||
LIST_FOREACH(t, &va->va_services, s_group_link)
|
||||
count++;
|
||||
tvec = alloca(sizeof(service_t *) * count);
|
||||
LIST_FOREACH(t, &va->va_services, s_group_link)
|
||||
tvec[i++] = t;
|
||||
|
||||
out = htsmsg_create_map();
|
||||
array = htsmsg_create_list();
|
||||
|
||||
qsort(tvec, count, sizeof(service_t *), v4l_servicecmp);
|
||||
|
||||
for(i = 0; i < count; i++)
|
||||
htsmsg_add_msg(array, NULL, build_record_v4l(tvec[i]));
|
||||
|
||||
htsmsg_add_msg(out, "entries", array);
|
||||
|
||||
} else if(!strcmp(op, "update")) {
|
||||
if(in != NULL) {
|
||||
extjs_service_update(in); // Generic service parameters
|
||||
service_update_v4l(in); // V4L speicifc
|
||||
}
|
||||
|
||||
out = htsmsg_create_map();
|
||||
|
||||
} else if(!strcmp(op, "create")) {
|
||||
|
||||
out = build_record_v4l(v4l_service_find(va, NULL, 1));
|
||||
|
||||
} else if(!strcmp(op, "delete")) {
|
||||
if(in != NULL)
|
||||
extjs_service_delete(in);
|
||||
|
||||
out = htsmsg_create_map();
|
||||
|
||||
} else {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
htsmsg_destroy(in);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
|
||||
htsmsg_destroy(in);
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
extjs_list_v4l_adapters(htsmsg_t *array)
|
||||
{
|
||||
v4l_adapter_t *va;
|
||||
|
||||
TAILQ_FOREACH(va, &v4l_adapters, va_global_link)
|
||||
htsmsg_add_msg(array, NULL, v4l_adapter_build_msg(va));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* WEB user interface
|
||||
*/
|
||||
void
|
||||
extjs_start_v4l(void)
|
||||
{
|
||||
http_path_add("/v4l/adapter",
|
||||
NULL, extjs_v4ladapter, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/v4l/services",
|
||||
NULL, extjs_v4lservices, ACCESS_ADMIN);
|
||||
}
|
|
@ -7,10 +7,10 @@ tvheadend.idnode_get_enum = function ( conf )
|
|||
{
|
||||
/* Build key */
|
||||
var key = conf.url;
|
||||
if (conf.event)
|
||||
key += conf.event;
|
||||
if (conf.params)
|
||||
key += '?' + Ext.util.JSON.encode(conf.params);
|
||||
if (conf.event)
|
||||
key += '+' + conf.event;
|
||||
|
||||
/* Use cached */
|
||||
if (key in tvheadend.idnode_enum_stores)
|
||||
|
@ -22,6 +22,7 @@ tvheadend.idnode_get_enum = function ( conf )
|
|||
url : conf.url,
|
||||
baseParams : conf.params || {},
|
||||
fields : conf.fields || [ 'key', 'val' ],
|
||||
id : conf.id || 'key',
|
||||
autoLoad : true,
|
||||
});
|
||||
tvheadend.idnode_enum_stores[key] = st;
|
||||
|
@ -206,13 +207,11 @@ tvheadend.idnode_editor = function(item, conf)
|
|||
handler : function() {
|
||||
var node = panel.getForm().getFieldValues();
|
||||
node.uuid = item.uuid;
|
||||
var params = {
|
||||
op : 'save',
|
||||
nodes : Ext.util.JSON.encode([node])
|
||||
};
|
||||
Ext.Ajax.request({
|
||||
url : 'api/idnode',
|
||||
params : params,
|
||||
url : 'api/idnode/save',
|
||||
params : {
|
||||
args : Ext.encode({node: node})
|
||||
},
|
||||
success : function(d) {
|
||||
}
|
||||
});
|
||||
|
@ -259,10 +258,12 @@ tvheadend.idnode_create = function(conf)
|
|||
params['uuid'] = puuid;
|
||||
if (pclass)
|
||||
params['class'] = pclass
|
||||
params['conf'] = Ext.util.JSON.encode(panel.getForm().getFieldValues());
|
||||
params['conf'] = panel.getForm().getFieldValues();
|
||||
Ext.Ajax.request({
|
||||
url : conf.create.url || conf.url,
|
||||
params : params,
|
||||
url : conf.create.url || conf.url + '/create',
|
||||
params : {
|
||||
args : Ext.util.JSON.encode(params)
|
||||
},
|
||||
success : function(d) {
|
||||
win.close();
|
||||
}
|
||||
|
@ -294,7 +295,7 @@ tvheadend.idnode_create = function(conf)
|
|||
|
||||
/* Create window */
|
||||
win = new Ext.Window({
|
||||
title : 'Add ' + conf.title,
|
||||
title : 'Add ' + conf.titleS,
|
||||
layout : 'fit',
|
||||
autoWidth : true,
|
||||
autoHeight : true,
|
||||
|
@ -379,7 +380,7 @@ tvheadend.idnode_create = function(conf)
|
|||
win.show();
|
||||
} else {
|
||||
Ext.Ajax.request({
|
||||
url : conf.url,
|
||||
url : conf.url + '/class',
|
||||
params : conf.params,
|
||||
success : function(d) {
|
||||
d = json_decode(d);
|
||||
|
@ -458,15 +459,12 @@ tvheadend.idnode_grid = function(panel, conf)
|
|||
/* Store */
|
||||
var store = new Ext.data.JsonStore({
|
||||
root : 'entries',
|
||||
url : conf.url,
|
||||
url : conf.url + '/grid',
|
||||
autoLoad : true,
|
||||
id : 'uuid',
|
||||
totalProperty : 'total',
|
||||
fields : fields,
|
||||
remoteSort : true,
|
||||
baseParams : {
|
||||
op : 'list',
|
||||
}
|
||||
remoteSort : true
|
||||
});
|
||||
|
||||
/* Model */
|
||||
|
@ -507,10 +505,9 @@ tvheadend.idnode_grid = function(panel, conf)
|
|||
out[x].uuid = mr[x].id;
|
||||
}
|
||||
Ext.Ajax.request({
|
||||
url : 'api/idnode',
|
||||
url : 'api/idnode/save',
|
||||
params : {
|
||||
op : 'save',
|
||||
nodes : Ext.encode(out)
|
||||
args : Ext.encode({node : out})
|
||||
},
|
||||
success : function(d)
|
||||
{
|
||||
|
@ -555,10 +552,9 @@ tvheadend.idnode_grid = function(panel, conf)
|
|||
for ( var i = 0; i < r.length; i++ )
|
||||
uuids.push(r[i].id)
|
||||
Ext.Ajax.request({
|
||||
url : conf.url,
|
||||
url : 'api/idnode/delete',
|
||||
params : {
|
||||
op: 'delete',
|
||||
args : Ext.util.JSON.encode({ uuids: uuids})
|
||||
args : Ext.util.JSON.encode({ uuid: uuids})
|
||||
},
|
||||
success : function(d)
|
||||
{
|
||||
|
@ -580,9 +576,8 @@ tvheadend.idnode_grid = function(panel, conf)
|
|||
if (r) {
|
||||
if (conf.edittree) {
|
||||
var p = tvheadend.idnode_tree({
|
||||
url : 'api/idnode',
|
||||
url : 'api/idnode/tree',
|
||||
params : {
|
||||
op : 'childs',
|
||||
root : r.id
|
||||
}
|
||||
});
|
||||
|
@ -598,15 +593,14 @@ tvheadend.idnode_grid = function(panel, conf)
|
|||
w.show();
|
||||
} else {
|
||||
Ext.Ajax.request({
|
||||
url : 'api/idnode',
|
||||
url : 'api/idnode/load',
|
||||
params : {
|
||||
op: 'get',
|
||||
uuid: r.id
|
||||
},
|
||||
success : function(d)
|
||||
{
|
||||
d = json_decode(d);
|
||||
var p = tvheadend.idnode_editor(d, {});
|
||||
var p = tvheadend.idnode_editor(d[0], {});
|
||||
var w = new Ext.Window({
|
||||
title : 'Edit ' + conf.titleS,
|
||||
layout : 'fit',
|
||||
|
@ -678,10 +672,7 @@ tvheadend.idnode_grid = function(panel, conf)
|
|||
/* Request data */
|
||||
if (!conf.fields) {
|
||||
Ext.Ajax.request({
|
||||
url : conf.url,
|
||||
params : {
|
||||
op: 'class'
|
||||
},
|
||||
url : conf.url + '/class',
|
||||
success : function(d)
|
||||
{
|
||||
build(json_decode(d).props);
|
||||
|
@ -696,7 +687,6 @@ 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 : params,
|
||||
|
|
|
@ -2,39 +2,47 @@
|
|||
* DVB network
|
||||
*/
|
||||
|
||||
tvheadend.network_classes = new Ext.data.JsonStore({
|
||||
autoLoad : true,
|
||||
tvheadend.network_builders = new Ext.data.JsonStore({
|
||||
url : 'api/mpegts/network/builders',
|
||||
root : 'entries',
|
||||
fields : [ 'class', 'caption', 'props' ],
|
||||
id : 'class',
|
||||
url : 'api/mpegts/network',
|
||||
baseParams : {
|
||||
op: 'class_list'
|
||||
}
|
||||
fields : [ 'class', 'caption', 'props' ],
|
||||
id : 'class',
|
||||
autoLoad : true,
|
||||
});
|
||||
|
||||
tvheadend.network_list = new Ext.data.JsonStore({
|
||||
url : 'api/idnode/load',
|
||||
baseParams : { class : 'mpegts_network', enum: 1 },
|
||||
root : 'entries',
|
||||
fields : [ 'uuid', 'title' ],
|
||||
id : 'uuid',
|
||||
autoLoad : true,
|
||||
});
|
||||
|
||||
tvheadend.comet.on('mpegts_network', function() {
|
||||
tvheadend.network_classes.reload();
|
||||
// TODO: Might be a bit excessive
|
||||
tvheadend.network_builders.reload();
|
||||
tvheadend.network_list.reload();
|
||||
});
|
||||
|
||||
tvheadend.networks = function(panel)
|
||||
{
|
||||
tvheadend.idnode_grid(panel, {
|
||||
titleS : 'Network',
|
||||
titleP : 'Networks',
|
||||
url : 'api/mpegts/network',
|
||||
comet : 'mpegts_network',
|
||||
titleS : 'Network',
|
||||
titleP : 'Networks',
|
||||
add : {
|
||||
url : 'api/mpegts/network',
|
||||
title : 'Network',
|
||||
titleS : 'Network',
|
||||
select : {
|
||||
caption : 'Type',
|
||||
store : tvheadend.network_classes,
|
||||
label : 'Type',
|
||||
store : tvheadend.network_builders,
|
||||
displayField : 'caption',
|
||||
valueField : 'class',
|
||||
propField : 'props',
|
||||
},
|
||||
create : {
|
||||
params : { op: 'create' }
|
||||
url : 'api/mpegts/network/create'
|
||||
}
|
||||
},
|
||||
del : true
|
||||
|
@ -44,24 +52,23 @@ tvheadend.networks = function(panel)
|
|||
tvheadend.muxes = function(panel)
|
||||
{
|
||||
tvheadend.idnode_grid(panel, {
|
||||
titleS : 'Mux',
|
||||
titleP : 'Muxes',
|
||||
url : 'api/mpegts/mux',
|
||||
comet : 'mpegts_mux',
|
||||
add : {
|
||||
title : 'Mux',
|
||||
url : 'api/mpegts/network',
|
||||
select : {
|
||||
caption : 'Network',
|
||||
params : { op: 'list', limit: -1 },
|
||||
displayField : 'networkname',
|
||||
titleS : 'Mux',
|
||||
titleP : 'Muxes',
|
||||
add : {
|
||||
titleS : 'Mux',
|
||||
select : {
|
||||
label : 'Network',
|
||||
store : tvheadend.network_list,
|
||||
displayField : 'title',
|
||||
valueField : 'uuid',
|
||||
clazz : {
|
||||
params : { op: 'mux_class' }
|
||||
url : 'api/mpegts/network/mux_class'
|
||||
}
|
||||
},
|
||||
create : {
|
||||
params : { op: 'mux_create' }
|
||||
create : {
|
||||
url : 'api/mpegts/network/mux_create',
|
||||
}
|
||||
},
|
||||
del : true
|
||||
|
@ -72,9 +79,9 @@ tvheadend.services = function(panel)
|
|||
{
|
||||
tvheadend.idnode_grid(panel, {
|
||||
url : 'api/mpegts/service',
|
||||
comet : 'service',
|
||||
titleS : 'Service',
|
||||
titleP : 'Services',
|
||||
comet : 'service',
|
||||
add : false,
|
||||
del : false
|
||||
});
|
||||
|
@ -83,20 +90,11 @@ tvheadend.services = function(panel)
|
|||
tvheadend.satconfs = function(panel)
|
||||
{
|
||||
tvheadend.idnode_grid(panel, {
|
||||
titleS : 'Satconf',
|
||||
titleP : 'Satconfs',
|
||||
url : 'api/linuxdvb/satconf',
|
||||
comet : 'linuxdvb_satconf',
|
||||
add : {
|
||||
title : 'Satconf',
|
||||
url : 'api/linuxdvb/satconf',
|
||||
create : {
|
||||
params : { op: 'create' }
|
||||
},
|
||||
params : {
|
||||
op: 'class'
|
||||
}
|
||||
},
|
||||
titleS : 'Satconf',
|
||||
titleP : 'Satconfs',
|
||||
add : {},
|
||||
del : true,
|
||||
edittree : true,
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
tvheadend.tvadapters = function() {
|
||||
// return tvheadend.item_browser('tvadapters', 'TV Adapters');
|
||||
return tvheadend.idnode_tree({ url: 'tvadapters', title: 'TV adapters'});
|
||||
return tvheadend.idnode_tree({ url: 'api/tvadapter/tree', title: 'TV adapters'});
|
||||
}
|
||||
|
|
|
@ -267,7 +267,9 @@ function accessUpdate(o) {
|
|||
tvheadend.capabilities.indexOf('v4l') != -1) {
|
||||
tabs2.push(new tvheadend.tvadapters);
|
||||
}
|
||||
/*
|
||||
tabs2.push(new tvheadend.iptv);
|
||||
*/
|
||||
tvheadend.conf_dvbin = new Ext.TabPanel({
|
||||
activeTab: 0,
|
||||
autoScroll: true,
|
||||
|
|
|
@ -974,5 +974,6 @@ webui_init(void)
|
|||
simpleui_start();
|
||||
extjs_start();
|
||||
comet_init();
|
||||
webui_api_init();
|
||||
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ void extjs_service_update(htsmsg_t *in);
|
|||
|
||||
void extjs_service_delete(htsmsg_t *in);
|
||||
|
||||
void webui_api_init ( void );
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
93
src/webui/webui_api.c
Normal file
93
src/webui/webui_api.c
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* tvheadend, WebAPI access point
|
||||
*
|
||||
* Copyright (C) 2013 Adam Sutton
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "webui.h"
|
||||
#include "access.h"
|
||||
#include "http.h"
|
||||
#include "api.h"
|
||||
#include "htsmsg.h"
|
||||
#include "htsmsg_json.h"
|
||||
|
||||
static int
|
||||
webui_api_handler
|
||||
( http_connection_t *hc, const char *remain, void *opaque )
|
||||
{
|
||||
int r;
|
||||
http_arg_t *ha;
|
||||
htsmsg_t *args, *resp = NULL;
|
||||
const char *a = http_arg_get(&hc->hc_req_args, "args");
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "method");
|
||||
|
||||
// Compat
|
||||
if (!op)
|
||||
op = http_arg_get(&hc->hc_req_args, "op");
|
||||
|
||||
/* Parse arguments */
|
||||
if (a)
|
||||
args = htsmsg_json_deserialize(a);
|
||||
else
|
||||
args = htsmsg_create_map();
|
||||
if (!args)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
/* Add HTTP arguments?? */
|
||||
TAILQ_FOREACH(ha, &hc->hc_req_args, link) {
|
||||
// Ignore obvious keys
|
||||
if (strcmp("op", ha->key) &&
|
||||
strcmp("method", ha->key) &&
|
||||
strcmp("args", ha->key))
|
||||
htsmsg_add_str(args, ha->key, ha->val);
|
||||
}
|
||||
|
||||
/* Add operation */
|
||||
if (!htsmsg_get_str(args, "method") && op)
|
||||
htsmsg_add_str(args, "method", op);
|
||||
|
||||
/* Call */
|
||||
r = api_exec(remain, args, &resp);
|
||||
|
||||
/* Convert error */
|
||||
if (r) {
|
||||
switch (r) {
|
||||
case EACCES:
|
||||
r = HTTP_STATUS_UNAUTHORIZED;
|
||||
case ENOENT:
|
||||
case ENOSYS:
|
||||
r = HTTP_STATUS_NOT_FOUND;
|
||||
default:
|
||||
r = HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
/* Output response */
|
||||
if (resp) {
|
||||
htsmsg_json_serialize(resp, &hc->hc_reply, 0);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
htsmsg_destroy(resp);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
webui_api_init ( void )
|
||||
{
|
||||
http_path_add("/api", NULL, webui_api_handler, ACCESS_WEB_INTERFACE);
|
||||
}
|
Loading…
Add table
Reference in a new issue