From 4521c1e7ae5371ab9d639adc617d17fb4e8ded0c Mon Sep 17 00:00:00 2001 From: José Bollo Date: Mon, 9 Apr 2018 18:16:07 +0200 Subject: api-v3: First draft MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces the bindings v3 API for bindings. The documentation has still to be improved and will come very soon. Change-Id: I8f9007370e29f671fdfd1da87fff7372a17db7af Signed-off-by: José Bollo --- bindings/samples/AuthLogin.c | 41 ++-- bindings/samples/CMakeLists.txt | 24 ++ bindings/samples/DemoContext.c | 83 +++---- bindings/samples/DemoPost.c | 43 ++-- bindings/samples/HelloWorld.c | 113 ++++------ bindings/samples/ave.c | 19 +- bindings/samples/hello3.c | 486 ++++++++++++++++++++++++++++++++++++++++ bindings/samples/hi3.c | 485 +++++++++++++++++++++++++++++++++++++++ bindings/samples/tic-tac-toe.c | 237 ++++++++++---------- 9 files changed, 1230 insertions(+), 301 deletions(-) create mode 100644 bindings/samples/hello3.c create mode 100644 bindings/samples/hi3.c (limited to 'bindings/samples') diff --git a/bindings/samples/AuthLogin.c b/bindings/samples/AuthLogin.c index a71f7d6e..0f29dd0d 100644 --- a/bindings/samples/AuthLogin.c +++ b/bindings/samples/AuthLogin.c @@ -19,7 +19,7 @@ #include #include -#define AFB_BINDING_VERSION 1 +#define AFB_BINDING_VERSION 3 #include // Dummy sample of Client Application Context @@ -37,7 +37,7 @@ static void clientContextFree(void *context) { } // Request Creation of new context if it does not exist -static void clientContextConnect (struct afb_req request) +static void clientContextConnect (afb_req_t request) { json_object *jresp; @@ -56,7 +56,7 @@ static void clientContextConnect (struct afb_req request) } // Before entering here token will be check and renew -static void clientContextRefresh (struct afb_req request) { +static void clientContextRefresh (afb_req_t request) { json_object *jresp; @@ -68,7 +68,7 @@ static void clientContextRefresh (struct afb_req request) { // Session token will we verified before entering here -static void clientContextCheck (struct afb_req request) { +static void clientContextCheck (afb_req_t request) { json_object *jresp = json_object_new_object(); json_object_object_add(jresp, "isvalid", json_object_new_boolean (TRUE)); @@ -78,7 +78,7 @@ static void clientContextCheck (struct afb_req request) { // Close and Free context -static void clientContextLogout (struct afb_req request) { +static void clientContextLogout (afb_req_t request) { json_object *jresp; /* after this call token will be reset @@ -95,7 +95,7 @@ static void clientContextLogout (struct afb_req request) { afb_req_session_set_LOA(request, 0); } // Close and Free context -static void clientGetPing (struct afb_req request) { +static void clientGetPing (afb_req_t request) { static int count=0; json_object *jresp; @@ -106,25 +106,18 @@ static void clientGetPing (struct afb_req request) { } -static const struct afb_verb_desc_v1 verbs[]= { - {"ping" , AFB_SESSION_NONE , clientGetPing ,"Ping Rest Test Service"}, - {"connect" , AFB_SESSION_LOA_EQ_0 | AFB_SESSION_RENEW, clientContextConnect,"Connect/Login Client"}, - {"refresh" , AFB_SESSION_LOA_GE_1 | AFB_SESSION_RENEW, clientContextRefresh,"Refresh Client Authentication Token"}, - {"check" , AFB_SESSION_LOA_GE_1 , clientContextCheck ,"Check Client Authentication Token"}, - {"logout" , AFB_SESSION_LOA_GE_1 | AFB_SESSION_CLOSE, clientContextLogout ,"Logout Client and Free resources"}, +static const struct afb_verb_v3 verbs[]= { + {.verb="ping" , .session=AFB_SESSION_NONE , .callback=clientGetPing ,.info="Ping Rest Test Service"}, + {.verb="connect" , .session=AFB_SESSION_LOA_0 | AFB_SESSION_RENEW, .callback=clientContextConnect,.info="Connect/Login Client"}, + {.verb="refresh" , .session=AFB_SESSION_LOA_1 | AFB_SESSION_RENEW, .callback=clientContextRefresh,.info="Refresh Client Authentication Token"}, + {.verb="check" , .session=AFB_SESSION_LOA_1 , .callback=clientContextCheck ,.info="Check Client Authentication Token"}, + {.verb="logout" , .session=AFB_SESSION_LOA_1 | AFB_SESSION_CLOSE, .callback=clientContextLogout ,.info="Logout Client and Free resources"}, {NULL} }; -static const struct afb_binding plugin_desc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "Application Framework Binder Authentication sample", - .prefix = "auth", - .verbs = verbs - } -}; - -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) +const struct afb_binding_v3 afbBindingV3 = { - return &plugin_desc; -} + .api = "auth", /* the API name (or binding name or prefix) */ + .info = "Application Framework Binder Authentication sample", /* short description of of the binding */ + .verbs = verbs /* the array describing the verbs of the API */ +}; diff --git a/bindings/samples/CMakeLists.txt b/bindings/samples/CMakeLists.txt index f596c333..d4e85e30 100644 --- a/bindings/samples/CMakeLists.txt +++ b/bindings/samples/CMakeLists.txt @@ -91,3 +91,27 @@ TARGET_LINK_LIBRARIES(tic-tac-toe ${link_libraries}) INSTALL(TARGETS tic-tac-toe LIBRARY DESTINATION ${binding_install_dir}) +################################################## +# hi3 +################################################## +ADD_LIBRARY(hi3 MODULE hi3.c) +SET_TARGET_PROPERTIES(hi3 PROPERTIES + PREFIX "" + LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map" +) +TARGET_LINK_LIBRARIES(hi3 ${link_libraries}) +INSTALL(TARGETS hi3 + LIBRARY DESTINATION ${binding_install_dir}) + +################################################## +# hello3 +################################################## +ADD_LIBRARY(hello3 MODULE hello3.c) +SET_TARGET_PROPERTIES(hello3 PROPERTIES + PREFIX "" + LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map" +) +TARGET_LINK_LIBRARIES(hello3 ${link_libraries}) +INSTALL(TARGETS hello3 + LIBRARY DESTINATION ${binding_install_dir}) + diff --git a/bindings/samples/DemoContext.c b/bindings/samples/DemoContext.c index bf35ab17..09f1764e 100644 --- a/bindings/samples/DemoContext.c +++ b/bindings/samples/DemoContext.c @@ -19,7 +19,7 @@ #include #include -#define AFB_BINDING_VERSION 1 +#define AFB_BINDING_VERSION 3 #include typedef struct { @@ -48,7 +48,7 @@ typedef struct { // This function is call at session open time. Any client trying to // call it with an already open session will be denied. // Ex: http://localhost:1234/api/context/create?token=123456789 -static void myCreate (struct afb_req request) +static void myCreate (afb_req_t request) { MyClientContextT *ctx = malloc (sizeof (MyClientContextT)); @@ -64,7 +64,7 @@ static void myCreate (struct afb_req request) // session timeout a standard renew api is avaliable at /api/token/renew this API // can be called automatically with HTML5 widget. // ex: http://localhost:1234/api/context/action?token=xxxxxx-xxxxxx-xxxxx-xxxxx-xxxxxx -static void myAction (struct afb_req request) +static void myAction (afb_req_t request) { MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request); @@ -81,7 +81,7 @@ static void myAction (struct afb_req request) // created a context [request->context != NULL] every plugins will be notified // that they should free context resources. // ex: http://localhost:1234/api/context/close?token=xxxxxx-xxxxxx-xxxxx-xxxxx-xxxxxx -static void myClose (struct afb_req request) +static void myClose (afb_req_t request) { MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request); @@ -95,75 +95,44 @@ static void myClose (struct afb_req request) } // Set the LOA -static void setLOA(struct afb_req request, unsigned loa) +static void setLOA(afb_req_t request, unsigned loa) { - if (afb_req_session_set_LOA(request, loa)) + if (afb_req_session_set_LOA(request, loa) >= 0) afb_req_success_f(request, NULL, "loa set to %u", loa); else afb_req_fail_f(request, "failed", "can't set loa to %u", loa); } -static void clientSetLOA0(struct afb_req request) +static void clientSetLOA(afb_req_t request) { - setLOA(request, 0); + setLOA(request, (unsigned)(intptr_t)request->vcbdata); } -static void clientSetLOA1(struct afb_req request) -{ - setLOA(request, 1); -} - -static void clientSetLOA2(struct afb_req request) -{ - setLOA(request, 2); -} - -static void clientSetLOA3(struct afb_req request) -{ - setLOA(request, 3); -} - -static void clientCheckLOA(struct afb_req request) +static void clientCheckLOA(afb_req_t request) { afb_req_success(request, NULL, "LOA checked and okay"); } // NOTE: this sample does not use session to keep test a basic as possible // in real application most APIs should be protected with AFB_SESSION_CHECK -static const struct afb_verb_desc_v1 verbs[]= { - {"create", AFB_SESSION_CREATE, myCreate , "Create a new session"}, - {"action", AFB_SESSION_CHECK , myAction , "Use Session Context"}, - {"close" , AFB_SESSION_CLOSE , myClose , "Free Context"}, - {"set_loa_0", AFB_SESSION_RENEW, clientSetLOA0 ,"Set level of assurance to 0"}, - {"set_loa_1", AFB_SESSION_RENEW, clientSetLOA1 ,"Set level of assurance to 1"}, - {"set_loa_2", AFB_SESSION_RENEW, clientSetLOA2 ,"Set level of assurance to 2"}, - {"set_loa_3", AFB_SESSION_RENEW, clientSetLOA3 ,"Set level of assurance to 3"}, - {"check_loa_ge_0", AFB_SESSION_LOA_GE_0, clientCheckLOA ,"Check whether level of assurance is greater or equal to 0"}, - {"check_loa_ge_1", AFB_SESSION_LOA_GE_1, clientCheckLOA ,"Check whether level of assurance is greater or equal to 1"}, - {"check_loa_ge_2", AFB_SESSION_LOA_GE_2, clientCheckLOA ,"Check whether level of assurance is greater or equal to 2"}, - {"check_loa_ge_3", AFB_SESSION_LOA_GE_3, clientCheckLOA ,"Check whether level of assurance is greater or equal to 3"}, - {"check_loa_le_0", AFB_SESSION_LOA_LE_0, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 0"}, - {"check_loa_le_1", AFB_SESSION_LOA_LE_1, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 1"}, - {"check_loa_le_2", AFB_SESSION_LOA_LE_2, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 2"}, - {"check_loa_le_3", AFB_SESSION_LOA_LE_3, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 3"}, - {"check_loa_eq_0", AFB_SESSION_LOA_EQ_0, clientCheckLOA ,"Check whether level of assurance is equal to 0"}, - {"check_loa_eq_1", AFB_SESSION_LOA_EQ_1, clientCheckLOA ,"Check whether level of assurance is equal to 1"}, - {"check_loa_eq_2", AFB_SESSION_LOA_EQ_2, clientCheckLOA ,"Check whether level of assurance is equal to 2"}, - {"check_loa_eq_3", AFB_SESSION_LOA_EQ_3, clientCheckLOA ,"Check whether level of assurance is equal to 3"}, +static const struct afb_verb_v3 verbs[]= { + {.verb="create", .session=AFB_SESSION_NONE, .callback=myCreate , .info="Create a new session"}, + {.verb="action", .session=AFB_SESSION_CHECK , .callback=myAction , .info="Use Session Context"}, + {.verb="close" , .session=AFB_SESSION_CLOSE , .callback=myClose , .info="Free Context"}, + {.verb="set_loa_0", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)0 ,.info="Set level of assurance to 0"}, + {.verb="set_loa_1", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)1 ,.info="Set level of assurance to 1"}, + {.verb="set_loa_2", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)2 ,.info="Set level of assurance to 2"}, + {.verb="set_loa_3", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)3 ,.info="Set level of assurance to 3"}, + {.verb="check_loa_ge_0", .session=AFB_SESSION_LOA_0, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)0 ,.info="Check whether level of assurance is greater or equal to 0"}, + {.verb="check_loa_ge_1", .session=AFB_SESSION_LOA_1, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)1 ,.info="Check whether level of assurance is greater or equal to 1"}, + {.verb="check_loa_ge_2", .session=AFB_SESSION_LOA_2, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)2 ,.info="Check whether level of assurance is greater or equal to 2"}, + {.verb="check_loa_ge_3", .session=AFB_SESSION_LOA_3, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)3 ,.info="Check whether level of assurance is greater or equal to 3"}, {NULL} }; -static const struct afb_binding plugin_desc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "Sample of Client Context Usage", - .prefix = "context", - .verbs = verbs, - } -}; - -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) +const struct afb_binding_v3 afbBindingV3 = { - return &plugin_desc; -} - + .api = "context", /* the API name (or binding name or prefix) */ + .info = "Sample of Client Context Usage", /* short description of of the binding */ + .verbs = verbs /* the array describing the verbs of the API */ +}; diff --git a/bindings/samples/DemoPost.c b/bindings/samples/DemoPost.c index d92d502f..3fd6f983 100644 --- a/bindings/samples/DemoPost.c +++ b/bindings/samples/DemoPost.c @@ -20,12 +20,12 @@ #include #include -#define AFB_BINDING_VERSION 1 +#define AFB_BINDING_VERSION 3 #include // Sample Generic Ping Debug API -static void getPingTest(struct afb_req request) +static void getPingTest(afb_req_t request) { static int pingcount = 0; json_object *query = afb_req_json(request); @@ -34,7 +34,7 @@ static void getPingTest(struct afb_req request) } // With content-type=json data are directly avaliable in request->post->data -static void GetJsonByPost (struct afb_req request) +static void GetJsonByPost (afb_req_t request) { struct afb_arg arg; json_object* jresp; @@ -46,7 +46,7 @@ static void GetJsonByPost (struct afb_req request) } // Upload a file and execute a function when upload is done -static void Uploads (struct afb_req request, const char *destination) +static void Uploads (afb_req_t request, const char *destination) { struct afb_arg a = afb_req_get(request, "file"); if (a.value == NULL || *a.value == 0) @@ -56,20 +56,20 @@ static void Uploads (struct afb_req request, const char *destination) } // Upload a file and execute a function when upload is done -static void UploadAppli (struct afb_req request) +static void UploadAppli (afb_req_t request) { Uploads(request, "applications"); } // Simples Upload case just upload a file -static void UploadMusic (struct afb_req request) +static void UploadMusic (afb_req_t request) { Uploads(request, "musics"); } // PostForm callback is called multiple times (one or each key within form, or once per file buffer) // When file has been fully uploaded call is call with item==NULL -static void UploadImage (struct afb_req request) +static void UploadImage (afb_req_t request) { Uploads(request, "images"); } @@ -77,25 +77,18 @@ static void UploadImage (struct afb_req request) // NOTE: this sample does not use session to keep test a basic as possible // in real application upload-xxx should be protected with AFB_SESSION_CHECK -static const struct afb_verb_desc_v1 verbs[]= { - {"ping" , AFB_SESSION_NONE , getPingTest ,"Ping Rest Test Service"}, - {"upload-json" , AFB_SESSION_NONE , GetJsonByPost ,"Demo for Json Buffer on Post"}, - {"upload-image" , AFB_SESSION_NONE , UploadImage ,"Demo for file upload"}, - {"upload-music" , AFB_SESSION_NONE , UploadMusic ,"Demo for file upload"}, - {"upload-appli" , AFB_SESSION_NONE , UploadAppli ,"Demo for file upload"}, - {NULL} +static const struct afb_verb_v3 verbs[]= { + {.verb="ping" , .session=AFB_SESSION_NONE , .callback=getPingTest ,.info="Ping Rest Test Service"}, + {.verb="upload-json" , .session=AFB_SESSION_NONE , .callback=GetJsonByPost ,.info="Demo for Json Buffer on Post"}, + {.verb="upload-image" , .session=AFB_SESSION_NONE , .callback=UploadImage ,.info="Demo for file upload"}, + {.verb="upload-music" , .session=AFB_SESSION_NONE , .callback=UploadMusic ,.info="Demo for file upload"}, + {.verb="upload-appli" , .session=AFB_SESSION_NONE , .callback=UploadAppli ,.info="Demo for file upload"}, + {.verb=NULL} }; -static const struct afb_binding plugin_desc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "Sample with Post Upload Files", - .prefix = "post", - .verbs = verbs - } +const struct afb_binding_v3 afbBindingV3 = { + .info = "Sample with Post Upload Files", + .api = "post", + .verbs = verbs }; -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) -{ - return &plugin_desc; -}; diff --git a/bindings/samples/HelloWorld.c b/bindings/samples/HelloWorld.c index fef87d2d..92d7c4d2 100644 --- a/bindings/samples/HelloWorld.c +++ b/bindings/samples/HelloWorld.c @@ -21,7 +21,7 @@ #include -#define AFB_BINDING_VERSION 2 +#define AFB_BINDING_VERSION 3 #include static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; @@ -29,7 +29,7 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; struct event { struct event *next; - struct afb_event event; + afb_event_t event; char tag[1]; }; @@ -80,7 +80,7 @@ static int event_add(const char *tag, const char *name) /* make the event */ e->event = afb_daemon_make_event(name); - if (!e->event.closure) { free(e); return -1; } + if (!e->event) { free(e); return -1; } /* link */ e->next = events; @@ -88,14 +88,14 @@ static int event_add(const char *tag, const char *name) return 0; } -static int event_subscribe(afb_req request, const char *tag) +static int event_subscribe(afb_req_t request, const char *tag) { struct event *e; e = event_get(tag); return e ? afb_req_subscribe(request, e->event) : -1; } -static int event_unsubscribe(afb_req request, const char *tag) +static int event_unsubscribe(afb_req_t request, const char *tag) { struct event *e; e = event_get(tag); @@ -117,34 +117,34 @@ static int event_broadcast(struct json_object *args, const char *tag) } // Sample Generic Ping Debug API -static void ping(afb_req request, json_object *jresp, const char *tag) +static void ping(afb_req_t request, json_object *jresp, const char *tag) { static int pingcount = 0; json_object *query = afb_req_json(request); afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query)); } -static void pingSample (afb_req request) +static void pingSample (afb_req_t request) { ping(request, json_object_new_string ("Some String"), "pingSample"); } -static void pingFail (afb_req request) +static void pingFail (afb_req_t request) { afb_req_fail(request, "failed", "Ping Binder Daemon fails"); } -static void pingNull (afb_req request) +static void pingNull (afb_req_t request) { ping(request, NULL, "pingNull"); } -static void pingBug (afb_req request) +static void pingBug (afb_req_t request) { - ping((afb_req){NULL,NULL}, NULL, "pingBug"); + ping(NULL, NULL, "pingBug"); } -static void pingEvent(afb_req request) +static void pingEvent(afb_req_t request) { json_object *query = afb_req_json(request); afb_daemon_broadcast_event("event", json_object_get(query)); @@ -153,7 +153,7 @@ static void pingEvent(afb_req request) // For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/ -static void pingJson (afb_req request) { +static void pingJson (afb_req_t request) { json_object *jresp, *embed; jresp = json_object_new_object(); @@ -169,38 +169,12 @@ static void pingJson (afb_req request) { ping(request, jresp, "pingJson"); } -static void subcallcb (void *prequest, int status, json_object *object) +static void subcallcb (void *closure, json_object *object, const char *error, const char *info, afb_req_t request) { - afb_req request = afb_req_unstore(prequest); - if (status < 0) - afb_req_fail(request, "failed", json_object_to_json_string(object)); - else - afb_req_success(request, json_object_get(object), NULL); - afb_req_unref(request); -} - -static void subcall (afb_req request) -{ - const char *api = afb_req_value(request, "api"); - const char *verb = afb_req_value(request, "verb"); - const char *args = afb_req_value(request, "args"); - json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; - - if (object == NULL) - afb_req_fail(request, "failed", "bad arguments"); - else - afb_req_subcall(request, api, verb, object, subcallcb, afb_req_store(request)); -} - -static void subcallreqcb (void *prequest, int status, json_object *object, afb_req request) -{ - if (status < 0) - afb_req_fail(request, "failed", json_object_to_json_string(object)); - else - afb_req_success(request, json_object_get(object), NULL); + afb_req_reply(request, json_object_get(object), error, info); } -static void subcallreq (afb_req request) +static void subcall (afb_req_t request) { const char *api = afb_req_value(request, "api"); const char *verb = afb_req_value(request, "verb"); @@ -210,10 +184,10 @@ static void subcallreq (afb_req request) if (object == NULL) afb_req_fail(request, "failed", "bad arguments"); else - afb_req_subcall_req(request, api, verb, object, subcallreqcb, NULL); + afb_req_subcall(request, api, verb, object, afb_req_subcall_pass_events, subcallcb, NULL); } -static void subcallsync (afb_req request) +static void subcallsync (afb_req_t request) { int rc; const char *api = afb_req_value(request, "api"); @@ -224,7 +198,7 @@ static void subcallsync (afb_req request) if (object == NULL) afb_req_fail(request, "failed", "bad arguments"); else { - rc = afb_req_subcall_sync(request, api, verb, object, &result); + rc = afb_req_subcall_sync_legacy(request, api, verb, object, &result); if (rc >= 0) afb_req_success(request, result, NULL); else { @@ -234,7 +208,7 @@ static void subcallsync (afb_req request) } } -static void eventadd (afb_req request) +static void eventadd (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); const char *name = afb_req_value(request, "name"); @@ -249,7 +223,7 @@ static void eventadd (afb_req request) pthread_mutex_unlock(&mutex); } -static void eventdel (afb_req request) +static void eventdel (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); @@ -263,7 +237,7 @@ static void eventdel (afb_req request) pthread_mutex_unlock(&mutex); } -static void eventsub (afb_req request) +static void eventsub (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); @@ -277,7 +251,7 @@ static void eventsub (afb_req request) pthread_mutex_unlock(&mutex); } -static void eventunsub (afb_req request) +static void eventunsub (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); @@ -291,7 +265,7 @@ static void eventunsub (afb_req request) pthread_mutex_unlock(&mutex); } -static void eventpush (afb_req request) +static void eventpush (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); const char *data = afb_req_value(request, "data"); @@ -308,9 +282,9 @@ static void eventpush (afb_req request) json_object_put(object); } -static void callcb (void *prequest, int status, json_object *object) +static void callcb (void *prequest, int status, json_object *object, afb_api_t api) { - afb_req request = afb_req_unstore(prequest); + afb_req_t request = prequest; if (status < 0) afb_req_fail(request, "failed", json_object_to_json_string(object)); else @@ -318,7 +292,7 @@ static void callcb (void *prequest, int status, json_object *object) afb_req_unref(request); } -static void call (afb_req request) +static void call (afb_req_t request) { const char *api = afb_req_value(request, "api"); const char *verb = afb_req_value(request, "verb"); @@ -328,10 +302,10 @@ static void call (afb_req request) if (object == NULL) afb_req_fail(request, "failed", "bad arguments"); else - afb_service_call(api, verb, object, callcb, afb_req_store(request)); + afb_service_call(api, verb, object, callcb, afb_req_addref(request)); } -static void callsync (afb_req request) +static void callsync (afb_req_t request) { int rc; const char *api = afb_req_value(request, "api"); @@ -352,7 +326,7 @@ static void callsync (afb_req request) } } -static void verbose (afb_req request) +static void verbose (afb_req_t request) { int level = 5; json_object *query = afb_req_json(request), *l; @@ -369,7 +343,7 @@ static void verbose (afb_req request) afb_req_success(request, NULL, NULL); } -static void exitnow (afb_req request) +static void exitnow (afb_req_t request) { int code = 0; json_object *query = afb_req_json(request), *l; @@ -387,7 +361,7 @@ static void exitnow (afb_req request) exit(code); } -static void broadcast(afb_req request) +static void broadcast(afb_req_t request) { const char *tag = afb_req_value(request, "tag"); const char *name = afb_req_value(request, "name"); @@ -412,7 +386,7 @@ static void broadcast(afb_req request) json_object_put(object); } -static void hasperm (afb_req request) +static void hasperm (afb_req_t request) { const char *perm = afb_req_value(request, "perm"); if (afb_req_has_permission(request, perm)) @@ -421,39 +395,39 @@ static void hasperm (afb_req request) afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)"); } -static void appid (afb_req request) +static void appid (afb_req_t request) { char *aid = afb_req_get_application_id(request); afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?"); free(aid); } -static void uid (afb_req request) +static void uid (afb_req_t request) { int uid = afb_req_get_uid(request); afb_req_success_f(request, json_object_new_int(uid), "uid is %d", uid); } -static int preinit() +static int preinit(afb_api_t api) { - AFB_NOTICE("hello binding comes to live"); + AFB_API_NOTICE(api, "hello binding comes to live"); return 0; } -static int init() +static int init(afb_api_t api) { - AFB_NOTICE("hello binding starting"); + AFB_API_NOTICE(api, "hello binding starting"); return 0; } -static void onevent(const char *event, struct json_object *object) +static void onevent(afb_api_t api, const char *event, struct json_object *object) { - AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object)); + AFB_API_NOTICE(api, "received event %s(%s)", event, json_object_to_json_string(object)); } // NOTE: this sample does not use session to keep test a basic as possible // in real application most APIs should be protected with AFB_SESSION_CHECK -static const afb_verb_v2 verbs[]= { +static const struct afb_verb_v3 verbs[]= { { .verb="ping", .callback=pingSample }, { .verb="pingfail", .callback=pingFail }, { .verb="pingnull", .callback=pingNull }, @@ -461,7 +435,6 @@ static const afb_verb_v2 verbs[]= { { .verb="pingJson", .callback=pingJson }, { .verb="pingevent", .callback=pingEvent }, { .verb="subcall", .callback=subcall }, - { .verb="subcallreq", .callback=subcallreq }, { .verb="subcallsync", .callback=subcallsync }, { .verb="eventadd", .callback=eventadd }, { .verb="eventdel", .callback=eventdel }, @@ -479,7 +452,7 @@ static const afb_verb_v2 verbs[]= { { .verb=NULL} }; -const afb_binding_v2 afbBindingV2 = { +const struct afb_binding_v3 afbBindingV3 = { .api = "hello", .specification = NULL, .verbs = verbs, diff --git a/bindings/samples/ave.c b/bindings/samples/ave.c index 5661e9a5..ce01c6dc 100644 --- a/bindings/samples/ave.c +++ b/bindings/samples/ave.c @@ -21,6 +21,7 @@ #include +#define AFB_BINDING_WANT_DYNAPI #define AFB_BINDING_VERSION 0 #include @@ -147,7 +148,7 @@ static void pingBug (afb_request *request) static void pingEvent(afb_request *request) { json_object *query = afb_request_json(request); - afb_dynapi_broadcast_event(request->dynapi, "event", json_object_get(query)); + afb_dynapi_broadcast_event(request->api, "event", json_object_get(query)); ping(request, json_object_get(query), "event"); } @@ -219,7 +220,7 @@ static void eventadd (afb_request *request) pthread_mutex_lock(&mutex); if (tag == NULL || name == NULL) afb_request_fail(request, "failed", "bad arguments"); - else if (0 != event_add(request->dynapi, tag, name)) + else if (0 != event_add(request->api, tag, name)) afb_request_fail(request, "failed", "creation error"); else afb_request_success(request, NULL, NULL); @@ -305,7 +306,7 @@ static void call (afb_request *request) if (object == NULL) afb_request_fail(request, "failed", "bad arguments"); else - afb_dynapi_call(request->dynapi, api, verb, object, callcb, afb_request_addref(request)); + afb_dynapi_call(request->api, api, verb, object, callcb, afb_request_addref(request)); } static void callsync (afb_request *request) @@ -319,7 +320,7 @@ static void callsync (afb_request *request) if (object == NULL) afb_request_fail(request, "failed", "bad arguments"); else { - rc = afb_dynapi_call_sync(request->dynapi, api, verb, object, &result); + rc = afb_dynapi_call_sync(request->api, api, verb, object, &result); if (rc >= 0) afb_request_success(request, result, NULL); else { @@ -379,7 +380,7 @@ static void broadcast(afb_request *request) afb_request_success(request, NULL, NULL); pthread_mutex_unlock(&mutex); } else if (name != NULL) { - if (0 > afb_dynapi_broadcast_event(request->dynapi, name, object)) + if (0 > afb_dynapi_broadcast_event(request->api, name, object)) afb_request_fail(request, "failed", "broadcast error"); else afb_request_success(request, NULL, NULL); @@ -447,13 +448,13 @@ static const struct { { .verb=NULL} }; -static void pingoo(afb_req req) +static void pingoo(struct afb_req_x1 req) { - json_object *args = afb_req_json(req); - afb_req_success_f(req, json_object_get(args), "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args)); + json_object *args = afb_req_x1_json(req); + afb_req_x1_reply_f(req, json_object_get(args), NULL, "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args)); } -static const afb_verb_v2 verbsv2[]= { +static const struct afb_verb_v2 verbsv2[]= { { .verb="pingoo", .callback=pingoo }, { .verb="ping", .callback=pingoo }, { .verb=NULL} diff --git a/bindings/samples/hello3.c b/bindings/samples/hello3.c new file mode 100644 index 00000000..ae70d1e5 --- /dev/null +++ b/bindings/samples/hello3.c @@ -0,0 +1,486 @@ +/* + * Copyright (C) 2015-2018 "IoT.bzh" + * Author "Fulup Ar Foll" + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define _GNU_SOURCE +#include +#include +#include + +#include + +#define AFB_BINDING_VERSION 3 +#include + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +struct event +{ + struct event *next; + afb_event_t event; + char tag[1]; +}; + +static struct event *events = 0; + +/* searchs the event of tag */ +static struct event *event_get(const char *tag) +{ + struct event *e = events; + while(e && strcmp(e->tag, tag)) + e = e->next; + return e; +} + +/* deletes the event of tag */ +static int event_del(const char *tag) +{ + struct event *e, **p; + + /* check exists */ + e = event_get(tag); + if (!e) return -1; + + /* unlink */ + p = &events; + while(*p != e) p = &(*p)->next; + *p = e->next; + + /* destroys */ + afb_event_unref(e->event); + free(e); + return 0; +} + +/* creates the event of tag */ +static int event_add(const char *tag, const char *name) +{ + struct event *e; + + /* check valid tag */ + e = event_get(tag); + if (e) return -1; + + /* creation */ + e = malloc(strlen(tag) + sizeof *e); + if (!e) return -1; + strcpy(e->tag, tag); + + /* make the event */ + e->event = afb_daemon_make_event(name); + if (!e->event) { free(e); return -1; } + + /* link */ + e->next = events; + events = e; + return 0; +} + +static int event_subscribe(afb_req_t request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_subscribe(request, e->event) : -1; +} + +static int event_unsubscribe(afb_req_t request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_unsubscribe(request, e->event) : -1; +} + +static int event_push(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_push(e->event, json_object_get(args)) : -1; +} + +static int event_broadcast(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1; +} + +// Sample Generic Ping Debug API +static void ping(afb_req_t request, json_object *jresp, const char *tag) +{ + static int pingcount = 0; + json_object *query = afb_req_json(request); + afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query)); +} + +static void pingSample (afb_req_t request) +{ + ping(request, json_object_new_string ("Some String"), "pingSample"); +} + +static void pingFail (afb_req_t request) +{ + afb_req_fail(request, "failed", "Ping Binder Daemon fails"); +} + +static void pingNull (afb_req_t request) +{ + ping(request, NULL, "pingNull"); +} + +static void pingBug (afb_req_t request) +{ + ping(NULL, NULL, "pingBug"); +} + +static void pingEvent(afb_req_t request) +{ + json_object *query = afb_req_json(request); + afb_daemon_broadcast_event("event", json_object_get(query)); + ping(request, json_object_get(query), "event"); +} + + +// For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/ +static void pingJson (afb_req_t request) { + json_object *jresp, *embed; + + jresp = json_object_new_object(); + json_object_object_add(jresp, "myString", json_object_new_string ("Some String")); + json_object_object_add(jresp, "myInt", json_object_new_int (1234)); + + embed = json_object_new_object(); + json_object_object_add(embed, "subObjString", json_object_new_string ("Some String")); + json_object_object_add(embed, "subObjInt", json_object_new_int (5678)); + + json_object_object_add(jresp,"eobj", embed); + + ping(request, jresp, "pingJson"); +} + +static void subcallcb (void *prequest, int status, json_object *object, afb_req_t request) +{ + if (status < 0) + afb_req_fail(request, "failed", json_object_to_json_string(object)); + else + afb_req_success(request, json_object_get(object), NULL); + afb_req_unref(request); +} + +static void subcall (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_req_subcall_legacy(request, api, verb, object, subcallcb, NULL); +} + +static void subcallreqcb (void *prequest, int status, json_object *object, afb_req_t request) +{ + if (status < 0) + afb_req_fail(request, "failed", json_object_to_json_string(object)); + else + afb_req_success(request, json_object_get(object), NULL); +} + +static void subcallreq (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_req_subcall_legacy(request, api, verb, object, subcallreqcb, NULL); +} + +static void subcallsync (afb_req_t request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_req_subcall_sync_legacy(request, api, verb, object, &result); + if (rc >= 0) + afb_req_success(request, result, NULL); + else { + afb_req_fail(request, "failed", json_object_to_json_string(result)); + json_object_put(result); + } + } +} + +static void eventadd (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + + pthread_mutex_lock(&mutex); + if (tag == NULL || name == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_add(tag, name)) + afb_req_fail(request, "failed", "creation error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventdel (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_del(tag)) + afb_req_fail(request, "failed", "deletion error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventsub (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_subscribe(request, tag)) + afb_req_fail(request, "failed", "subscription error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventunsub (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_unsubscribe(request, tag)) + afb_req_fail(request, "failed", "unsubscription error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventpush (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 > event_push(object, tag)) + afb_req_fail(request, "failed", "push error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); + json_object_put(object); +} + +static void callcb (void *prequest, json_object *object, const char *error, const char *info, afb_api_t api) +{ + afb_req_t request = afb_req_unstore(prequest); + afb_req_reply(request, json_object_get(object), error, info); + afb_req_unref(request); +} + +static void call (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_api_call(request->api, api, verb, object, callcb, afb_req_store(request)); +} + +static void callsync (afb_req_t request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_service_call_sync(api, verb, object, &result); + if (rc >= 0) + afb_req_success(request, result, NULL); + else { + afb_req_fail(request, "failed", json_object_to_json_string(result)); + json_object_put(result); + } + } +} + +static void verbose (afb_req_t request) +{ + int level = 5; + json_object *query = afb_req_json(request), *l; + + if (json_object_is_type(query,json_type_int)) + level = json_object_get_int(query); + else if (json_object_object_get_ex(query, "level", &l) && json_object_is_type(l, json_type_int)) + level = json_object_get_int(l); + + if (!json_object_object_get_ex(query,"message",&l)) + l = query; + + AFB_REQ_VERBOSE(request, level, "verbose called for %s", json_object_get_string(l)); + afb_req_success(request, NULL, NULL); +} + +static void exitnow (afb_req_t request) +{ + int code = 0; + json_object *query = afb_req_json(request), *l; + + if (json_object_is_type(query,json_type_int)) + code = json_object_get_int(query); + else if (json_object_object_get_ex(query, "code", &l) && json_object_is_type(l, json_type_int)) + code = json_object_get_int(l); + + if (!json_object_object_get_ex(query,"reason",&l)) + l = NULL; + + AFB_REQ_NOTICE(request, "in phase of exiting with code %d, reason: %s", code, l ? json_object_get_string(l) : "unknown"); + afb_req_success(request, NULL, NULL); + exit(code); +} + +static void broadcast(afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + if (tag != NULL) { + pthread_mutex_lock(&mutex); + if (0 > event_broadcast(object, tag)) + afb_req_fail(request, "failed", "broadcast error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); + } else if (name != NULL) { + if (0 > afb_daemon_broadcast_event(name, object)) + afb_req_fail(request, "failed", "broadcast error"); + else + afb_req_success(request, NULL, NULL); + } else { + afb_req_fail(request, "failed", "bad arguments"); + } + json_object_put(object); +} + +static void hasperm (afb_req_t request) +{ + const char *perm = afb_req_value(request, "perm"); + if (afb_req_has_permission(request, perm)) + afb_req_success_f(request, NULL, "permission %s granted", perm?:"(null)"); + else + afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)"); +} + +static void appid (afb_req_t request) +{ + char *aid = afb_req_get_application_id(request); + afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?"); + free(aid); +} + +static void uid (afb_req_t request) +{ + int uid = afb_req_get_uid(request); + afb_req_success_f(request, json_object_new_int(uid), "uid is %d", uid); +} + +static int preinit() +{ + AFB_NOTICE("hello binding comes to live"); + return 0; +} + +static int init() +{ + AFB_NOTICE("hello binding starting"); + return 0; +} + +static void onevent(afb_api_t api, const char *event, struct json_object *object) +{ + AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object)); +} + +// NOTE: this sample does not use session to keep test a basic as possible +// in real application most APIs should be protected with AFB_SESSION_CHECK +static const struct afb_verb_v3 verbs[]= { + { .verb="ping", .callback=pingSample }, + { .verb="pingfail", .callback=pingFail }, + { .verb="pingnull", .callback=pingNull }, + { .verb="pingbug", .callback=pingBug }, + { .verb="pingJson", .callback=pingJson }, + { .verb="pingevent", .callback=pingEvent }, + { .verb="subcall", .callback=subcall }, + { .verb="subcallreq", .callback=subcallreq }, + { .verb="subcallsync", .callback=subcallsync }, + { .verb="eventadd", .callback=eventadd }, + { .verb="eventdel", .callback=eventdel }, + { .verb="eventsub", .callback=eventsub }, + { .verb="eventunsub", .callback=eventunsub }, + { .verb="eventpush", .callback=eventpush }, + { .verb="call", .callback=call }, + { .verb="callsync", .callback=callsync }, + { .verb="verbose", .callback=verbose }, + { .verb="broadcast", .callback=broadcast }, + { .verb="hasperm", .callback=hasperm }, + { .verb="appid", .callback=appid }, + { .verb="uid", .callback=uid }, + { .verb="exit", .callback=exitnow }, + { .verb=NULL} +}; + +const struct afb_binding_v3 afbBindingV3 = { + .api = "hello3", + .specification = NULL, + .verbs = verbs, + .preinit = preinit, + .init = init, + .onevent = onevent +}; + diff --git a/bindings/samples/hi3.c b/bindings/samples/hi3.c new file mode 100644 index 00000000..5202c46a --- /dev/null +++ b/bindings/samples/hi3.c @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2015-2018 "IoT.bzh" + * Author José Bollo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define _GNU_SOURCE +#include +#include +#include + +#include + +#define AFB_BINDING_VERSION 3 +#include + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +struct event +{ + struct event *next; + afb_event_t event; + char tag[1]; +}; + +static struct event *events = 0; + +/* searchs the event of tag */ +static struct event *event_get(const char *tag) +{ + struct event *e = events; + while(e && strcmp(e->tag, tag)) + e = e->next; + return e; +} + +/* deletes the event of tag */ +static int event_del(const char *tag) +{ + struct event *e, **p; + + /* check exists */ + e = event_get(tag); + if (!e) return -1; + + /* unlink */ + p = &events; + while(*p != e) p = &(*p)->next; + *p = e->next; + + /* destroys */ + afb_event_unref(e->event); + free(e); + return 0; +} + +/* creates the event of tag */ +static int event_add(afb_api_t api, const char *tag, const char *name) +{ + struct event *e; + + /* check valid tag */ + e = event_get(tag); + if (e) return -1; + + /* creation */ + e = malloc(strlen(tag) + sizeof *e); + if (!e) return -1; + strcpy(e->tag, tag); + + /* make the event */ + e->event = afb_api_make_event(api, name); + if (!e->event) { free(e); return -1; } + + /* link */ + e->next = events; + events = e; + return 0; +} + +static int event_subscribe(afb_req_t request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_subscribe(request, e->event) : -1; +} + +static int event_unsubscribe(afb_req_t request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_unsubscribe(request, e->event) : -1; +} + +static int event_push(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_push(e->event, json_object_get(args)) : -1; +} + +static int event_broadcast(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1; +} + +// Sample Generic Ping Debug API +static void ping(afb_req_t request, json_object *jresp, const char *tag) +{ + static int pingcount = 0; + json_object *query = afb_req_json(request); + afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query)); +} + +static void pingSample (afb_req_t request) +{ + ping(request, json_object_new_string ("Some String"), "pingSample"); +} + +static void pingFail (afb_req_t request) +{ + afb_req_fail(request, "failed", "Ping Binder Daemon fails"); +} + +static void pingNull (afb_req_t request) +{ + ping(request, NULL, "pingNull"); +} + +static void pingBug (afb_req_t request) +{ + ping(NULL, NULL, "pingBug"); +} + +static void pingEvent(afb_req_t request) +{ + json_object *query = afb_req_json(request); + afb_api_broadcast_event(request->api, "event", json_object_get(query)); + ping(request, json_object_get(query), "event"); +} + + +// For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/ +static void pingJson (afb_req_t request) { + json_object *jresp, *embed; + + jresp = json_object_new_object(); + json_object_object_add(jresp, "myString", json_object_new_string ("Some String")); + json_object_object_add(jresp, "myInt", json_object_new_int (1234)); + + embed = json_object_new_object(); + json_object_object_add(embed, "subObjString", json_object_new_string ("Some String")); + json_object_object_add(embed, "subObjInt", json_object_new_int (5678)); + + json_object_object_add(jresp,"eobj", embed); + + ping(request, jresp, "pingJson"); +} + +static void subcallcb (void *closure, json_object *object, const char *error, const char *info, afb_req_t request) +{ + afb_req_reply(request, json_object_get(object), error, info); +} + +static void subcall (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_req_subcall(request, api, verb, object, afb_req_subcall_pass_events, subcallcb, NULL); +} + +static void subcallsync (afb_req_t request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *oargs = api && verb && args ? json_tokener_parse(args) : NULL; + json_object *object; + char *error, *info; + + if (oargs == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_req_subcall_sync(request, api, verb, oargs, afb_req_subcall_pass_events, &object, &error, &info); + afb_req_reply_f(request, object, error, "rc=%d, info=%s", rc, info?:"NULL"); + free(error); + free(info); + } +} + +static void eventadd (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + + pthread_mutex_lock(&mutex); + if (tag == NULL || name == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_add(request->api, tag, name)) + afb_req_fail(request, "failed", "creation error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventdel (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_del(tag)) + afb_req_fail(request, "failed", "deletion error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventsub (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_subscribe(request, tag)) + afb_req_fail(request, "failed", "subscription error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventunsub (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_unsubscribe(request, tag)) + afb_req_fail(request, "failed", "unsubscription error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventpush (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 > event_push(object, tag)) + afb_req_fail(request, "failed", "push error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); + json_object_put(object); +} + +static void callcb (void *prequest, json_object *object, const char *error, const char *info, afb_api_t api) +{ + afb_req_t request = prequest; + afb_req_reply(request, json_object_get(object), error, info); + afb_req_unref(request); +} + +static void call (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_api_call(request->api, api, verb, object, callcb, afb_req_addref(request)); +} + +static void callsync (afb_req_t request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *oargs = api && verb && args ? json_tokener_parse(args) : NULL; + json_object *object; + char *error, *info; + + if (oargs == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_api_call_sync(request->api, api, verb, oargs, &object, &error, &info); + afb_req_reply_f(request, object, error, "rc=%d, info=%s", rc, info); + free(error); + free(info); + } +} + +static void verbose (afb_req_t request) +{ + int level = 5; + json_object *query = afb_req_json(request), *l; + + if (json_object_is_type(query,json_type_int)) + level = json_object_get_int(query); + else if (json_object_object_get_ex(query, "level", &l) && json_object_is_type(l, json_type_int)) + level = json_object_get_int(l); + + if (!json_object_object_get_ex(query,"message",&l)) + l = query; + + AFB_REQ_VERBOSE(request, level, "verbose called for %s", json_object_get_string(l)); + afb_req_success(request, NULL, NULL); +} + +static void exitnow (afb_req_t request) +{ + int code = 0; + json_object *query = afb_req_json(request), *l; + + if (json_object_is_type(query,json_type_int)) + code = json_object_get_int(query); + else if (json_object_object_get_ex(query, "code", &l) && json_object_is_type(l, json_type_int)) + code = json_object_get_int(l); + + if (!json_object_object_get_ex(query,"reason",&l)) + l = NULL; + + AFB_REQ_NOTICE(request, "in phase of exiting with code %d, reason: %s", code, l ? json_object_get_string(l) : "unknown"); + afb_req_success(request, NULL, NULL); + exit(code); +} + +static void broadcast(afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + if (tag != NULL) { + pthread_mutex_lock(&mutex); + if (0 > event_broadcast(object, tag)) + afb_req_fail(request, "failed", "broadcast error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); + } else if (name != NULL) { + if (0 > afb_api_broadcast_event(request->api, name, object)) + afb_req_fail(request, "failed", "broadcast error"); + else + afb_req_success(request, NULL, NULL); + } else { + afb_req_fail(request, "failed", "bad arguments"); + } + json_object_put(object); +} + +static void hasperm (afb_req_t request) +{ + const char *perm = afb_req_value(request, "perm"); + if (afb_req_has_permission(request, perm)) + afb_req_success_f(request, NULL, "permission %s granted", perm?:"(null)"); + else + afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)"); +} + +static void appid (afb_req_t request) +{ + char *aid = afb_req_get_application_id(request); + afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?"); + free(aid); +} + +static int init(afb_api_t api) +{ + AFB_API_NOTICE(api, "dynamic binding AVE(%s) starting", (const char*)api->userdata); + return 0; +} + +static void onevent(afb_api_t api, const char *event, struct json_object *object) +{ + AFB_API_NOTICE(api, "received event %s(%s) by AVE(%s)", + event, json_object_to_json_string(object), + (const char*)afb_api_get_userdata(api)); +} + +// NOTE: this sample does not use session to keep test a basic as possible +// in real application most APIs should be protected with AFB_SESSION_CHECK +static const struct { + const char *verb; + void (*callback)(afb_req_t); } verbs[] = +{ + { .verb="ping", .callback=pingSample }, + { .verb="pingfail", .callback=pingFail }, + { .verb="pingnull", .callback=pingNull }, + { .verb="pingbug", .callback=pingBug }, + { .verb="pingJson", .callback=pingJson }, + { .verb="pingevent", .callback=pingEvent }, + { .verb="subcall", .callback=subcall }, + { .verb="subcallsync", .callback=subcallsync }, + { .verb="eventadd", .callback=eventadd }, + { .verb="eventdel", .callback=eventdel }, + { .verb="eventsub", .callback=eventsub }, + { .verb="eventunsub", .callback=eventunsub }, + { .verb="eventpush", .callback=eventpush }, + { .verb="call", .callback=call }, + { .verb="callsync", .callback=callsync }, + { .verb="verbose", .callback=verbose }, + { .verb="broadcast", .callback=broadcast }, + { .verb="hasperm", .callback=hasperm }, + { .verb="appid", .callback=appid }, + { .verb="exit", .callback=exitnow }, + { .verb=NULL} +}; + +static void pingoo(struct afb_req_x1 req) +{ + json_object *args = afb_req_x1_json(req); + afb_req_x1_reply_f(req, json_object_get(args), NULL, "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args)); +} + +static const struct afb_verb_v2 verbsv2[]= { + { .verb="pingoo", .callback=pingoo }, + { .verb="ping", .callback=pingoo }, + { .verb=NULL} +}; + +static const char *apis[] = { "ave3", "hi3", "salut3", NULL }; + +static int build_api(void *closure, afb_api_t api) +{ + int i, rc; + + afb_api_set_userdata(api, closure); + AFB_API_NOTICE(api, "dynamic binding AVE(%s) comes to live", (const char*)afb_api_get_userdata(api)); + afb_api_on_init(api, init); + afb_api_on_event(api, onevent); + + rc = afb_api_set_verbs_v2(api, verbsv2); + for (i = rc = 0; verbs[i].verb && rc >= 0 ; i++) { + rc = afb_api_add_verb(api, verbs[i].verb, NULL, verbs[i].callback, (void*)(intptr_t)i, NULL, 0, 0); + } + afb_api_seal(api); + return rc; +} + +int afbBindingV3entry(afb_api_t api) +{ + int i; + afb_api_t napi; + + for (i = 0; apis[i] ; i++) { + napi = afb_api_new_api(api, apis[i], NULL, 0, build_api, (void*)apis[i]); + if (!napi) + AFB_API_ERROR(api, "can't create API %s", apis[i]); + } + return 0; +} + diff --git a/bindings/samples/tic-tac-toe.c b/bindings/samples/tic-tac-toe.c index 6b7022b8..2ee251cb 100644 --- a/bindings/samples/tic-tac-toe.c +++ b/bindings/samples/tic-tac-toe.c @@ -20,17 +20,14 @@ #include #include -#define AFB_BINDING_VERSION 2 +#define AFB_BINDING_VERSION 3 #include -/* - * definition of waiters - */ -struct waiter -{ - struct waiter *next; - struct afb_req req; -}; +static const char SPACE = ' '; +static const char CROSS = 'X'; +static const char ROUND = 'O'; +static const char NHERE = '+'; +static const int DEFLVL = 8; /* * definition of a board @@ -44,7 +41,7 @@ struct board int id; int level; char board[9]; - struct waiter *waiters; + afb_event_t event; }; /* @@ -67,19 +64,21 @@ static struct board *search_board(int id) /* * Creates a new board and returns it. */ -static struct board *get_new_board() +static struct board *get_new_board(afb_req_t req) { /* allocation */ struct board *board = calloc(1, sizeof *board); /* initialisation */ - memset(board->board, ' ', sizeof board->board); + memset(board->board, SPACE, sizeof board->board); board->use_count = 1; - board->level = 1; + board->level = DEFLVL; board->moves = 0; do { board->id = (rand() >> 2) % 1000; } while(board->id == 0 || search_board(board->id) != NULL); + board->event = afb_daemon_make_event("board"); + afb_req_subscribe(req, board->event); /* link */ board->next = all_boards; @@ -87,6 +86,12 @@ static struct board *get_new_board() return board; } +static void *get_new_board_cb(void *closure) +{ + afb_req_t req = closure; + return get_new_board(req); +} + /* * Release a board */ @@ -95,6 +100,7 @@ static void release_board(struct board *board) /* decrease the reference count ... */ if (--board->use_count == 0) { /* ... no more use */ + afb_event_unref(board->event); /* unlink from the list of boards */ struct board **prv = &all_boards; while (*prv != NULL && *prv != board) @@ -106,6 +112,24 @@ static void release_board(struct board *board) } } +static void release_board_cb(void *closure) +{ + struct board *board = closure; + return release_board(board); +} + +/* + * Checks who wins + * Returns zero if there is no winner + * Returns the char of the winner if a player won + */ +static char wins(const char b[9], int first, int incr) +{ + char c = b[first]; + + return c != SPACE && b[first + incr] == c && b[first + incr + incr] == c ? c : 0; +} + /* * Checks who wins * Returns zero if there is no winner @@ -113,31 +137,39 @@ static void release_board(struct board *board) */ static char winner(const char b[9]) { - int i; char c; - /* check diagonals */ - c = b[4]; - if (c != ' ') { - if (b[0] == c && b[8] == c) - return c; - if (b[2] == c && b[6] == c) - return c; - } + c = wins(b, 0, 1); + if (c) + return c; - /* check lines */ - for (i = 0 ; i <= 6 ; i += 3) { - c = b[i]; - if (c != ' ' && b[i+1] == c && b[i+2] == c) - return c; - } + c = wins(b, 3, 1); + if (c) + return c; - /* check columns */ - for (i = 0 ; i <= 2 ; i++) { - c = b[i]; - if (c != ' ' && b[i+3] == c && b[i+6] == c) - return c; - } + c = wins(b, 6, 1); + if (c) + return c; + + c = wins(b, 0, 3); + if (c) + return c; + + c = wins(b, 1, 3); + if (c) + return c; + + c = wins(b, 2, 3); + if (c) + return c; + + c = wins(b, 0, 4); + if (c) + return c; + + c = wins(b, 2, 2); + if (c) + return c; return 0; } @@ -145,7 +177,7 @@ static char winner(const char b[9]) /* get the color (X or 0) of the move of index 'move' */ static char color(int move) { - return (move & 1) == 0 ? 'X' : '0'; + return (move & 1) == 0 ? CROSS : ROUND; } /* adds the move to the board */ @@ -160,7 +192,7 @@ static void add_move(struct board *board, int index) static int get_random_move(char b[9]) { int index = rand() % 9; - while (b[index] != ' ') + while (b[index] != SPACE) index = (index + 1) % 9; return index; } @@ -174,40 +206,41 @@ static int get_random_move(char b[9]) */ static int score_position(char b[9], char c, int depth) { - int i, t, r; + int i, s, nc, wc, lc; /* check if winner */ if (winner(b) == c) return 1; /* when depth of analysis is reached return unknown case */ - if (--depth == 0) + if (--depth <= 0) return 0; /* switch to the opponent */ - c = (char)('O' + 'X' - c); + c = (char)(ROUND + CROSS - c); /* inspect opponent moves */ - r = 1; + nc = wc = lc = 0; for (i = 0 ; i < 9 ; i++) { - if (b[i] == ' ') { + if (b[i] == SPACE) { b[i] = c; - t = score_position(b, c, depth); - b[i] = ' '; - if (t > 0) - return -1; /* opponent will win */ - - if (t == 0) - r = 0; /* something not clear */ + s = score_position(b, c, depth); + b[i] = SPACE; + if (s > 0) + lc++; /* opponent's victory, inc loose count */ + else if (s < 0) + wc++; /* current's victory, inc win count */ + else + nc++; /* none wins, increment null count */ } } - return r; + return lc ? -lc : wc; } /* get one move: return the computed index of the move */ static int get_move(struct board *board) { - int index, depth, t, f; + int index, depth, f, s, smax, imax; char c; char b[9]; @@ -222,22 +255,24 @@ static int get_move(struct board *board) /* depth and more */ memcpy(b, board->board, 9); + f = smax = 0; c = color(board->moves); - f = 0; for (index = 0 ; index < 9 ; index++) { - if (board->board[index] == ' ') { + if (board->board[index] == SPACE) { board->board[index] = c; - t = score_position(board->board, c, depth); - board->board[index] = ' '; - if (t > 0) - return index; - if (t < 0) - b[index] = '+'; - else + s = score_position(board->board, c, depth); + board->board[index] = SPACE; + if (s < 0) + b[index] = NHERE; + else if (s <= smax) f = 1; + else { + smax = s; + imax = index; + } } } - return get_random_move(f ? b : board->board); + return smax ? imax : get_random_move(f ? b : board->board); } /* @@ -279,37 +314,21 @@ static struct json_object *describe(struct board *board) */ static void changed(struct board *board, const char *reason) { - struct waiter *waiter, *next; - struct json_object *description; - - /* get the description */ - description = describe(board); - - waiter = board->waiters; - board->waiters = NULL; - while (waiter != NULL) { - next = waiter->next; - afb_req_success(waiter->req, json_object_get(description), reason); - afb_req_unref(waiter->req); - free(waiter); - waiter = next; - } - - afb_daemon_broadcast_event(reason, description); + afb_event_push(board->event, json_object_new_string(reason)); } /* * retrieves the board of the request */ -static inline struct board *board_of_req(struct afb_req req) +static inline struct board *board_of_req(afb_req_t req) { - return afb_req_context(req, (void*)get_new_board, (void*)release_board); + return afb_req_context(req, 0, get_new_board_cb, release_board_cb, req); } /* * start a new game */ -static void new(struct afb_req req) +static void new(afb_req_t req) { struct board *board; @@ -318,7 +337,7 @@ static void new(struct afb_req req) AFB_INFO("method 'new' called for boardid %d", board->id); /* reset the game */ - memset(board->board, ' ', sizeof board->board); + memset(board->board, SPACE, sizeof board->board); board->moves = 0; /* replies */ @@ -331,7 +350,7 @@ static void new(struct afb_req req) /* * get the board */ -static void board(struct afb_req req) +static void board(afb_req_t req) { struct board *board; struct json_object *description; @@ -350,7 +369,7 @@ static void board(struct afb_req req) /* * move a piece */ -static void move(struct afb_req req) +static void move(afb_req_t req) { struct board *board; int i; @@ -379,7 +398,7 @@ static void move(struct afb_req req) } /* checks validity of the move */ - if (board->board[i] != ' ') { + if (board->board[i] != SPACE) { AFB_WARNING("can't move to %s: room occupied", index); afb_req_fail(req, "error", "occupied"); return; @@ -399,7 +418,7 @@ static void move(struct afb_req req) /* * set the level */ -static void level(struct afb_req req) +static void level(afb_req_t req) { struct board *board; int l; @@ -434,7 +453,7 @@ static void level(struct afb_req req) /* * Join a board */ -static void join(struct afb_req req) +static void join(afb_req_t req) { struct board *board, *new_board; const char *id; @@ -450,8 +469,8 @@ static void join(struct afb_req req) /* none is a special id for joining a new session */ if (strcmp(id, "none") == 0) { - new_board = get_new_board(); - goto success; + new_board = get_new_board(req); + goto setctx; } /* searchs the board to join */ @@ -466,13 +485,16 @@ static void join(struct afb_req req) * function 'release_board'. So the use_count MUST not * be incremented. */ - if (new_board != board) - new_board->use_count++; + if (new_board == board) + goto success; -success: + new_board->use_count++; +setctx: /* set the new board (and leaves the previous one) */ - afb_req_context_set(req, new_board, (void*)release_board); + afb_req_context(req, 1, NULL, release_board_cb, new_board); + afb_req_unsubscribe(req, board->event); +success: /* replies */ afb_req_success(req, NULL, NULL); return; @@ -486,7 +508,7 @@ bad_request: /* * Undo the last move */ -static void undo(struct afb_req req) +static void undo(afb_req_t req) { struct board *board; int i; @@ -504,7 +526,7 @@ static void undo(struct afb_req req) /* undo the last move */ i = board->history[--board->moves]; - board->board[i] = ' '; + board->board[i] = SPACE; /* replies */ afb_req_success(req, NULL, NULL); @@ -516,7 +538,7 @@ static void undo(struct afb_req req) /* * computer plays */ -static void play(struct afb_req req) +static void play(afb_req_t req) { struct board *board; int index; @@ -543,27 +565,10 @@ static void play(struct afb_req req) changed(board, "play"); } -static void wait(struct afb_req req) -{ - struct board *board; - struct waiter *waiter; - - /* retrieves the context for the session */ - board = board_of_req(req); - AFB_INFO("method 'wait' called for boardid %d", board->id); - - /* creates the waiter and enqueues it */ - waiter = calloc(1, sizeof *waiter); - waiter->req = req; - waiter->next = board->waiters; - afb_req_addref(req); - board->waiters = waiter; -} - /* * array of the verbs exported to afb-daemon */ -static const struct afb_verb_v2 verbs[] = { +static const afb_verb_t verbs[] = { { .verb="new", .callback=new }, { .verb="play", .callback=play }, { .verb="move", .callback=move }, @@ -571,17 +576,17 @@ static const struct afb_verb_v2 verbs[] = { { .verb="level", .callback=level }, { .verb="join", .callback=join }, { .verb="undo", .callback=undo }, - { .verb="wait", .callback=wait }, { .verb=NULL } }; /* * description of the binding for afb-daemon */ -const afb_binding_v2 afbBindingV2 = { +const afb_binding_t afbBindingV3 = { .api = "tictactoe", .specification = NULL, - .verbs = verbs + .verbs = verbs, + .noconcurrency = 1 }; -- cgit 1.2.3-korg