Make possible to call a method from a binding
[src/app-framework-binder.git] / src / afb-subcall.c
1 /*
2  * Copyright (C) 2016 "IoT.bzh"
3  * Author: José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <json-c/json.h>
24 #include <afb/afb-req-itf.h>
25
26 #include "afb-subcall.h"
27 #include "afb-msg-json.h"
28 #include "afb-apis.h"
29 #include "afb-context.h"
30 #include "verbose.h"
31
32 struct afb_subcall;
33
34 static void subcall_addref(struct afb_subcall *subcall);
35 static void subcall_unref(struct afb_subcall *subcall);
36 static struct json_object *subcall_json(struct afb_subcall *subcall);
37 static struct afb_arg subcall_get(struct afb_subcall *subcall, const char *name);
38 static void subcall_fail(struct afb_subcall *subcall, const char *status, const char *info);
39 static void subcall_success(struct afb_subcall *subcall, struct json_object *obj, const char *info);
40 static const char *subcall_raw(struct afb_subcall *subcall, size_t *size);
41 static void subcall_send(struct afb_subcall *subcall, const char *buffer, size_t size);
42 static int subcall_subscribe(struct afb_subcall *subcall, struct afb_event event);
43 static int subcall_unsubscribe(struct afb_subcall *subcall, struct afb_event event);
44 static void subcall_session_close(struct afb_subcall *subcall);
45 static int subcall_session_set_LOA(struct afb_subcall *subcall, unsigned loa);
46 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);
47
48 const struct afb_req_itf afb_subcall_req_itf = {
49         .json = (void*)subcall_json,
50         .get = (void*)subcall_get,
51         .success = (void*)subcall_success,
52         .fail = (void*)subcall_fail,
53         .raw = (void*)subcall_raw,
54         .send = (void*)subcall_send,
55         .context_get = (void*)afb_context_get,
56         .context_set = (void*)afb_context_set,
57         .addref = (void*)subcall_addref,
58         .unref = (void*)subcall_unref,
59         .session_close = (void*)subcall_session_close,
60         .session_set_LOA = (void*)subcall_session_set_LOA,
61         .subscribe = (void*)subcall_subscribe,
62         .unsubscribe = (void*)subcall_unsubscribe,
63         .subcall = (void*)subcall_subcall
64 };
65
66 struct afb_subcall
67 {
68         /*
69          * CAUTION: 'context' field should be the first because there
70          * is an implicit convertion to struct afb_context
71          */
72         struct afb_context context;
73         struct afb_context *original_context;
74         int refcount;
75         struct json_object *args;
76         struct afb_req req;
77         void (*callback)(void*, int, struct json_object*);
78         void *closure;
79 };
80
81 static void subcall_addref(struct afb_subcall *subcall)
82 {
83         subcall->refcount++;
84 }
85
86 static void subcall_unref(struct afb_subcall *subcall)
87 {
88         if (0 == --subcall->refcount) {
89                 json_object_put(subcall->args);
90                 afb_req_unref(subcall->req);
91                 free(subcall);
92         }
93 }
94
95 static struct json_object *subcall_json(struct afb_subcall *subcall)
96 {
97         return subcall->args;
98 }
99
100 static struct afb_arg subcall_get(struct afb_subcall *subcall, const char *name)
101 {
102         struct afb_arg arg;
103         struct json_object *value;
104
105         if (json_object_object_get_ex(subcall->args, name, &value)) {
106                 arg.name = name;
107                 arg.value = json_object_get_string(value);
108         } else {
109                 arg.name = NULL;
110                 arg.value = NULL;
111         }
112         arg.path = NULL;
113         return arg;
114 }
115
116 static void subcall_emit(struct afb_subcall *subcall, int iserror, struct json_object *object)
117 {
118         if (subcall->context.refreshing != 0)
119                 subcall->original_context->refreshing = 1;
120
121         subcall->callback(subcall->closure, iserror, object);
122         json_object_put(object);
123 }
124
125 static void subcall_fail(struct afb_subcall *subcall, const char *status, const char *info)
126 {
127         subcall_emit(subcall, 1, afb_msg_json_reply_error(status, info, NULL, NULL));
128 }
129
130 static void subcall_success(struct afb_subcall *subcall, struct json_object *obj, const char *info)
131 {
132         subcall_emit(subcall, 0, afb_msg_json_reply_ok(info, obj, NULL, NULL));
133 }
134
135 static const char *subcall_raw(struct afb_subcall *subcall, size_t *size)
136 {
137         const char *result = json_object_to_json_string(subcall->args);
138         if (size != NULL)
139                 *size = strlen(result);
140         return result;
141 }
142
143 static void subcall_send(struct afb_subcall *subcall, const char *buffer, size_t size)
144 {
145         subcall_emit(subcall, 0, json_tokener_parse(buffer));
146 }
147
148 static void subcall_session_close(struct afb_subcall *subcall)
149 {
150         afb_req_session_close(subcall->req);
151 }
152
153 static int subcall_session_set_LOA(struct afb_subcall *subcall, unsigned loa)
154 {
155         return afb_req_session_set_LOA(subcall->req, loa);
156 }
157
158 static int subcall_subscribe(struct afb_subcall *subcall, struct afb_event event)
159 {
160         return afb_req_subscribe(subcall->req, event);
161 }
162
163 static int subcall_unsubscribe(struct afb_subcall *subcall, struct afb_event event)
164 {
165         return afb_req_unsubscribe(subcall->req, event);
166 }
167
168 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)
169 {
170         afb_subcall(&subcall->context, api, verb, args, callback, closure, (struct afb_req){ .itf = &afb_subcall_req_itf, .closure = subcall });
171 }
172
173 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)
174 {
175         struct afb_subcall *subcall;
176
177         subcall = calloc(1, sizeof *subcall);
178         if (subcall == NULL) {
179                 callback(closure, 1, afb_msg_json_reply_error("failed", "out of memory", NULL, NULL));
180                 return;
181         }
182
183         subcall->original_context = context;
184         subcall->refcount = 1;
185         subcall->args = args;
186         subcall->req = req;
187         subcall->callback = callback;
188         subcall->closure = closure;
189         subcall->context = *context;
190         afb_req_addref(req);
191         afb_apis_call_((struct afb_req){ .itf = &afb_subcall_req_itf, .closure = subcall }, &subcall->context, api, verb);
192         subcall_unref(subcall);
193 }
194
195