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