2 * Copyright (C) 2016, 2017 "IoT.bzh"
3 * Author: José Bollo <jose.bollo@iot.bzh>
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include <json-c/json.h>
26 #include <afb/afb-binding-v1.h>
27 #include <afb/afb-binding-v2.h>
29 #include "afb-session.h"
30 #include "afb-context.h"
32 #include "afb-msg-json.h"
36 #include "afb-apiset.h"
41 * Structure for recording service
45 /* session of the service */
46 struct afb_session *session;
48 /* the apiset for the service */
49 struct afb_apiset *apiset;
51 /* event listener of the service or NULL */
52 struct afb_evt_listener *listener;
54 /* on event callback for the service */
55 void (*on_event)(const char *event, struct json_object *object);
59 * Structure for requests initiated by the service
68 void (*callback)(void*, int, struct json_object*);
72 struct jobloop *jobloop;
73 struct json_object *result;
77 /* functions for services */
78 static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object);
79 static void svc_call(void *closure, const char *api, const char *verb, struct json_object *args,
80 void (*callback)(void*, int, struct json_object*), void *cbclosure);
81 static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
82 struct json_object **result);
84 /* the interface for services */
85 static const struct afb_service_itf service_itf = {
87 .call_sync = svc_call_sync
90 /* the interface for events */
91 static const struct afb_evt_itf evt_itf = {
92 .broadcast = svc_on_event,
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);
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
106 /* the common session for services sharing their session */
107 static struct afb_session *common_session;
109 static inline struct afb_service to_afb_service(struct afb_svc *svc)
111 return (struct afb_service){ .itf = &service_itf, .closure = svc };
117 static void svc_free(struct afb_svc *svc)
119 if (svc->listener != NULL)
120 afb_evt_listener_unref(svc->listener);
122 afb_session_unref(svc->session);
123 afb_apiset_unref(svc->apiset);
128 * Allocates a new service
130 static struct afb_svc *afb_svc_alloc(
131 struct afb_apiset *apiset,
137 /* allocates the svc handler */
138 svc = calloc(1, sizeof * svc);
144 /* instanciate the apiset */
145 svc->apiset = afb_apiset_addref(apiset);
147 /* instanciate the session */
149 /* session shared with other svcs */
150 if (common_session == NULL) {
151 common_session = afb_session_create (NULL, 0);
152 if (common_session == NULL)
155 svc->session = afb_session_addref(common_session);
157 /* session dedicated to the svc */
158 svc->session = afb_session_create (NULL, 0);
159 if (svc->session == NULL)
171 * Creates a new service
173 struct afb_svc *afb_svc_create_v1(
174 struct afb_apiset *apiset,
176 int (*start)(struct afb_service service),
177 void (*on_event)(const char *event, struct json_object *object)
183 /* allocates the svc handler */
184 svc = afb_svc_alloc(apiset, share_session);
188 /* initialises the listener if needed */
190 svc->on_event = on_event;
191 svc->listener = afb_evt_listener_create(&evt_itf, svc);
192 if (svc->listener == NULL)
196 /* initialises the svc now */
197 rc = start(to_afb_service(svc));
209 * Creates a new service
211 struct afb_svc *afb_svc_create_v2(
212 struct afb_apiset *apiset,
215 void (*on_event)(const char *event, struct json_object *object),
216 struct afb_binding_data_v2 *data
222 /* allocates the svc handler */
223 svc = afb_svc_alloc(apiset, share_session);
226 data->service = to_afb_service(svc);
228 /* initialises the listener if needed */
230 svc->on_event = on_event;
231 svc->listener = afb_evt_listener_create(&evt_itf, svc);
232 if (svc->listener == NULL)
236 /* starts the svc if needed */
251 * Propagates the event to the service
253 static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object)
255 struct afb_svc *svc = closure;
256 svc->on_event(event, object);
257 json_object_put(object);
263 static struct svc_req *svcreq_create(struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
265 struct svc_req *svcreq;
266 size_t lenapi, lenverb;
269 /* allocates the request */
270 lenapi = 1 + strlen(api);
271 lenverb = 1 + strlen(verb);
272 svcreq = malloc(lenapi + lenverb + sizeof *svcreq);
273 if (svcreq != NULL) {
274 /* initialises the request */
275 afb_xreq_init(&svcreq->xreq, &afb_svc_xreq_itf);
276 afb_context_init(&svcreq->xreq.context, svc->session, NULL);
277 svcreq->xreq.context.validated = 1;
278 svcreq->xreq.cred = afb_cred_current();
279 copy = (char*)&svcreq[1];
280 memcpy(copy, api, lenapi);
281 svcreq->xreq.api = copy;
282 copy = ©[lenapi];
283 memcpy(copy, verb, lenverb);
284 svcreq->xreq.verb = copy;
285 svcreq->xreq.listener = svc->listener;
286 svcreq->xreq.json = args;
293 * destroys the svc_req
295 static void svcreq_destroy(struct afb_xreq *xreq)
297 struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq);
299 afb_context_disconnect(&svcreq->xreq.context);
300 json_object_put(svcreq->xreq.json);
301 afb_cred_unref(svcreq->xreq.cred);
305 static void svcreq_sync_leave(struct svc_req *svcreq)
307 struct jobloop *jobloop = svcreq->jobloop;
310 svcreq->jobloop = NULL;
315 static void svcreq_reply(struct afb_xreq *xreq, int iserror, json_object *obj)
317 struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq);
318 if (svcreq->callback) {
319 svcreq->callback(svcreq->closure, iserror, obj);
320 json_object_put(obj);
322 svcreq->iserror = iserror;
323 svcreq->result = obj;
324 svcreq_sync_leave(svcreq);
328 static void svcreq_sync_enter(int signum, void *closure, struct jobloop *jobloop)
330 struct svc_req *svcreq = closure;
333 svcreq->jobloop = jobloop;
334 afb_xreq_process(&svcreq->xreq, svcreq->svc->apiset);
336 svcreq->result = afb_msg_json_internal_error();
338 svcreq_sync_leave(svcreq);
343 * Initiates a call for the service
345 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)
347 struct afb_svc *svc = closure;
348 struct svc_req *svcreq;
349 struct json_object *ierr;
351 /* allocates the request */
352 svcreq = svcreq_create(svc, api, verb, args);
353 if (svcreq == NULL) {
354 ERROR("out of memory");
355 json_object_put(args);
356 ierr = afb_msg_json_internal_error();
357 callback(cbclosure, 1, ierr);
358 json_object_put(ierr);
362 /* initialises the request */
363 svcreq->jobloop = NULL;
364 svcreq->callback = callback;
365 svcreq->closure = cbclosure;
367 /* terminates and frees ressources if needed */
368 afb_xreq_process(&svcreq->xreq, svc->apiset);
371 static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
372 struct json_object **result)
374 struct afb_svc *svc = closure;
375 struct svc_req *svcreq;
378 /* allocates the request */
379 svcreq = svcreq_create(svc, api, verb, args);
380 if (svcreq == NULL) {
381 ERROR("out of memory");
383 json_object_put(args);
384 *result = afb_msg_json_internal_error();
388 /* initialises the request */
389 svcreq->jobloop = NULL;
390 svcreq->callback = NULL;
391 svcreq->result = NULL;
393 afb_xreq_addref(&svcreq->xreq);
394 rc = jobs_enter(NULL, 0, svcreq_sync_enter, svcreq);
395 rc = rc >= 0 && !svcreq->iserror;
396 *result = (rc || svcreq->result) ? svcreq->result : afb_msg_json_internal_error();
397 afb_xreq_unref(&svcreq->xreq);