Launch job at a earlier step
[src/app-framework-binder.git] / src / afb-xreq.c
1 /*
2  * Copyright (C) 2017 "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 #define NO_BINDING_VERBOSE_MACRO
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include <json-c/json.h>
26 #include <afb/afb-binding.h>
27
28 #include "afb-context.h"
29 #include "afb-xreq.h"
30 #include "afb-evt.h"
31 #include "afb-msg-json.h"
32 #include "afb-subcall.h"
33 #include "verbose.h"
34
35
36 static struct json_object *xreq_json_cb(void *closure);
37 static struct afb_arg xreq_get_cb(void *closure, const char *name);
38
39 static void xreq_success_cb(void *closure, struct json_object *obj, const char *info);
40 static void xreq_fail_cb(void *closure, const char *status, const char *info);
41
42 static const char *xreq_raw_cb(void *closure, size_t *size);
43 static void xreq_send_cb(void *closure, const char *buffer, size_t size);
44
45 static void *xreq_context_get_cb(void *closure);
46 static void xreq_context_set_cb(void *closure, void *value, void (*free_value)(void*));
47
48 static void xreq_addref_cb(void *closure);
49 static void xreq_unref_cb(void *closure);
50
51 static void xreq_session_close_cb(void *closure);
52 static int xreq_session_set_LOA_cb(void *closure, unsigned level);
53
54 static int xreq_subscribe_cb(void *closure, struct afb_event event);
55 static int xreq_unsubscribe_cb(void *closure, struct afb_event event);
56
57 static void xreq_subcall_cb(
58                 void *closure,
59                 const char *api,
60                 const char *verb,
61                 struct json_object *args,
62                 void (*callback)(void*, int, struct json_object*),
63                 void *cb_closure);
64
65 const struct afb_req_itf xreq_itf = {
66         .json = xreq_json_cb,
67         .get = xreq_get_cb,
68         .success = xreq_success_cb,
69         .fail = xreq_fail_cb,
70         .raw = xreq_raw_cb,
71         .send = xreq_send_cb,
72         .context_get = xreq_context_get_cb,
73         .context_set = xreq_context_set_cb,
74         .addref = xreq_addref_cb,
75         .unref = xreq_unref_cb,
76         .session_close = xreq_session_close_cb,
77         .session_set_LOA = xreq_session_set_LOA_cb,
78         .subscribe = xreq_subscribe_cb,
79         .unsubscribe = xreq_unsubscribe_cb,
80         .subcall = xreq_subcall_cb
81 };
82
83 static struct json_object *xreq_json_cb(void *closure)
84 {
85         struct afb_xreq *xreq = closure;
86         return xreq->json ? : (xreq->json = xreq->queryitf->json(xreq->query));
87 }
88
89 static struct afb_arg xreq_get_cb(void *closure, const char *name)
90 {
91         struct afb_xreq *xreq = closure;
92         if (xreq->queryitf->get)
93                 return xreq->queryitf->get(xreq->query, name);
94         else
95                 return afb_msg_json_get_arg(xreq_json_cb(closure), name);
96 }
97
98 static void xreq_success_cb(void *closure, struct json_object *obj, const char *info)
99 {
100         struct afb_xreq *xreq = closure;
101         afb_xreq_success(xreq, obj, info);
102 }
103
104 void afb_xreq_success(struct afb_xreq *xreq, struct json_object *obj, const char *info)
105 {
106         if (xreq->replied) {
107                 ERROR("reply called more than one time!!");
108                 json_object_put(obj);
109         } else {
110                 xreq->replied = 1;
111                 if (xreq->queryitf->success)
112                         xreq->queryitf->success(xreq->query, obj, info);
113                 else
114                         xreq->queryitf->reply(xreq->query, 0, afb_msg_json_reply_ok(info, obj, &xreq->context, NULL));
115         }
116 }
117
118 static void xreq_fail_cb(void *closure, const char *status, const char *info)
119 {
120         struct afb_xreq *xreq = closure;
121         afb_xreq_fail(xreq, status, info);
122 }
123
124 void afb_xreq_fail(struct afb_xreq *xreq, const char *status, const char *info)
125 {
126         if (xreq->replied) {
127                 ERROR("reply called more than one time!!");
128         } else {
129                 xreq->replied = 1;
130                 if (xreq->queryitf->fail)
131                         xreq->queryitf->fail(xreq->query, status, info);
132                 else
133                         xreq->queryitf->reply(xreq->query, 1, afb_msg_json_reply_error(status, info, &xreq->context, NULL));
134         }
135 }
136
137 static const char *xreq_raw_cb(void *closure, size_t *size)
138 {
139         struct afb_xreq *xreq = closure;
140         return afb_xreq_raw(xreq, size);
141 }
142
143 const char *afb_xreq_raw(struct afb_xreq *xreq, size_t *size)
144 {
145         const char *result = json_object_to_json_string(xreq_json_cb(xreq));
146         if (size != NULL)
147                 *size = strlen(result);
148         return result;
149 }
150
151 static void xreq_send_cb(void *closure, const char *buffer, size_t size)
152 {
153         struct json_object *obj = json_tokener_parse(buffer);
154         if (!obj == !buffer)
155                 xreq_success_cb(closure, obj, "fake send");
156         else
157                 xreq_fail_cb(closure, "fake-send-failed", "fake send");
158 }
159
160 static void *xreq_context_get_cb(void *closure)
161 {
162         struct afb_xreq *xreq = closure;
163         return afb_context_get(&xreq->context);
164 }
165
166 static void xreq_context_set_cb(void *closure, void *value, void (*free_value)(void*))
167 {
168         struct afb_xreq *xreq = closure;
169         afb_context_set(&xreq->context, value, free_value);
170 }
171
172 static void xreq_addref_cb(void *closure)
173 {
174         struct afb_xreq *xreq = closure;
175         afb_xreq_addref(xreq);
176 }
177
178 void afb_xreq_addref(struct afb_xreq *xreq)
179 {
180         xreq->refcount++;
181 }
182
183 static void xreq_unref_cb(void *closure)
184 {
185         struct afb_xreq *xreq = closure;
186         afb_xreq_unref(xreq);
187 }
188
189 void afb_xreq_unref(struct afb_xreq *xreq)
190 {
191         if (!--xreq->refcount) {
192                 xreq->queryitf->unref(xreq->query);
193         }
194 }
195
196 static void xreq_session_close_cb(void *closure)
197 {
198         struct afb_xreq *xreq = closure;
199         afb_context_close(&xreq->context);
200 }
201
202 static int xreq_session_set_LOA_cb(void *closure, unsigned level)
203 {
204         struct afb_xreq *xreq = closure;
205         return afb_context_change_loa(&xreq->context, level);
206 }
207
208 static int xreq_subscribe_cb(void *closure, struct afb_event event)
209 {
210         struct afb_xreq *xreq = closure;
211         return afb_xreq_subscribe(xreq, event);
212 }
213
214 int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_event event)
215 {
216         if (xreq->listener)
217                 return afb_evt_add_watch(xreq->listener, event);
218         if (xreq->queryitf->subscribe)
219                 return xreq->queryitf->subscribe(xreq->query, event);
220         ERROR("no event listener, subscription impossible");
221         errno = EINVAL;
222         return -1;
223 }
224
225 static int xreq_unsubscribe_cb(void *closure, struct afb_event event)
226 {
227         struct afb_xreq *xreq = closure;
228         return afb_xreq_unsubscribe(xreq, event);
229 }
230
231 int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_event event)
232 {
233         if (xreq->listener)
234                 return afb_evt_remove_watch(xreq->listener, event);
235         if (xreq->queryitf->unsubscribe)
236                 return xreq->queryitf->unsubscribe(xreq->query, event);
237         ERROR("no event listener, unsubscription impossible");
238         errno = EINVAL;
239         return -1;
240 }
241
242 static void xreq_subcall_cb(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
243 {
244         struct afb_xreq *xreq = closure;
245         if (xreq->queryitf->subcall)
246                 xreq->queryitf->subcall(xreq->query, api, verb, args, callback, cb_closure);
247         else
248                 afb_subcall(xreq, api, verb, args, callback, cb_closure);
249 }
250
251 void afb_xreq_success_f(struct afb_xreq *xreq, struct json_object *obj, const char *info, ...)
252 {
253         char *message;
254         va_list args;
255         va_start(args, info);
256         if (info == NULL || vasprintf(&message, info, args) < 0)
257                 message = NULL;
258         va_end(args);
259         afb_xreq_success(xreq, obj, message);
260         free(message);
261 }
262
263 void afb_xreq_fail_f(struct afb_xreq *xreq, const char *status, const char *info, ...)
264 {
265         char *message;
266         va_list args;
267         va_start(args, info);
268         if (info == NULL || vasprintf(&message, info, args) < 0)
269                 message = NULL;
270         va_end(args);
271         afb_xreq_fail(xreq, status, message);
272         free(message);
273 }
274
275 static int xcheck(struct afb_xreq *xreq)
276 {
277         int stag = xreq->sessionflags;
278
279         if ((stag & (AFB_SESSION_CREATE|AFB_SESSION_CLOSE|AFB_SESSION_RENEW|AFB_SESSION_CHECK|AFB_SESSION_LOA_EQ)) != 0) {
280                 if (!afb_context_check(&xreq->context)) {
281                         afb_context_close(&xreq->context);
282                         afb_xreq_fail_f(xreq, "failed", "invalid token's identity");
283                         return 0;
284                 }
285         }
286
287         if ((stag & AFB_SESSION_CREATE) != 0) {
288                 if (afb_context_check_loa(&xreq->context, 1)) {
289                         afb_xreq_fail_f(xreq, "failed", "invalid creation state");
290                         return 0;
291                 }
292                 afb_context_change_loa(&xreq->context, 1);
293                 afb_context_refresh(&xreq->context);
294         }
295
296         if ((stag & (AFB_SESSION_CREATE | AFB_SESSION_RENEW)) != 0)
297                 afb_context_refresh(&xreq->context);
298
299         if ((stag & AFB_SESSION_CLOSE) != 0) {
300                 afb_context_change_loa(&xreq->context, 0);
301                 afb_context_close(&xreq->context);
302         }
303
304         if ((stag & AFB_SESSION_LOA_GE) != 0) {
305                 int loa = (stag >> AFB_SESSION_LOA_SHIFT) & AFB_SESSION_LOA_MASK;
306                 if (!afb_context_check_loa(&xreq->context, loa)) {
307                         afb_xreq_fail_f(xreq, "failed", "invalid LOA");
308                         return 0;
309                 }
310         }
311
312         if ((stag & AFB_SESSION_LOA_LE) != 0) {
313                 int loa = (stag >> AFB_SESSION_LOA_SHIFT) & AFB_SESSION_LOA_MASK;
314                 if (afb_context_check_loa(&xreq->context, loa + 1)) {
315                         afb_xreq_fail_f(xreq, "failed", "invalid LOA");
316                         return 0;
317                 }
318         }
319         return 1;
320 }
321
322 void afb_xreq_call(struct afb_xreq *xreq)
323 {
324         if (xcheck(xreq))
325                 xreq->callback((struct afb_req){ .itf = &xreq_itf, .closure = xreq });
326 }
327