From 6518887513840471ea9c5af7e534787717e6bd82 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Thu, 9 Jun 2016 16:59:19 +0200 Subject: [PATCH] Make possible to call a method from a binding MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The new request call 'afb_req_subcall' allows a binding to call the method of an other binding. Change-Id: I8538185be7a1663153a25db2bc940f9e2bdedb1a Signed-off-by: José Bollo --- include/afb/afb-req-itf.h | 16 +++- plugins/samples/HelloWorld.c | 24 ++++++ src/CMakeLists.txt | 1 + src/afb-api-dbus.c | 25 +++++- src/afb-hreq.c | 10 ++- src/afb-msg-json.c | 16 ++-- src/afb-subcall.c | 195 +++++++++++++++++++++++++++++++++++++++++++ src/afb-subcall.h | 26 ++++++ src/afb-ws-json1.c | 13 ++- 9 files changed, 313 insertions(+), 13 deletions(-) create mode 100644 src/afb-subcall.c create mode 100644 src/afb-subcall.h diff --git a/include/afb/afb-req-itf.h b/include/afb/afb-req-itf.h index 2b3bc467..3efb089d 100644 --- a/include/afb/afb-req-itf.h +++ b/include/afb/afb-req-itf.h @@ -70,6 +70,8 @@ struct afb_req_itf { int (*subscribe)(void *closure, struct afb_event event); int (*unsubscribe)(void *closure, struct afb_event event); + + void (*subcall)(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure); }; /* @@ -340,8 +342,18 @@ static inline int afb_req_unsubscribe(struct afb_req req, struct afb_event event return req.itf->unsubscribe(req.closure, event); } - - +/* + * Makes a call to the method of name 'api' / 'verb' with the object 'args'. + * This call is made in the context of the request 'req'. + * On completion, the function 'callback' is invoked with the + * 'closure' given at call and two other parameters: 'iserror' and 'result'. + * 'iserror' is a boolean that indicates if the reply is an error reply. + * 'result' is the json object of the reply. + */ +static inline void afb_req_subcall(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result), void *closure) +{ + req.itf->subcall(req.closure, api, verb, args, callback, closure); +} /* internal use */ static inline const char *afb_req_raw(struct afb_req req, size_t *size) diff --git a/plugins/samples/HelloWorld.c b/plugins/samples/HelloWorld.c index e487304f..259b42f1 100644 --- a/plugins/samples/HelloWorld.c +++ b/plugins/samples/HelloWorld.c @@ -76,6 +76,29 @@ static void pingJson (struct afb_req request) { ping(request, jresp, "pingJson"); } +static void subcallcb (void *prequest, int iserror, json_object *object) +{ + struct afb_req request = afb_req_unstore(prequest); + if (iserror) + afb_req_fail(request, "failed", json_object_to_json_string(object)); + else + afb_req_success(request, object, NULL); + afb_req_unref(request); +} + +static void subcall (struct 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)); +} + // 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[]= { @@ -85,6 +108,7 @@ static const struct AFB_verb_desc_v1 verbs[]= { {"pingbug" , AFB_SESSION_NONE, pingBug , "Do a Memory Violation"}, {"pingJson" , AFB_SESSION_NONE, pingJson , "Return a JSON object"}, {"pingevent", AFB_SESSION_NONE, pingEvent , "Send an event"}, + {"subcall", AFB_SESSION_NONE, subcall , "Call api/verb(args)"}, {NULL} }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cbaf286f..286b8254 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,6 +42,7 @@ ADD_LIBRARY(afb-lib STATIC afb-method.c afb-msg-json.c afb-sig-handler.c + afb-subcall.c afb-websock.c afb-ws-client.c afb-ws-json1.c diff --git a/src/afb-api-dbus.c b/src/afb-api-dbus.c index eda7985f..905c723d 100644 --- a/src/afb-api-dbus.c +++ b/src/afb-api-dbus.c @@ -36,6 +36,7 @@ #include "afb-api-so.h" #include "afb-context.h" #include "afb-evt.h" +#include "afb-subcall.h" #include "verbose.h" static const char DEFAULT_PATH_PREFIX[] = "/org/agl/afb/api/"; @@ -446,6 +447,18 @@ static void dbus_req_send(struct dbus_req *dreq, const char *buffer, size_t size dbus_req_reply(dreq, RETRAW, buffer, ""); } +static int dbus_req_subscribe(struct dbus_req *dreq, struct afb_event event) +{ + return -1; +} + +static int dbus_req_unsubscribe(struct dbus_req *dreq, struct afb_event event) +{ + return -1; +} + +static void dbus_req_subcall(struct dbus_req *dreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure); + const struct afb_req_itf afb_api_dbus_req_itf = { .json = (void*)dbus_req_json, .get = (void*)dbus_req_get, @@ -456,9 +469,19 @@ const struct afb_req_itf afb_api_dbus_req_itf = { .context_get = (void*)afb_context_get, .context_set = (void*)afb_context_set, .addref = (void*)dbus_req_addref, - .unref = (void*)dbus_req_unref + .unref = (void*)dbus_req_unref, + .session_close = (void*)afb_context_close, + .session_set_LOA = (void*)afb_context_change_loa, + .subscribe = (void*)dbus_req_subscribe, + .unsubscribe = (void*)dbus_req_unsubscribe, + .subcall = (void*)dbus_req_subcall }; +static void dbus_req_subcall(struct dbus_req *dreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure) +{ + afb_subcall(&dreq->context, api, verb, args, callback, closure, (struct afb_req){ .itf = &afb_api_dbus_req_itf, .closure = dreq }); +} + /******************* server part **********************************/ /* called when the object for the service is called */ diff --git a/src/afb-hreq.c b/src/afb-hreq.c index 1e38b412..d1a262f7 100644 --- a/src/afb-hreq.c +++ b/src/afb-hreq.c @@ -37,6 +37,7 @@ #include "afb-msg-json.h" #include "afb-context.h" #include "afb-hreq.h" +#include "afb-subcall.h" #include "session.h" #include "verbose.h" @@ -75,6 +76,7 @@ static void req_success(struct afb_hreq *hreq, json_object *obj, const char *inf static const char *req_raw(struct afb_hreq *hreq, size_t *size); static void req_send(struct afb_hreq *hreq, const char *buffer, size_t size); static int req_subscribe_unsubscribe_error(struct afb_hreq *hreq, struct afb_event event); +static void req_subcall(struct afb_hreq *hreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure); const struct afb_req_itf afb_hreq_req_itf = { .json = (void*)req_json, @@ -90,7 +92,8 @@ const struct afb_req_itf afb_hreq_req_itf = { .session_close = (void*)afb_context_close, .session_set_LOA = (void*)afb_context_change_loa, .subscribe = (void*)req_subscribe_unsubscribe_error, - .unsubscribe = (void*)req_subscribe_unsubscribe_error + .unsubscribe = (void*)req_subscribe_unsubscribe_error, + .subcall = (void*)req_subcall }; static struct hreq_data *get_data(struct afb_hreq *hreq, const char *key, int create) @@ -807,6 +810,11 @@ static int req_subscribe_unsubscribe_error(struct afb_hreq *hreq, struct afb_eve return -1; } +static void req_subcall(struct afb_hreq *hreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure) +{ + afb_subcall(&hreq->context, api, verb, args, callback, closure, (struct afb_req){ .itf = &afb_hreq_req_itf, .closure = hreq }); +} + int afb_hreq_init_context(struct afb_hreq *hreq) { const char *uuid; diff --git a/src/afb-msg-json.c b/src/afb-msg-json.c index d5f6f5a5..8f543ff1 100644 --- a/src/afb-msg-json.c +++ b/src/afb-msg-json.c @@ -47,13 +47,15 @@ struct json_object *afb_msg_json_reply(const char *status, const char *info, str if (reqid != NULL) json_object_object_add(request, "reqid", json_object_new_string(reqid)); - token = afb_context_sent_token(context); - if (token != NULL) - json_object_object_add(request, "token", json_object_new_string(token)); - - uuid = afb_context_sent_uuid(context); - if (uuid != NULL) - json_object_object_add(request, "uuid", json_object_new_string(uuid)); + if (context != NULL) { + token = afb_context_sent_token(context); + if (token != NULL) + json_object_object_add(request, "token", json_object_new_string(token)); + + uuid = afb_context_sent_uuid(context); + if (uuid != NULL) + json_object_object_add(request, "uuid", json_object_new_string(uuid)); + } return msg; } diff --git a/src/afb-subcall.c b/src/afb-subcall.c new file mode 100644 index 00000000..4d18bee7 --- /dev/null +++ b/src/afb-subcall.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2016 "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 + +#include "afb-subcall.h" +#include "afb-msg-json.h" +#include "afb-apis.h" +#include "afb-context.h" +#include "verbose.h" + +struct afb_subcall; + +static void subcall_addref(struct afb_subcall *subcall); +static void subcall_unref(struct afb_subcall *subcall); +static struct json_object *subcall_json(struct afb_subcall *subcall); +static struct afb_arg subcall_get(struct afb_subcall *subcall, const char *name); +static void subcall_fail(struct afb_subcall *subcall, const char *status, const char *info); +static void subcall_success(struct afb_subcall *subcall, struct json_object *obj, const char *info); +static const char *subcall_raw(struct afb_subcall *subcall, size_t *size); +static void subcall_send(struct afb_subcall *subcall, const char *buffer, size_t size); +static int subcall_subscribe(struct afb_subcall *subcall, struct afb_event event); +static int subcall_unsubscribe(struct afb_subcall *subcall, struct afb_event event); +static void subcall_session_close(struct afb_subcall *subcall); +static int subcall_session_set_LOA(struct afb_subcall *subcall, unsigned loa); +static void subcall_subcall(struct afb_subcall *subcall, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure); + +const struct afb_req_itf afb_subcall_req_itf = { + .json = (void*)subcall_json, + .get = (void*)subcall_get, + .success = (void*)subcall_success, + .fail = (void*)subcall_fail, + .raw = (void*)subcall_raw, + .send = (void*)subcall_send, + .context_get = (void*)afb_context_get, + .context_set = (void*)afb_context_set, + .addref = (void*)subcall_addref, + .unref = (void*)subcall_unref, + .session_close = (void*)subcall_session_close, + .session_set_LOA = (void*)subcall_session_set_LOA, + .subscribe = (void*)subcall_subscribe, + .unsubscribe = (void*)subcall_unsubscribe, + .subcall = (void*)subcall_subcall +}; + +struct afb_subcall +{ + /* + * CAUTION: 'context' field should be the first because there + * is an implicit convertion to struct afb_context + */ + struct afb_context context; + struct afb_context *original_context; + int refcount; + struct json_object *args; + struct afb_req req; + void (*callback)(void*, int, struct json_object*); + void *closure; +}; + +static void subcall_addref(struct afb_subcall *subcall) +{ + subcall->refcount++; +} + +static void subcall_unref(struct afb_subcall *subcall) +{ + if (0 == --subcall->refcount) { + json_object_put(subcall->args); + afb_req_unref(subcall->req); + free(subcall); + } +} + +static struct json_object *subcall_json(struct afb_subcall *subcall) +{ + return subcall->args; +} + +static struct afb_arg subcall_get(struct afb_subcall *subcall, const char *name) +{ + struct afb_arg arg; + struct json_object *value; + + if (json_object_object_get_ex(subcall->args, name, &value)) { + arg.name = name; + arg.value = json_object_get_string(value); + } else { + arg.name = NULL; + arg.value = NULL; + } + arg.path = NULL; + return arg; +} + +static void subcall_emit(struct afb_subcall *subcall, int iserror, struct json_object *object) +{ + if (subcall->context.refreshing != 0) + subcall->original_context->refreshing = 1; + + subcall->callback(subcall->closure, iserror, object); + json_object_put(object); +} + +static void subcall_fail(struct afb_subcall *subcall, const char *status, const char *info) +{ + subcall_emit(subcall, 1, afb_msg_json_reply_error(status, info, NULL, NULL)); +} + +static void subcall_success(struct afb_subcall *subcall, struct json_object *obj, const char *info) +{ + subcall_emit(subcall, 0, afb_msg_json_reply_ok(info, obj, NULL, NULL)); +} + +static const char *subcall_raw(struct afb_subcall *subcall, size_t *size) +{ + const char *result = json_object_to_json_string(subcall->args); + if (size != NULL) + *size = strlen(result); + return result; +} + +static void subcall_send(struct afb_subcall *subcall, const char *buffer, size_t size) +{ + subcall_emit(subcall, 0, json_tokener_parse(buffer)); +} + +static void subcall_session_close(struct afb_subcall *subcall) +{ + afb_req_session_close(subcall->req); +} + +static int subcall_session_set_LOA(struct afb_subcall *subcall, unsigned loa) +{ + return afb_req_session_set_LOA(subcall->req, loa); +} + +static int subcall_subscribe(struct afb_subcall *subcall, struct afb_event event) +{ + return afb_req_subscribe(subcall->req, event); +} + +static int subcall_unsubscribe(struct afb_subcall *subcall, struct afb_event event) +{ + return afb_req_unsubscribe(subcall->req, event); +} + +static void subcall_subcall(struct afb_subcall *subcall, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure) +{ + afb_subcall(&subcall->context, api, verb, args, callback, closure, (struct afb_req){ .itf = &afb_subcall_req_itf, .closure = subcall }); +} + +void afb_subcall(struct afb_context *context, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure, struct afb_req req) +{ + struct afb_subcall *subcall; + + subcall = calloc(1, sizeof *subcall); + if (subcall == NULL) { + callback(closure, 1, afb_msg_json_reply_error("failed", "out of memory", NULL, NULL)); + return; + } + + subcall->original_context = context; + subcall->refcount = 1; + subcall->args = args; + subcall->req = req; + subcall->callback = callback; + subcall->closure = closure; + subcall->context = *context; + afb_req_addref(req); + afb_apis_call_((struct afb_req){ .itf = &afb_subcall_req_itf, .closure = subcall }, &subcall->context, api, verb); + subcall_unref(subcall); +} + + diff --git a/src/afb-subcall.h b/src/afb-subcall.h new file mode 100644 index 00000000..8fbc4ad8 --- /dev/null +++ b/src/afb-subcall.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 "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. + */ + +#pragma once + +struct afb_context; +struct afb_req; +struct json_object; + +extern void afb_subcall(struct afb_context *context, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure, struct afb_req req); + + diff --git a/src/afb-ws-json1.c b/src/afb-ws-json1.c index 5ef751f1..31e9e42e 100644 --- a/src/afb-ws-json1.c +++ b/src/afb-ws-json1.c @@ -25,14 +25,16 @@ #include +#include + #include "afb-wsj1.h" #include "afb-ws-json1.h" #include "afb-msg-json.h" #include "session.h" -#include #include "afb-apis.h" #include "afb-context.h" #include "afb-evt.h" +#include "afb-subcall.h" #include "verbose.h" static void aws_on_hangup(struct afb_ws_json1 *ws, struct afb_wsj1 *wsj1); @@ -144,6 +146,7 @@ static const char *wsreq_raw(struct afb_wsreq *wsreq, size_t *size); static void wsreq_send(struct afb_wsreq *wsreq, const char *buffer, size_t size); static int wsreq_subscribe(struct afb_wsreq *wsreq, struct afb_event event); static int wsreq_unsubscribe(struct afb_wsreq *wsreq, struct afb_event event); +static void wsreq_subcall(struct afb_wsreq *wsreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure); const struct afb_req_itf afb_ws_json1_req_itf = { .json = (void*)wsreq_json, @@ -159,7 +162,8 @@ const struct afb_req_itf afb_ws_json1_req_itf = { .session_close = (void*)afb_context_close, .session_set_LOA = (void*)afb_context_change_loa, .subscribe = (void*)wsreq_subscribe, - .unsubscribe = (void*)wsreq_unsubscribe + .unsubscribe = (void*)wsreq_unsubscribe, + .subcall = (void*)wsreq_subcall }; static void aws_on_call(struct afb_ws_json1 *ws, const char *api, const char *verb, struct afb_wsj1_msg *msg) @@ -282,3 +286,8 @@ static int wsreq_unsubscribe(struct afb_wsreq *wsreq, struct afb_event event) return afb_evt_remove_watch(wsreq->aws->listener, event); } +static void wsreq_subcall(struct afb_wsreq *wsreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure) +{ + afb_subcall(&wsreq->context, api, verb, args, callback, closure, (struct afb_req){ .itf = &afb_ws_json1_req_itf, .closure = wsreq }); +} + -- 2.16.6