<p>George Joseph <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/10929">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 0b229bf..8e9c6c7 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 7dd3893..4ce7052 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/+/10929">change 10929</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/+/10929"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ie86d125d2966f93de74ee00f47ae6fbc8c081c5f </div>
<div style="display:none"> Gerrit-Change-Number: 10929 </div>
<div style="display:none"> Gerrit-PatchSet: 21 </div>
<div style="display:none"> Gerrit-Owner: sungtae kim <pchero21@gmail.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>