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"
42 #define HOOK(x,...) if((svc)->hookflags & afb_hook_flag_svc_##x) afb_hook_svc_##x(__VA_ARGS__)
45 * Structure for requests initiated by the service
54 void (*callback)(void*, int, struct json_object*);
58 struct jobloop *jobloop;
59 struct json_object *result;
64 /* functions for services */
65 static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object);
66 static void svc_call(void *closure, const char *api, const char *verb, struct json_object *args,
67 void (*callback)(void*, int, struct json_object*), void *cbclosure);
68 static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
69 struct json_object **result);
71 /* the interface for services */
72 static const struct afb_service_itf service_itf = {
74 .call_sync = svc_call_sync
77 /* the interface for events */
78 static const struct afb_evt_itf evt_itf = {
79 .broadcast = svc_on_event,
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 status, json_object *obj);
87 /* interface for requests of services */
88 const struct afb_xreq_query_itf afb_svc_xreq_itf = {
89 .unref = svcreq_destroy,
93 /* the common session for services sharing their session */
94 static struct afb_session *common_session;
96 static inline struct afb_service to_afb_service(struct afb_svc *svc)
98 return (struct afb_service){ .itf = &service_itf, .closure = svc };
104 void afb_svc_destroy(struct afb_svc *svc, struct afb_service *service)
107 *service = (struct afb_service){ .itf = NULL, .closure = NULL };
109 if (svc->listener != NULL)
110 afb_evt_listener_unref(svc->listener);
112 afb_session_unref(svc->session);
113 afb_apiset_unref(svc->apiset);
119 * Creates a new service
121 struct afb_svc *afb_svc_create(
123 struct afb_apiset *apiset,
125 void (*on_event)(const char *event, struct json_object *object),
126 struct afb_service *service
131 /* allocates the svc handler */
132 svc = calloc(1, sizeof * svc);
138 /* instanciate the apiset */
140 svc->apiset = afb_apiset_addref(apiset);
142 /* instanciate the 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)
150 svc->session = afb_session_addref(common_session);
152 /* session dedicated to the svc */
153 svc->session = afb_session_create (NULL, 0);
154 if (svc->session == NULL)
158 svc->hookflags = afb_hook_flags_svc(svc->api);
160 *service = to_afb_service(svc);
162 /* initialises the listener if needed */
164 svc->on_event = on_event;
165 svc->listener = afb_evt_listener_create(&evt_itf, svc);
166 if (svc->listener == NULL)
173 afb_svc_destroy(svc, service);
178 * Starts a new service (v1)
180 int afb_svc_start_v1(struct afb_svc *svc, int (*start)(struct afb_service))
184 HOOK(start_before, svc);
185 rc = start(to_afb_service(svc));
186 HOOK(start_after, svc, rc);
191 * Starts a new service (v2)
193 int afb_svc_start_v2(struct afb_svc *svc, int (*start)())
197 HOOK(start_before, svc);
199 HOOK(start_after, svc, rc);
204 * Request to updates the hooks
206 void afb_svc_update_hook(struct afb_svc *svc)
208 svc->hookflags = afb_hook_flags_svc(svc->api);
212 * Propagates the event to the service
214 static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object)
216 struct afb_svc *svc = closure;
218 HOOK(on_event_before, svc, event, eventid, object);
219 svc->on_event(event, object);
220 HOOK(on_event_after, svc, event, eventid, object);
221 json_object_put(object);
227 static struct svc_req *svcreq_create(struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
229 struct svc_req *svcreq;
230 size_t lenapi, lenverb;
233 /* allocates the request */
234 lenapi = 1 + strlen(api);
235 lenverb = 1 + strlen(verb);
236 svcreq = malloc(lenapi + lenverb + sizeof *svcreq);
237 if (svcreq != NULL) {
238 /* initialises the request */
239 afb_xreq_init(&svcreq->xreq, &afb_svc_xreq_itf);
240 afb_context_init(&svcreq->xreq.context, svc->session, NULL);
241 svcreq->xreq.context.validated = 1;
242 copy = (char*)&svcreq[1];
243 memcpy(copy, api, lenapi);
244 svcreq->xreq.api = copy;
245 copy = ©[lenapi];
246 memcpy(copy, verb, lenverb);
247 svcreq->xreq.verb = copy;
248 svcreq->xreq.listener = svc->listener;
249 svcreq->xreq.json = args;
256 * destroys the svc_req
258 static void svcreq_destroy(struct afb_xreq *xreq)
260 struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq);
262 afb_context_disconnect(&svcreq->xreq.context);
263 json_object_put(svcreq->xreq.json);
264 afb_cred_unref(svcreq->xreq.cred);
268 static void svcreq_sync_leave(struct svc_req *svcreq)
270 struct jobloop *jobloop = svcreq->jobloop;
273 svcreq->jobloop = NULL;
278 static void svcreq_reply(struct afb_xreq *xreq, int status, json_object *obj)
280 struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq);
282 struct afb_svc *svc = svcreq->svc;
283 if (svcreq->callback)
284 svcreq->callback(svcreq->closure, status, obj);
285 HOOK(call_result, svc, status, obj);
286 json_object_put(obj);
288 svcreq->status = status;
289 svcreq->result = obj;
290 svcreq_sync_leave(svcreq);
294 static void svcreq_sync_enter(int signum, void *closure, struct jobloop *jobloop)
296 struct svc_req *svcreq = closure;
299 svcreq->jobloop = jobloop;
300 afb_xreq_process(&svcreq->xreq, svcreq->svc->apiset);
302 svcreq->result = afb_msg_json_internal_error();
304 svcreq_sync_leave(svcreq);
309 * Initiates a call for the service
311 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)
313 struct afb_svc *svc = closure;
314 struct svc_req *svcreq;
315 struct json_object *ierr;
317 HOOK(call, svc, api, verb, args);
319 /* allocates the request */
320 svcreq = svcreq_create(svc, api, verb, args);
321 if (svcreq == NULL) {
322 ERROR("out of memory");
323 json_object_put(args);
324 ierr = afb_msg_json_internal_error();
326 callback(cbclosure, -1, ierr);
327 HOOK(call_result, svc, -1, ierr);
328 json_object_put(ierr);
332 /* initialises the request */
333 svcreq->jobloop = NULL;
334 svcreq->callback = callback;
335 svcreq->closure = cbclosure;
338 /* terminates and frees ressources if needed */
339 afb_xreq_process(&svcreq->xreq, svc->apiset);
342 static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
343 struct json_object **result)
345 struct afb_svc *svc = closure;
346 struct svc_req *svcreq;
347 struct json_object *resu;
350 HOOK(callsync, svc, api, verb, args);
352 /* allocates the request */
353 svcreq = svcreq_create(svc, api, verb, args);
354 if (svcreq == NULL) {
355 ERROR("out of memory");
357 json_object_put(args);
358 resu = afb_msg_json_internal_error();
361 /* initialises the request */
362 svcreq->jobloop = NULL;
363 svcreq->callback = NULL;
364 svcreq->result = NULL;
367 afb_xreq_addref(&svcreq->xreq);
368 rc = jobs_enter(NULL, 0, svcreq_sync_enter, svcreq);
371 resu = (rc >= 0 || svcreq->result) ? svcreq->result : afb_msg_json_internal_error();
372 afb_xreq_unref(&svcreq->xreq);
374 HOOK(callsync_result, svc, rc, resu);
378 json_object_put(resu);