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