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