2 * Copyright (C) 2015-2020 "IoT.bzh"
3 * Author "Fulup Ar Foll"
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.
25 #include <sys/types.h>
28 #include <json-c/json.h>
30 #define AFB_BINDING_VERSION 3
31 #include <afb/afb-binding.h>
34 #define APINAME "hello"
37 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
39 /**************************************************************************/
48 static struct event *events = 0;
50 /* searchs the event of tag */
51 static struct event *event_get(const char *tag)
53 struct event *e = events;
54 while(e && strcmp(e->tag, tag))
59 /* deletes the event of tag */
60 static int event_del(const char *tag)
70 while(*p != e) p = &(*p)->next;
74 afb_event_unref(e->event);
79 /* creates the event of tag */
80 static int event_add(const char *tag, const char *name)
89 e = malloc(strlen(tag) + sizeof *e);
94 e->event = afb_daemon_make_event(name);
95 if (!e->event) { free(e); return -1; }
103 static int event_subscribe(afb_req_t request, const char *tag)
107 return e ? afb_req_subscribe(request, e->event) : -1;
110 static int event_unsubscribe(afb_req_t request, const char *tag)
114 return e ? afb_req_unsubscribe(request, e->event) : -1;
117 static int event_push(struct json_object *args, const char *tag)
121 return e ? afb_event_push(e->event, json_object_get(args)) : -1;
124 static int event_broadcast(struct json_object *args, const char *tag)
128 return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1;
131 /**************************************************************************/
140 static struct api *apis = 0;
142 /* search the api of name */
143 static struct api *searchapi(const char *name, struct api ***previous)
145 struct api *a, **p = &apis;
146 while((a = *p) && strcmp(a->name, name))
153 /**************************************************************************/
155 // Sample Generic Ping Debug API
156 static void ping(afb_req_t request, json_object *jresp, const char *tag)
158 static int pingcount = 0;
159 json_object *query = afb_req_json(request);
160 afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query));
163 static void pingSample (afb_req_t request)
165 ping(request, json_object_new_string ("Some String"), "pingSample");
168 static void pingFail (afb_req_t request)
170 afb_req_fail(request, "failed", "Ping Binder Daemon fails");
173 static void pingNull (afb_req_t request)
175 ping(request, NULL, "pingNull");
178 static void pingBug (afb_req_t request)
180 ping(NULL, NULL, "pingBug");
183 static void pingEvent(afb_req_t request)
185 json_object *query = afb_req_json(request);
186 afb_daemon_broadcast_event("event", json_object_get(query));
187 ping(request, json_object_get(query), "event");
191 // For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/
192 static void pingJson (afb_req_t request) {
193 json_object *jresp, *embed;
195 jresp = json_object_new_object();
196 json_object_object_add(jresp, "myString", json_object_new_string ("Some String"));
197 json_object_object_add(jresp, "myInt", json_object_new_int (1234));
199 embed = json_object_new_object();
200 json_object_object_add(embed, "subObjString", json_object_new_string ("Some String"));
201 json_object_object_add(embed, "subObjInt", json_object_new_int (5678));
203 json_object_object_add(jresp,"eobj", embed);
205 ping(request, jresp, "pingJson");
208 static void subcallcb (void *prequest, int status, json_object *object, afb_req_t request)
211 afb_req_fail(request, "failed", json_object_to_json_string(object));
213 afb_req_success(request, json_object_get(object), NULL);
216 static void subcall (afb_req_t request)
218 const char *api = afb_req_value(request, "api");
219 const char *verb = afb_req_value(request, "verb");
220 const char *args = afb_req_value(request, "args");
221 json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
224 afb_req_fail(request, "failed", "bad arguments");
226 afb_req_subcall_legacy(request, api, verb, object, subcallcb, NULL);
229 static void subcallreqcb (void *prequest, int status, json_object *object, afb_req_t request)
232 afb_req_fail(request, "failed", json_object_to_json_string(object));
234 afb_req_success(request, json_object_get(object), NULL);
237 static void subcallreq (afb_req_t request)
239 const char *api = afb_req_value(request, "api");
240 const char *verb = afb_req_value(request, "verb");
241 const char *args = afb_req_value(request, "args");
242 json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
245 afb_req_fail(request, "failed", "bad arguments");
247 afb_req_subcall_legacy(request, api, verb, object, subcallreqcb, NULL);
250 static void subcallsync (afb_req_t request)
253 const char *api = afb_req_value(request, "api");
254 const char *verb = afb_req_value(request, "verb");
255 const char *args = afb_req_value(request, "args");
256 json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL;
259 afb_req_fail(request, "failed", "bad arguments");
261 rc = afb_req_subcall_sync_legacy(request, api, verb, object, &result);
263 afb_req_success(request, result, NULL);
265 afb_req_fail(request, "failed", json_object_to_json_string(result));
266 json_object_put(result);
271 static void eventadd (afb_req_t request)
273 const char *tag = afb_req_value(request, "tag");
274 const char *name = afb_req_value(request, "name");
276 pthread_mutex_lock(&mutex);
277 if (tag == NULL || name == NULL)
278 afb_req_fail(request, "failed", "bad arguments");
279 else if (0 != event_add(tag, name))
280 afb_req_fail(request, "failed", "creation error");
282 afb_req_success(request, NULL, NULL);
283 pthread_mutex_unlock(&mutex);
286 static void eventdel (afb_req_t request)
288 const char *tag = afb_req_value(request, "tag");
290 pthread_mutex_lock(&mutex);
292 afb_req_fail(request, "failed", "bad arguments");
293 else if (0 != event_del(tag))
294 afb_req_fail(request, "failed", "deletion error");
296 afb_req_success(request, NULL, NULL);
297 pthread_mutex_unlock(&mutex);
300 static void eventsub (afb_req_t request)
302 const char *tag = afb_req_value(request, "tag");
304 pthread_mutex_lock(&mutex);
306 afb_req_fail(request, "failed", "bad arguments");
307 else if (0 != event_subscribe(request, tag))
308 afb_req_fail(request, "failed", "subscription error");
310 afb_req_success(request, NULL, NULL);
311 pthread_mutex_unlock(&mutex);
314 static void eventunsub (afb_req_t request)
316 const char *tag = afb_req_value(request, "tag");
318 pthread_mutex_lock(&mutex);
320 afb_req_fail(request, "failed", "bad arguments");
321 else if (0 != event_unsubscribe(request, tag))
322 afb_req_fail(request, "failed", "unsubscription error");
324 afb_req_success(request, NULL, NULL);
325 pthread_mutex_unlock(&mutex);
328 static void eventpush (afb_req_t request)
330 const char *tag = afb_req_value(request, "tag");
331 const char *data = afb_req_value(request, "data");
332 json_object *object = data ? json_tokener_parse(data) : NULL;
334 pthread_mutex_lock(&mutex);
336 afb_req_fail(request, "failed", "bad arguments");
337 else if (0 > event_push(object, tag))
338 afb_req_fail(request, "failed", "push error");
340 afb_req_success(request, NULL, NULL);
341 pthread_mutex_unlock(&mutex);
342 json_object_put(object);
345 static void callcb (void *prequest, json_object *object, const char *error, const char *info, afb_api_t api)
347 afb_req_t request = prequest;
348 afb_req_reply(request, json_object_get(object), error, info);
349 afb_req_unref(request);
352 static void call (afb_req_t request)
354 const char *api = afb_req_value(request, "api");
355 const char *verb = afb_req_value(request, "verb");
356 const char *args = afb_req_value(request, "args");
357 json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
359 afb_service_call(api, verb, object, callcb, afb_req_addref(request));
362 static void callsync (afb_req_t request)
364 const char *api = afb_req_value(request, "api");
365 const char *verb = afb_req_value(request, "verb");
366 const char *args = afb_req_value(request, "args");
367 json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
371 afb_service_call_sync(api, verb, object, &result, &error, &info);
372 afb_req_reply(request, result, error, info);
377 static void verbose (afb_req_t request)
380 json_object *query = afb_req_json(request), *l;
382 if (json_object_is_type(query,json_type_int))
383 level = json_object_get_int(query);
384 else if (json_object_object_get_ex(query, "level", &l) && json_object_is_type(l, json_type_int))
385 level = json_object_get_int(l);
387 if (!json_object_object_get_ex(query,"message",&l))
390 AFB_REQ_VERBOSE(request, level, "verbose called for %s", json_object_get_string(l));
391 afb_req_success(request, NULL, NULL);
394 static void exitnow (afb_req_t request)
397 json_object *query = afb_req_json(request), *l;
399 if (json_object_is_type(query,json_type_int))
400 code = json_object_get_int(query);
401 else if (json_object_object_get_ex(query, "code", &l) && json_object_is_type(l, json_type_int))
402 code = json_object_get_int(l);
404 if (!json_object_object_get_ex(query,"reason",&l))
407 AFB_REQ_NOTICE(request, "in phase of exiting with code %d, reason: %s", code, l ? json_object_get_string(l) : "unknown");
408 afb_req_success(request, NULL, NULL);
412 static void broadcast(afb_req_t request)
414 const char *tag = afb_req_value(request, "tag");
415 const char *name = afb_req_value(request, "name");
416 const char *data = afb_req_value(request, "data");
417 json_object *object = data ? json_tokener_parse(data) : NULL;
420 pthread_mutex_lock(&mutex);
421 if (0 > event_broadcast(object, tag))
422 afb_req_fail(request, "failed", "broadcast error");
424 afb_req_success(request, NULL, NULL);
425 pthread_mutex_unlock(&mutex);
426 } else if (name != NULL) {
427 if (0 > afb_daemon_broadcast_event(name, json_object_get(object)))
428 afb_req_fail(request, "failed", "broadcast error");
430 afb_req_success(request, NULL, NULL);
432 afb_req_fail(request, "failed", "bad arguments");
434 json_object_put(object);
437 static void hasperm (afb_req_t request)
439 const char *perm = afb_req_value(request, "perm");
440 if (afb_req_has_permission(request, perm))
441 afb_req_success_f(request, NULL, "permission %s granted", perm?:"(null)");
443 afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)");
446 static void appid (afb_req_t request)
448 char *aid = afb_req_get_application_id(request);
449 afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?");
453 static void uid (afb_req_t request)
455 int uid = afb_req_get_uid(request);
456 afb_req_success_f(request, json_object_new_int(uid), "uid is %d", uid);
459 static void closess (afb_req_t request)
461 afb_req_session_close(request);
462 afb_req_reply(request, NULL, NULL, "session closed");
465 static void setloa (afb_req_t request)
467 int loa = json_object_get_int(afb_req_json(request));
468 afb_req_session_set_LOA(request, loa);
469 afb_req_reply_f(request, NULL, NULL, "LOA set to %d", loa);
472 static void ok (afb_req_t request)
474 afb_req_reply_f(request, NULL, NULL, NULL);
477 static void setctx (afb_req_t request)
479 struct json_object *x = afb_req_json(request);
480 afb_req_context(request, (int)(intptr_t)afb_req_get_vcbdata(request), (void*)json_object_get, (void*)json_object_put, x);
481 afb_req_reply(request, json_object_get(x), NULL, "context set");
484 static void getctx (afb_req_t request)
486 struct json_object *x = afb_req_context(request, 0, 0, 0, 0);
487 afb_req_reply(request, json_object_get(x), NULL, "returning the context");
490 static void info (afb_req_t request)
492 afb_req_reply(request, afb_req_get_client_info(request), NULL, NULL);
495 static void eventloop (afb_req_t request)
497 afb_api_t api = afb_req_get_api(request);
498 struct sd_event *ev = afb_api_get_event_loop(api);
499 afb_req_reply(request, NULL, ev ? NULL : "no-event-loop", NULL);
502 static void dbus (afb_req_t request)
504 afb_api_t api = afb_req_get_api(request);
505 json_object *json = afb_req_json(request);
506 struct sd_bus *bus = (json_object_get_boolean(json) ? afb_api_get_system_bus : afb_api_get_user_bus)(api);
507 afb_req_reply(request, NULL, bus ? NULL : "no-bus", NULL);
510 static void replycount (afb_req_t request)
512 json_object *json = afb_req_json(request);
513 int count = json_object_get_int(json);
515 afb_req_reply(request, NULL, NULL, NULL);
518 static void get(afb_req_t request)
520 struct afb_arg arg = afb_req_get(request, "name");
521 const char *name, *value, *path;
523 if (!arg.name || !arg.value)
524 afb_req_reply(request, NULL, "invalid", "the parameter 'name' is missing");
527 value = afb_req_value(request, name);
528 path = afb_req_path(request, name);
529 afb_req_reply_f(request, NULL, NULL, "found for '%s': %s", name, value ?: path ?: "NULL");
533 static void ref(afb_req_t request)
535 afb_req_addref(request);
536 afb_req_reply(request, NULL, NULL, NULL);
537 afb_req_unref(request);
540 static void mute(afb_req_t request)
544 static void mutebug(afb_req_t request)
546 afb_req_addref(request);
549 void queue_cb(int signum, void *arg)
551 afb_req_t request = arg;
552 afb_req_reply(request, NULL, NULL, NULL);
553 afb_req_unref(request);
556 static void queue(afb_req_t request)
558 afb_req_addref(request);
559 afb_api_queue_job(afb_req_get_api(request), queue_cb, request, NULL, 0);
562 static void settings(afb_req_t request)
564 afb_api_t api = afb_req_get_api(request);
565 struct json_object *object = afb_api_settings(api);
566 afb_req_reply(request, json_object_get(object), NULL, NULL);
569 static void rootdir (afb_req_t request)
572 afb_api_t api = afb_req_get_api(request);
573 int fd = afb_api_rootdir_get_fd(api);
574 char buffer[150], root[1025];
575 sprintf(buffer, "/proc/self/fd/%d", fd);
576 s = readlink(buffer, root, sizeof root - 1);
578 afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
581 afb_req_reply(request, json_object_new_string(root), NULL, NULL);
585 static void locale (afb_req_t request)
587 char buffer[150], root[1025];
588 const char *lang, *file;
590 json_object *json = afb_req_json(request), *x;
591 afb_api_t api = afb_req_get_api(request);
595 if (json_object_is_type(json, json_type_string))
596 file = json_object_get_string(json);
598 if (!json_object_object_get_ex(json, "file", &x)) {
599 afb_req_reply(request, NULL, "invalid", "no file");
602 file = json_object_get_string(x);
603 if (json_object_object_get_ex(json, "lang", &x))
604 lang = json_object_get_string(x);
607 fd = afb_api_rootdir_open_locale(api, file, O_RDONLY, lang);
609 afb_req_reply_f(request, NULL, "error", "can't open %s [%s]: %m", file?:"NULL", lang?:"NULL");
611 sprintf(buffer, "/proc/self/fd/%d", fd);
612 s = readlink(buffer, root, sizeof root - 1);
614 afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
617 afb_req_reply(request, json_object_new_string(root), NULL, NULL);
623 static void in_after (afb_req_t request)
632 ty = afb_req_value(request, "type") ?: "call";
633 if (strcmp(ty, "call") && strcmp(ty, "callsync")
634 && strcmp(ty, "subcall") && strcmp(ty, "subcallsync"))
635 return afb_req_reply(request, NULL, "invalid", "bad type");
638 ts = afb_req_value(request, "delay");
640 return afb_req_reply(request, NULL, "invalid", "no delay");
641 td = strtod(ts, &te);
642 if (*te || td < 0 || td > 3e6) /* a month is the biggest accepted */
643 return afb_req_reply(request, NULL, "invalid", "bad delay");
645 /* wait for that time */
647 t.tv_nsec = (long)(1e6 * modf(td, &td));
648 t.tv_sec = (time_t)td;
650 rc = nanosleep(&t, &t);
651 } while (rc != 0 && errno == EINTR);
654 return afb_req_reply(request, NULL, "error", "sleep failed");
658 if (!strcmp(ty, "subcallsync"))
660 else if (!strcmp(ty, "subcall"))
661 subcallsync(request);
662 else if (!strcmp(ty, "callsync"))
668 static void *thread_after (void *closure)
670 afb_req_t request = closure;
672 afb_req_unref(request);
676 static void after (afb_req_t request)
682 afb_req_addref(request);
684 pthread_attr_init(&attr);
685 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
686 rc =pthread_create(&tid, &attr, thread_after, request);
687 pthread_attr_destroy(&attr);
690 afb_req_unref(request);
691 afb_req_reply(request, NULL, "cant-start", NULL);
695 static void api (afb_req_t request);
698 * Definition of an authorization entry
700 static struct afb_auth auths[] = {
707 .type = afb_auth_And,
715 .type = afb_auth_And,
720 .type = afb_auth_LOA,
732 .type = afb_auth_Not,
739 .type = afb_auth_And,
749 .type = afb_auth_Not,
753 .type = afb_auth_Token
756 .type = afb_auth_And,
766 .type = afb_auth_Not,
770 .type = afb_auth_Permission,
779 // NOTE: this sample does not use session to keep test a basic as possible
780 // in real application most APIs should be protected with AFB_SESSION_CHECK
781 static const struct afb_verb_v3 verbs[]= {
782 { .verb="ping", .callback=pingSample },
783 { .verb="pingfail", .callback=pingFail },
784 { .verb="pingnull", .callback=pingNull },
785 { .verb="pingbug", .callback=pingBug },
786 { .verb="pingJson", .callback=pingJson },
787 { .verb="pingevent", .callback=pingEvent },
788 { .verb="subcall", .callback=subcall },
789 { .verb="subcallreq", .callback=subcallreq },
790 { .verb="subcallsync", .callback=subcallsync },
791 { .verb="eventadd", .callback=eventadd },
792 { .verb="eventdel", .callback=eventdel },
793 { .verb="eventsub", .callback=eventsub },
794 { .verb="eventunsub", .callback=eventunsub },
795 { .verb="eventpush", .callback=eventpush },
796 { .verb="call", .callback=call },
797 { .verb="callsync", .callback=callsync },
798 { .verb="verbose", .callback=verbose },
799 { .verb="broadcast", .callback=broadcast },
800 { .verb="hasperm", .callback=hasperm },
801 { .verb="appid", .callback=appid },
802 { .verb="uid", .callback=uid },
803 { .verb="exit", .callback=exitnow },
804 { .verb="close", .callback=closess, .session=AFB_SESSION_CLOSE },
805 { .verb="set-loa", .callback=setloa, .auth = &auths[0] },
806 { .verb="has-loa-1", .callback=ok, .session=AFB_SESSION_LOA_1 },
807 { .verb="has-loa-2", .callback=ok, .session=AFB_SESSION_LOA_2 },
808 { .verb="has-loa-3", .callback=ok, .session=AFB_SESSION_LOA_3 },
809 { .verb="setctx", .callback=setctx, .vcbdata = (void*)(intptr_t)1 },
810 { .verb="setctxif", .callback=setctx, .vcbdata = (void*)(intptr_t)0 },
811 { .verb="getctx", .callback=getctx },
812 { .verb="checktok", .callback=ok, .session=AFB_SESSION_CHECK },
813 { .verb="reftok", .callback=ok, .session=AFB_SESSION_CHECK | AFB_SESSION_REFRESH },
814 { .verb="info", .callback=info },
815 { .verb="eventloop", .callback=eventloop },
816 { .verb="dbus", .callback=dbus },
817 { .verb="reply-count", .callback=replycount },
818 { .verb="get", .callback=get},
819 { .verb="ref", .callback=ref},
820 { .verb="rootdir", .callback=rootdir},
821 { .verb="locale", .callback=locale},
822 { .verb="api", .callback=api},
823 { .verb="mute", .callback=mute},
824 { .verb="mutebug", .callback=mutebug},
825 { .verb="queue", .callback=queue},
826 { .verb="settings", .callback=settings},
827 { .verb="after", .callback=after},
831 static void pingSample2 (struct afb_req_x1 req)
833 pingSample(req.closure);
836 static const struct afb_verb_v2 apiverbs2[]= {
837 { .verb="ping", .callback=pingSample2 },
838 { .verb="ping2", .callback=pingSample2 },
842 static int apipreinit(void *closure, afb_api_t api)
844 afb_api_set_verbs_v2(api, apiverbs2);
845 afb_api_set_verbs_v3(api, verbs);
849 static void apiverb (afb_req_t request)
851 afb_req_reply_f(request, json_object_get(afb_req_json(request)), NULL, "api: %s, verb: %s",
852 afb_req_get_called_api(request), afb_req_get_called_verb(request));
855 static void apievhndl(void *closure, const char *event, struct json_object *args, afb_api_t api)
857 struct json_object *obj = closure;
858 afb_api_verbose(api, 0, NULL, 0, NULL, "the handler of closure(%s) received the event %s(%s)",
859 json_object_get_string(obj), event, json_object_get_string(args));
862 static void api (afb_req_t request)
864 struct api *sapi, **psapi;
865 const char *action, *apiname, *verbname, *pattern;
866 json_object *json = afb_req_json(request), *x, *closure;
867 afb_api_t api = afb_req_get_api(request), oapi;
870 if (!json_object_object_get_ex(json, "action", &x)) {
871 afb_req_reply(request, NULL, "invalid", "no action");
874 action = json_object_get_string(x);
877 verbname = json_object_object_get_ex(json, "verb", &x) ?
878 json_object_get_string(x) : NULL;
880 /* get the pattern */
881 pattern = json_object_object_get_ex(json, "pattern", &x) ?
882 json_object_get_string(x) : NULL;
884 /* get the closure */
886 json_object_object_get_ex(json, "closure", &closure);
889 if (json_object_object_get_ex(json, "api", &x)) {
890 apiname = json_object_get_string(x);
891 sapi = searchapi(apiname, &psapi);
892 oapi = sapi ? sapi->api : NULL;
895 apiname = afb_api_name(api);
896 sapi = searchapi(apiname, &psapi);
899 /* search the sapi */
900 if (!strcasecmp(action, "create")) {
902 afb_req_reply(request, NULL, "invalid", "no api");
906 afb_req_reply(request, NULL, "already-exist", NULL);
909 sapi = malloc (sizeof * sapi + strlen(apiname));
911 afb_req_reply(request, NULL, "out-of-memory", NULL);
914 sapi->api = afb_api_new_api(api, apiname, NULL, 1, apipreinit, NULL);
917 afb_req_reply_f(request, NULL, "cant-create", "%m");
920 strcpy(sapi->name, apiname);
925 afb_req_reply(request, NULL, "cant-find-api", NULL);
928 if (!strcasecmp(action, "destroy")) {
930 afb_req_reply(request, NULL, "cant-destroy", NULL);
933 afb_api_delete_api(oapi);
936 } else if (!strcasecmp(action, "addverb")) {
938 afb_req_reply(request, NULL, "invalid", "no verb");
941 afb_api_add_verb(oapi, verbname, NULL, apiverb, NULL, NULL, 0, !!strchr(verbname, '*'));
942 } else if (!strcasecmp(action, "delverb")) {
944 afb_req_reply(request, NULL, "invalid", "no verb");
947 afb_api_del_verb(oapi, verbname, NULL);
948 } else if (!strcasecmp(action, "addhandler")) {
950 afb_req_reply(request, NULL, "invalid", "no pattern");
953 afb_api_event_handler_add(oapi, pattern, apievhndl, json_object_get(closure));
954 } else if (!strcasecmp(action, "delhandler")) {
956 afb_req_reply(request, NULL, "invalid", "no pattern");
960 afb_api_event_handler_del(oapi, pattern, (void**)&closure);
961 json_object_put(closure);
962 } else if (!strcasecmp(action, "seal")) {
965 afb_req_reply_f(request, NULL, "invalid", "unknown action %s", action ?: "NULL");
969 afb_req_reply(request, NULL, NULL, NULL);
973 /*************************************************************/
975 static int preinit(afb_api_t api)
977 AFB_NOTICE("hello binding comes to live");
978 #if defined(PREINIT_PROVIDE_CLASS)
979 afb_api_provide_class(api, PREINIT_PROVIDE_CLASS);
981 #if defined(PREINIT_REQUIRE_CLASS)
982 afb_api_require_class(api, PREINIT_REQUIRE_CLASS);
987 static int init(afb_api_t api)
989 AFB_NOTICE("hello binding starting");
990 #if defined(INIT_REQUIRE_API)
991 afb_api_require_api(api, INIT_REQUIRE_API, 1);
993 afb_api_add_alias(api, api->apiname, "fakename");
997 static void onevent(afb_api_t api, const char *event, struct json_object *object)
999 AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object));
1002 const struct afb_binding_v3 afbBindingV3 = {
1004 .specification = NULL,