2 * Copyright (C) 2015-2018 "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.
22 #include <json-c/json.h>
24 #define AFB_BINDING_WANT_DYNAPI
25 #define AFB_BINDING_VERSION 0
26 #include <afb/afb-binding.h>
28 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
37 static struct event *events = 0;
39 /* searchs the event of tag */
40 static struct event *event_get(const char *tag)
42 struct event *e = events;
43 while(e && strcmp(e->tag, tag))
48 /* deletes the event of tag */
49 static int event_del(const char *tag)
59 while(*p != e) p = &(*p)->next;
63 afb_eventid_unref(e->eventid);
68 /* creates the event of tag */
69 static int event_add(afb_dynapi *dynapi, const char *tag, const char *name)
78 e = malloc(strlen(tag) + sizeof *e);
83 e->eventid = afb_dynapi_make_eventid(dynapi, name);
84 if (!e->eventid) { free(e); return -1; }
92 static int event_subscribe(afb_request *request, const char *tag)
96 return e ? afb_request_subscribe(request, e->eventid) : -1;
99 static int event_unsubscribe(afb_request *request, const char *tag)
103 return e ? afb_request_unsubscribe(request, e->eventid) : -1;
106 static int event_push(struct json_object *args, const char *tag)
110 return e ? afb_eventid_push(e->eventid, json_object_get(args)) : -1;
113 static int event_broadcast(struct json_object *args, const char *tag)
117 return e ? afb_eventid_broadcast(e->eventid, json_object_get(args)) : -1;
120 // Sample Generic Ping Debug API
121 static void ping(afb_request *request, json_object *jresp, const char *tag)
123 static int pingcount = 0;
124 json_object *query = afb_request_json(request);
125 afb_request_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query));
128 static void pingSample (afb_request *request)
130 ping(request, json_object_new_string ("Some String"), "pingSample");
133 static void pingFail (afb_request *request)
135 afb_request_fail(request, "failed", "Ping Binder Daemon fails");
138 static void pingNull (afb_request *request)
140 ping(request, NULL, "pingNull");
143 static void pingBug (afb_request *request)
145 ping(NULL, NULL, "pingBug");
148 static void pingEvent(afb_request *request)
150 json_object *query = afb_request_json(request);
151 afb_dynapi_broadcast_event(request->api, "event", json_object_get(query));
152 ping(request, json_object_get(query), "event");
156 // For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/
157 static void pingJson (afb_request *request) {
158 json_object *jresp, *embed;
160 jresp = json_object_new_object();
161 json_object_object_add(jresp, "myString", json_object_new_string ("Some String"));
162 json_object_object_add(jresp, "myInt", json_object_new_int (1234));
164 embed = json_object_new_object();
165 json_object_object_add(embed, "subObjString", json_object_new_string ("Some String"));
166 json_object_object_add(embed, "subObjInt", json_object_new_int (5678));
168 json_object_object_add(jresp,"eobj", embed);
170 ping(request, jresp, "pingJson");
173 static void subcallcb (void *closure, int status, json_object *object, afb_request *request)
176 afb_request_fail(request, "failed", json_object_to_json_string(object));
178 afb_request_success(request, json_object_get(object), NULL);
181 static void subcall (afb_request *request)
183 const char *api = afb_request_value(request, "api");
184 const char *verb = afb_request_value(request, "verb");
185 const char *args = afb_request_value(request, "args");
186 json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
189 afb_request_fail(request, "failed", "bad arguments");
191 afb_request_subcall(request, api, verb, object, subcallcb, NULL);
194 static void subcallsync (afb_request *request)
197 const char *api = afb_request_value(request, "api");
198 const char *verb = afb_request_value(request, "verb");
199 const char *args = afb_request_value(request, "args");
200 json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL;
203 afb_request_fail(request, "failed", "bad arguments");
205 rc = afb_request_subcall_sync(request, api, verb, object, &result);
207 afb_request_success(request, result, NULL);
209 afb_request_fail(request, "failed", json_object_to_json_string(result));
210 json_object_put(result);
215 static void eventadd (afb_request *request)
217 const char *tag = afb_request_value(request, "tag");
218 const char *name = afb_request_value(request, "name");
220 pthread_mutex_lock(&mutex);
221 if (tag == NULL || name == NULL)
222 afb_request_fail(request, "failed", "bad arguments");
223 else if (0 != event_add(request->api, tag, name))
224 afb_request_fail(request, "failed", "creation error");
226 afb_request_success(request, NULL, NULL);
227 pthread_mutex_unlock(&mutex);
230 static void eventdel (afb_request *request)
232 const char *tag = afb_request_value(request, "tag");
234 pthread_mutex_lock(&mutex);
236 afb_request_fail(request, "failed", "bad arguments");
237 else if (0 != event_del(tag))
238 afb_request_fail(request, "failed", "deletion error");
240 afb_request_success(request, NULL, NULL);
241 pthread_mutex_unlock(&mutex);
244 static void eventsub (afb_request *request)
246 const char *tag = afb_request_value(request, "tag");
248 pthread_mutex_lock(&mutex);
250 afb_request_fail(request, "failed", "bad arguments");
251 else if (0 != event_subscribe(request, tag))
252 afb_request_fail(request, "failed", "subscription error");
254 afb_request_success(request, NULL, NULL);
255 pthread_mutex_unlock(&mutex);
258 static void eventunsub (afb_request *request)
260 const char *tag = afb_request_value(request, "tag");
262 pthread_mutex_lock(&mutex);
264 afb_request_fail(request, "failed", "bad arguments");
265 else if (0 != event_unsubscribe(request, tag))
266 afb_request_fail(request, "failed", "unsubscription error");
268 afb_request_success(request, NULL, NULL);
269 pthread_mutex_unlock(&mutex);
272 static void eventpush (afb_request *request)
274 const char *tag = afb_request_value(request, "tag");
275 const char *data = afb_request_value(request, "data");
276 json_object *object = data ? json_tokener_parse(data) : NULL;
278 pthread_mutex_lock(&mutex);
280 afb_request_fail(request, "failed", "bad arguments");
281 else if (0 > event_push(object, tag))
282 afb_request_fail(request, "failed", "push error");
284 afb_request_success(request, NULL, NULL);
285 pthread_mutex_unlock(&mutex);
286 json_object_put(object);
289 static void callcb (void *prequest, int status, json_object *object, afb_dynapi *dynapi)
291 afb_request *request = prequest;
293 afb_request_fail(request, "failed", json_object_to_json_string(object));
295 afb_request_success(request, json_object_get(object), NULL);
296 afb_request_unref(request);
299 static void call (afb_request *request)
301 const char *api = afb_request_value(request, "api");
302 const char *verb = afb_request_value(request, "verb");
303 const char *args = afb_request_value(request, "args");
304 json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
307 afb_request_fail(request, "failed", "bad arguments");
309 afb_dynapi_call(request->api, api, verb, object, callcb, afb_request_addref(request));
312 static void callsync (afb_request *request)
315 const char *api = afb_request_value(request, "api");
316 const char *verb = afb_request_value(request, "verb");
317 const char *args = afb_request_value(request, "args");
318 json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL;
321 afb_request_fail(request, "failed", "bad arguments");
323 rc = afb_dynapi_call_sync(request->api, api, verb, object, &result);
325 afb_request_success(request, result, NULL);
327 afb_request_fail(request, "failed", json_object_to_json_string(result));
328 json_object_put(result);
333 static void verbose (afb_request *request)
336 json_object *query = afb_request_json(request), *l;
338 if (json_object_is_type(query,json_type_int))
339 level = json_object_get_int(query);
340 else if (json_object_object_get_ex(query, "level", &l) && json_object_is_type(l, json_type_int))
341 level = json_object_get_int(l);
343 if (!json_object_object_get_ex(query,"message",&l))
346 AFB_REQUEST_VERBOSE(request, level, "verbose called for %s", json_object_get_string(l));
347 afb_request_success(request, NULL, NULL);
350 static void exitnow (afb_request *request)
353 json_object *query = afb_request_json(request), *l;
355 if (json_object_is_type(query,json_type_int))
356 code = json_object_get_int(query);
357 else if (json_object_object_get_ex(query, "code", &l) && json_object_is_type(l, json_type_int))
358 code = json_object_get_int(l);
360 if (!json_object_object_get_ex(query,"reason",&l))
363 AFB_REQUEST_NOTICE(request, "in phase of exiting with code %d, reason: %s", code, l ? json_object_get_string(l) : "unknown");
364 afb_request_success(request, NULL, NULL);
368 static void broadcast(afb_request *request)
370 const char *tag = afb_request_value(request, "tag");
371 const char *name = afb_request_value(request, "name");
372 const char *data = afb_request_value(request, "data");
373 json_object *object = data ? json_tokener_parse(data) : NULL;
376 pthread_mutex_lock(&mutex);
377 if (0 > event_broadcast(object, tag))
378 afb_request_fail(request, "failed", "broadcast error");
380 afb_request_success(request, NULL, NULL);
381 pthread_mutex_unlock(&mutex);
382 } else if (name != NULL) {
383 if (0 > afb_dynapi_broadcast_event(request->api, name, object))
384 afb_request_fail(request, "failed", "broadcast error");
386 afb_request_success(request, NULL, NULL);
388 afb_request_fail(request, "failed", "bad arguments");
390 json_object_put(object);
393 static void hasperm (afb_request *request)
395 const char *perm = afb_request_value(request, "perm");
396 if (afb_request_has_permission(request, perm))
397 afb_request_success_f(request, NULL, "permission %s granted", perm?:"(null)");
399 afb_request_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)");
402 static void appid (afb_request *request)
404 char *aid = afb_request_get_application_id(request);
405 afb_request_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?");
409 static int init(afb_dynapi *dynapi)
411 AFB_DYNAPI_NOTICE(dynapi, "dynamic binding AVE(%s) starting", (const char*)dynapi->userdata);
415 static void onevent(afb_dynapi *dynapi, const char *event, struct json_object *object)
417 AFB_DYNAPI_NOTICE(dynapi, "received event %s(%s) by AVE(%s)",
418 event, json_object_to_json_string(object),
419 (const char*)afb_dynapi_get_userdata(dynapi));
422 // NOTE: this sample does not use session to keep test a basic as possible
423 // in real application most APIs should be protected with AFB_SESSION_CHECK
424 static const struct {
426 void (*callback)(afb_request*); } verbs[] =
428 { .verb="ping", .callback=pingSample },
429 { .verb="pingfail", .callback=pingFail },
430 { .verb="pingnull", .callback=pingNull },
431 { .verb="pingbug", .callback=pingBug },
432 { .verb="pingJson", .callback=pingJson },
433 { .verb="pingevent", .callback=pingEvent },
434 { .verb="subcall", .callback=subcall },
435 { .verb="subcallsync", .callback=subcallsync },
436 { .verb="eventadd", .callback=eventadd },
437 { .verb="eventdel", .callback=eventdel },
438 { .verb="eventsub", .callback=eventsub },
439 { .verb="eventunsub", .callback=eventunsub },
440 { .verb="eventpush", .callback=eventpush },
441 { .verb="call", .callback=call },
442 { .verb="callsync", .callback=callsync },
443 { .verb="verbose", .callback=verbose },
444 { .verb="broadcast", .callback=broadcast },
445 { .verb="hasperm", .callback=hasperm },
446 { .verb="appid", .callback=appid },
447 { .verb="exit", .callback=exitnow },
451 static void pingoo(struct afb_req_x1 req)
453 json_object *args = afb_req_x1_json(req);
454 afb_req_x1_reply_f(req, json_object_get(args), NULL, "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args));
457 static const struct afb_verb_v2 verbsv2[]= {
458 { .verb="pingoo", .callback=pingoo },
459 { .verb="ping", .callback=pingoo },
463 static const char *apis[] = { "ave", "hi", "salut", NULL };
465 static int build_api(void *closure, afb_dynapi *dynapi)
469 afb_dynapi_set_userdata(dynapi, closure);
470 AFB_DYNAPI_NOTICE(dynapi, "dynamic binding AVE(%s) comes to live", (const char*)afb_dynapi_get_userdata(dynapi));
471 afb_dynapi_on_init(dynapi, init);
472 afb_dynapi_on_event(dynapi, onevent);
474 rc = afb_dynapi_set_verbs_v2(dynapi, verbsv2);
475 for (i = rc = 0; verbs[i].verb && rc >= 0 ; i++) {
476 rc = afb_dynapi_add_verb(dynapi, verbs[i].verb, NULL, verbs[i].callback, (void*)(intptr_t)i, NULL, 0);
478 afb_dynapi_seal(dynapi);
482 int afbBindingVdyn(afb_dynapi *dynapi)
486 for (i = 0; apis[i] ; i++) {
487 rc = afb_dynapi_new_api(dynapi, apis[i], NULL, 0, build_api, (void*)apis[i]);
489 AFB_DYNAPI_ERROR(dynapi, "can't create API %s", apis[i]);