CLI: Create ast_cli_completion_add function.
[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 #include "asterisk/astobj2.h"
33 #include "asterisk/stasis_cache_pattern.h"
34
35 struct stasis_cp_all {
36         struct stasis_topic *topic;
37         struct stasis_topic *topic_cached;
38         struct stasis_cache *cache;
39
40         struct stasis_forward *forward_all_to_cached;
41 };
42
43 struct stasis_cp_single {
44         struct stasis_topic *topic;
45         struct stasis_caching_topic *topic_cached;
46
47         struct stasis_forward *forward_topic_to_all;
48         struct stasis_forward *forward_cached_to_all;
49 };
50
51 static void all_dtor(void *obj)
52 {
53         struct stasis_cp_all *all = obj;
54
55         ao2_cleanup(all->topic);
56         all->topic = NULL;
57         ao2_cleanup(all->topic_cached);
58         all->topic_cached = NULL;
59         ao2_cleanup(all->cache);
60         all->cache = NULL;
61         stasis_forward_cancel(all->forward_all_to_cached);
62         all->forward_all_to_cached = NULL;
63 }
64
65 struct stasis_cp_all *stasis_cp_all_create(const char *name,
66         snapshot_get_id id_fn)
67 {
68         RAII_VAR(char *, cached_name, NULL, ast_free);
69         RAII_VAR(struct stasis_cp_all *, all, NULL, ao2_cleanup);
70
71         all = ao2_t_alloc(sizeof(*all), all_dtor, name);
72         if (!all) {
73                 return NULL;
74         }
75
76         ast_asprintf(&cached_name, "%s-cached", name);
77         if (!cached_name) {
78                 return NULL;
79         }
80
81         all->topic = stasis_topic_create(name);
82         all->topic_cached = stasis_topic_create(cached_name);
83         all->cache = stasis_cache_create(id_fn);
84         all->forward_all_to_cached =
85                 stasis_forward_all(all->topic, all->topic_cached);
86
87         if (!all->topic || !all->topic_cached || !all->cache ||
88                 !all->forward_all_to_cached) {
89                 return NULL;
90         }
91
92         ao2_ref(all, +1);
93         return all;
94 }
95
96 struct stasis_topic *stasis_cp_all_topic(struct stasis_cp_all *all)
97 {
98         if (!all) {
99                 return NULL;
100         }
101         return all->topic;
102 }
103
104 struct stasis_topic *stasis_cp_all_topic_cached(
105         struct stasis_cp_all *all)
106 {
107         if (!all) {
108                 return NULL;
109         }
110         return all->topic_cached;
111 }
112
113 struct stasis_cache *stasis_cp_all_cache(struct stasis_cp_all *all)
114 {
115         if (!all) {
116                 return NULL;
117         }
118         return all->cache;
119 }
120
121 static void one_dtor(void *obj)
122 {
123         struct stasis_cp_single *one = obj;
124
125         /* Should already be unsubscribed */
126         ast_assert(one->topic_cached == NULL);
127         ast_assert(one->forward_topic_to_all == NULL);
128         ast_assert(one->forward_cached_to_all == NULL);
129
130         ao2_cleanup(one->topic);
131         one->topic = NULL;
132 }
133
134 struct stasis_cp_single *stasis_cp_single_create(struct stasis_cp_all *all,
135         const char *name)
136 {
137         RAII_VAR(struct stasis_cp_single *, one, NULL, ao2_cleanup);
138
139         one = stasis_cp_sink_create(all, name);
140         if (!one) {
141                 return NULL;
142         }
143
144         one->forward_topic_to_all = stasis_forward_all(one->topic, all->topic);
145         if (!one->forward_topic_to_all) {
146                 return NULL;
147         }
148         one->forward_cached_to_all = stasis_forward_all(
149                 stasis_caching_get_topic(one->topic_cached), all->topic_cached);
150         if (!one->forward_cached_to_all) {
151                 return NULL;
152         }
153
154         ao2_ref(one, +1);
155         return one;
156 }
157
158 struct stasis_cp_single *stasis_cp_sink_create(struct stasis_cp_all *all,
159         const char *name)
160 {
161         RAII_VAR(struct stasis_cp_single *, one, NULL, ao2_cleanup);
162
163         one = ao2_t_alloc(sizeof(*one), one_dtor, name);
164         if (!one) {
165                 return NULL;
166         }
167
168         one->topic = stasis_topic_create(name);
169         if (!one->topic) {
170                 return NULL;
171         }
172         one->topic_cached = stasis_caching_topic_create(one->topic, all->cache);
173         if (!one->topic_cached) {
174                 return NULL;
175         }
176
177         ao2_ref(one, +1);
178         return one;
179 }
180
181 void stasis_cp_single_unsubscribe(struct stasis_cp_single *one)
182 {
183         if (!one) {
184                 return;
185         }
186
187         stasis_forward_cancel(one->forward_topic_to_all);
188         one->forward_topic_to_all = NULL;
189         stasis_forward_cancel(one->forward_cached_to_all);
190         one->forward_cached_to_all = NULL;
191         stasis_caching_unsubscribe(one->topic_cached);
192         one->topic_cached = NULL;
193
194         ao2_cleanup(one);
195 }
196
197 struct stasis_topic *stasis_cp_single_topic(struct stasis_cp_single *one)
198 {
199         if (!one) {
200                 return NULL;
201         }
202         return one->topic;
203 }
204
205 struct stasis_topic *stasis_cp_single_topic_cached(
206         struct stasis_cp_single *one)
207 {
208         if (!one) {
209                 return NULL;
210         }
211         return stasis_caching_get_topic(one->topic_cached);
212 }
213