<p>George Joseph <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/11013">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Joshua Colp: Looks good to me, but someone else must approve
George Joseph: Looks good to me, approved; Approved for Submit
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">stasis.c: Added topic_all container<br><br>Added topic_all container for centralizing the topic. This makes more<br>easier to managing the topics.<br><br>Added cli commands.<br>stasis show topics : It shows all registered topics.<br>stasis show topic <name> : It shows speicifed topic's detail info.<br><br>ASTERISK-28264<br><br>Change-Id: Ie86d125d2966f93de74ee00f47ae6fbc8c081c5f<br>---<br>M include/asterisk/stasis.h<br>M main/stasis.c<br>2 files changed, 350 insertions(+), 16 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/stasis.h b/include/asterisk/stasis.h</span><br><span>index 71c6b4f..00b5c23 100644</span><br><span>--- a/include/asterisk/stasis.h</span><br><span>+++ b/include/asterisk/stasis.h</span><br><span>@@ -520,15 +520,56 @@</span><br><span> struct stasis_topic *stasis_topic_create(const char *name);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Create a new topic with given detail.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param name Name of the new topic.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param detail Detail description of the new topic. i.e. "Queue main topic for subscribing every queue event"</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return New topic instance.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return \c NULL on error.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note There is no explicit ability to unsubscribe all subscribers</span><br><span style="color: hsl(120, 100%, 40%);">+ * from a topic and destroy it. As a result the topic can persist until</span><br><span style="color: hsl(120, 100%, 40%);">+ * the last subscriber unsubscribes itself even if there is no</span><br><span style="color: hsl(120, 100%, 40%);">+ * publisher.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct stasis_topic *stasis_topic_create_with_detail(</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *name, const char *detail);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Get a topic of the given name.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param name Topic's name.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return Name of the topic.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return \c NULL on error or not exist.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note This SHOULD NOT be used in normal operation for publishing messages.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct stasis_topic *stasis_topic_get(const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Return the uniqueid of a topic.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param topic Topic.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return Uniqueid of the topic.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return \c NULL if topic is \c NULL.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *stasis_topic_uniqueid(const struct stasis_topic *topic);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * \brief Return the name of a topic.</span><br><span> * \param topic Topic.</span><br><span> * \return Name of the topic.</span><br><span> * \return \c NULL if topic is \c NULL.</span><br><span style="color: hsl(0, 100%, 40%);">- * \since 12</span><br><span> */</span><br><span> const char *stasis_topic_name(const struct stasis_topic *topic);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Return the detail of a topic.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param topic Topic.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return Detail of the topic.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return \c NULL if topic is \c NULL.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 12</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *stasis_topic_detail(const struct stasis_topic *topic);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * \brief Return the number of subscribers of a topic.</span><br><span> * \param topic Topic.</span><br><span> * \return Number of subscribers of the topic.</span><br><span>diff --git a/main/stasis.c b/main/stasis.c</span><br><span>index c0bb8b4..fd3bdc4 100644</span><br><span>--- a/main/stasis.c</span><br><span>+++ b/main/stasis.c</span><br><span>@@ -41,9 +41,7 @@</span><br><span> #include "asterisk/stasis_bridges.h"</span><br><span> #include "asterisk/stasis_endpoints.h"</span><br><span> #include "asterisk/config_options.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#ifdef AST_DEVMODE</span><br><span> #include "asterisk/cli.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span> </span><br><span> /*** DOCUMENTATION</span><br><span> <managerEvent language="en_US" name="UserEvent"></span><br><span>@@ -307,6 +305,16 @@</span><br><span> </span><br><span> STASIS_MESSAGE_TYPE_DEFN(stasis_subscription_change_type);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(LOW_MEMORY)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define TOPIC_ALL_BUCKETS 257</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define TOPIC_ALL_BUCKETS 997</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifdef AST_DEVMODE</span><br><span> </span><br><span> /*! The number of buckets to use for topic statistics */</span><br><span>@@ -372,9 +380,37 @@</span><br><span> int subscriber_id;</span><br><span> </span><br><span> /*! Name of the topic */</span><br><span style="color: hsl(0, 100%, 40%);">- char name[0];</span><br><span style="color: hsl(120, 100%, 40%);">+ char *name;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Detail of the topic */</span><br><span style="color: hsl(120, 100%, 40%);">+ char *detail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Creation time */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct timeval *creationtime;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ao2_container *topic_all;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct topic_proxy {</span><br><span style="color: hsl(120, 100%, 40%);">+ AO2_WEAKPROXY();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ char *name;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *detail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct timeval creationtime;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ char buf[0];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AO2_STRING_FIELD_HASH_FN(topic_proxy, name);</span><br><span style="color: hsl(120, 100%, 40%);">+AO2_STRING_FIELD_CMP_FN(topic_proxy, name);</span><br><span style="color: hsl(120, 100%, 40%);">+AO2_STRING_FIELD_CASE_SORT_FN(topic_proxy, name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void proxy_dtor(void *weakproxy, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlink(topic_all, weakproxy);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Forward declarations for the tightly-coupled subscription object */</span><br><span> static int topic_add_subscription(struct stasis_topic *topic,</span><br><span> struct stasis_subscription *sub);</span><br><span>@@ -394,6 +430,9 @@</span><br><span> {</span><br><span> struct stasis_topic *topic = obj;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(2, "Destroying topic. name: %s, detail: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ topic->name, topic->detail);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Subscribers hold a reference to topics, so they should all be</span><br><span> * unsubscribed before we get here. */</span><br><span> ast_assert(AST_VECTOR_SIZE(&topic->subscribers) == 0);</span><br><span>@@ -442,40 +481,145 @@</span><br><span> }</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_topic *stasis_topic_create(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+static int link_topic_proxy(struct stasis_topic *topic, const char *name, const char *detail)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct topic_proxy *proxy;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stasis_topic* topic_tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!topic || !name || !strlen(name) || !detail) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_wrlock(topic_all);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ topic_tmp = stasis_topic_get(name);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (topic_tmp) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "The same topic is already exist. name: %s\n", name);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(topic_tmp, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(topic_all);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ proxy = ao2_t_weakproxy_alloc(</span><br><span style="color: hsl(120, 100%, 40%);">+ sizeof(*proxy) + strlen(name) + 1 + strlen(detail) + 1, NULL, topic->name);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!proxy) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(topic_all);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* set the proxy info */</span><br><span style="color: hsl(120, 100%, 40%);">+ proxy->name = proxy->buf;</span><br><span style="color: hsl(120, 100%, 40%);">+ proxy->detail = proxy->name + strlen(name) + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ strcpy(proxy->name, name); /* SAFE */</span><br><span style="color: hsl(120, 100%, 40%);">+ strcpy(proxy->detail, detail); /* SAFE */</span><br><span style="color: hsl(120, 100%, 40%);">+ proxy->creationtime = ast_tvnow();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We have exclusive access to proxy, no need for locking here. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ao2_t_weakproxy_set_object(proxy, topic, OBJ_NOLOCK, "weakproxy link")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(topic_all);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ao2_weakproxy_subscribe(proxy, proxy_dtor, NULL, OBJ_NOLOCK)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(topic_all);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* setting the topic point to the proxy */</span><br><span style="color: hsl(120, 100%, 40%);">+ topic->name = proxy->name;</span><br><span style="color: hsl(120, 100%, 40%);">+ topic->detail = proxy->detail;</span><br><span style="color: hsl(120, 100%, 40%);">+ topic->creationtime = &(proxy->creationtime);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_link_flags(topic_all, proxy, OBJ_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(proxy, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(topic_all);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct stasis_topic *stasis_topic_create_with_detail(</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *name, const char* detail</span><br><span style="color: hsl(120, 100%, 40%);">+ )</span><br><span> {</span><br><span> struct stasis_topic *topic;</span><br><span> int res = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- topic = ao2_t_alloc(sizeof(*topic) + strlen(name) + 1, topic_dtor, name);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!name|| !strlen(name) || !detail) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(2, "Creating topic. name: %s, detail: %s\n", name, detail);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ topic = stasis_topic_get(name);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (topic) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(2, "Topic is already exist. name: %s, detail: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ name, detail);</span><br><span style="color: hsl(120, 100%, 40%);">+ return topic;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ topic = ao2_t_alloc(sizeof(*topic), topic_dtor, name);</span><br><span> if (!topic) {</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- strcpy(topic->name, name); /* SAFE */</span><br><span> res |= AST_VECTOR_INIT(&topic->subscribers, INITIAL_SUBSCRIBERS_MAX);</span><br><span> res |= AST_VECTOR_INIT(&topic->upstream_topics, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_debug(1, "Topic '%s': %p created\n", topic->name, topic);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#ifdef AST_DEVMODE</span><br><span style="color: hsl(0, 100%, 40%);">- topic->statistics = stasis_topic_statistics_create(topic);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!topic->name || !topic->statistics || res)</span><br><span style="color: hsl(0, 100%, 40%);">-#else</span><br><span style="color: hsl(0, 100%, 40%);">- if (!topic->name || res)</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">- {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res) {</span><br><span> ao2_ref(topic, -1);</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* link to the proxy */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (link_topic_proxy(topic, name, detail)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(topic, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef AST_DEVMODE</span><br><span style="color: hsl(120, 100%, 40%);">+ topic->statistics = stasis_topic_statistics_create(topic);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!topic->statistics) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(topic, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(1, "Topic '%s': %p created\n", topic->name, topic);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> return topic;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct stasis_topic *stasis_topic_create(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return stasis_topic_create_with_detail(name, "");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct stasis_topic *stasis_topic_get(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return ao2_weakproxy_find(topic_all, name, OBJ_SEARCH_KEY, "");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> const char *stasis_topic_name(const struct stasis_topic *topic)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!topic) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> return topic->name;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+const char *stasis_topic_detail(const struct stasis_topic *topic)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!topic) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return topic->detail;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> size_t stasis_topic_subscribers(const struct stasis_topic *topic)</span><br><span> {</span><br><span> return AST_VECTOR_SIZE(&topic->subscribers);</span><br><span>@@ -2134,6 +2278,142 @@</span><br><span> </span><br><span> /*! @} */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief CLI command implementation for 'stasis show topics'</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static char *stasis_show_topics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ao2_iterator iter;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct topic_proxy *topic;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ao2_container *tmp_container;</span><br><span style="color: hsl(120, 100%, 40%);">+ int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+#define FMT_HEADERS "%-64s %-64s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define FMT_FIELDS "%-64s %-64s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ e->command = "stasis show topics";</span><br><span style="color: hsl(120, 100%, 40%);">+ e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+ "Usage: stasis show topics\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ " Shows a list of topics\n";</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (a->argc != e->args) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "\n" FMT_HEADERS, "Name", "Detail");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ tmp_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ topic_proxy_sort_fn, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!tmp_container || ao2_container_dup(tmp_container, topic_all, OBJ_SEARCH_OBJECT)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(tmp_container);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* getting all topic in order */</span><br><span style="color: hsl(120, 100%, 40%);">+ iter = ao2_iterator_init(tmp_container, AO2_ITERATOR_UNLINK);</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((topic = ao2_iterator_next(&iter))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, FMT_FIELDS, topic->name, topic->detail);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(topic, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ++count;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_iterator_destroy(&iter);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(tmp_container);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "\n%d Total topics\n\n", count);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#undef FMT_HEADERS</span><br><span style="color: hsl(120, 100%, 40%);">+#undef FMT_FIELDS</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief CLI tab completion for topic names</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static char *topic_complete_name(const char *word)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct topic_proxy *topic;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ao2_iterator it;</span><br><span style="color: hsl(120, 100%, 40%);">+ int wordlen = strlen(word);</span><br><span style="color: hsl(120, 100%, 40%);">+ int ret;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ it = ao2_iterator_init(topic_all, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((topic = ao2_iterator_next(&it))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!strncasecmp(word, topic->name, wordlen)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ret = ast_cli_completion_add(ast_strdup(topic->name));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ret) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(topic, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(topic, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_iterator_destroy(&it);</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief CLI command implementation for 'stasis show topic'</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static char *stasis_show_topic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stasis_topic *topic;</span><br><span style="color: hsl(120, 100%, 40%);">+ char print_time[32];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ e->command = "stasis show topic";</span><br><span style="color: hsl(120, 100%, 40%);">+ e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+ "Usage: stasis show topic <name>\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ " Show stasis topic detail info.\n";</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+ if (a->pos == 3) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return topic_complete_name(a->word);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (a->argc != 4) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ topic = stasis_topic_get(a->argv[3]);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!topic) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "Specified topic '%s' does not exist\n", a->argv[3]);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_FAILURE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "Name: %s\n", topic->name);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "Detail: %s\n", topic->detail);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "Subscribers count: %lu\n", AST_VECTOR_SIZE(&topic->subscribers));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "Forwarding topic count: %lu\n", AST_VECTOR_SIZE(&topic->upstream_topics));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - topic->creationtime->tv_sec, print_time, sizeof(print_time));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "Duration time: %s\n", print_time);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(topic, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_cli_entry cli_stasis[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_CLI_DEFINE(stasis_show_topics, "Show all topics"),</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_CLI_DEFINE(stasis_show_topic, "Show topic"),</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifdef AST_DEVMODE</span><br><span> </span><br><span> AO2_STRING_FIELD_SORT_FN(stasis_subscription_statistics, uniqueid);</span><br><span>@@ -2646,6 +2926,9 @@</span><br><span> ao2_cleanup(subscription_statistics);</span><br><span> ao2_cleanup(topic_statistics);</span><br><span> #endif</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli_unregister_multiple(cli_stasis, ARRAY_LEN(cli_stasis));</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(topic_all);</span><br><span style="color: hsl(120, 100%, 40%);">+ topic_all = NULL;</span><br><span> ast_threadpool_shutdown(pool);</span><br><span> pool = NULL;</span><br><span> STASIS_MESSAGE_TYPE_CLEANUP(stasis_subscription_change_type);</span><br><span>@@ -2740,6 +3023,16 @@</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ topic_all = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, TOPIC_ALL_BUCKETS,</span><br><span style="color: hsl(120, 100%, 40%);">+ topic_proxy_hash_fn, 0, topic_proxy_cmp_fn);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!topic_all) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_cli_register_multiple(cli_stasis, ARRAY_LEN(cli_stasis))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifdef AST_DEVMODE</span><br><span> /* Statistics information is stored separately so that we don't alter or interrupt the lifetime of the underlying</span><br><span> * topic or subscripton.</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/11013">change 11013</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/11013"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: Ie86d125d2966f93de74ee00f47ae6fbc8c081c5f </div>
<div style="display:none"> Gerrit-Change-Number: 11013 </div>
<div style="display:none"> Gerrit-PatchSet: 10 </div>
<div style="display:none"> Gerrit-Owner: sungtae kim <pchero21@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Corey Farrell <git@cfware.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: sungtae kim <pchero21@gmail.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>