evt: exposes name of events
[src/app-framework-binder.git] / src / afb-evt.c
1 /*
2  * Copyright (C) 2015, 2016 "IoT.bzh"
3  * Author "Fulup Ar Foll"
4  * Author José Bollo <jose.bollo@iot.bzh>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #define _GNU_SOURCE
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <assert.h>
24 #include <errno.h>
25
26 #include <json-c/json.h>
27 #include <afb/afb-event-itf.h>
28
29 #include "afb-evt.h"
30
31 struct afb_evt_watch;
32
33 /*
34  * Structure for event listeners
35  */
36 struct afb_evt_listener {
37
38         /* chaining listeners */
39         struct afb_evt_listener *next;
40
41         /* callback on event */
42         void (*send)(void *closure, const char *event, struct json_object *object);
43
44         /* closure for the callback */
45         void *closure;
46
47         /* head of the list of events listened */
48         struct afb_evt_watch *watchs;
49
50         /* count of reference to the listener */
51         int refcount;
52 };
53
54 /*
55  * Structure for describing events
56  */
57 struct afb_evt_event {
58
59         /* head of the list of listeners watching the event */
60         struct afb_evt_watch *watchs;
61
62         /* name of the event */
63         char name[1];
64 };
65
66 /*
67  * Structure for associating events and listeners
68  */
69 struct afb_evt_watch {
70
71         /* the event */
72         struct afb_evt_event *event;
73
74         /* link to the next listener for the same event */
75         struct afb_evt_watch *next_by_event;
76
77         /* the listener */
78         struct afb_evt_listener *listener;
79
80         /* link to the next event for the same listener */
81         struct afb_evt_watch *next_by_listener;
82 };
83
84 /* declare functions */
85 static int evt_broadcast(struct afb_evt_event *evt, struct json_object *obj);
86 static int evt_push(struct afb_evt_event *evt, struct json_object *obj);
87 static void evt_destroy(struct afb_evt_event *evt);
88
89 /* the interface for events */
90 static struct afb_event_itf afb_evt_event_itf = {
91         .broadcast = (void*)evt_broadcast,
92         .push = (void*)evt_push,
93         .drop = (void*)evt_destroy
94 };
95
96 /* head of the list of listeners */
97 static struct afb_evt_listener *listeners = NULL;
98
99 /*
100  * Broadcasts the event 'evt' with its 'object'
101  * 'object' is released (like json_object_put)
102  * Returns the count of listener that received the event.
103  */
104 static int evt_broadcast(struct afb_evt_event *evt, struct json_object *object)
105 {
106         return afb_evt_broadcast(evt->name, object);
107 }
108
109 /*
110  * Broadcasts the 'event' with its 'object'
111  * 'object' is released (like json_object_put)
112  * Returns the count of listener having receive the event.
113  */
114 int afb_evt_broadcast(const char *event, struct json_object *object)
115 {
116         int result;
117         struct afb_evt_listener *listener;
118
119         result = 0;
120         listener = listeners;
121         while(listener) {
122                 listener->send(listener->closure, event, json_object_get(object));
123                 listener = listener->next;
124                 result++;
125         }
126         json_object_put(object);
127         return result;
128 }
129
130 /*
131  * Broadcasts the event 'evt' with its 'object'
132  * 'object' is released (like json_object_put)
133  * Returns the count of listener taht received the event.
134  */
135 static int evt_push(struct afb_evt_event *evt, struct json_object *obj)
136 {
137         int result;
138         struct afb_evt_watch *watch;
139         struct afb_evt_listener *listener;
140
141         result = 0;
142         watch = evt->watchs;
143         while(listener) {
144                 listener = watch->listener;
145                 listener->send(listener->closure, evt->name, json_object_get(obj));
146                 watch = watch->next_by_event;
147                 result++;
148         }
149         json_object_put(obj);
150         return result;
151 }
152
153 /*
154  * remove the 'watch'
155  */
156 static void remove_watch(struct afb_evt_watch *watch)
157 {
158         struct afb_evt_watch **prv;
159
160         /* unlink the watch for its event */
161         prv = &watch->event->watchs;
162         while(*prv != watch)
163                 prv = &(*prv)->next_by_event;
164         *prv = watch->next_by_event;
165
166         /* unlink the watch for its listener */
167         prv = &watch->listener->watchs;
168         while(*prv != watch)
169                 prv = &(*prv)->next_by_listener;
170         *prv = watch->next_by_listener;
171
172         /* recycle memory */
173         free(watch);
174 }
175
176 /*
177  * Destroys the event 'evt'
178  */
179 static void evt_destroy(struct afb_evt_event *evt)
180 {
181         if (evt != NULL) {
182                 /* removes all watchers */
183                 while(evt->watchs != NULL)
184                         remove_watch(evt->watchs);
185                 free(evt);
186         }
187 }
188
189 /*
190  * Creates an event of 'name' and returns it.
191  * Returns an event with closure==NULL in case of error.
192  */
193 struct afb_event afb_evt_create_event(const char *name)
194 {
195         size_t len;
196         struct afb_evt_event *evt;
197
198         len = strlen(name);
199         evt = malloc(len + sizeof * evt);
200         if (evt != NULL) {
201                 evt->watchs = NULL;
202                 memcpy(evt->name, name, len + 1);
203         }
204         return (struct afb_event){ .itf = &afb_evt_event_itf, .closure = evt };
205 }
206
207 /*
208  * Returns the name of the 'event'
209  */
210 const char *afb_evt_event_name(struct afb_event event)
211 {
212         return (event.itf != &afb_evt_event_itf) ? NULL : ((struct afb_evt_event *)event.closure)->name;
213 }
214
215 /*
216  * Returns an instance of the listener defined by the 'send' callback
217  * and the 'closure'.
218  * Returns NULL in case of memory depletion.
219  */
220 struct afb_evt_listener *afb_evt_listener_create(void (*send)(void *closure, const char *event, struct json_object *object), void *closure)
221 {
222         struct afb_evt_listener *listener;
223
224         /* search if an instance already exists */
225         listener = listeners;
226         while (listener != NULL) {
227                 if (listener->send == send && listener->closure == closure)
228                         return afb_evt_listener_addref(listener);
229                 listener = listener->next;
230         }
231
232         /* allocates */
233         listener = calloc(1, sizeof *listener);
234         if (listener != NULL) {
235                 /* init */
236                 listener->next = listeners;
237                 listener->send = send;
238                 listener->closure = closure;
239                 listener->watchs = NULL;
240                 listener->refcount = 1;
241                 listeners = listener;
242         }
243         return listener;
244 }
245
246 /*
247  * Increases the reference count of 'listener' and returns it
248  */
249 struct afb_evt_listener *afb_evt_listener_addref(struct afb_evt_listener *listener)
250 {
251         listener->refcount++;
252         return listener;
253 }
254
255 /*
256  * Decreases the reference count of the 'listener' and destroys it
257  * when no more used.
258  */
259 void afb_evt_listener_unref(struct afb_evt_listener *listener)
260 {
261         if (0 == --listener->refcount) {
262                 struct afb_evt_listener **prv;
263
264                 /* remove the watchers */
265                 while (listener->watchs != NULL)
266                         remove_watch(listener->watchs);
267
268                 /* unlink the listener */
269                 prv = &listeners;
270                 while (*prv != listener)
271                         prv = &(*prv)->next;
272                 *prv = listener->next;
273
274                 /* free the listener */
275                 free(listener);
276         }
277 }
278
279 /*
280  * Makes the 'listener' watching 'event'
281  * Returns 0 in case of success or else -1.
282  */
283 int afb_evt_add_watch(struct afb_evt_listener *listener, struct afb_event event)
284 {
285         struct afb_evt_watch *watch;
286         struct afb_evt_event *evt;
287
288         /* check parameter */
289         if (event.itf != &afb_evt_event_itf) {
290                 errno = EINVAL;
291                 return -1;
292         }
293
294         /* search the existing watch */
295         watch = listener->watchs;
296         while(watch != NULL) {
297                 if (watch->event == event.closure)
298                         return 0;
299                 watch = watch->next_by_listener;
300         }
301
302         /* not found, allocate a new */
303         watch = malloc(sizeof *watch);
304         if (watch == NULL) {
305                 errno = ENOMEM;
306                 return -1;
307         }
308
309         /* initialise and link */
310         evt = event.closure;
311         watch->event = evt;
312         watch->next_by_event = evt->watchs;
313         watch->listener = listener;
314         watch->next_by_listener = listener->watchs;
315         evt->watchs = watch;
316         listener->watchs = watch;
317         
318         return 0;
319 }
320
321 /*
322  * Avoids the 'listener' to watch 'event'
323  * Returns 0 in case of success or else -1.
324  */
325 int afb_evt_remove_watch(struct afb_evt_listener *listener, struct afb_event event)
326 {
327         struct afb_evt_watch *watch;
328
329         /* check parameter */
330         if (event.itf != &afb_evt_event_itf) {
331                 errno = EINVAL;
332                 return -1;
333         }
334
335         /* search the existing watch */
336         watch = listener->watchs;
337         while(watch != NULL) {
338                 if (watch->event == event.closure) {
339                         /* found: remove it */
340                         remove_watch(watch);
341                         break;
342                 }
343                 watch = watch->next_by_listener;
344         }
345         return 0;
346 }
347
348