2d350df2214dfcd7ad3dafaf1eed702e21223115
[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 <json.h>
22
23 #include "afb-plugin.h"
24 #include "afb-req-itf.h"
25 #include "afb-poll-itf.h"
26
27 #include "utils-sbus.h"
28 #include "utils-jbus.h"
29
30 static const char _auto_[]      = "auto";
31 static const char _continue_[]  = "continue";
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
50 static struct jbus *jbus;
51
52 static struct json_object *embed(const char *tag, struct json_object *obj)
53 {
54         struct json_object *result;
55
56         if (obj == NULL)
57                 result = NULL;
58         else if (!tag)
59                 result = obj;
60         else {
61                 result = json_object_new_object();
62                 if (result == NULL) {
63                         /* can't embed */
64                         result = obj;
65                 }
66                 else {
67                         /* TODO why is json-c not returning a status? */
68                         json_object_object_add(result, tag, obj);
69                 }
70         }
71         return result;
72 }
73
74 static void embed_call_void(struct afb_req request, const char *method)
75 {
76         struct json_object *obj = jbus_call_sj_sync(jbus, method, "true");
77         if (interface->verbosity)
78                 fprintf(stderr, "(afm-main-plugin) %s(true) -> %s\n", method,
79                         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,
108                         obj ? json_object_to_json_string(obj) : "NULL");
109         free(sid);
110         if (obj == NULL) {
111                 afb_req_fail(request, "failed", "framework daemon failure");
112                 return;
113         }
114         afb_req_success(request, obj, NULL);
115 }
116
117 static void call_runid(struct afb_req request, const char *method)
118 {
119         struct json_object *obj;
120         const char *id = afb_req_value(request, _runid_);
121         if (id == NULL) {
122                 afb_req_fail(request, "bad-request", "missing 'runid'");
123                 return;
124         }
125         obj = jbus_call_sj_sync(jbus, method, id);
126         if (interface->verbosity)
127                 fprintf(stderr, "(afm-main-plugin) %s(%s) -> %s\n", method, id,
128                                 obj ? json_object_to_json_string(obj) : "NULL");
129         if (obj == NULL) {
130                 afb_req_fail(request, "failed", "framework daemon failure");
131                 return;
132         }
133         afb_req_success(request, obj, NULL);
134 }
135
136
137 /************************** entries ******************************/
138
139 static void runnables(struct afb_req request)
140 {
141         embed_call_void(request, _runnables_);
142 }
143
144 static void detail(struct afb_req request)
145 {
146         call_appid(request, _detail_);
147 }
148
149 static void start(struct afb_req request)
150 {
151         struct json_object *obj;
152         const char *id, *mode;
153         char *query;
154         int rc;
155
156         /* get the id */
157         id = afb_req_value(request, _id_);
158         if (id == NULL) {
159                 afb_req_fail(request, "bad-request", "missing 'id'");
160                 return;
161         }
162         /* get the mode */
163         mode = afb_req_value(request, _mode_);
164         if (mode == NULL || !strcmp(mode, _auto_)) {
165                 mode = interface->mode == AFB_MODE_REMOTE ? _remote_ : _local_;
166         }
167
168         /* create the query */
169         rc = asprintf(&query, "{\"id\":\"%s\",\"mode\":\"%s\"}", id, mode);
170         if (rc < 0) {
171                 afb_req_fail(request, "server-error", "out of memory");
172                 return;
173         }
174
175         /* calls the service */
176         obj = jbus_call_sj_sync(jbus, _start_, query);
177         if (interface->verbosity)
178                 fprintf(stderr, "(afm-main-plugin) start(%s) -> %s\n", query,
179                         obj ? json_object_to_json_string(obj) : "NULL");
180         free(query);
181
182         /* check status */
183         if (obj == NULL) {
184                 afb_req_fail(request, "failed", "framework daemon failure");
185                 return;
186         }
187
188         /* embed if needed */
189         if (json_object_get_type(obj) == json_type_int)
190                 obj = embed(_runid_, obj);
191         afb_req_success(request, obj, NULL);
192 }
193
194 static void terminate(struct afb_req request)
195 {
196         call_runid(request, _terminate_);
197 }
198
199 static void stop(struct afb_req request)
200 {
201         call_runid(request, _stop_);
202 }
203
204 static void continue_(struct afb_req request)
205 {
206         call_runid(request, _continue_);
207 }
208
209 static void runners(struct afb_req request)
210 {
211         embed_call_void(request, _runners_);
212 }
213
214 static void state(struct afb_req request)
215 {
216         call_runid(request, _state_);
217 }
218
219 static void install(struct afb_req request)
220 {
221         struct json_object *obj;
222         char *query;
223         const char *filename;
224         struct afb_arg arg;
225
226         /* get the argument */
227         arg = afb_req_get(request, "widget");
228         filename = arg.path;
229         if (filename == NULL) {
230                 afb_req_fail(request, "bad-request", "missing 'widget' file");
231                 return;
232         }
233
234         /* makes the query */
235         if (0 >= asprintf(&query, "\"%s\"", filename)) {
236                 afb_req_fail(request, "server-error", "out of memory");
237                 return;
238         }
239
240         obj = jbus_call_sj_sync(jbus, _install_, query);
241         if (interface->verbosity)
242                 fprintf(stderr, "(afm-main-plugin) install(%s) -> %s\n", query,
243                         obj ? json_object_to_json_string(obj) : "NULL");
244         free(query);
245
246         /* check status */
247         if (obj == NULL) {
248                 afb_req_fail(request, "failed", "framework daemon failure");
249                 return;
250         }
251
252         /* embed if needed */
253         obj = embed(_id_, obj);
254         afb_req_success(request, obj, NULL);
255 }
256
257 static void uninstall(struct afb_req request)
258 {
259         call_appid(request, _uninstall_);
260 }
261
262 static const struct AFB_restapi plug_apis[] =
263 {
264         {_runnables_, AFB_SESSION_CHECK, runnables,  "Get list of runnable applications"},
265         {_detail_   , AFB_SESSION_CHECK, detail, "Get the details for one application"},
266         {_start_    , AFB_SESSION_CHECK, start, "Start an application"},
267         {_terminate_, AFB_SESSION_CHECK, terminate, "Terminate a running application"},
268         {_stop_     , AFB_SESSION_CHECK, stop, "Stop (pause) a running application"},
269         {_continue_ , AFB_SESSION_CHECK, continue_, "Continue (resume) a stopped application"},
270         {_runners_  , AFB_SESSION_CHECK, runners,  "Get the list of running applications"},
271         {_state_    , AFB_SESSION_CHECK, state, "Get the state of a running application"},
272         {_install_  , AFB_SESSION_CHECK, install,  "Install an application using a widget file"},
273         {_uninstall_, AFB_SESSION_CHECK, uninstall, "Uninstall an application"},
274         { NULL, 0, NULL, NULL }
275 };
276
277 static const struct AFB_plugin plug_desc = {
278         .type = AFB_PLUGIN_JSON,
279         .info = "Application Framework Master Service",
280         .prefix = "afm-main",
281         .apis = plug_apis
282 };
283
284 static struct sbus_itf sbusitf;
285
286 const struct AFB_plugin *pluginRegister(const struct AFB_interface *itf)
287 {
288         struct sbus *sbus;
289
290         /* records the interface */
291         assert (interface == NULL);
292
293         /* creates the sbus for session */
294         sbusitf.wait = itf->pollitf->wait;
295         sbusitf.open = itf->pollitf->open;
296         sbusitf.on_readable = itf->pollitf->on_readable;
297         sbusitf.on_writable = itf->pollitf->on_writable;
298         sbusitf.on_hangup = itf->pollitf->on_hangup;
299         sbusitf.close = itf->pollitf->close;
300         sbus = sbus_session(&sbusitf, itf->pollclosure);
301         if (sbus == NULL) {
302                 fprintf(stderr, "ERROR: %s:%d: can't connect to DBUS session\n", __FILE__, __LINE__);
303                 return NULL;
304         }
305
306         /* creates the jbus for accessing afm-user-daemon */
307         jbus = create_jbus(sbus, "/org/AGL/afm/user");
308         if (jbus == NULL) {
309                 sbus_unref(sbus);
310                 return NULL;
311         }
312
313         
314         return &plug_desc;
315 }
316