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