summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/afb/afb-req-itf.h16
-rw-r--r--plugins/samples/HelloWorld.c24
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/afb-api-dbus.c25
-rw-r--r--src/afb-hreq.c10
-rw-r--r--src/afb-msg-json.c16
-rw-r--r--src/afb-subcall.c195
-rw-r--r--src/afb-subcall.h26
-rw-r--r--src/afb-ws-json1.c13
9 files changed, 313 insertions, 13 deletions
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 <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
index 00000000..8fbc4ad8
--- /dev/null
+++ b/src/afb-subcall.h
@@ -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);
+
+
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 <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 });
+}
+