evt: minor cleanup
[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
32 struct afb_evt_watch;
33
34 struct afb_evt_listener {
35         struct afb_evt_listener *next;
36         void (*send)(void *closure, const char *event, struct json_object *object);
37         void *closure;
38         struct afb_evt_watch *watchs;
39         int refcount;
40 };
41
42 struct afb_evt_event {
43         struct afb_evt_watch *watchs;
44         char name[1];
45 };
46
47 struct afb_evt_watch {
48         struct afb_evt_event *event;
49         struct afb_evt_watch *next_by_event;
50         struct afb_evt_listener *listener;
51         struct afb_evt_watch *next_by_listener;
52 };
53
54 static int evt_broadcast(struct afb_evt_event *evt, struct json_object *obj);
55 static int evt_push(struct afb_evt_event *evt, struct json_object *obj);
56 static void evt_drop(struct afb_evt_event *evt);
57
58 static struct afb_event_itf afb_evt_event_itf = {
59         .broadcast = (void*)evt_broadcast,
60         .push = (void*)evt_push,
61         .drop = (void*)evt_drop
62 };
63
64 static struct afb_evt_listener *listeners = NULL;
65
66 static int evt_broadcast(struct afb_evt_event *evt, struct json_object *object)
67 {
68         return afb_evt_broadcast(evt->name, object);
69 }
70
71 int afb_evt_broadcast(const char *event, struct json_object *object)
72 {
73         int result;
74         struct afb_evt_listener *listener;
75
76         result = 0;
77         listener = listeners;
78         while(listener) {
79                 listener->send(listener->closure, event, json_object_get(object));
80                 listener = listener->next;
81         }
82         json_object_put(object);
83         return result;
84 }
85
86 static int evt_push(struct afb_evt_event *evt, struct json_object *obj)
87 {
88         int result;
89         struct afb_evt_watch *watch;
90         struct afb_evt_listener *listener;
91
92         result = 0;
93         watch = evt->watchs;
94         while(listener) {
95                 listener = watch->listener;
96                 listener->send(listener->closure, evt->name, json_object_get(obj));
97                 watch = watch->next_by_event;
98         }
99         json_object_put(obj);
100         return result;
101 }
102
103 static void remove_watch(struct afb_evt_watch *watch)
104 {
105         struct afb_evt_watch **prv;
106
107         prv = &watch->event->watchs;
108         while(*prv != watch)
109                 prv = &(*prv)->next_by_event;
110         *prv = watch->next_by_event;
111
112         prv = &watch->listener->watchs;
113         while(*prv != watch)
114                 prv = &(*prv)->next_by_listener;
115         *prv = watch->next_by_listener;
116
117         free(watch);
118 }
119
120 static void evt_drop(struct afb_evt_event *evt)
121 {
122         if (evt != NULL) {
123                 while(evt->watchs != NULL)
124                         remove_watch(evt->watchs);
125                 free(evt);
126         }
127 }
128
129 struct afb_event afb_evt_create_event(const char *name)
130 {
131         size_t len;
132         struct afb_evt_event *evt;
133
134         len = strlen(name);
135         evt = malloc(len + sizeof * evt);
136         if (evt != NULL) {
137                 evt->watchs = NULL;
138                 memcpy(evt->name, name, len + 1);
139         }
140         return (struct afb_event){ .itf = &afb_evt_event_itf, .closure = evt };
141 }
142
143 struct afb_evt_listener *afb_evt_listener_create(void (*send)(void *closure, const char *event, struct json_object *object), void *closure)
144 {
145         struct afb_evt_listener *listener;
146
147         /* search if an instance already exists */
148         listener = listeners;
149         while (listener != NULL) {
150                 if (listener->send == send && listener->closure == closure)
151                         return afb_evt_listener_addref(listener);
152                 listener = listener->next;
153         }
154
155         /* allocates */
156         listener = calloc(1, sizeof *listener);
157         if (listener != NULL) {
158                 /* init */
159                 listener->next = listeners;
160                 listener->send = send;
161                 listener->closure = closure;
162                 listener->watchs = NULL;
163                 listener->refcount = 1;
164                 listeners = listener;
165         }
166         return listener;
167 }
168
169 struct afb_evt_listener *afb_evt_listener_addref(struct afb_evt_listener *listener)
170 {
171         listener->refcount++;
172         return listener;
173 }
174
175 void afb_evt_listener_unref(struct afb_evt_listener *listener)
176 {
177         if (0 == --listener->refcount) {
178                 struct afb_evt_listener **prv;
179
180                 /* remove the watchers */
181                 while (listener->watchs != NULL)
182                         remove_watch(listener->watchs);
183
184                 /* unlink the listener */
185                 prv = &listeners;
186                 while (*prv != listener)
187                         prv = &(*prv)->next;
188                 *prv = listener->next;
189
190                 /* free the listener */
191                 free(listener);
192         }
193 }
194
195 int afb_evt_add_watch(struct afb_evt_listener *listener, struct afb_event event)
196 {
197         struct afb_evt_watch *watch;
198         struct afb_evt_event *evt;
199
200         /* check parameter */
201         if (event.itf != &afb_evt_event_itf) {
202                 errno = EINVAL;
203                 return -1;
204         }
205
206         /* search the existing watch */
207         watch = listener->watchs;
208         while(watch != NULL) {
209                 if (watch->event == event.closure)
210                         return 0;
211                 watch = watch->next_by_listener;
212         }
213
214         /* not found, allocate a new */
215         watch = malloc(sizeof *watch);
216         if (watch == NULL) {
217                 errno = ENOMEM;
218                 return -1;
219         }
220
221         /* initialise and link */
222         evt = event.closure;
223         watch->event = evt;
224         watch->next_by_event = evt->watchs;
225         watch->listener = listener;
226         watch->next_by_listener = listener->watchs;
227         evt->watchs = watch;
228         listener->watchs = watch;
229         
230         return 0;
231 }
232
233 int afb_evt_remove_watch(struct afb_evt_listener *listener, struct afb_event event)
234 {
235         struct afb_evt_watch *watch;
236
237         /* check parameter */
238         if (event.itf != &afb_evt_event_itf) {
239                 errno = EINVAL;
240                 return -1;
241         }
242
243         /* search the existing watch */
244         watch = listener->watchs;
245         while(watch != NULL) {
246                 if (watch->event == event.closure) {
247                         /* found: remove it */
248                         remove_watch(watch);
249                         break;
250                 }
251                 watch = watch->next_by_listener;
252         }
253         return 0;
254 }
255
256