Make possible to call a method from a binding 35/5935/1
authorJosé Bollo <jose.bollo@iot.bzh>
Thu, 9 Jun 2016 14:59:19 +0000 (16:59 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Thu, 9 Jun 2016 14:59:19 +0000 (16:59 +0200)
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 <jose.bollo@iot.bzh>
include/afb/afb-req-itf.h
plugins/samples/HelloWorld.c
src/CMakeLists.txt
src/afb-api-dbus.c
src/afb-hreq.c
src/afb-msg-json.c
src/afb-subcall.c [new file with mode: 0644]
src/afb-subcall.h [new file with mode: 0644]
src/afb-ws-json1.c

index 2b3bc46..3efb089 100644 (file)
@@ -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)
index e487304..259b42f 100644 (file)
@@ -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}
 };
 
index cbaf286..286b825 100644 (file)
@@ -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
index eda7985..905c723 100644 (file)
@@ -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 */
index 1e38b41..d1a262f 100644 (file)
@@ -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;
index d5f6f5a..8f543ff 100644 (file)
@@ -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 (file)
index 0000000..4d18bee
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2016 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <json-c/json.h>
+#include <afb/afb-req-itf.h>
+
+#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 (file)
index 0000000..8fbc4ad
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * 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);
+
+
index 5ef751f..31e9e42 100644 (file)
 
 #include <json-c/json.h>
 
+#include <afb/afb-req-itf.h>
+
 #include "afb-wsj1.h"
 #include "afb-ws-json1.h"
 #include "afb-msg-json.h"
 #include "session.h"
-#include <afb/afb-req-itf.h>
 #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 });
+}
+