Introduce apiset for grouping apis
[src/app-framework-binder.git] / src / afb-subcall.c
index 65bef2f..8a8c77a 100644 (file)
 
 #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);
 
-static struct afb_arg subcall_get(struct afb_subcall *subcall, const char *name)
-{
-       return afb_msg_json_get_arg(subcall->args, name);
+       subcall->callback(subcall->closure, iserror, obj);
+       json_object_put(obj);
 }
 
-static void subcall_emit(struct afb_subcall *subcall, int iserror, struct json_object *object)
+static int subcall_subscribe(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_subscribe(subcall->caller, event);
 }
 
-static void subcall_fail(struct afb_subcall *subcall, const char *status, const char *info)
+static int subcall_unsubscribe(struct afb_xreq *xreq, struct afb_event event)
 {
-       subcall_emit(subcall, 1, afb_msg_json_reply_error(status, info, NULL, NULL));
-}
+       struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
 
-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;
+       size_t lenapi, lenverb;
+       char *copy;
 
-static void subcall_send(struct afb_subcall *subcall, const char *buffer, size_t size)
-{
-       subcall_emit(subcall, 0, json_tokener_parse(buffer));
+       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 = &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 void subcall_session_close(struct afb_subcall *subcall)
+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
+)
 {
-       afb_req_session_close(subcall->req);
-}
+       struct subcall *subcall;
 
-static int subcall_session_set_LOA(struct afb_subcall *subcall, unsigned loa)
-{
-       return afb_req_session_set_LOA(subcall->req, loa);
-}
+       subcall = create_subcall(caller, api, verb, args, callback, closure);
+       if (subcall == NULL) {
+               callback(closure, 1, afb_msg_json_internal_error());
+               return;
+       }
 
-static int subcall_subscribe(struct afb_subcall *subcall, struct afb_event event)
-{
-       return afb_req_subscribe(subcall->req, event);
+       afb_xreq_process(&subcall->xreq, caller->apiset);
 }
 
-static int subcall_unsubscribe(struct afb_subcall *subcall, struct afb_event event)
+struct subcall_sync
 {
-       return afb_req_unsubscribe(subcall->req, event);
-}
+       struct afb_xreq *caller;
+       const char *api;
+       const char *verb;
+       struct json_object *args;
+       struct jobloop *jobloop;
+       struct json_object *result;
+       int iserror;
+};
 
-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_sync *sync)
 {
-       afb_subcall(&subcall->context, api, verb, args, callback, closure, (struct afb_req){ .itf = &afb_subcall_req_itf, .closure = subcall });
+       struct jobloop *jobloop = sync->jobloop;
+       sync->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_reply(void *closure, int iserror, struct json_object *obj)
 {
-       static struct json_object *obj;
-
-       if (obj == NULL)
-               obj = afb_msg_json_reply_error("failed", "internal error", NULL, NULL);
+       struct subcall_sync *sync = closure;
 
-       callback(closure, 1, obj);
+       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) {
-               afb_subcall_internal_error(callback, closure);
-               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;
 }