#include "afb-msg-json.h"
#include "afb-apis.h"
#include "afb-context.h"
+#include "afb-xreq.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(void *closure);
+static void subcall_reply(void *closure, int iserror, struct json_object *obj);
+static int subcall_subscribe(void *closure, struct afb_event event);
+static int subcall_unsubscribe(void *closure, struct afb_event event);
+static void subcall_sync_leave(struct subcall *subcall);
+
+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;
+ struct jobloop *jobloop;
+ struct json_object *result;
+ int iserror;
};
-static void subcall_addref(struct afb_subcall *subcall)
+static void subcall_destroy(void *closure)
{
- subcall->refcount++;
-}
+ struct subcall *subcall = closure;
-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_xreq_unref(subcall->caller);
+ free(subcall);
}
-static struct json_object *subcall_json(struct afb_subcall *subcall)
+static void subcall_reply(void *closure, int iserror, struct json_object *obj)
{
- return subcall->args;
-}
+ struct subcall *subcall = closure;
-static struct afb_arg subcall_get(struct afb_subcall *subcall, const char *name)
-{
- return afb_msg_json_get_arg(subcall->args, name);
+ if (subcall->callback) {
+ subcall->callback(subcall->closure, iserror, obj);
+ json_object_put(obj);
+ } else {
+ subcall->result = obj;
+ subcall->iserror = iserror;
+ subcall_sync_leave(subcall);
+ }
}
-static void subcall_emit(struct afb_subcall *subcall, int iserror, struct json_object *object)
+static int subcall_subscribe(void *closure, struct afb_event event)
{
- if (subcall->context.refreshing != 0)
- subcall->original_context->refreshing = 1;
+ struct subcall *subcall = closure;
- subcall->callback(subcall->closure, iserror, object);
- json_object_put(object);
+ return afb_xreq_subscribe(subcall->caller, event);
}
-static void subcall_fail(struct afb_subcall *subcall, const char *status, const char *info)
+static int subcall_unsubscribe(void *closure, struct afb_event event)
{
- subcall_emit(subcall, 1, afb_msg_json_reply_error(status, info, NULL, NULL));
-}
+ struct subcall *subcall = closure;
-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));
+ return afb_xreq_unsubscribe(subcall->caller, event);
}
-static const char *subcall_raw(struct afb_subcall *subcall, size_t *size)
+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)
{
- 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 = calloc(1, sizeof *subcall);
+ if (subcall == NULL) {
+ return NULL;
+ }
-static void subcall_session_close(struct afb_subcall *subcall)
-{
- afb_req_session_close(subcall->req);
+ afb_context_subinit(&subcall->xreq.context, &caller->context);
+ subcall->xreq.refcount = 1;
+ subcall->xreq.json = args;
+ subcall->xreq.api = api; /* TODO: alloc ? */
+ subcall->xreq.verb = verb; /* TODO: alloc ? */
+ subcall->xreq.query = subcall;
+ subcall->xreq.queryitf = &afb_subcall_xreq_itf;
+ subcall->caller = caller;
+ subcall->callback = callback;
+ subcall->closure = closure;
+ afb_xreq_addref(caller);
+ json_object_get(args);
+ return subcall;
}
-static int subcall_session_set_LOA(struct afb_subcall *subcall, unsigned loa)
+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
+)
{
- return afb_req_session_set_LOA(subcall->req, loa);
-}
+ struct subcall *subcall;
-static int subcall_subscribe(struct afb_subcall *subcall, struct afb_event event)
-{
- return afb_req_subscribe(subcall->req, event);
-}
+ subcall = create_subcall(caller, api, verb, args, callback, closure);
+ if (subcall == NULL) {
+ callback(closure, 1, afb_msg_json_internal_error());
+ return;
+ }
-static int subcall_unsubscribe(struct afb_subcall *subcall, struct afb_event event)
-{
- return afb_req_unsubscribe(subcall->req, event);
+ afb_apis_call(&subcall->xreq);
+ afb_xreq_unref(&subcall->xreq);
}
-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)
+static void subcall_sync_leave(struct subcall *subcall)
{
- afb_subcall(&subcall->context, api, verb, args, callback, closure, (struct afb_req){ .itf = &afb_subcall_req_itf, .closure = subcall });
+ struct jobloop *jobloop = subcall->jobloop;
+ subcall->jobloop = NULL;
+ if (jobloop)
+ jobs_leave(jobloop);
}
-void afb_subcall_internal_error(void (*callback)(void*, int, struct json_object*), void *closure)
+static void subcall_sync_cb(int signum, void *closure, struct jobloop *jobloop)
{
- static struct json_object *obj;
-
- if (obj == NULL)
- obj = afb_msg_json_reply_error("failed", "internal error", NULL, NULL);
+ struct subcall *subcall = closure;
- callback(closure, 1, obj);
+ if (!signum) {
+ subcall->jobloop = jobloop;
+ afb_apis_call_direct(&subcall->xreq);
+ } else {
+ afb_xreq_fail_f(&subcall->xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum);
+ }
+ subcall_sync_leave(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)
+int afb_subcall_sync(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result
+)
{
- struct afb_subcall *subcall;
+ int rc;
+ struct subcall *subcall;
- subcall = calloc(1, sizeof *subcall);
+ subcall = create_subcall(caller, api, verb, args, NULL, NULL);
if (subcall == NULL) {
- afb_subcall_internal_error(callback, closure);
- return;
+ *result = json_object_get(afb_msg_json_internal_error());
+ return 0;
}
- 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);
+ rc = jobs_enter(NULL, 0, subcall_sync_cb, subcall);
+ if (rc < 0) {
+ subcall->result = json_object_get(afb_msg_json_internal_error());
+ subcall->iserror = 1;
+ }
+ rc = !subcall->iserror;
+ *result = subcall->result;
+ afb_xreq_unref(&subcall->xreq);
+ return rc;
}