prepares event propagation
[src/app-framework-binder.git] / plugins / afm-main-plugin / afm-main-plugin.c
1 /*
2  * Copyright (C) 2015 "IoT.bzh"
3  * Author "Fulup Ar Foll"
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE         /* See feature_test_macros(7) */
19 #include <stdio.h>
20 #include <string.h>
21 #include <assert.h>
22 #include <json.h>
23
24 #include "afb-plugin.h"
25
26 #include "utils-sbus.h"
27 #include "utils-jbus.h"
28
29 static const char _auto_[]      = "auto";
30 static const char _continue_[]  = "continue";
31 static const char _changed_[]   = "changed";
32 static const char _detail_[]    = "detail";
33 static const char _id_[]        = "id";
34 static const char _install_[]   = "install";
35 static const char _local_[]     = "local";
36 static const char _mode_[]      = "mode";
37 static const char _remote_[]    = "remote";
38 static const char _runid_[]     = "runid";
39 static const char _runnables_[] = "runnables";
40 static const char _runners_[]   = "runners";
41 static const char _start_[]     = "start";
42 static const char _state_[]     = "state";
43 static const char _stop_[]      = "stop";
44 static const char _terminate_[] = "terminate";
45 static const char _uninstall_[] = "uninstall";
46 static const char _uri_[]       = "uri";
47
48 static const struct AFB_interface *interface;
49 static struct afb_evmgr evmgr;
50
51 static struct jbus *jbus;
52
53 static void application_list_changed(const char *data, void *closure)
54 {
55         afb_evmgr_push(evmgr, "application-list-changed", NULL);
56 }
57
58 static struct json_object *embed(const char *tag, struct json_object *obj)
59 {
60         struct json_object *result;
61
62         if (obj == NULL)
63                 result = NULL;
64         else if (!tag)
65                 result = obj;
66         else {
67                 result = json_object_new_object();
68                 if (result == NULL) {
69                         /* can't embed */
70                         result = obj;
71                 }
72                 else {
73                         /* TODO why is json-c not returning a status? */
74                         json_object_object_add(result, tag, obj);
75                 }
76         }
77         return result;
78 }
79
80 static void embed_call_void(struct afb_req request, const char *method)
81 {
82         struct json_object *obj = jbus_call_sj_sync(jbus, method, "true");
83         if (interface->verbosity)
84                 fprintf(stderr, "(afm-main-plugin) %s(true) -> %s\n", method,
85                         obj ? json_object_to_json_string(obj) : "NULL");
86         if (obj == NULL) {
87                 afb_req_fail(request, "failed", "framework daemon failure");
88                 return;
89         }
90         obj = embed(method, obj);
91         if (obj == NULL) {
92                 afb_req_fail(request, "failed", "framework daemon failure");
93                 return;
94         }
95         afb_req_success(request, obj, NULL);
96 }
97
98 static void call_appid(struct afb_req request, const char *method)
99 {
100         struct json_object *obj;
101         char *sid;
102         const char *id = afb_req_value(request, _id_);
103         if (id == NULL) {
104                 afb_req_fail(request, "bad-request", "missing 'id'");
105                 return;
106         }
107         if (asprintf(&sid, "\"%s\"", id) <= 0) {
108                 afb_req_fail(request, "server-error", "out of memory");
109                 return;
110         }
111         obj = jbus_call_sj_sync(jbus, method, sid);
112         if (interface->verbosity)
113                 fprintf(stderr, "(afm-main-plugin) %s(%s) -> %s\n", method, sid,
114                         obj ? json_object_to_json_string(obj) : "NULL");
115         free(sid);
116         if (obj == NULL) {
117                 afb_req_fail(request, "failed", "framework daemon failure");
118                 return;
119         }
120         afb_req_success(request, obj, NULL);
121 }
122
123 static void call_runid(struct afb_req request, const char *method)
124 {
125         struct json_object *obj;
126         const char *id = afb_req_value(request, _runid_);
127         if (id == NULL) {
128                 afb_req_fail(request, "bad-request", "missing 'runid'");
129                 return;
130         }
131         obj = jbus_call_sj_sync(jbus, method, id);
132         if (interface->verbosity)
133                 fprintf(stderr, "(afm-main-plugin) %s(%s) -> %s\n", method, id,
134                                 obj ? json_object_to_json_string(obj) : "NULL");
135         if (obj == NULL) {
136                 afb_req_fail(request, "failed", "framework daemon failure");
137                 return;
138         }
139         afb_req_success(request, obj, NULL);
140 }
141
142
143 /************************** entries ******************************/
144
145 static void runnables(struct afb_req request)
146 {
147         embed_call_void(request, _runnables_);
148 }
149
150 static void detail(struct afb_req request)
151 {
152         call_appid(request, _detail_);
153 }
154
155 static void start(struct afb_req request)
156 {
157         struct json_object *obj;
158         const char *id, *mode;
159         char *query;
160         int rc;
161
162         /* get the id */
163         id = afb_req_value(request, _id_);
164         if (id == NULL) {
165                 afb_req_fail(request, "bad-request", "missing 'id'");
166                 return;
167         }
168         /* get the mode */
169         mode = afb_req_value(request, _mode_);
170         if (mode == NULL || !strcmp(mode, _auto_)) {
171                 mode = interface->mode == AFB_MODE_REMOTE ? _remote_ : _local_;
172         }
173
174         /* create the query */
175         rc = asprintf(&query, "{\"id\":\"%s\",\"mode\":\"%s\"}", id, mode);
176         if (rc < 0) {
177                 afb_req_fail(request, "server-error", "out of memory");
178                 return;
179         }
180
181         /* calls the service */
182         obj = jbus_call_sj_sync(jbus, _start_, query);
183         if (interface->verbosity)
184                 fprintf(stderr, "(afm-main-plugin) start(%s) -> %s\n", query,
185                         obj ? json_object_to_json_string(obj) : "NULL");
186         free(query);
187
188         /* check status */
189         if (obj == NULL) {
190                 afb_req_fail(request, "failed", "framework daemon failure");
191                 return;
192         }
193
194         /* embed if needed */
195         if (json_object_get_type(obj) == json_type_int)
196                 obj = embed(_runid_, obj);
197         afb_req_success(request, obj, NULL);
198 }
199
200 static void terminate(struct afb_req request)
201 {
202         call_runid(request, _terminate_);
203 }
204
205 static void stop(struct afb_req request)
206 {
207         call_runid(request, _stop_);
208 }
209
210 static void continue_(struct afb_req request)
211 {
212         call_runid(request, _continue_);
213 }
214
215 static void runners(struct afb_req request)
216 {
217         embed_call_void(request, _runners_);
218 }
219
220 static void state(struct afb_req request)
221 {
222         call_runid(request, _state_);
223 }
224
225 static void install(struct afb_req request)
226 {
227         struct json_object *obj;
228         char *query;
229         const char *filename;
230         struct afb_arg arg;
231
232         /* get the argument */
233         arg = afb_req_get(request, "widget");
234         filename = arg.path;
235         if (filename == NULL) {
236                 afb_req_fail(request, "bad-request", "missing 'widget' file");
237                 return;
238         }
239
240         /* makes the query */
241         if (0 >= asprintf(&query, "\"%s\"", filename)) {
242                 afb_req_fail(request, "server-error", "out of memory");
243                 return;
244         }
245
246         obj = jbus_call_sj_sync(jbus, _install_, query);
247         if (interface->verbosity)
248                 fprintf(stderr, "(afm-main-plugin) install(%s) -> %s\n", query,
249                         obj ? json_object_to_json_string(obj) : "NULL");
250         free(query);
251
252         /* check status */
253         if (obj == NULL) {
254                 afb_req_fail(request, "failed", "framework daemon failure");
255                 return;
256         }
257
258         /* embed if needed */
259         obj = embed(_id_, obj);
260         afb_req_success(request, obj, NULL);
261 }
262
263 static void uninstall(struct afb_req request)
264 {
265         call_appid(request, _uninstall_);
266 }
267
268 static const struct AFB_restapi plug_apis[] =
269 {
270         {_runnables_, AFB_SESSION_CHECK, runnables,  "Get list of runnable applications"},
271         {_detail_   , AFB_SESSION_CHECK, detail, "Get the details for one application"},
272         {_start_    , AFB_SESSION_CHECK, start, "Start an application"},
273         {_terminate_, AFB_SESSION_CHECK, terminate, "Terminate a running application"},
274         {_stop_     , AFB_SESSION_CHECK, stop, "Stop (pause) a running application"},
275         {_continue_ , AFB_SESSION_CHECK, continue_, "Continue (resume) a stopped application"},
276         {_runners_  , AFB_SESSION_CHECK, runners,  "Get the list of running applications"},
277         {_state_    , AFB_SESSION_CHECK, state, "Get the state of a running application"},
278         {_install_  , AFB_SESSION_CHECK, install,  "Install an application using a widget file"},
279         {_uninstall_, AFB_SESSION_CHECK, uninstall, "Uninstall an application"},
280         { NULL, 0, NULL, NULL }
281 };
282
283 static const struct AFB_plugin plug_desc = {
284         .type = AFB_PLUGIN_JSON,
285         .info = "Application Framework Master Service",
286         .prefix = "afm-main",
287         .apis = plug_apis
288 };
289
290 static struct sbus_itf sbusitf;
291
292 const struct AFB_plugin *pluginRegister(const struct AFB_interface *itf)
293 {
294         int rc;
295         struct afb_pollmgr pollmgr;
296         struct sbus *sbus;
297
298         /* records the interface */
299         assert (interface == NULL);
300         interface = itf;
301         evmgr = afb_daemon_get_evmgr(itf->daemon);
302
303         /* creates the sbus for session */
304         pollmgr = afb_daemon_get_pollmgr(itf->daemon);
305         sbusitf.wait = pollmgr.itf->wait;
306         sbusitf.open = pollmgr.itf->open;
307         sbusitf.on_readable = pollmgr.itf->on_readable;
308         sbusitf.on_writable = pollmgr.itf->on_writable;
309         sbusitf.on_hangup = pollmgr.itf->on_hangup;
310         sbusitf.close = pollmgr.itf->close;
311         sbus = sbus_session(&sbusitf, pollmgr.closure);
312         if (sbus == NULL) {
313                 fprintf(stderr, "ERROR: %s:%d: can't connect to DBUS session\n", __FILE__, __LINE__);
314                 return NULL;
315         }
316
317         /* creates the jbus for accessing afm-user-daemon */
318         jbus = create_jbus(sbus, "/org/AGL/afm/user");
319         if (jbus == NULL) {
320                 sbus_unref(sbus);
321                 return NULL;
322         }
323
324         /* records the signal handler */
325         rc = jbus_on_signal_s(jbus, _changed_, application_list_changed, NULL);
326         if (rc < 0) {
327                 jbus_unref(jbus);
328                 return NULL;
329         }
330
331         return &plug_desc;
332 }
333