sample binding "hello" receives events
[src/app-framework-binder.git] / bindings / samples / HelloWorld.c
1 /*
2  * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
3  * Author "Fulup Ar Foll"
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 #define _GNU_SOURCE
18 #include <stdio.h>
19 #include <string.h>
20 #include <pthread.h>
21
22 #include <json-c/json.h>
23
24 #define AFB_BINDING_VERSION 2
25 #include <afb/afb-binding.h>
26
27 const struct afb_binding_interface *interface;
28 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
29
30 struct event
31 {
32         struct event *next;
33         struct afb_event event;
34         char tag[1];
35 };
36
37 static struct event *events = 0;
38
39 /* searchs the event of tag */
40 static struct event *event_get(const char *tag)
41 {
42         struct event *e = events;
43         while(e && strcmp(e->tag, tag))
44                 e = e->next;
45         return e;
46 }
47
48 /* deletes the event of tag */
49 static int event_del(const char *tag)
50 {
51         struct event *e, **p;
52
53         /* check exists */
54         e = event_get(tag);
55         if (!e) return -1;
56
57         /* unlink */
58         p = &events;
59         while(*p != e) p = &(*p)->next;
60         *p = e->next;
61
62         /* destroys */
63         afb_event_drop(e->event);
64         free(e);
65         return 0;
66 }
67
68 /* creates the event of tag */
69 static int event_add(const char *tag, const char *name)
70 {
71         struct event *e;
72
73         /* check valid tag */
74         e = event_get(tag);
75         if (e) return -1;
76
77         /* creation */
78         e = malloc(strlen(tag) + sizeof *e);
79         if (!e) return -1;
80         strcpy(e->tag, tag);
81
82         /* make the event */
83         e->event = afb_daemon_make_event(name);
84         if (!e->event.closure) { free(e); return -1; }
85
86         /* link */
87         e->next = events;
88         events = e;
89         return 0;
90 }
91
92 static int event_subscribe(struct afb_req request, const char *tag)
93 {
94         struct event *e;
95         e = event_get(tag);
96         return e ? afb_req_subscribe(request, e->event) : -1;
97 }
98
99 static int event_unsubscribe(struct afb_req request, const char *tag)
100 {
101         struct event *e;
102         e = event_get(tag);
103         return e ? afb_req_unsubscribe(request, e->event) : -1;
104 }
105
106 static int event_push(struct json_object *args, const char *tag)
107 {
108         struct event *e;
109         e = event_get(tag);
110         return e ? afb_event_push(e->event, json_object_get(args)) : -1;
111 }
112
113 // Sample Generic Ping Debug API
114 static void ping(struct afb_req request, json_object *jresp, const char *tag)
115 {
116         static int pingcount = 0;
117         json_object *query = afb_req_json(request);
118         afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query));
119 }
120
121 static void pingSample (struct afb_req request)
122 {
123         ping(request, json_object_new_string ("Some String"), "pingSample");
124 }
125
126 static void pingFail (struct afb_req request)
127 {
128         afb_req_fail(request, "failed", "Ping Binder Daemon fails");
129 }
130
131 static void pingNull (struct afb_req request)
132 {
133         ping(request, NULL, "pingNull");
134 }
135
136 static void pingBug (struct afb_req request)
137 {
138         ping((struct afb_req){NULL,NULL}, NULL, "pingBug");
139 }
140
141 static void pingEvent(struct afb_req request)
142 {
143         json_object *query = afb_req_json(request);
144         afb_daemon_broadcast_event("event", json_object_get(query));
145         ping(request, json_object_get(query), "event");
146 }
147
148
149 // For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/
150 static void pingJson (struct afb_req request) {
151     json_object *jresp, *embed;
152
153     jresp = json_object_new_object();
154     json_object_object_add(jresp, "myString", json_object_new_string ("Some String"));
155     json_object_object_add(jresp, "myInt", json_object_new_int (1234));
156
157     embed  = json_object_new_object();
158     json_object_object_add(embed, "subObjString", json_object_new_string ("Some String"));
159     json_object_object_add(embed, "subObjInt", json_object_new_int (5678));
160
161     json_object_object_add(jresp,"eobj", embed);
162
163     ping(request, jresp, "pingJson");
164 }
165
166 static void subcallcb (void *prequest, int iserror, json_object *object)
167 {
168         struct afb_req request = afb_req_unstore(prequest);
169         if (iserror)
170                 afb_req_fail(request, "failed", json_object_to_json_string(object));
171         else
172                 afb_req_success(request, json_object_get(object), NULL);
173         afb_req_unref(request);
174 }
175
176 static void subcall (struct afb_req request)
177 {
178         const char *api = afb_req_value(request, "api");
179         const char *verb = afb_req_value(request, "verb");
180         const char *args = afb_req_value(request, "args");
181         json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
182
183         if (object == NULL)
184                 afb_req_fail(request, "failed", "bad arguments");
185         else
186                 afb_req_subcall(request, api, verb, object, subcallcb, afb_req_store(request));
187 }
188
189 static void subcallsync (struct afb_req request)
190 {
191         int rc;
192         const char *api = afb_req_value(request, "api");
193         const char *verb = afb_req_value(request, "verb");
194         const char *args = afb_req_value(request, "args");
195         json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL;
196
197         if (object == NULL)
198                 afb_req_fail(request, "failed", "bad arguments");
199         else {
200                 rc = afb_req_subcall_sync(request, api, verb, object, &result);
201                 if (rc)
202                         afb_req_success(request, result, NULL);
203                 else {
204                         afb_req_fail(request, "failed", json_object_to_json_string(result));
205                         json_object_put(result);
206                 }
207         }
208 }
209
210 static void eventadd (struct afb_req request)
211 {
212         const char *tag = afb_req_value(request, "tag");
213         const char *name = afb_req_value(request, "name");
214
215         pthread_mutex_lock(&mutex);
216         if (tag == NULL || name == NULL)
217                 afb_req_fail(request, "failed", "bad arguments");
218         else if (0 != event_add(tag, name))
219                 afb_req_fail(request, "failed", "creation error");
220         else
221                 afb_req_success(request, NULL, NULL);
222         pthread_mutex_unlock(&mutex);
223 }
224
225 static void eventdel (struct afb_req request)
226 {
227         const char *tag = afb_req_value(request, "tag");
228
229         pthread_mutex_lock(&mutex);
230         if (tag == NULL)
231                 afb_req_fail(request, "failed", "bad arguments");
232         else if (0 != event_del(tag))
233                 afb_req_fail(request, "failed", "deletion error");
234         else
235                 afb_req_success(request, NULL, NULL);
236         pthread_mutex_unlock(&mutex);
237 }
238
239 static void eventsub (struct afb_req request)
240 {
241         const char *tag = afb_req_value(request, "tag");
242
243         pthread_mutex_lock(&mutex);
244         if (tag == NULL)
245                 afb_req_fail(request, "failed", "bad arguments");
246         else if (0 != event_subscribe(request, tag))
247                 afb_req_fail(request, "failed", "subscription error");
248         else
249                 afb_req_success(request, NULL, NULL);
250         pthread_mutex_unlock(&mutex);
251 }
252
253 static void eventunsub (struct afb_req request)
254 {
255         const char *tag = afb_req_value(request, "tag");
256
257         pthread_mutex_lock(&mutex);
258         if (tag == NULL)
259                 afb_req_fail(request, "failed", "bad arguments");
260         else if (0 != event_unsubscribe(request, tag))
261                 afb_req_fail(request, "failed", "unsubscription error");
262         else
263                 afb_req_success(request, NULL, NULL);
264         pthread_mutex_unlock(&mutex);
265 }
266
267 static void eventpush (struct afb_req request)
268 {
269         const char *tag = afb_req_value(request, "tag");
270         const char *data = afb_req_value(request, "data");
271         json_object *object = data ? json_tokener_parse(data) : NULL;
272
273         pthread_mutex_lock(&mutex);
274         if (tag == NULL)
275                 afb_req_fail(request, "failed", "bad arguments");
276         else if (0 > event_push(object, tag))
277                 afb_req_fail(request, "failed", "push error");
278         else
279                 afb_req_success(request, NULL, NULL);
280         pthread_mutex_unlock(&mutex);
281         json_object_put(object);
282 }
283
284 static void callcb (void *prequest, int iserror, json_object *object)
285 {
286         struct afb_req request = afb_req_unstore(prequest);
287         if (iserror)
288                 afb_req_fail(request, "failed", json_object_to_json_string(object));
289         else
290                 afb_req_success(request, json_object_get(object), NULL);
291         afb_req_unref(request);
292 }
293
294 static void call (struct afb_req request)
295 {
296         const char *api = afb_req_value(request, "api");
297         const char *verb = afb_req_value(request, "verb");
298         const char *args = afb_req_value(request, "args");
299         json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
300
301         if (object == NULL)
302                 afb_req_fail(request, "failed", "bad arguments");
303         else
304                 afb_service_call(api, verb, object, callcb, afb_req_store(request));
305 }
306
307 static void callsync (struct afb_req request)
308 {
309         int rc;
310         const char *api = afb_req_value(request, "api");
311         const char *verb = afb_req_value(request, "verb");
312         const char *args = afb_req_value(request, "args");
313         json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL;
314
315         if (object == NULL)
316                 afb_req_fail(request, "failed", "bad arguments");
317         else {
318                 rc = afb_service_call_sync(api, verb, object, &result);
319                 if (rc)
320                         afb_req_success(request, result, NULL);
321                 else {
322                         afb_req_fail(request, "failed", json_object_to_json_string(result));
323                         json_object_put(result);
324                 }
325         }
326 }
327
328 static void exitnow (struct afb_req request)
329 {
330         exit(0);
331 }
332
333 static int preinit()
334 {
335         NOTICE("hello binding comes to live");
336         return 0;
337 }
338
339 static int init()
340 {
341         NOTICE("hello binding starting");
342         return 0;
343 }
344
345 static void onevent(const char *event, struct json_object *object)
346 {
347         NOTICE("received event %s(%s)", event, json_object_to_json_string(object));
348 }
349
350 // NOTE: this sample does not use session to keep test a basic as possible
351 //       in real application most APIs should be protected with AFB_SESSION_CHECK
352 static const struct afb_verb_v2 verbs[]= {
353   { "ping"     ,    pingSample , NULL, AFB_SESSION_NONE },
354   { "pingfail" ,    pingFail   , NULL, AFB_SESSION_NONE },
355   { "pingnull" ,    pingNull   , NULL, AFB_SESSION_NONE },
356   { "pingbug"  ,    pingBug    , NULL, AFB_SESSION_NONE },
357   { "pingJson" ,    pingJson   , NULL, AFB_SESSION_NONE },
358   { "pingevent",    pingEvent  , NULL, AFB_SESSION_NONE },
359   { "subcall",      subcall    , NULL, AFB_SESSION_NONE },
360   { "subcallsync",  subcallsync, NULL, AFB_SESSION_NONE },
361   { "eventadd",     eventadd   , NULL, AFB_SESSION_NONE },
362   { "eventdel",     eventdel   , NULL, AFB_SESSION_NONE },
363   { "eventsub",     eventsub   , NULL, AFB_SESSION_NONE },
364   { "eventunsub",   eventunsub , NULL, AFB_SESSION_NONE },
365   { "eventpush",    eventpush  , NULL, AFB_SESSION_NONE },
366   { "call",         call       , NULL, AFB_SESSION_NONE },
367   { "callsync",     callsync   , NULL, AFB_SESSION_NONE },
368   { "exit",         exitnow    , NULL, AFB_SESSION_NONE },
369   { NULL}
370 };
371
372 const struct afb_binding_v2 afbBindingV2 = {
373         .api = "hello",
374         .specification = NULL,
375         .verbs = verbs,
376         .preinit = preinit,
377         .init = init,
378         .onevent = onevent
379 };
380