Project

General

Profile

UPPDATE: Error /api/idnode/load -- 400 » api_idnode.c

bruce Herrington, 2013-11-17 19:39

 
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__ */
(1-1/5)