418cc5081789306d3f714ad215fcd1912e606a99
[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  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #define _GNU_SOURCE         /* See feature_test_macros(7) */
20 #include <stdio.h>
21 #include <string.h>
22 #include <json.h>
23
24 #include "afb-plugin.h"
25 #include "afb-req-itf.h"
26 #include "afb-poll-itf.h"
27
28 #include "utils-sbus.h"
29 #include "utils-jbus.h"
30
31 static const char _auto_[]      = "auto";
32 static const char _continue_[]  = "continue";
33 static const char _detail_[]    = "detail";
34 static const char _id_[]        = "id";
35 static const char _install_[]   = "install";
36 static const char _local_[]     = "local";
37 static const char _mode_[]      = "mode";
38 static const char _remote_[]    = "remote";
39 static const char _runid_[]     = "runid";
40 static const char _runnables_[] = "runnables";
41 static const char _runners_[]   = "runners";
42 static const char _start_[]     = "start";
43 static const char _state_[]     = "state";
44 static const char _stop_[]      = "stop";
45 static const char _terminate_[] = "terminate";
46 static const char _uninstall_[] = "uninstall";
47 static const char _uri_[]       = "uri";
48
49 static const struct AFB_interface *interface;
50
51 static struct jbus *jbus;
52
53 static struct json_object *embed(const char *tag, struct json_object *obj)
54 {
55         struct json_object *result;
56
57         if (obj == NULL)
58                 result = NULL;
59         else if (!tag)
60                 result = obj;
61         else {
62                 result = json_object_new_object();
63                 if (result == NULL) {
64                         /* can't embed */
65                         result = obj;
66                 }
67                 else {
68                         /* TODO why is json-c not returning a status? */
69                         json_object_object_add(result, tag, obj);
70                 }
71         }
72         return result;
73 }
74
75 static void embed_call_void(struct afb_req request, const char *method)
76 {
77         struct json_object *obj = jbus_call_sj_sync(jbus, method, "true");
78         if (interface->verbosity)
79                 fprintf(stderr, "(afm-main-plugin) %s(true) -> %s\n", method, obj ? json_object_to_json_string(obj) : "NULL");
80         if (obj == NULL) {
81                 afb_req_fail(request, "failed", "framework daemon failure");
82                 return;
83         }
84         obj = embed(method, obj);
85         if (obj == NULL) {
86                 afb_req_fail(request, "failed", "framework daemon failure");
87                 return;
88         }
89         afb_req_success(request, obj, NULL);
90 }
91
92 static void call_appid(struct afb_req request, const char *method)
93 {
94         struct json_object *obj;
95         char *sid;
96         const char *id = afb_req_value(request, _id_);
97         if (id == NULL) {
98                 afb_req_fail(request, "bad-request", "missing 'id'");
99                 return;
100         }
101         if (asprintf(&sid, "\"%s\"", id) <= 0) {
102                 afb_req_fail(request, "server-error", "out of memory");
103                 return;
104         }
105         obj = jbus_call_sj_sync(jbus, method, sid);
106         if (interface->verbosity)
107                 fprintf(stderr, "(afm-main-plugin) %s(%s) -> %s\n", method, sid, obj ? json_object_to_json_string(obj) : "NULL");
108         free(sid);
109         if (obj == NULL) {
110                 afb_req_fail(request, "failed", "framework daemon failure");
111                 return;
112         }
113         afb_req_success(request, obj, NULL);
114 }
115
116 static void call_runid(struct afb_req request, const char *method)
117 {
118         struct json_object *obj;
119         const char *id = afb_req_value(request, _runid_);
120         if (id == NULL) {
121                 afb_req_fail(request, "bad-request", "missing 'runid'");
122                 return;
123         }
124         obj = jbus_call_sj_sync(jbus, method, id);
125         if (interface->verbosity)
126                 fprintf(stderr, "(afm-main-plugin) %s(%s) -> %s\n", method, id,
127                                 obj ? json_object_to_json_string(obj) : "NULL");
128         if (obj == NULL) {
129                 afb_req_fail(request, "failed", "framework daemon failure");
130                 return;
131         }
132         afb_req_success(request, obj, NULL);
133 }
134
135
136 /************************** entries ******************************/
137
138 static void runnables(struct afb_req request)
139 {
140         embed_call_void(request, _runnables_);
141 }
142
143 static void detail(struct afb_req request)
144 {
145         call_appid(request, _detail_);
146 }
147
148 static void start(struct afb_req request)
149 {
150         struct json_object *obj;
151         const char *id, *mode;
152         char *query;
153         int rc;
154
155         /* get the id */
156         id = afb_req_value(request, _id_);
157         if (id == NULL) {
158                 afb_req_fail(request, "bad-request", "missing 'id'");
159                 return;
160         }
161         /* get the mode */
162         mode = afb_req_value(request, _mode_);
163         if (mode == NULL || !strcmp(mode, _auto_)) {
164                 mode = interface->mode == AFB_MODE_REMOTE ? _remote_ : _local_;
165         }
166
167         /* create the query */
168         rc = asprintf(&query, "{\"id\":\"%s\",\"mode\":\"%s\"}", id, mode);
169         if (rc < 0) {
170                 afb_req_fail(request, "server-error", "out of memory");
171                 return;
172         }
173
174         /* calls the service */
175         obj = jbus_call_sj_sync(jbus, _start_, query);
176         if (interface->verbosity)
177                 fprintf(stderr, "(afm-main-plugin) start(%s) -> %s\n", query, obj ? json_object_to_json_string(obj) : "NULL");
178         free(query);
179
180         /* check status */
181         if (obj == NULL) {
182                 afb_req_fail(request, "failed", "framework daemon failure");
183                 return;
184         }
185
186         /* embed if needed */
187         if (json_object_get_type(obj) == json_type_int)
188                 obj = embed(_runid_, obj);
189         afb_req_success(request, obj, NULL);
190 }
191
192 static void terminate(struct afb_req request)
193 {
194         call_runid(request, _terminate_);
195 }
196
197 static void stop(struct afb_req request)
198 {
199         call_runid(request, _stop_);
200 }
201
202 static void continue_(struct afb_req request)
203 {
204         call_runid(request, _continue_);
205 }
206
207 static void runners(struct afb_req request)
208 {
209         embed_call_void(request, _runners_);
210 }
211
212 static void state(struct afb_req request)
213 {
214         call_runid(request, _state_);
215 }
216
217 static void install(struct afb_req request)
218 {
219         struct json_object *obj;
220         char *query;
221         const char *filename;
222         struct afb_arg arg;
223
224         /* get the argument */
225         arg = afb_req_get(request, "widget");
226         filename = arg.path;
227         if (filename == NULL) {
228                 afb_req_fail(request, "bad-request", "missing 'widget' file");
229                 return;
230         }
231
232         /* makes the query */
233         if (0 >= asprintf(&query, "\"%s\"", filename)) {
234                 afb_req_fail(request, "server-error", "out of memory");
235                 return;
236         }
237
238         obj = jbus_call_sj_sync(jbus, _install_, query);
239         if (interface->verbosity)
240                 fprintf(stderr, "(afm-main-plugin) install(%s) -> %s\n", query, obj ? json_object_to_json_string(obj) : "NULL");
241         free(query);
242
243         /* check status */
244         if (obj == NULL) {
245                 afb_req_fail(request, "failed", "framework daemon failure");
246                 return;
247         }
248
249         /* embed if needed */
250         obj = embed(_id_, obj);
251         afb_req_success(request, obj, NULL);
252 }
253
254 static void uninstall(struct afb_req request)
255 {
256         call_appid(request, _uninstall_);
257 }
258
259 static const struct AFB_restapi plug_apis[] =
260 {
261         {_runnables_, AFB_SESSION_CHECK, runnables,  "Get list of runnable applications"},
262         {_detail_   , AFB_SESSION_CHECK, detail, "Get the details for one application"},
263         {_start_    , AFB_SESSION_CHECK, start, "Start an application"},
264         {_terminate_, AFB_SESSION_CHECK, terminate, "Terminate a running application"},
265         {_stop_     , AFB_SESSION_CHECK, stop, "Stop (pause) a running application"},
266         {_continue_ , AFB_SESSION_CHECK, continue_, "Continue (resume) a stopped application"},
267         {_runners_  , AFB_SESSION_CHECK, runners,  "Get the list of running applications"},
268         {_state_    , AFB_SESSION_CHECK, state, "Get the state of a running application"},
269         {_install_  , AFB_SESSION_CHECK, install,  "Install an application using a widget file"},
270         {_uninstall_, AFB_SESSION_CHECK, uninstall, "Uninstall an application"},
271         { NULL, 0, NULL, NULL }
272 };
273
274 static const struct AFB_plugin plug_desc = {
275         .type = AFB_PLUGIN_JSON,
276         .info = "Application Framework Master Service",
277         .prefix = "afm-main",
278         .apis = plug_apis
279 };
280
281 static struct sbus_itf sbusitf;
282
283 const struct AFB_plugin *pluginRegister(const struct AFB_interface *itf)
284 {
285         struct sbus *sbus;
286
287         if (interface != NULL)
288                 return NULL;
289
290         interface = itf;
291         sbusitf.wait = itf->pollitf->wait;
292         sbusitf.open = itf->pollitf->open;
293         sbusitf.on_readable = itf->pollitf->on_readable;
294         sbusitf.on_writable = itf->pollitf->on_writable;
295         sbusitf.on_hangup = itf->pollitf->on_hangup;
296         sbusitf.close = itf->pollitf->close;
297
298         sbus = sbus_session(&sbusitf, itf->pollclosure);
299         if (sbus == NULL) {
300                 fprintf(stderr, "ERROR: %s:%d: can't connect to DBUS session\n", __FILE__, __LINE__);
301                 return NULL;
302         }
303
304         jbus = create_jbus(sbus, "/org/AGL/afm/user");
305         if (jbus)
306                 return &plug_desc;
307         sbus_unref(sbus);
308         return NULL;
309 }
310