Asterisk - The Open Source Telephony Project GIT-master-f36a736
stasis_state.h
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2019, Sangoma Technologies Corporation
5 *
6 * Kevin Harwell <kharwell@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#ifndef _STASIS_STATE_H
20#define _STASIS_STATE_H
21
22/*! \file
23 *
24 * \brief Stasis State API.
25 *
26 * \par Intro
27 *
28 * This module defines the data structures, and handling of "state" for topics within
29 * stasis. State is defined as the last stasis message, and its contained message data,
30 * published on a given topic.
31 *
32 * Concepts to know:
33 * - \ref stasis_state_manager
34 * - \ref stasis_state_subscriber
35 * - \ref stasis_state_publisher
36 * - \ref stasis_state_observer
37 *
38 * \par stasis_state_manager
39 *
40 * The manager stores and well, manages state data. Each state is an association of
41 * a unique stasis topic, and the last known published stasis message on that topic.
42 * There is only ever one managed state object per topic. For each topic all messages
43 * are forwarded to an "all" topic also maintained by the manager. This allows
44 * subscriptions to all managed topics, and their state. Managed state is created in
45 * one of several ways:
46 *
47 * Adding an explicit subscriber
48 * Adding an explicit publisher
49 * Adding an implicit publisher
50 * Retrieving a stasis state topic from the manager via the \ref stasis_state_topic
51 * function prior to doing one of the above (DO NOT DO THIS).
52 *
53 * More on the first three options later (see relevant section descriptions below). The
54 * last option, creation through retrieving a topic is not only NOT recommended, but
55 * should NOT even BE DONE. Doing so will inevitably result in a memory leak. Why then
56 * is this even allowed? The short answer is backwards compatibility. The slightly longer
57 * answer is at the time of this module's creation that's how things were historically
58 * done using a combination of stasis topic management spread throughout various other
59 * modules, and stasis caching. And yes it did cause a memory leak.
60 *
61 * Preferably, any new code wishing to track topics and states should do so by adding
62 * either an explicit subscriber and/or publisher.
63 *
64 * \par stasis_state_subscriber
65 *
66 * As mentioned, topic and state can be created, or referenced within the manager by adding
67 * a \ref stasis_state_subscriber. When adding a subscriber if no state currently exists
68 * new managed state is immediately created. If managed state already exists then a new
69 * subscriber is created referencing that state. The managed state is guaranteed to live
70 * throughout the subscriber's lifetime. State is only removed from the manager when no
71 * other entities require it (no more subscribers, or publishers).
72 *
73 * Subscribers are ao2 objects. Therefore there is no explicit cleanup required aside from
74 * dereferencing the subscriber object using normal ao2 dereferencing methods.
75 *
76 * \par stasis_state_publisher
77 *
78 * There are two ways of tracking publishers: explicitly and implicitly.
79 *
80 * Topic and state can be created, or referenced within the manager by also explicitly adding
81 * a \ref stasis_state_publisher. When adding a publisher if no state currently exists new
82 * managed state is created. If managed state already exists then a new publisher is created
83 * referencing that state. The managed state is guaranteed to live throughout the publisher's
84 * lifetime. State is only removed from the manager when no other entities require it (no more
85 * publishers, or subscribers).
86 *
87 * Explicit publishers are ao2 objects. Therefore there is no cleanup required aside from
88 * dereferencing the publisher object using normal ao2 dereferencing methods.
89 *
90 * When adding an explicit publisher, messages should be published using the \ref
91 * stasis_state_publish function. This not only skips a lookup, but doesn't add an implicit
92 * publisher. They are not necessarily mutually exclusive it's just that the two ways exist
93 * to solve two different problems.
94 *
95 * For example (using an explicit publisher):
96 *
97 * // Add an explicit publisher to topic/state "8675309" within
98 * // a given manager context
99 * pub = stasis_state_add_publisher(manager, "8675309");
100 *
101 * // Publish a stasis message to the topic/state
102 * stasis_state_publish(pub, msg);
103 *
104 * // Publish another a stasis message to the topic/state
105 * stasis_state_publish(pub, msg);
106 *
107 * // Done with the publisher release the reference
108 * ao2_ref(pub, -1);
109 *
110 * An implicit publisher can also be created by calling \ref stasis_state_publish_by_id. Calling
111 * this function not only publishes the message within stasis (creating managed state if needed)
112 * it also sets up internal tracking of the publishing module using an \ref ast_eid. However, a
113 * final call to \ref stasis_state_remove_publish_by_id must be done in order to remove the eid
114 * reference, which will subsequently allow the underlying managed state to be eventually deleted.
115 *
116 * For example (using an implicit publisher):
117 *
118 * // Publish a stasis message to topic/state 8675309 within a
119 * // given manager context and use the system's default eid
120 * stasis_state_publish_by_id(manager, "8675309", NULL, msg);
121 *
122 * // Do some stuff and then publish again
123 * stasis_state_publish_by_id(manager, "8675309", NULL, msg);
124 *
125 * // Done with all our publishing, so post a final clearing
126 * // message and remove the implicit publisher
127 * stasis_state_remove_publish_by_id(manager, "8675309", NULL, msg);
128 *
129 * Explicit publisher/publishing is preferred. However, implicit publishing is allowed for those
130 * situations where it makes more sense to do so, but has been implemented mostly for backwards
131 * compatibility with some modules (using implicit publishing required less initial code changes
132 * to some legacy subsystems).
133 *
134 * \par stasis_state_observer
135 *
136 * Some modules may wish to watch for, and react to managed state events. By registering a state
137 * observer, and implementing handlers for the desired callbacks those modules can do so.
138 */
139
140#include "asterisk/stasis.h"
141
142struct ast_eid;
143
144/*!
145 * \brief Manages a collection of stasis states.
146 *
147 * Maintains data related to stasis state. Managed state is an association of a unique stasis
148 * topic (named by a given unique id), and the last known published message.
149 *
150 * \since 13.28.0
151 * \since 16.5.0
152 */
154
155/*!
156 * \brief Create a stasis state manager.
157 *
158 * \note The state manager is an ao2_object. When done simply decrement its reference
159 * for object cleanup.
160 *
161 * \param topic_name The name of the topic to create that all state topics
162 * get forwarded to
163 *
164 * \retval A stasis state manager
165 * \retval NULL if an error occurred
166 *
167 * \since 13.28.0
168 * \since 16.5.0
169 */
170struct stasis_state_manager *stasis_state_manager_create(const char *topic_name);
171
172/*!
173 * \brief Retrieve the manager's topic (the topic that all state topics get forwarded to)
174 *
175 * \param manager The manager object
176 *
177 * \retval The manager's topic.
178 *
179 * \since 13.28.0
180 * \since 16.5.0
181 */
183
184/*!
185 * \brief Retrieve a managed topic creating one if not currently managed.
186 *
187 * WARNING This function should not be called before adding a publisher or subscriber or
188 * it will cause a memory leak within the stasis state manager. This function is here in
189 * order to allow for compatibility with how things used to work.
190 *
191 * Also much like the similar functionality from before it returns the stasis topic, but
192 * does not bump its reference.
193 *
194 * \param manager The manager object
195 * \param id The unique id of/for the topic
196 *
197 * \retval A managed stasis topic.
198 * \retval NULL if an error occurred
199 *
200 * \since 13.28.0
201 * \since 16.5.0
202 */
203struct stasis_topic *stasis_state_topic(struct stasis_state_manager *manager, const char *id);
204
205/*!
206 * \brief A stasis state subscriber
207 *
208 * A subscriber to a particular stasis state. As such it holds a reference to the
209 * underlying stasis state, so that managed state is guaranteed to exist for the
210 * lifetime of the subscriber.
211 *
212 * \since 13.28.0
213 * \since 16.5.0
214 */
216
217/*!
218 * \brief Add a subscriber to the managed stasis state for the given id
219 *
220 * Adds a subscriber to a managed state based on id. If managed state does not already
221 * exists for the given id then new managed state is created. Otherwise the existing
222 * state is subscribed to.
223 *
224 * \param manager The manager object
225 * \param id The unique id of a managed state
226 *
227 * \retval A stasis state subscriber
228 * \retval NULL if an error occurred
229 *
230 * \since 13.28.0
231 * \since 16.5.0
232 */
234 struct stasis_state_manager *manager, const char *id);
235
236/*!
237 * \brief Add a subscriber, and subscribe to its underlying stasis topic.
238 *
239 * Adds a subscriber to a managed state based on id. If managed state does not already
240 * exists for the given id then new managed state is created. Otherwise the existing
241 * state is subscribed to. If the state is successfully subscribed to then a stasis
242 * subscription is subsequently created as well.
243 *
244 * \param manager The manager object
245 * \param id The unique id of a managed state
246 * \param callback The stasis subscription callback
247 * \param data A user data object passed to the stasis subscription
248 *
249 * \retval A stasis state subscriber
250 * \retval NULL if an error occurred
251 *
252 * \since 13.28.0
253 * \since 16.5.0
254 */
256 const char *id, stasis_subscription_cb callback, void *data);
257
258/*!
259 * \brief Unsubscribe from the stasis topic and stasis state.
260 *
261 * \param sub A stasis state subscriber
262 *
263 * \retval NULL
264 *
265 * \since 13.28.0
266 * \since 16.5.0
267 */
269
270/*!
271 * \brief Unsubscribe from the stasis topic, block until the final message
272 * is received, and then unsubscribe from stasis state.
273 *
274 * \param sub A stasis state subscriber
275 *
276 * \retval NULL
277 *
278 * \since 13.28.0
279 * \since 16.5.0
280 */
282
283/*!
284 * \brief Retrieve the underlying subscribed to state's unique id
285 *
286 * \param sub A stasis state subscriber
287 *
288 * \retval The managed state's id
289 *
290 * \since 13.28.0
291 * \since 16.5.0
292 */
294
295/*!
296 * \brief Retrieve the subscriber's topic
297 *
298 * \note Returned topic's reference count is NOT incremented. However, the topic is
299 * guaranteed to live for the lifetime of the subscriber.
300 *
301 * \param sub A stasis state subscriber
302 *
303 * \retval The subscriber's topic
304 *
305 * \since 13.28.0
306 * \since 16.5.0
307 */
309
310/*!
311 * \brief Retrieve the last known state stasis message payload for the subscriber
312 *
313 * If a stasis message has been published to this state, this function returns
314 * that message's payload object. If no stasis message has been published on the
315 * state, or the message's payload does not exist then NULL is returned.
316 *
317 * \note Returned data's reference count is incremented
318 *
319 * \param sub A stasis state subscriber
320 *
321 * \retval The subscriber's state message data
322 * \retval NULL if no data has been published yet
323 *
324 * \since 13.28.0
325 * \since 16.5.0
326 */
328
329/*!
330 * \brief Retrieve the stasis topic subscription if available.
331 *
332 * \param sub A stasis state subscriber
333 *
334 * \retval The subscriber's stasis subscription
335 * \retval NULL if no subscription available
336 *
337 * \since 13.28.0
338 * \since 16.5.0
339 */
342
343/*!
344 * \brief A stasis state publisher
345 *
346 * A publisher to a particular stasis state and topic. As such it holds a reference to
347 * the underlying stasis state, so that managed state is guaranteed to exist for the
348 * lifetime of the publisher.
349 *
350 * \since 13.28.0
351 * \since 16.5.0
352 */
354
355/*!
356 * \brief Add a publisher to the managed state for the given id
357 *
358 * Adds a publisher to a managed state based on id. If managed state does not already
359 * exists for the given id then new managed state is created. Otherwise the existing
360 * state is used.
361 *
362 * \param manager The manager object
363 * \param id The unique id of a managed state
364 *
365 * \retval A stasis state publisher
366 * \retval NULL if an error occurred
367 *
368 * \since 13.28.0
369 * \since 16.5.0
370 */
372 struct stasis_state_manager *manager, const char *id);
373
374/*!
375 * \brief Retrieve the publisher's underlying state's unique id
376 *
377 * \param pub A stasis state publisher
378 *
379 * \retval The managed state's id
380 *
381 * \since 13.28.0
382 * \since 16.5.0
383 */
384const char *stasis_state_publisher_id(const struct stasis_state_publisher *pub);
385
386/*!
387 * \brief Retrieve the publisher's topic
388 *
389 * \note Returned topic's reference count is NOT incremented. However, the topic is
390 * guaranteed to live for the lifetime of the publisher.
391 *
392 * \param pub A stasis state publisher
393 *
394 * \retval The publisher's topic
395 *
396 * \since 13.28.0
397 * \since 16.5.0
398 */
400
401/*!
402 * \brief Publish to a managed state (topic) using a publisher.
403 *
404 * \param pub The publisher to use to publish the message
405 * \param msg The message to publish
406 *
407 * \since 13.28.0
408 * \since 16.5.0
409 */
410void stasis_state_publish(struct stasis_state_publisher *pub, struct stasis_message *msg);
411
412/*!
413 * \brief Publish to a managed named by id topic, and add an implicit subscriber.
414 *
415 * \note It is recommended when adding new publisher functionality within a module
416 * to create and use an explicit publisher instead of using this method.
417 *
418 * This creates an implicit publisher keyed off the eid. This ability was mainly
419 * implemented in order to maintain compatibility with already established code.
420 * Allowing the creation of an implicit publisher made is so less changes were
421 * required when stasis state module was initially added.
422 *
423 * There should only ever be one publisher for a specifically named managed topic
424 * within the system. This being the case we can use the eid to implicitly track
425 * the publisher. However once publishing is no longer needed for a topic a call
426 * to stasis_state_remove_publish_by_id is required in order to remove the implicit
427 * publisher. Thus allowing for its eventual destruction. Without the call to remove
428 * a memory leak will occur.
429 *
430 * \param manager The state manager
431 * \param id A state's unique id
432 * \param eid The unique system id
433 * \param msg The message to publish
434 *
435 * \since 13.28.0
436 * \since 16.5.0
437 */
438void stasis_state_publish_by_id(struct stasis_state_manager *manager, const char *id,
439 const struct ast_eid *eid, struct stasis_message *msg);
440
441/*!
442 * \brief Publish to a managed named by id topic, and remove an implicit publisher.
443 *
444 * This function should be called after calling stasis_state_publish_by_id at least once
445 * for the same manager, id, and eid. If the given stasis message is NULL then the implicit
446 * publisher is removed, but no last message is published.
447 *
448 * See note and description on stasis_state_publish_by_id for more details about if, and
449 * when this function should be used.
450 *
451 * \param manager The state manager
452 * \param id A state's unique id
453 * \param eid The unique system id
454 * \param msg The message to publish (can be NULL)
455 *
456 * \since 13.28.0
457 * \since 16.5.0
458 */
460 const char *id, const struct ast_eid *eid, struct stasis_message *msg);
461
462/*! \brief Managed stasis state event interface */
464 /*!
465 * \brief Raised when any managed state is being subscribed.
466 *
467 * \param id The unique id of the managed state
468 * \param sub The subscriber subscribed
469 */
470 void (*on_subscribe)(const char *id, struct stasis_state_subscriber *sub);
471
472 /*!
473 * \brief Raised when any managed state is being unsubscribed.
474 *
475 * \param id The unique id of the managed state
476 * \param sub The subscriber to unsubscribe
477 */
478 void (*on_unsubscribe)(const char *id, struct stasis_state_subscriber *sub);
479};
480
481/*!
482 * \brief Add an observer to receive managed state related events.
483 *
484 * \param manager The state manager
485 * \param observer The observer handling events
486 *
487 * \retval 0 if successfully registered
488 * \retval -1 on failure
489 *
490 * \since 13.28.0
491 * \since 16.5.0
492 */
495
496/*!
497 * \brief Remove an observer (will no longer receive managed state related events).
498 *
499 * \param manager The state manager
500 * \param observer The observer being removed
501 *
502 * \since 13.28.0
503 * \since 16.5.0
504 */
507
508/*!
509 * \brief The delegate called for each managed state.
510 *
511 * \param id The unique id of a managed state object
512 * \param msg The last published message on the state, or NULL
513 * \param user_data Data object the user passed into the manager callback
514 *
515 * \retval 0 to continue traversing
516 * \retval CMP_STOP (2) to stop traversing
517 *
518 * \since 13.28.0
519 * \since 16.5.0
520 */
521typedef int (*on_stasis_state)(const char *id, struct stasis_message *msg, void *user_data);
522
523/*!
524 * \brief For each managed state call the given handler.
525 *
526 * \param manager The state manager
527 * \param handler The handler to call for each managed state
528 * \param data User to data to pass on to the handler
529 *
530 * \since 13.28.0
531 * \since 16.5.0
532 */
534 void *data);
535
536/*!
537 * \brief For each managed, and explicitly subscribed state call the given handler.
538 *
539 * \param manager The state manager
540 * \param handler The handler to call for each managed state
541 * \param data User to data to pass on to the handler
542 *
543 * \since 13.28.0
544 * \since 16.5.0
545 */
547 void *data);
548
549#endif /* _STASIS_STATE_H */
enum queue_result id
Definition: app_queue.c:1667
struct stasis_forward * sub
Definition: res_corosync.c:240
struct ast_sorcery_instance_observer observer
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
void(* stasis_subscription_cb)(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Callback function type for Stasis subscriptions.
Definition: stasis.h:611
void * stasis_state_unsubscribe(struct stasis_state_subscriber *sub)
Unsubscribe from the stasis topic and stasis state.
Definition: stasis_state.c:471
struct stasis_topic * stasis_state_all_topic(struct stasis_state_manager *manager)
Retrieve the manager's topic (the topic that all state topics get forwarded to)
Definition: stasis_state.c:365
const char * stasis_state_subscriber_id(const struct stasis_state_subscriber *sub)
Retrieve the underlying subscribed to state's unique id.
Definition: stasis_state.c:488
void stasis_state_callback_all(struct stasis_state_manager *manager, on_stasis_state handler, void *data)
For each managed state call the given handler.
Definition: stasis_state.c:741
struct stasis_state_subscriber * stasis_state_add_subscriber(struct stasis_state_manager *manager, const char *id)
Add a subscriber to the managed stasis state for the given id.
Definition: stasis_state.c:413
struct stasis_state_manager * stasis_state_manager_create(const char *topic_name)
Create a stasis state manager.
Definition: stasis_state.c:325
void stasis_state_publish_by_id(struct stasis_state_manager *manager, const char *id, const struct ast_eid *eid, struct stasis_message *msg)
Publish to a managed named by id topic, and add an implicit subscriber.
Definition: stasis_state.c:639
int(* on_stasis_state)(const char *id, struct stasis_message *msg, void *user_data)
The delegate called for each managed state.
Definition: stasis_state.h:521
void stasis_state_remove_observer(struct stasis_state_manager *manager, struct stasis_state_observer *observer)
Remove an observer (will no longer receive managed state related events).
Definition: stasis_state.c:701
void * stasis_state_unsubscribe_and_join(struct stasis_state_subscriber *sub)
Unsubscribe from the stasis topic, block until the final message is received, and then unsubscribe fr...
Definition: stasis_state.c:478
struct stasis_topic * stasis_state_publisher_topic(struct stasis_state_publisher *pub)
Retrieve the publisher's topic.
Definition: stasis_state.c:558
int stasis_state_add_observer(struct stasis_state_manager *manager, struct stasis_state_observer *observer)
Add an observer to receive managed state related events.
Definition: stasis_state.c:689
const char * stasis_state_publisher_id(const struct stasis_state_publisher *pub)
Retrieve the publisher's underlying state's unique id.
Definition: stasis_state.c:553
struct stasis_subscription * stasis_state_subscriber_subscription(struct stasis_state_subscriber *sub)
Retrieve the stasis topic subscription if available.
Definition: stasis_state.c:514
struct stasis_state_subscriber * stasis_state_subscribe_pool(struct stasis_state_manager *manager, const char *id, stasis_subscription_cb callback, void *data)
Add a subscriber, and subscribe to its underlying stasis topic.
Definition: stasis_state.c:447
struct stasis_topic * stasis_state_subscriber_topic(struct stasis_state_subscriber *sub)
Retrieve the subscriber's topic.
Definition: stasis_state.c:493
void stasis_state_callback_subscribed(struct stasis_state_manager *manager, on_stasis_state handler, void *data)
For each managed, and explicitly subscribed state call the given handler.
Definition: stasis_state.c:764
void stasis_state_remove_publish_by_id(struct stasis_state_manager *manager, const char *id, const struct ast_eid *eid, struct stasis_message *msg)
Publish to a managed named by id topic, and remove an implicit publisher.
Definition: stasis_state.c:659
void stasis_state_publish(struct stasis_state_publisher *pub, struct stasis_message *msg)
Publish to a managed state (topic) using a publisher.
Definition: stasis_state.c:563
struct stasis_topic * stasis_state_topic(struct stasis_state_manager *manager, const char *id)
Retrieve a managed topic creating one if not currently managed.
Definition: stasis_state.c:370
struct stasis_state_publisher * stasis_state_add_publisher(struct stasis_state_manager *manager, const char *id)
Add a publisher to the managed state for the given id.
Definition: stasis_state.c:532
void * stasis_state_subscriber_data(struct stasis_state_subscriber *sub)
Retrieve the last known state stasis message payload for the subscriber.
Definition: stasis_state.c:498
An Entity ID is essentially a MAC address, brief and unique.
Definition: utils.h:813
Managed stasis state event interface.
Definition: stasis_state.h:463
void(* on_unsubscribe)(const char *id, struct stasis_state_subscriber *sub)
Raised when any managed state is being unsubscribed.
Definition: stasis_state.h:478
void(* on_subscribe)(const char *id, struct stasis_state_subscriber *sub)
Raised when any managed state is being subscribed.
Definition: stasis_state.h:470
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59