1
|
/*
|
2
|
* API - idnode related API calls
|
3
|
*
|
4
|
* Copyright (C) 2013 Adam Sutton
|
5
|
*
|
6
|
* This program is free software: you can redistribute it and/or modify
|
7
|
* it under the terms of the GNU General Public License as published by
|
8
|
* the Free Software Foundation, either version 3 of the License, or
|
9
|
* (at your option) any later version.
|
10
|
*
|
11
|
* This program is distributed in the hope that it will be useful,
|
12
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
* GNU General Public License for more details.
|
15
|
*
|
16
|
* You should have received a copy of the GNU General Public License
|
17
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
*/
|
19
|
|
20
|
#ifndef __TVH_API_IDNODE_H__
|
21
|
#define __TVH_API_IDNODE_H__
|
22
|
|
23
|
#include "tvheadend.h"
|
24
|
#include "access.h"
|
25
|
#include "idnode.h"
|
26
|
#include "htsmsg.h"
|
27
|
#include "api.h"
|
28
|
|
29
|
static struct strtab filtcmptab[] = {
|
30
|
{ "gt", IC_GT },
|
31
|
{ "lt", IC_LT },
|
32
|
{ "eq", IC_EQ }
|
33
|
};
|
34
|
|
35
|
static void
|
36
|
api_idnode_grid_conf
|
37
|
( htsmsg_t *args, api_idnode_grid_conf_t *conf )
|
38
|
{
|
39
|
htsmsg_field_t *f;
|
40
|
htsmsg_t *filter, *e;
|
41
|
const char *str;
|
42
|
|
43
|
/* Start */
|
44
|
if ((str = htsmsg_get_str(args, "start")))
|
45
|
conf->start = atoi(str);
|
46
|
else
|
47
|
conf->start = 0;
|
48
|
|
49
|
/* Limit */
|
50
|
if ((str = htsmsg_get_str(args, "limit")))
|
51
|
conf->limit = atoi(str);
|
52
|
else
|
53
|
conf->limit = 50;
|
54
|
|
55
|
/* Filter */
|
56
|
if ((filter = htsmsg_get_list(args, "filter"))) {
|
57
|
HTSMSG_FOREACH(f, filter) {
|
58
|
const char *k, *t, *v;
|
59
|
if (!(e = htsmsg_get_map_by_field(f))) continue;
|
60
|
if (!(k = htsmsg_get_str(e, "field"))) continue;
|
61
|
if (!(t = htsmsg_get_str(e, "type"))) continue;
|
62
|
if (!strcmp(t, "string")) {
|
63
|
if ((v = htsmsg_get_str(e, "value")))
|
64
|
idnode_filter_add_str(&conf->filter, k, v, IC_RE);
|
65
|
} else if (!strcmp(t, "numeric")) {
|
66
|
uint32_t v;
|
67
|
if (!htsmsg_get_u32(e, "value", &v)) {
|
68
|
int t = str2val(htsmsg_get_str(e, "comparison") ?: "",
|
69
|
filtcmptab);
|
70
|
idnode_filter_add_num(&conf->filter, k, v, t == -1 ? IC_EQ : t);
|
71
|
}
|
72
|
} else if (!strcmp(t, "boolean")) {
|
73
|
uint32_t v;
|
74
|
if (!htsmsg_get_u32(e, "value", &v))
|
75
|
idnode_filter_add_bool(&conf->filter, k, v, IC_EQ);
|
76
|
}
|
77
|
}
|
78
|
}
|
79
|
|
80
|
/* Sort */
|
81
|
if ((str = htsmsg_get_str(args, "sort"))) {
|
82
|
conf->sort.key = str;
|
83
|
if ((str = htsmsg_get_str(args, "dir")) && !strcmp(str, "DESC"))
|
84
|
conf->sort.dir = IS_DSC;
|
85
|
else
|
86
|
conf->sort.dir = IS_ASC;
|
87
|
} else
|
88
|
conf->sort.key = NULL;
|
89
|
}
|
90
|
|
91
|
int
|
92
|
api_idnode_grid
|
93
|
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
94
|
{
|
95
|
int i;
|
96
|
htsmsg_t *list, *e;
|
97
|
api_idnode_grid_conf_t conf = { 0 };
|
98
|
idnode_set_t ins = { 0 };
|
99
|
api_idnode_grid_callback_t cb = opaque;
|
100
|
|
101
|
/* Grid configuration */
|
102
|
api_idnode_grid_conf(args, &conf);
|
103
|
|
104
|
/* Create list */
|
105
|
pthread_mutex_lock(&global_lock);
|
106
|
cb(&ins, &conf, args);
|
107
|
|
108
|
/* Sort */
|
109
|
if (conf.sort.key)
|
110
|
idnode_set_sort(&ins, &conf.sort);
|
111
|
|
112
|
/* Paginate */
|
113
|
list = htsmsg_create_list();
|
114
|
for (i = conf.start; i < ins.is_count && conf.limit != 0; i++) {
|
115
|
e = htsmsg_create_map();
|
116
|
htsmsg_add_str(e, "uuid", idnode_uuid_as_str(ins.is_array[i]));
|
117
|
idnode_read0(ins.is_array[i], e, 0);
|
118
|
htsmsg_add_msg(list, NULL, e);
|
119
|
if (conf.limit > 0) conf.limit--;
|
120
|
}
|
121
|
|
122
|
pthread_mutex_unlock(&global_lock);
|
123
|
|
124
|
/* Output */
|
125
|
*resp = htsmsg_create_map();
|
126
|
htsmsg_add_msg(*resp, "entries", list);
|
127
|
htsmsg_add_u32(*resp, "total", ins.is_count);
|
128
|
|
129
|
/* Cleanup */
|
130
|
free(ins.is_array);
|
131
|
idnode_filter_clear(&conf.filter);
|
132
|
|
133
|
return 0;
|
134
|
}
|
135
|
|
136
|
int
|
137
|
api_idnode_load_by_class
|
138
|
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
139
|
{
|
140
|
int i, _enum;
|
141
|
const idclass_t *idc;
|
142
|
idnode_set_t *is;
|
143
|
idnode_t *in;
|
144
|
htsmsg_t *l, *e;
|
145
|
|
146
|
// TODO: this only works if pass as integer
|
147
|
_enum = htsmsg_get_bool_or_default(args, "enum", 0);
|
148
|
|
149
|
pthread_mutex_lock(&global_lock);
|
150
|
|
151
|
/* Find class */
|
152
|
idc = opaque;
|
153
|
assert(idc);
|
154
|
|
155
|
l = htsmsg_create_list();
|
156
|
if ((is = idnode_find_all(idc))) {
|
157
|
for (i = 0; i < is->is_count; i++) {
|
158
|
in = is->is_array[i];
|
159
|
|
160
|
/* Name/UUID only */
|
161
|
if (_enum) {
|
162
|
e = htsmsg_create_map();
|
163
|
htsmsg_add_str(e, "key", idnode_uuid_as_str(in));
|
164
|
htsmsg_add_str(e, "val", idnode_get_title(in));
|
165
|
|
166
|
/* Full record */
|
167
|
} else
|
168
|
e = idnode_serialize(in);
|
169
|
|
170
|
if (e)
|
171
|
htsmsg_add_msg(l, NULL, e);
|
172
|
}
|
173
|
}
|
174
|
*resp = htsmsg_create_map();
|
175
|
htsmsg_add_msg(*resp, "entries", l);
|
176
|
|
177
|
pthread_mutex_unlock(&global_lock);
|
178
|
|
179
|
return 0;
|
180
|
}
|
181
|
|
182
|
static int
|
183
|
api_idnode_load
|
184
|
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
185
|
{
|
186
|
int err = 0;
|
187
|
idnode_t *in;
|
188
|
htsmsg_t *uuids, *l = NULL;
|
189
|
htsmsg_field_t *f;
|
190
|
const char *uuid, *class;
|
191
|
|
192
|
/* Class based */
|
193
|
if ((class = htsmsg_get_str(args, "class"))) {
|
194
|
const idclass_t *idc;
|
195
|
pthread_mutex_lock(&global_lock);
|
196
|
idc = idclass_find(class);
|
197
|
pthread_mutex_unlock(&global_lock);
|
198
|
if (!idc)
|
199
|
return EINVAL;
|
200
|
// TODO: bit naff that 2 locks are required here
|
201
|
return api_idnode_load_by_class((void*)idc, NULL, args, resp);
|
202
|
}
|
203
|
|
204
|
/* UUIDs */
|
205
|
if (!(f = htsmsg_field_find(args, "uuid")))
|
206
|
return EINVAL;
|
207
|
if (!(uuids = htsmsg_field_get_list(f)))
|
208
|
if (!(uuid = htsmsg_field_get_str(f)))
|
209
|
return EINVAL;
|
210
|
|
211
|
pthread_mutex_lock(&global_lock);
|
212
|
|
213
|
/* Multiple */
|
214
|
if (uuids) {
|
215
|
l = htsmsg_create_list();
|
216
|
HTSMSG_FOREACH(f, uuids) {
|
217
|
if (!(uuid = htsmsg_field_get_str(f))) continue;
|
218
|
if (!(in = idnode_find(uuid, NULL))) continue;
|
219
|
htsmsg_add_msg(l, NULL, idnode_serialize(in));
|
220
|
}
|
221
|
|
222
|
/* Single */
|
223
|
} else {
|
224
|
if (!(in = idnode_find(uuid, NULL)))
|
225
|
err = ENOENT;
|
226
|
else {
|
227
|
l = htsmsg_create_list();
|
228
|
htsmsg_add_msg(l, NULL, idnode_serialize(in));
|
229
|
}
|
230
|
}
|
231
|
|
232
|
if (l) {
|
233
|
*resp = htsmsg_create_map();
|
234
|
htsmsg_add_msg(*resp, "entries", l);
|
235
|
}
|
236
|
|
237
|
pthread_mutex_unlock(&global_lock);
|
238
|
|
239
|
return err;
|
240
|
}
|
241
|
|
242
|
static int
|
243
|
api_idnode_save
|
244
|
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
245
|
{
|
246
|
int err = EINVAL;
|
247
|
idnode_t *in;
|
248
|
htsmsg_t *msg, *conf;
|
249
|
htsmsg_field_t *f;
|
250
|
const char *uuid;
|
251
|
|
252
|
if (!(f = htsmsg_field_find(args, "node")))
|
253
|
return EINVAL;
|
254
|
if (!(msg = htsmsg_field_get_list(f)))
|
255
|
if (!(msg = htsmsg_field_get_map(f)))
|
256
|
return EINVAL;
|
257
|
|
258
|
pthread_mutex_lock(&global_lock);
|
259
|
|
260
|
/* Single */
|
261
|
if (!msg->hm_islist) {
|
262
|
if (!(uuid = htsmsg_get_str(msg, "uuid")))
|
263
|
goto exit;
|
264
|
if (!(in = idnode_find(uuid, NULL)))
|
265
|
goto exit;
|
266
|
idnode_update(in, msg);
|
267
|
err = 0;
|
268
|
|
269
|
/* Multiple */
|
270
|
} else {
|
271
|
HTSMSG_FOREACH(f, msg) {
|
272
|
if (!(conf = htsmsg_field_get_map(f)))
|
273
|
continue;
|
274
|
if (!(uuid = htsmsg_get_str(conf, "uuid")))
|
275
|
continue;
|
276
|
if (!(in = idnode_find(uuid, NULL)))
|
277
|
continue;
|
278
|
idnode_update(in, conf);
|
279
|
}
|
280
|
err = 0;
|
281
|
}
|
282
|
|
283
|
// TODO: return updated UUIDs?
|
284
|
|
285
|
exit:
|
286
|
pthread_mutex_unlock(&global_lock);
|
287
|
|
288
|
return err;
|
289
|
}
|
290
|
|
291
|
int
|
292
|
api_idnode_tree
|
293
|
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
294
|
{
|
295
|
const char *uuid;
|
296
|
const char *root = NULL;
|
297
|
int isroot;
|
298
|
idnode_t *node = NULL;
|
299
|
api_idnode_tree_callback_t rootfn = opaque;
|
300
|
|
301
|
/* UUID */
|
302
|
if (!(uuid = htsmsg_get_str(args, "uuid")))
|
303
|
return EINVAL;
|
304
|
|
305
|
/* Root UUID */
|
306
|
if (!rootfn)
|
307
|
root = htsmsg_get_str(args, "root");
|
308
|
|
309
|
/* Is root? */
|
310
|
isroot = (strcmp("root", uuid) == 0);
|
311
|
if (isroot && !(root || rootfn))
|
312
|
return EINVAL;
|
313
|
|
314
|
pthread_mutex_lock(&global_lock);
|
315
|
|
316
|
if (!isroot || root) {
|
317
|
if (!(node = idnode_find(isroot ? root : uuid, NULL))) {
|
318
|
pthread_mutex_unlock(&global_lock);
|
319
|
return EINVAL;
|
320
|
}
|
321
|
}
|
322
|
|
323
|
*resp = htsmsg_create_list();
|
324
|
|
325
|
/* Root node */
|
326
|
if (isroot && node) {
|
327
|
htsmsg_t *m = idnode_serialize(node);
|
328
|
htsmsg_add_u32(m, "leaf", idnode_is_leaf(node));
|
329
|
htsmsg_add_msg(*resp, NULL, m);
|
330
|
|
331
|
/* Children */
|
332
|
} else {
|
333
|
idnode_set_t *v = node ? idnode_get_childs(node) : rootfn();
|
334
|
if (v) {
|
335
|
int i;
|
336
|
idnode_set_sort_by_title(v);
|
337
|
for(i = 0; i < v->is_count; i++) {
|
338
|
htsmsg_t *m = idnode_serialize(v->is_array[i]);
|
339
|
htsmsg_add_u32(m, "leaf", idnode_is_leaf(v->is_array[i]));
|
340
|
htsmsg_add_msg(*resp, NULL, m);
|
341
|
}
|
342
|
idnode_set_free(v);
|
343
|
}
|
344
|
}
|
345
|
pthread_mutex_unlock(&global_lock);
|
346
|
|
347
|
return 0;
|
348
|
}
|
349
|
|
350
|
int
|
351
|
api_idnode_class
|
352
|
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
353
|
{
|
354
|
int err = EINVAL;
|
355
|
const char *name;
|
356
|
const idclass_t *idc;
|
357
|
|
358
|
pthread_mutex_lock(&global_lock);
|
359
|
|
360
|
/* Lookup */
|
361
|
if (!opaque) {
|
362
|
if (!(name = htsmsg_get_str(args, "name")))
|
363
|
goto exit;
|
364
|
if (!(idc = idclass_find(name)))
|
365
|
goto exit;
|
366
|
|
367
|
} else {
|
368
|
idc = opaque;
|
369
|
}
|
370
|
|
371
|
err = 0;
|
372
|
*resp = idclass_serialize(idc);
|
373
|
|
374
|
exit:
|
375
|
pthread_mutex_unlock(&global_lock);
|
376
|
|
377
|
return err;
|
378
|
}
|
379
|
|
380
|
static int
|
381
|
api_idnode_delete
|
382
|
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
383
|
{
|
384
|
int err = 0;
|
385
|
idnode_t *in;
|
386
|
htsmsg_t *uuids;
|
387
|
htsmsg_field_t *f;
|
388
|
const char *uuid;
|
389
|
|
390
|
/* ID based */
|
391
|
if (!(f = htsmsg_field_find(args, "uuid")))
|
392
|
return EINVAL;
|
393
|
if (!(uuids = htsmsg_field_get_list(f)))
|
394
|
if (!(uuid = htsmsg_field_get_str(f)))
|
395
|
return EINVAL;
|
396
|
|
397
|
pthread_mutex_lock(&global_lock);
|
398
|
|
399
|
/* Multiple */
|
400
|
if (uuids) {
|
401
|
HTSMSG_FOREACH(f, uuids) {
|
402
|
if (!(uuid = htsmsg_field_get_string(f))) continue;
|
403
|
if (!(in = idnode_find(uuid, NULL))) continue;
|
404
|
idnode_delete(in);
|
405
|
}
|
406
|
|
407
|
/* Single */
|
408
|
} else {
|
409
|
uuid = htsmsg_field_get_string(f);
|
410
|
if (!(in = idnode_find(uuid, NULL)))
|
411
|
err = ENOENT;
|
412
|
else
|
413
|
idnode_delete(in);
|
414
|
}
|
415
|
|
416
|
pthread_mutex_unlock(&global_lock);
|
417
|
|
418
|
return err;
|
419
|
}
|
420
|
|
421
|
void api_idnode_init ( void )
|
422
|
{
|
423
|
static api_hook_t ah[] = {
|
424
|
{ "idnode/load", ACCESS_ANONYMOUS, api_idnode_load, NULL },
|
425
|
{ "idnode/save", ACCESS_ADMIN, api_idnode_save, NULL },
|
426
|
{ "idnode/tree", ACCESS_ANONYMOUS, api_idnode_tree, NULL },
|
427
|
{ "idnode/class", ACCESS_ANONYMOUS, api_idnode_class, NULL },
|
428
|
{ "idnode/delete", ACCESS_ADMIN, api_idnode_delete, NULL },
|
429
|
{ NULL },
|
430
|
};
|
431
|
|
432
|
api_register_all(ah);
|
433
|
}
|
434
|
|
435
|
|
436
|
#endif /* __TVH_API_IDNODE_H__ */
|