Prepare bindings version 2
[src/app-framework-binder.git] / src / afb-svc.c
1 /*
2  * Copyright (C) 2016, 2017 "IoT.bzh"
3  * Author: José Bollo <jose.bollo@iot.bzh>
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
19
20 #include <stdlib.h>
21 #include <errno.h>
22
23 #include <json-c/json.h>
24
25 #include <afb/afb-req-itf.h>
26 #include <afb/afb-service-itf.h>
27
28 #include "afb-session.h"
29 #include "afb-context.h"
30 #include "afb-evt.h"
31 #include "afb-msg-json.h"
32 #include "afb-svc.h"
33 #include "afb-xreq.h"
34 #include "afb-cred.h"
35 #include "afb-apiset.h"
36 #include "afb-ditf.h"
37 #include "verbose.h"
38
39 /*
40  * Structure for recording service
41  */
42 struct afb_svc
43 {
44         /* session of the service */
45         struct afb_session *session;
46
47         /* the apiset for the service */
48         struct afb_apiset *apiset;
49
50         /* event listener of the service or NULL */
51         struct afb_evt_listener *listener;
52
53         /* on event callback for the service */
54         union {
55                 void (*on_event_v1)(const char *event, struct json_object *object);
56                 void (*on_event_v2)(struct afb_service service, const char *event, struct json_object *object);
57         };
58
59         /* the daemon interface */
60         struct afb_ditf *ditf;
61 };
62
63 /*
64  * Structure for requests initiated by the service
65  */
66 struct svc_req
67 {
68         struct afb_xreq xreq;
69
70         /* the args */
71         void (*callback)(void*, int, struct json_object*);
72         void *closure;
73 };
74
75 /* functions for services */
76 static void svc_on_event_v1(void *closure, const char *event, int eventid, struct json_object *object);
77 static void svc_on_event_v2(void *closure, const char *event, int eventid, struct json_object *object);
78 static void svc_call(void *closure, const char *api, const char *verb, struct json_object *args,
79                                 void (*callback)(void*, int, struct json_object*), void *cbclosure);
80
81 /* the interface for services */
82 static const struct afb_service_itf service_itf = {
83         .call = svc_call
84 };
85
86 /* the interface for events */
87 static const struct afb_evt_itf evt_itf_v1 = {
88         .broadcast = svc_on_event_v1,
89         .push = svc_on_event_v1
90 };
91 static const struct afb_evt_itf evt_itf_v2 = {
92         .broadcast = svc_on_event_v2,
93         .push = svc_on_event_v2
94 };
95
96 /* functions for requests of services */
97 static void svcreq_destroy(struct afb_xreq *xreq);
98 static void svcreq_reply(struct afb_xreq *xreq, int iserror, json_object *obj);
99
100 /* interface for requests of services */
101 const struct afb_xreq_query_itf afb_svc_xreq_itf = {
102         .unref = svcreq_destroy,
103         .reply = svcreq_reply
104 };
105
106 /* the common session for services sharing their session */
107 static struct afb_session *common_session;
108
109 static inline struct afb_service to_afb_service_v1(struct afb_svc *svc)
110 {
111         return (struct afb_service){ .itf = &service_itf, .closure = svc };
112 }
113
114 static inline struct afb_service to_afb_service_v2(struct afb_svc *svc)
115 {
116         return (struct afb_service){ .itf = &service_itf, .closure = svc };
117 }
118
119 /*
120  * Frees a service
121  */
122 static void svc_free(struct afb_svc *svc)
123 {
124         if (svc->listener != NULL)
125                 afb_evt_listener_unref(svc->listener);
126         if (svc->session)
127                 afb_session_unref(svc->session);
128         afb_apiset_unref(svc->apiset);
129         free(svc);
130 }
131
132 /*
133  * Allocates a new service
134  */
135 static struct afb_svc *afb_svc_alloc(
136                         struct afb_apiset *apiset,
137                         int share_session
138 )
139 {
140         struct afb_svc *svc;
141
142         /* allocates the svc handler */
143         svc = calloc(1, sizeof * svc);
144         if (svc == NULL) {
145                 errno = ENOMEM;
146                 return NULL;
147         }
148
149         /* instanciate the apiset */
150         svc->apiset = afb_apiset_addref(apiset);
151
152         /* instanciate the session */
153         if (share_session) {
154                 /* session shared with other svcs */
155                 if (common_session == NULL) {
156                         common_session = afb_session_create (NULL, 0);
157                         if (common_session == NULL)
158                                 goto error;
159                 }
160                 svc->session = afb_session_addref(common_session);
161         } else {
162                 /* session dedicated to the svc */
163                 svc->session = afb_session_create (NULL, 0);
164                 if (svc->session == NULL)
165                         goto error;
166         }
167
168         return svc;
169
170 error:
171         svc_free(svc);
172         return NULL;
173 }
174
175 /*
176  * Creates a new service
177  */
178 struct afb_svc *afb_svc_create_v1(
179                 struct afb_apiset *apiset,
180                 int share_session,
181                 int (*start)(struct afb_service service),
182                 void (*on_event)(const char *event, struct json_object *object)
183 )
184 {
185         int rc;
186         struct afb_svc *svc;
187
188         /* allocates the svc handler */
189         svc = afb_svc_alloc(apiset, share_session);
190         if (svc == NULL)
191                 goto error;
192
193         /* initialises the listener if needed */
194         if (on_event) {
195                 svc->on_event_v1 = on_event;
196                 svc->listener = afb_evt_listener_create(&evt_itf_v1, svc);
197                 if (svc->listener == NULL)
198                         goto error;
199         }
200
201         /* initialises the svc now */
202         rc = start(to_afb_service_v1(svc));
203         if (rc < 0)
204                 goto error;
205
206         return svc;
207
208 error:
209         svc_free(svc);
210         return NULL;
211 }
212
213 /*
214  * Creates a new service
215  */
216 struct afb_svc *afb_svc_create_v2(
217                         struct afb_apiset *apiset,
218                         int share_session,
219                         int (*start)(struct afb_service service),
220                         void (*on_event)(struct afb_service service, const char *event, struct json_object *object),
221                         struct afb_ditf *ditf
222 )
223 {
224         int rc;
225         struct afb_svc *svc;
226
227         /* allocates the svc handler */
228         svc = afb_svc_alloc(apiset, share_session);
229         if (svc == NULL)
230                 goto error;
231         svc->ditf = ditf;
232
233         /* initialises the listener if needed */
234         if (on_event) {
235                 svc->on_event_v2 = on_event;
236                 svc->listener = afb_evt_listener_create(&evt_itf_v2, svc);
237                 if (svc->listener == NULL)
238                         goto error;
239         }
240
241         /* initialises the svc now */
242         rc = start(to_afb_service_v2(svc));
243         if (rc < 0)
244                 goto error;
245
246         return svc;
247
248 error:
249         svc_free(svc);
250         return NULL;
251 }
252
253 /*
254  * Propagates the event to the service
255  */
256 static void svc_on_event_v1(void *closure, const char *event, int eventid, struct json_object *object)
257 {
258         struct afb_svc *svc = closure;
259         svc->on_event_v1(event, object);
260         json_object_put(object);
261 }
262
263 /*
264  * Propagates the event to the service
265  */
266 static void svc_on_event_v2(void *closure, const char *event, int eventid, struct json_object *object)
267 {
268         struct afb_svc *svc = closure;
269         svc->on_event_v2(to_afb_service_v2(svc), event, object);
270         json_object_put(object);
271 }
272
273 /*
274  * Initiates a call for the service
275  */
276 static void svc_call(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cbclosure)
277 {
278         struct afb_svc *svc = closure;
279         struct svc_req *svcreq;
280
281         /* allocates the request */
282         svcreq = calloc(1, sizeof *svcreq);
283         if (svcreq == NULL) {
284                 ERROR("out of memory");
285                 json_object_put(args);
286                 callback(cbclosure, 1, afb_msg_json_internal_error());
287                 return;
288         }
289
290         /* initialises the request */
291         afb_xreq_init(&svcreq->xreq, &afb_svc_xreq_itf);
292         afb_context_init(&svcreq->xreq.context, svc->session, NULL);
293         svcreq->xreq.context.validated = 1;
294         svcreq->xreq.cred = afb_cred_current();
295         svcreq->xreq.api = api;
296         svcreq->xreq.verb = verb;
297         svcreq->xreq.listener = svc->listener;
298         svcreq->xreq.json = args;
299         svcreq->callback = callback;
300         svcreq->closure = cbclosure;
301
302         /* terminates and frees ressources if needed */
303         afb_xreq_process(&svcreq->xreq, svc->apiset);
304 }
305
306 static void svcreq_destroy(struct afb_xreq *xreq)
307 {
308         struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq);
309         afb_context_disconnect(&svcreq->xreq.context);
310         json_object_put(svcreq->xreq.json);
311         afb_cred_unref(svcreq->xreq.cred);
312         free(svcreq);
313 }
314
315 static void svcreq_reply(struct afb_xreq *xreq, int iserror, json_object *obj)
316 {
317         struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq);
318         svcreq->callback(svcreq->closure, iserror, obj);
319         json_object_put(obj);
320 }
321