/*
- * Copyright (C) 2016 "IoT.bzh"
+ * Copyright (C) 2016, 2017 "IoT.bzh"
* Author: José Bollo <jose.bollo@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
#include "afb-subcall.h"
#include "afb-msg-json.h"
-#include "afb-apis.h"
+#include "afb-apiset.h"
#include "afb-context.h"
+#include "afb-xreq.h"
+#include "afb-cred.h"
#include "verbose.h"
+#include "jobs.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 subcall;
+
+static void subcall_destroy(struct afb_xreq *xreq);
+static void subcall_reply(struct afb_xreq *xreq, int iserror, struct json_object *obj);
+static int subcall_subscribe(struct afb_xreq *xreq, struct afb_event event);
+static int subcall_unsubscribe(struct afb_xreq *xreq, struct afb_event event);
+
+const struct afb_xreq_query_itf afb_subcall_xreq_itf = {
+ .reply = subcall_reply,
+ .unref = subcall_destroy,
+ .subscribe = subcall_subscribe,
+ .unsubscribe = subcall_unsubscribe
};
-struct afb_subcall
+struct 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;
+ struct afb_xreq xreq;
+ struct afb_xreq *caller;
void (*callback)(void*, int, struct json_object*);
void *closure;
};
-static void subcall_addref(struct afb_subcall *subcall)
+static void subcall_destroy(struct afb_xreq *xreq)
{
- subcall->refcount++;
-}
+ struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
-static void subcall_unref(struct afb_subcall *subcall)
-{
- if (0 == --subcall->refcount) {
- json_object_put(subcall->args);
- afb_req_unref(subcall->req);
- free(subcall);
- }
+ json_object_put(subcall->xreq.json);
+ afb_cred_unref(subcall->xreq.cred);
+ afb_xreq_unref(subcall->caller);
+ free(subcall);
}
-static struct json_object *subcall_json(struct afb_subcall *subcall)
+static void subcall_reply(struct afb_xreq *xreq, int iserror, struct json_object *obj)
{
- return subcall->args;
+ struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
+
+ subcall->callback(subcall->closure, iserror, obj);
+ json_object_put(obj);
}
-static struct afb_arg subcall_get(struct afb_subcall *subcall, const char *name)
+static int subcall_subscribe(struct afb_xreq *xreq, struct afb_event event)
{
- struct afb_arg arg;
- struct json_object *value;
+ struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
- 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;
+ return afb_xreq_subscribe(subcall->caller, event);
}
-static void subcall_emit(struct afb_subcall *subcall, int iserror, struct json_object *object)
+static int subcall_unsubscribe(struct afb_xreq *xreq, struct afb_event event)
{
- if (subcall->context.refreshing != 0)
- subcall->original_context->refreshing = 1;
+ struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
- subcall->callback(subcall->closure, iserror, object);
- json_object_put(object);
+ return afb_xreq_unsubscribe(subcall->caller, event);
}
-static void subcall_fail(struct afb_subcall *subcall, const char *status, const char *info)
+static struct subcall *create_subcall(struct afb_xreq *caller, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure)
{
- subcall_emit(subcall, 1, afb_msg_json_reply_error(status, info, NULL, NULL));
-}
+ struct subcall *subcall;
+ size_t lenapi, lenverb;
+ char *copy;
-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));
+ lenapi = 1 + strlen(api);
+ lenverb = 1 + strlen(verb);
+ subcall = malloc(lenapi + lenverb + sizeof *subcall);
+ if (subcall == NULL) {
+ return NULL;
+ }
+ afb_xreq_init(&subcall->xreq, &afb_subcall_xreq_itf);
+ afb_context_subinit(&subcall->xreq.context, &caller->context);
+ subcall->xreq.cred = afb_cred_addref(caller->cred);
+ subcall->xreq.json = args;
+ copy = (char*)&subcall[1];
+ memcpy(copy, api, lenapi);
+ subcall->xreq.api = copy;
+ copy = ©[lenapi];
+ memcpy(copy, verb, lenverb);
+ subcall->xreq.verb = copy;
+ subcall->caller = caller;
+ subcall->callback = callback;
+ subcall->closure = closure;
+ afb_xreq_addref(caller);
+ json_object_get(args);
+ return subcall;
}
-static const char *subcall_raw(struct afb_subcall *subcall, size_t *size)
+void afb_subcall(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*),
+ void *closure
+)
{
- const char *result = json_object_to_json_string(subcall->args);
- if (size != NULL)
- *size = strlen(result);
- return result;
-}
+ struct subcall *subcall;
-static void subcall_send(struct afb_subcall *subcall, const char *buffer, size_t size)
-{
- subcall_emit(subcall, 0, json_tokener_parse(buffer));
-}
+ subcall = create_subcall(caller, api, verb, args, callback, closure);
+ if (subcall == NULL) {
+ callback(closure, 1, afb_msg_json_internal_error());
+ return;
+ }
-static void subcall_session_close(struct afb_subcall *subcall)
-{
- afb_req_session_close(subcall->req);
+ afb_xreq_process(&subcall->xreq, caller->apiset);
}
-static int subcall_session_set_LOA(struct afb_subcall *subcall, unsigned loa)
+struct subcall_sync
{
- return afb_req_session_set_LOA(subcall->req, loa);
-}
+ struct afb_xreq *caller;
+ const char *api;
+ const char *verb;
+ struct json_object *args;
+ struct jobloop *jobloop;
+ struct json_object *result;
+ int iserror;
+};
-static int subcall_subscribe(struct afb_subcall *subcall, struct afb_event event)
+static void subcall_sync_leave(struct subcall_sync *sync)
{
- return afb_req_subscribe(subcall->req, event);
+ struct jobloop *jobloop = sync->jobloop;
+ sync->jobloop = NULL;
+ if (jobloop)
+ jobs_leave(jobloop);
}
-static int subcall_unsubscribe(struct afb_subcall *subcall, struct afb_event event)
+static void subcall_sync_reply(void *closure, int iserror, struct json_object *obj)
{
- return afb_req_unsubscribe(subcall->req, event);
-}
+ struct subcall_sync *sync = closure;
-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 });
+ sync->iserror = iserror;
+ sync->result = obj;
+ json_object_get(obj);
+ subcall_sync_leave(sync);
}
-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)
+static void subcall_sync_enter(int signum, void *closure, struct jobloop *jobloop)
{
- struct afb_subcall *subcall;
+ struct subcall_sync *sync = closure;
- subcall = calloc(1, sizeof *subcall);
- if (subcall == NULL) {
- callback(closure, 1, afb_msg_json_reply_error("failed", "out of memory", NULL, NULL));
- return;
+ if (!signum) {
+ sync->jobloop = jobloop;
+ afb_xreq_unhooked_subcall(sync->caller, sync->api, sync->verb, sync->args, subcall_sync_reply, sync);
+ } else {
+ sync->result = json_object_get(afb_msg_json_internal_error());
+ sync->iserror = 1;
+ subcall_sync_leave(sync);
}
+}
- 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);
+int afb_subcall_sync(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result
+)
+{
+ int rc;
+ struct subcall_sync sync;
+
+ sync.caller = caller;
+ sync.api = api;
+ sync.verb = verb;
+ sync.args = args;
+ sync.jobloop = NULL;
+ sync.result = NULL;
+ sync.iserror = 1;
+
+ rc = jobs_enter(NULL, 0, subcall_sync_enter, &sync);
+ if (rc < 0) {
+ sync.result = json_object_get(afb_msg_json_internal_error());
+ sync.iserror = 1;
+ }
+ rc = !sync.iserror;
+ *result = sync.result;
+ return rc;
}