c6fa779cb1f3c2e9d4559c1f5d47a351d342113f
[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 #include <afb/afb-binding.h>
25
26 const struct afb_binding_interface *interface;
27 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
28
29 struct event
30 {
31         struct event *next;
32         struct afb_event event;
33         char tag[1];
34 };
35
36 static struct event *events = 0;
37
38 /* searchs the event of tag */
39 static struct event *event_get(const char *tag)
40 {
41         struct event *e = events;
42         while(e && strcmp(e->tag, tag))
43                 e = e->next;
44         return e;
45 }
46
47 /* deletes the event of tag */
48 static int event_del(const char *tag)
49 {
50         struct event *e, **p;
51
52         /* check exists */
53         e = event_get(tag);
54         if (!e) return -1;
55
56         /* unlink */
57         p = &events;
58         while(*p != e) p = &(*p)->next;
59         *p = e->next;
60
61         /* destroys */
62         afb_event_drop(e->event);
63         free(e);
64         return 0;
65 }
66
67 /* creates the event of tag */
68 static int event_add(const char *tag, const char *name)
69 {
70         struct event *e;
71
72         /* check valid tag */
73         e = event_get(tag);
74         if (e) return -1;
75
76         /* creation */
77         e = malloc(strlen(tag) + sizeof *e);
78         if (!e) return -1;
79         strcpy(e->tag, tag);
80
81         /* make the event */
82         e->event = afb_daemon_make_event(interface->daemon, name);
83         if (!e->event.closure) { free(e); return -1; }
84
85         /* link */
86         e->next = events;
87         events = e;
88         return 0;
89 }
90
91 static int event_subscribe(struct afb_req request, const char *tag)
92 {
93         struct event *e;
94         e = event_get(tag);
95         return e ? afb_req_subscribe(request, e->event) : -1;
96 }
97
98 static int event_unsubscribe(struct afb_req request, const char *tag)
99 {
100         struct event *e;
101         e = event_get(tag);
102         return e ? afb_req_unsubscribe(request, e->event) : -1;
103 }
104
105 static int event_push(struct json_object *args, const char *tag)
106 {
107         struct event *e;
108         e = event_get(tag);
109         return e ? afb_event_push(e->event, json_object_get(args)) : -1;
110 }
111
112 // Sample Generic Ping Debug API
113 static void ping(struct afb_req request, json_object *jresp, const char *tag)
114 {
115         static int pingcount = 0;
116         json_object *query = afb_req_json(request);
117         afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query));
118 }
119
120 static void pingSample (struct afb_req request)
121 {
122         ping(request, json_object_new_string ("Some String"), "pingSample");
123 }
124
125 static void pingFail (struct afb_req request)
126 {
127         afb_req_fail(request, "failed", "Ping Binder Daemon fails");
128 }
129
130 static void pingNull (struct afb_req request)
131 {
132         ping(request, NULL, "pingNull");
133 }
134
135 static void pingBug (struct afb_req request)
136 {
137         ping((struct afb_req){NULL,NULL}, NULL, "pingBug");
138 }
139
140 static void pingEvent(struct afb_req request)
141 {
142         json_object *query = afb_req_json(request);
143         afb_daemon_broadcast_event(interface->daemon, "event", json_object_get(query));
144         ping(request, json_object_get(query), "event");
145 }
146
147
148 // For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/
149 static void pingJson (struct afb_req request) {
150     json_object *jresp, *embed;
151
152     jresp = json_object_new_object();
153     json_object_object_add(jresp, "myString", json_object_new_string ("Some String"));
154     json_object_object_add(jresp, "myInt", json_object_new_int (1234));
155
156     embed  = json_object_new_object();
157     json_object_object_add(embed, "subObjString", json_object_new_string ("Some String"));
158     json_object_object_add(embed, "subObjInt", json_object_new_int (5678));
159
160     json_object_object_add(jresp,"eobj", embed);
161
162     ping(request, jresp, "pingJson");
163 }
164
165 static void subcallcb (void *prequest, int iserror, json_object *object)
166 {
167         struct afb_req request = afb_req_unstore(prequest);
168         if (iserror)
169                 afb_req_fail(request, "failed", json_object_to_json_string(object));
170         else
171                 afb_req_success(request, json_object_get(object), NULL);
172         afb_req_unref(request);
173 }
174
175 static void subcall (struct afb_req request)
176 {
177         const char *api = afb_req_value(request, "api");
178         const char *verb = afb_req_value(request, "verb");
179         const char *args = afb_req_value(request, "args");
180         json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
181
182         if (object == NULL)
183                 afb_req_fail(request, "failed", "bad arguments");
184         else {
185                 afb_req_subcall(request, api, verb, object, subcallcb, afb_req_store(request));
186                 json_object_put(object);
187         }
188 }
189
190 static void subcallsync (struct afb_req request)
191 {
192         int rc;
193         const char *api = afb_req_value(request, "api");
194         const char *verb = afb_req_value(request, "verb");
195         const char *args = afb_req_value(request, "args");
196         json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL;
197
198         if (object == NULL)
199                 afb_req_fail(request, "failed", "bad arguments");
200         else {
201                 rc = afb_req_subcall_sync(request, api, verb, object, &result);
202                 if (rc) {
203                         afb_req_success(request, result, NULL);
204                 } else {
205                         afb_req_fail(request, "failed", json_object_to_json_string(result));
206                         json_object_put(result);
207                 }
208                 json_object_put(object);
209         }
210 }
211
212 static void eventadd (struct afb_req request)
213 {
214         const char *tag = afb_req_value(request, "tag");
215         const char *name = afb_req_value(request, "name");
216
217         pthread_mutex_lock(&mutex);
218         if (tag == NULL || name == NULL)
219                 afb_req_fail(request, "failed", "bad arguments");
220         else if (0 != event_add(tag, name))
221                 afb_req_fail(request, "failed", "creation error");
222         else
223                 afb_req_success(request, NULL, NULL);
224         pthread_mutex_unlock(&mutex);
225 }
226
227 static void eventdel (struct afb_req request)
228 {
229         const char *tag = afb_req_value(request, "tag");
230
231         pthread_mutex_lock(&mutex);
232         if (tag == NULL)
233                 afb_req_fail(request, "failed", "bad arguments");
234         else if (0 != event_del(tag))
235                 afb_req_fail(request, "failed", "deletion error");
236         else
237                 afb_req_success(request, NULL, NULL);
238         pthread_mutex_unlock(&mutex);
239 }
240
241 static void eventsub (struct afb_req request)
242 {
243         const char *tag = afb_req_value(request, "tag");
244
245         pthread_mutex_lock(&mutex);
246         if (tag == NULL)
247                 afb_req_fail(request, "failed", "bad arguments");
248         else if (0 != event_subscribe(request, tag))
249                 afb_req_fail(request, "failed", "subscription error");
250         else
251                 afb_req_success(request, NULL, NULL);
252         pthread_mutex_unlock(&mutex);
253 }
254
255 static void eventunsub (struct afb_req request)
256 {
257         const char *tag = afb_req_value(request, "tag");
258
259         pthread_mutex_lock(&mutex);
260         if (tag == NULL)
261                 afb_req_fail(request, "failed", "bad arguments");
262         else if (0 != event_unsubscribe(request, tag))
263                 afb_req_fail(request, "failed", "unsubscription error");
264         else
265                 afb_req_success(request, NULL, NULL);
266         pthread_mutex_unlock(&mutex);
267 }
268
269 static void eventpush (struct afb_req request)
270 {
271         const char *tag = afb_req_value(request, "tag");
272         const char *data = afb_req_value(request, "data");
273         json_object *object = data ? json_tokener_parse(data) : NULL;
274
275         pthread_mutex_lock(&mutex);
276         if (tag == NULL)
277                 afb_req_fail(request, "failed", "bad arguments");
278         else if (0 > event_push(object, tag))
279                 afb_req_fail(request, "failed", "push error");
280         else
281                 afb_req_success(request, NULL, NULL);
282         pthread_mutex_unlock(&mutex);
283         json_object_put(object);
284 }
285
286 static void exitnow (struct afb_req request)
287 {
288         exit(0);
289 }
290
291 // NOTE: this sample does not use session to keep test a basic as possible
292 //       in real application most APIs should be protected with AFB_SESSION_CHECK
293 static const struct afb_verb_desc_v1 verbs[]= {
294   {"ping"     , AFB_SESSION_NONE, pingSample  , "Ping Application Framework"},
295   {"pingfail" , AFB_SESSION_NONE, pingFail    , "Fails"},
296   {"pingnull" , AFB_SESSION_NONE, pingNull    , "Return NULL"},
297   {"pingbug"  , AFB_SESSION_NONE, pingBug     , "Do a Memory Violation"},
298   {"pingJson" , AFB_SESSION_NONE, pingJson    , "Return a JSON object"},
299   {"pingevent", AFB_SESSION_NONE, pingEvent   , "Send an event"},
300   {"subcall",   AFB_SESSION_NONE, subcall     , "Call api/verb(args)"},
301   {"subcallsync",   AFB_SESSION_NONE, subcallsync     , "Call api/verb(args)"},
302   {"eventadd",  AFB_SESSION_NONE, eventadd    , "adds the event of 'name' for the 'tag'"},
303   {"eventdel",  AFB_SESSION_NONE, eventdel    , "deletes the event of 'tag'"},
304   {"eventsub",  AFB_SESSION_NONE, eventsub    , "subscribes to the event of 'tag'"},
305   {"eventunsub",AFB_SESSION_NONE, eventunsub  , "unsubscribes to the event of 'tag'"},
306   {"eventpush", AFB_SESSION_NONE, eventpush   , "pushs the event of 'tag' with the 'data'"},
307   {"exit",      AFB_SESSION_NONE, exitnow     , "exits from afb-daemon"},
308   {NULL}
309 };
310
311 static const struct afb_binding plugin_desc = {
312         .type = AFB_BINDING_VERSION_1,
313         .v1 = {
314                 .info = "Minimal Hello World Sample",
315                 .prefix = "hello",
316                 .verbs = verbs
317         }
318 };
319
320 const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
321 {
322         interface = itf;
323         NOTICE(interface, "hello plugin comes to live");
324         return &plugin_desc;
325 }