6a625ca8a17eae2eb24689c5820ca7f99de0ad50
[src/app-framework-main.git] / src / appfwk.c
1 /*
2  Copyright 2015 IoT.bzh
3
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7
8      http://www.apache.org/licenses/LICENSE-2.0
9
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <assert.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25
26 #include <json.h>
27
28 #include <wgt-info.h>
29
30 struct afapps {
31         struct json_object *pubarr;
32         struct json_object *direct;
33         struct json_object *byapp;
34 };
35
36 struct appfwk {
37         int refcount;
38         int nrroots;
39         char **roots;
40         struct afapps applications;
41         struct json_object *runners;
42 };
43
44 struct appfwk *appfwk_create()
45 {
46         struct appfwk *appfwk = malloc(sizeof * appfwk);
47         if (appfwk == NULL)
48                 errno = ENOMEM;
49         else {
50                 appfwk->runners = json_object_new_object();
51                 if (appfwk->runners == NULL) {
52                         free(appfwk);
53                         appfwk = NULL;
54                         errno = ENOMEM;
55                 } else {
56                         appfwk->refcount = 1;
57                         appfwk->nrroots = 0;
58                         appfwk->roots = NULL;
59                         appfwk->applications.pubarr = NULL;
60                         appfwk->applications.direct = NULL;
61                         appfwk->applications.byapp = NULL;
62                 }
63         }
64         return appfwk;
65 }
66
67 void appfwk_addref(struct appfwk *appfwk)
68 {
69         assert(appfwk);
70         appfwk->refcount++;
71 }
72
73 void appfwk_unref(struct appfwk *appfwk)
74 {
75         assert(appfwk);
76         if (!--appfwk->refcount) {
77                 json_object_put(appfwk->applications.pubarr);
78                 json_object_put(appfwk->applications.direct);
79                 json_object_put(appfwk->applications.byapp);
80                 json_object_put(appfwk->runners);
81                 while (appfwk->nrroots)
82                         free(appfwk->roots[--appfwk->nrroots]);
83                 free(appfwk->roots);
84                 free(appfwk);
85         }
86 }
87
88 int appfwk_add_root(struct appfwk *appfwk, const char *path)
89 {
90         int i, n;
91         char *r, **roots;
92
93         assert(appfwk);
94
95         /* don't depend on the cwd and unique name */
96         r = realpath(path, NULL);
97         if (!r)
98                 return -1;
99
100         /* avoiding duplications */
101         n = appfwk->nrroots;
102         roots = appfwk->roots;
103         for (i = 0 ; i < n ; i++) {
104                 if (!strcmp(r, roots[i])) {
105                         free(r);
106                         return 0;
107                 }
108         }
109
110         /* add */
111         roots = realloc(roots, (n + 1) * sizeof(roots[0]));
112         if (!roots) {
113                 free(r);
114                 errno = ENOMEM;
115                 return -1;
116         }
117         roots[n++] = r;
118         appfwk->roots = roots;
119         appfwk->nrroots = n;
120         return 0;
121 }
122
123 static int json_add(struct json_object *obj, const char *key, struct json_object *val)
124 {
125         json_object_object_add(obj, key, val);
126         return 0;
127 }
128
129 static int json_add_str(struct json_object *obj, const char *key, const char *val)
130 {
131         struct json_object *str = json_object_new_string (val ? val : "");
132         return str ? json_add(obj, key, str) : -1;
133 }
134
135 static int json_add_int(struct json_object *obj, const char *key, int val)
136 {
137         struct json_object *v = json_object_new_int (val);
138         return v ? json_add(obj, key, v) : -1;
139 }
140
141 static int addapp(struct afapps *apps, const char *path)
142 {
143         struct wgt_info *info;
144         const struct wgt_desc *desc;
145         const struct wgt_desc_feature *feat;
146         struct json_object *priv = NULL, *pub, *bya, *plugs, *str;
147         char *appid, *end;
148
149         /* connect to the widget */
150         info = wgt_info_createat(AT_FDCWD, path, 0, 1, 0);
151         if (info == NULL)
152                 goto error;
153         desc = wgt_info_desc(info);
154
155         /* create the application id */
156         appid = alloca(2 + strlen(desc->id) + strlen(desc->version));
157         end = stpcpy(appid, desc->id);
158         *end++ = '@';
159         strcpy(end, desc->version);
160
161         /* create the application structure */
162         priv = json_object_new_object();
163         if (!priv)
164                 goto error2;
165
166         pub = json_object_new_object();
167         if (!priv)
168                 goto error2;
169
170         if (json_add(priv, "public", pub)) {
171                 json_object_put(pub);
172                 goto error2;
173         }
174
175         plugs = json_object_new_array();
176         if (!priv)
177                 goto error2;
178
179         if (json_add(priv, "plugins", plugs)) {
180                 json_object_put(plugs);
181                 goto error2;
182         }
183
184         if(json_add_str(pub, "id", appid)
185         || json_add_str(priv, "id", desc->id)
186         || json_add_str(pub, "version", desc->version)
187         || json_add_str(priv, "path", path)
188         || json_add_int(pub, "width", desc->width)
189         || json_add_int(pub, "height", desc->height)
190         || json_add_str(pub, "name", desc->name)
191         || json_add_str(pub, "description", desc->description)
192         || json_add_str(pub, "shortname", desc->name_short)
193         || json_add_str(pub, "author", desc->author))
194                 goto error2;
195
196         feat = desc->features;
197         while (feat) {
198                 static const char prefix[] = FWK_PREFIX_PLUGIN;
199                 if (!memcmp(feat->name, prefix, sizeof prefix - 1)) {
200                         str = json_object_new_string (feat->name + sizeof prefix - 1);
201                         if (str == NULL)
202                                 goto error2;
203                         if (json_object_array_add(plugs, str)) {
204                                 json_object_put(str);
205                                 goto error2;
206                         }
207                 }
208                 feat = feat->next;
209         }
210
211         /* record the application structure */
212         if (!json_object_object_get_ex(apps->byapp, desc->id, &bya)) {
213                 bya = json_object_new_object();
214                 if (!bya)
215                         goto error2;
216                 if (json_add(apps->byapp, desc->id, bya)) {
217                         json_object_put(bya);
218                         goto error2;
219                 }
220         }
221
222         if (json_add(apps->direct, appid, priv))
223                 goto error2;
224         json_object_get(priv);
225
226         if (json_add(bya, desc->version, priv)) {
227                 json_object_put(priv);
228                 goto error2;
229         }
230
231         if (json_object_array_add(apps->pubarr, pub))
232                 goto error2;
233
234         wgt_info_unref(info);
235         return 0;
236
237 error2:
238         json_object_put(priv);
239         wgt_info_unref(info);
240 error:
241         return -1;
242 }
243
244 struct enumdata {
245         char path[PATH_MAX];
246         int length;
247         struct afapps apps;
248 };
249
250 static int enumentries(struct enumdata *data, int (*callto)(struct enumdata *))
251 {
252         DIR *dir;
253         int rc;
254         char *beg, *end;
255         struct dirent entry, *e;
256
257         /* opens the directory */
258         dir = opendir(data->path);
259         if (!dir)
260                 return -1;
261
262         /* prepare appending entry names */
263         beg = data->path + data->length;
264         *beg++ = '/';
265
266         /* enumerate entries */
267         rc = readdir_r(dir, &entry, &e);
268         while (!rc && e) {
269                 if (entry.d_name[0] != '.' || (entry.d_name[1] && (entry.d_name[1] != '.' || entry.d_name[2]))) {
270                         /* prepare callto */
271                         end = stpcpy(beg, entry.d_name);
272                         data->length = end - data->path;
273                         /* call the function */
274                         rc = callto(data);
275                         if (rc)
276                                 break;
277                 }       
278                 rc = readdir_r(dir, &entry, &e);
279         }
280         closedir(dir);
281         return rc;
282 }
283
284 static int recordapp(struct enumdata *data)
285 {
286         return addapp(&data->apps, data->path);
287 }
288
289 /* enumerate the versions */
290 static int enumvers(struct enumdata *data)
291 {
292         int rc = enumentries(data, recordapp);
293         return !rc || errno != ENOTDIR ? 0 : rc;
294 }
295
296 /* regenerate the list of applications */
297 int appfwk_update_applications(struct appfwk *af)
298 {
299         int rc, iroot;
300         struct enumdata edata;
301         struct afapps oldapps;
302
303         /* create the result */
304         edata.apps.pubarr = json_object_new_array();
305         edata.apps.direct = json_object_new_object();
306         edata.apps.byapp = json_object_new_object();
307         if (edata.apps.pubarr == NULL || edata.apps.direct == NULL || edata.apps.byapp == NULL) {
308                 errno = ENOMEM;
309                 goto error;
310         }
311         /* for each root */
312         for (iroot = 0 ; iroot < af->nrroots ; iroot++) {
313                 edata.length = stpcpy(edata.path, af->roots[iroot]) - edata.path;
314                 assert(edata.length < sizeof edata.path);
315                 /* enumerate the applications */
316                 rc = enumentries(&edata, enumvers);
317                 if (rc)
318                         goto error;
319         }
320         /* commit the result */
321         oldapps = af->applications;
322         af->applications = edata.apps;
323         json_object_put(oldapps.pubarr);
324         json_object_put(oldapps.direct);
325         json_object_put(oldapps.byapp);
326         return 0;
327
328 error:
329         json_object_put(edata.apps.pubarr);
330         json_object_put(edata.apps.direct);
331         json_object_put(edata.apps.byapp);
332         return -1;
333 }
334
335 int appfwk_ensure_applications(struct appfwk *af)
336 {
337         return af->applications.pubarr ? 0 : appfwk_update_applications(af);
338 }
339
340 struct json_object *appfwk_application_list(struct appfwk *af)
341 {
342         return appfwk_ensure_applications(af) ? NULL : af->applications.pubarr;
343 }
344
345 struct json_object *appfwk_get_application(struct appfwk *af, const char *id)
346 {
347         struct json_object *result;
348         if (!appfwk_ensure_applications(af) && json_object_object_get_ex(obj, id, &result))
349                 return result;
350         }
351         return NULL;
352 }
353
354 struct json_object *appfwk_get_application_public(struct appfwk *af, const char *id)
355 {
356         struct json_object *result = appfwk_get_application(af, id);
357         return result && json_object_object_get_ex(result, "public", &result) ? result : NULL;
358 }
359
360 static struct json_object *mkrunner(const char *appid, const char *runid)
361 {
362         struct json_object *result = json_object_new_object();
363         if (result) {
364                 if(json_add_str(result, "id", appid)
365                 || json_add_str(result, "runid", runid)
366                 || json_add_str(result, "state", NULL)) {
367                         json_object_put(result);
368                         result = NULL;
369                 }
370         }
371         return result;
372 }
373
374 const char *appfwk_start(struct appfwk *af, const char *appid)
375 {
376         struct json_object *appli;
377         struct json_object *runner;
378         char buffer[250];
379
380         /* get the application description */
381         appli = appfwk_get_application(af, appid);
382         if (appli == NULL) {
383                 errno = ENOENT;
384                 return -1;
385         }
386
387         /* prepare the execution */
388         snprintf(buffer, sizeof buffer, "{\"id\":\"%s\",\"runid\":\"%s\"
389 }
390
391 int appfwk_stop(struct appfwk *af, const char *runid)
392 {
393         struct json_object *runner;
394         runner = appfwk_state(af, runid);
395         if (runner == NULL) {
396                 errno = ENOENT;
397                 return -1;
398         }
399         json_object_get(runner);
400         json_object_object_del(af->runners, runid);
401
402
403
404
405
406
407 ..........
408
409
410
411
412
413
414         json_object_put(runner);
415 }
416
417 int appfwk_suspend(struct appfwk *af, const char *runid)
418 {
419 }
420
421 int appfwk_resume(struct appfwk *af, const char *runid)
422 {
423 }
424
425 struct json_object *appfwk_running_list(struct appfwk *af)
426 {
427         return af->runners;
428 }
429
430 struct json_object *appfwk_state(struct appfwk *af, const char *runid)
431 {
432         struct json_object *result;
433         int status = json_object_object_get_ex(af->runners, runid, &result);
434         return status ? result : NULL;
435 }
436
437
438
439
440
441
442
443 #if defined(TESTAPPFWK)
444 #include <stdio.h>
445 int main()
446 {
447 struct appfwk *af = appfwk_create();
448 appfwk_add_root(af,FWK_APP_DIR);
449 appfwk_update_applications(af);
450 printf("array = %s\n", json_object_to_json_string_ext(af->applications.pubarr, 3));
451 printf("direct = %s\n", json_object_to_json_string_ext(af->applications.direct, 3));
452 printf("byapp = %s\n", json_object_to_json_string_ext(af->applications.byapp, 3));
453 return 0;
454 }
455 #endif
456