ARI: Add ability to raise arbitrary User Events
[asterisk/asterisk.git] / main / stasis_cache_pattern.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Typical cache pattern for Stasis topics.
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include "asterisk/astobj2.h"
35 #include "asterisk/stasis_cache_pattern.h"
36
37 struct stasis_cp_all {
38         struct stasis_topic *topic;
39         struct stasis_topic *topic_cached;
40         struct stasis_cache *cache;
41
42         struct stasis_forward *forward_all_to_cached;
43 };
44
45 struct stasis_cp_single {
46         struct stasis_topic *topic;
47         struct stasis_caching_topic *topic_cached;
48
49         struct stasis_forward *forward_topic_to_all;
50         struct stasis_forward *forward_cached_to_all;
51 };
52
53 static void all_dtor(void *obj)
54 {
55         struct stasis_cp_all *all = obj;
56
57         ao2_cleanup(all->topic);
58         all->topic = NULL;
59         ao2_cleanup(all->topic_cached);
60         all->topic_cached = NULL;
61         ao2_cleanup(all->cache);
62         all->cache = NULL;
63         stasis_forward_cancel(all->forward_all_to_cached);
64         all->forward_all_to_cached = NULL;
65 }
66
67 struct stasis_cp_all *stasis_cp_all_create(const char *name,
68         snapshot_get_id id_fn)
69 {
70         RAII_VAR(char *, cached_name, NULL, ast_free);
71         RAII_VAR(struct stasis_cp_all *, all, NULL, ao2_cleanup);
72
73         all = ao2_alloc(sizeof(*all), all_dtor);
74         if (!all) {
75                 return NULL;
76         }
77
78         ast_asprintf(&cached_name, "%s-cached", name);
79         if (!cached_name) {
80                 return NULL;
81         }
82
83         all->topic = stasis_topic_create(name);
84         all->topic_cached = stasis_topic_create(cached_name);
85         all->cache = stasis_cache_create(id_fn);
86         all->forward_all_to_cached =
87                 stasis_forward_all(all->topic, all->topic_cached);
88
89         if (!all->topic || !all->topic_cached || !all->cache ||
90                 !all->forward_all_to_cached) {
91                 return NULL;
92         }
93
94         ao2_ref(all, +1);
95         return all;
96 }
97
98 struct stasis_topic *stasis_cp_all_topic(struct stasis_cp_all *all)
99 {
100         if (!all) {
101                 return NULL;
102         }
103         return all->topic;
104 }
105
106 struct stasis_topic *stasis_cp_all_topic_cached(
107         struct stasis_cp_all *all)
108 {
109         if (!all) {
110                 return NULL;
111         }
112         return all->topic_cached;
113 }
114
115 struct stasis_cache *stasis_cp_all_cache(struct stasis_cp_all *all)
116 {
117         if (!all) {
118                 return NULL;
119         }
120         return all->cache;
121 }
122
123 static void one_dtor(void *obj)
124 {
125         struct stasis_cp_single *one = obj;
126
127         /* Should already be unsubscribed */
128         ast_assert(one->topic_cached == NULL);
129         ast_assert(one->forward_topic_to_all == NULL);
130         ast_assert(one->forward_cached_to_all == NULL);
131
132         ao2_cleanup(one->topic);
133         one->topic = NULL;
134 }
135
136 struct stasis_cp_single *stasis_cp_single_create(struct stasis_cp_all *all,
137         const char *name)
138 {
139         RAII_VAR(struct stasis_cp_single *, one, NULL, ao2_cleanup);
140
141         one = ao2_alloc(sizeof(*one), one_dtor);
142         if (!one) {
143                 return NULL;
144         }
145
146         one->topic = stasis_topic_create(name);
147         if (!one->topic) {
148                 return NULL;
149         }
150         one->topic_cached = stasis_caching_topic_create(one->topic, all->cache);
151         if (!one->topic_cached) {
152                 return NULL;
153         }
154
155         one->forward_topic_to_all = stasis_forward_all(one->topic, all->topic);
156         if (!one->forward_topic_to_all) {
157                 return NULL;
158         }
159         one->forward_cached_to_all = stasis_forward_all(
160                 stasis_caching_get_topic(one->topic_cached), all->topic_cached);
161         if (!one->forward_cached_to_all) {
162                 return NULL;
163         }
164
165         ao2_ref(one, +1);
166         return one;
167 }
168
169 void stasis_cp_single_unsubscribe(struct stasis_cp_single *one)
170 {
171         if (!one) {
172                 return;
173         }
174
175         stasis_forward_cancel(one->forward_topic_to_all);
176         one->forward_topic_to_all = NULL;
177         stasis_forward_cancel(one->forward_cached_to_all);
178         one->forward_cached_to_all = NULL;
179         stasis_caching_unsubscribe(one->topic_cached);
180         one->topic_cached = NULL;
181
182         ao2_cleanup(one);
183 }
184
185 struct stasis_topic *stasis_cp_single_topic(struct stasis_cp_single *one)
186 {
187         if (!one) {
188                 return NULL;
189         }
190         return one->topic;
191 }
192
193 struct stasis_topic *stasis_cp_single_topic_cached(
194         struct stasis_cp_single *one)
195 {
196         if (!one) {
197                 return NULL;
198         }
199         return stasis_caching_get_topic(one->topic_cached);
200 }
201