[asterisk-commits] sgriepentrog: branch sgriepentrog/12-userevent r413026 - /team/sgriepentrog/1...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Apr 25 15:40:54 CDT 2014
Author: sgriepentrog
Date: Fri Apr 25 15:40:51 2014
New Revision: 413026
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=413026
Log:
userevent: missed a file
Added:
team/sgriepentrog/12-userevent/main/stasis_user.c (with props)
Added: team/sgriepentrog/12-userevent/main/stasis_user.c
URL: http://svnview.digium.com/svn/asterisk/team/sgriepentrog/12-userevent/main/stasis_user.c?view=auto&rev=413026
==============================================================================
--- team/sgriepentrog/12-userevent/main/stasis_user.c (added)
+++ team/sgriepentrog/12-userevent/main/stasis_user.c Fri Apr 25 15:40:51 2014
@@ -1,0 +1,430 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2014, Digium, Inc.
+ *
+ * Scott Griepentrog <sgriepentrog at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Stasis Messages and Data Types for User Events with Multiple Objects
+ *
+ * \author \verbatim Scott Griepentrog <sgriepentrog at digium.com> \endverbatim
+ *
+ */
+
+/*** MODULEINFO
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/astobj2.h"
+#include "asterisk/json.h"
+#include "asterisk/pbx.h"
+#include "asterisk/bridge.h"
+#include "asterisk/translate.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_cache_pattern.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/stasis_user.h"
+
+/*
+ * notes on mapping of URI to snapshot structures
+ *
+ * channel: = ast_channel_snapshot
+ * bridge: = ast_bridge_snapshot
+ * endpoint: = ast_endpoint_snapshot
+ * deviceState: = ???
+ *
+*/
+
+/*! \brief Object type code to identify snapshot contents */
+enum stasis_user_multi_object_snapshot_type {
+ STASIS_UMOS_CHANNEL,
+ STASIS_UMOS_BRIDGE,
+ STASIS_UMOS_ENDPOINT,
+};
+
+#define NUM_MULTI_OBJECT_BLOB_BUCKETS 7
+
+/*! \brief The key portion of multi object snapshot wrapper */
+struct ast_multi_object_snapshot_key {
+ enum stasis_user_multi_object_snapshot_type type; /*!< Object type */
+ char name[0]; /*!< The name assigned to the object */
+};
+
+/*! \brief A wrapper for multiple types of snapshot objects */
+struct ast_multi_object_snapshot {
+ void *snapshot; /*!< An object snapshot */
+ struct ast_multi_object_snapshot_key key; /*!< The key for this object */
+};
+
+/*! \internal \brief custom hash generator for multipart key */
+static force_inline int attribute_pure mos_hash(const struct ast_multi_object_snapshot_key *key)
+{
+ const char *str = key->name;
+ int hash = 5381;
+ hash = hash * 33 ^ key->type;
+
+ while (*str)
+ hash = hash * 33 ^ tolower(*str++);
+
+ return abs(hash);
+}
+
+/*! \internal \brief ao2 hash generator callback */
+static int multi_object_snapshot_hash_cb(const void *obj, const int flags)
+{
+ const struct ast_multi_object_snapshot *mos = obj;
+ const struct ast_multi_object_snapshot_key *key = (flags & OBJ_KEY) ? obj : &mos->key;
+ return mos_hash(key);
+}
+
+/*! \internal \brief ao2 comparator callback */
+static int multi_object_snapshot_single_cmp_cb(void *obj, void *arg, int flags)
+{
+ struct ast_multi_object_snapshot *lobj = obj;
+ struct ast_multi_object_snapshot *robj = arg;
+ struct ast_multi_object_snapshot_key *lkey = &lobj->key;
+ struct ast_multi_object_snapshot_key *rkey = (flags & OBJ_KEY) ? arg : &robj->key;
+ if (lkey->type != rkey->type) {
+ return 0;
+ }
+ return strcasecmp(lkey->name, rkey->name) ? 0 : (CMP_MATCH);
+}
+
+/*! \brief A multi object blob data structure for multi_object_blob stasis messages */
+struct ast_multi_object_blob {
+ struct ao2_container *object_snapshots; /*!< A container holding the snapshots */
+ struct ast_json *blob; /*< A blob of JSON data */
+};
+
+/*! \internal \brief destructor for multi object snapshot wrapper */
+static void multi_object_snapshot_dtor(void *obj)
+{
+ struct ast_multi_object_snapshot *mos = obj;
+
+ switch (mos->key.type) {
+ case STASIS_UMOS_CHANNEL:
+ case STASIS_UMOS_BRIDGE:
+ case STASIS_UMOS_ENDPOINT:
+ ao2_cleanup(mos->snapshot);
+ break;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Destructor for \ref ast_multi_object_blob objects
+ */
+static void multi_object_blob_dtor(void *obj)
+{
+ struct ast_multi_object_blob *multi_blob = obj;
+
+ ao2_cleanup(multi_blob->object_snapshots);
+ ast_json_unref(multi_blob->blob);
+}
+
+/*! \brief Create a stasis user event multi object blob */
+struct ast_multi_object_blob *ast_multi_object_blob_create(struct ast_json *blob)
+{
+ RAII_VAR(struct ast_multi_object_blob *, obj,
+ ao2_alloc(sizeof(*obj), multi_object_blob_dtor),
+ ao2_cleanup);
+
+ ast_assert(blob != NULL);
+
+ if (!obj) {
+ return NULL;
+ }
+
+ obj->object_snapshots = ao2_container_alloc(NUM_MULTI_OBJECT_BLOB_BUCKETS,
+ multi_object_snapshot_hash_cb, multi_object_snapshot_single_cmp_cb);
+ if (!obj->object_snapshots) {
+ return NULL;
+ }
+
+ obj->blob = ast_json_ref(blob);
+
+ ao2_ref(obj, +1);
+ return obj;
+}
+
+static void ast_multi_object_blob_add_object(struct ast_multi_object_blob *multi,
+ char *typename, char *supplied_name, void *object)
+{
+ RAII_VAR(struct ast_multi_object_snapshot *, mos, NULL, ao2_cleanup);
+ char *name = supplied_name;
+ int name_len;
+
+ if (!multi || !object) {
+ return;
+ }
+ ast_log(LOG_ERROR,"have name = %s\n", name);
+
+ if (ast_strlen_zero(name)) {
+ int count = ao2_container_count(multi->object_snapshots);
+ ast_log(LOG_ERROR,"have count = %d\n", count);
+ if (count) {
+ ast_asprintf(&name, "%s%d", typename, ++count);
+ } else {
+ name = typename;
+ }
+ }
+ name_len = strlen(name) + 1;
+
+ mos = ao2_alloc(sizeof(*mos) + name_len, multi_object_snapshot_dtor);
+ if (!mos) {
+ return;
+ }
+ ast_copy_string(mos->key.name, name, name_len);
+ mos->key.type = STASIS_UMOS_CHANNEL;
+ mos->snapshot = object;
+ //ao2_ref(mos->snapshot, +1);
+ ao2_link(multi->object_snapshots, mos);
+}
+
+/*! \brief Add a channel snapshot to a stasis user event multi object blob */
+void ast_multi_object_blob_add_channel(struct ast_multi_object_blob *multi,
+ char *name, struct ast_channel_snapshot *channel_snapshot)
+{
+ ast_multi_object_blob_add_object(multi, "channel", name, channel_snapshot);
+}
+
+/*! \brief Add a bridge snapshot to a stasis user event multi object blob */
+void ast_multi_object_blob_add_bridge(struct ast_multi_object_blob *multi,
+ char *name, struct ast_bridge_snapshot *bridge_snapshot)
+{
+ ast_multi_object_blob_add_object(multi, "bridge", name, bridge_snapshot);
+}
+
+/*! \brief Add a endpoint snapshot to a stasis user event multi object blob */
+void ast_multi_object_blob_add_endpoint(struct ast_multi_object_blob *multi,
+ char *name, struct ast_endpoint_snapshot *endpoint_snapshot)
+{
+ ast_multi_object_blob_add_object(multi, "endpoint", name, endpoint_snapshot);
+}
+
+/*! \brief Publish single channel user event (for app_userevent compatibility) */
+void ast_multi_object_blob_single_channel_publish(struct ast_channel *chan,
+ struct stasis_message_type *type, struct ast_json *blob)
+{
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, channel_snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_multi_object_blob *, multi, NULL, ao2_cleanup);
+
+ multi = ast_multi_object_blob_create(blob);
+ if (!multi) {
+ return;
+ }
+
+ channel_snapshot = ast_channel_snapshot_create(chan);
+ ao2_ref(channel_snapshot, +1);
+ ast_multi_object_blob_add_channel(multi, NULL, channel_snapshot);
+
+ message = stasis_message_create(type, multi);
+ if (message) {
+ /* app_userevent still publishes to channel */
+ stasis_publish(ast_channel_topic(chan), message);
+ }
+}
+
+/*! \internal \brief convert multi object blob to ari json */
+static struct ast_json *multi_user_event_to_json(
+ struct stasis_message *message,
+ const struct stasis_message_sanitizer *sanitize)
+{
+ RAII_VAR(struct ast_json *, out, NULL, ast_json_unref);
+ struct ast_multi_object_blob *multi = stasis_message_data(message);
+ struct ast_multi_object_snapshot *mos;
+ struct ast_json *blob = multi->blob;
+ const struct timeval *tv = stasis_message_timestamp(message);
+ struct ao2_iterator it_snapshots;
+
+ out = ast_json_object_create();
+ if (!out) {
+ return NULL;
+ }
+
+ ast_json_object_set(out, "type", ast_json_string_create("ChannelUserevent"));
+ ast_json_object_set(out, "timestamp", ast_json_timeval(*tv, NULL));
+ ast_json_object_set(out, "eventname", ast_json_object_get(blob, "eventname"));
+ ast_json_object_set(out, "userevent", ast_json_ref(blob)); /* eventname gets duplicated, that's ok */
+
+ it_snapshots = ao2_iterator_init(multi->object_snapshots, 0);
+ while ((mos = ao2_iterator_next(&it_snapshots))) {
+ struct ast_json *json_object = NULL;
+ switch (mos->key.type) {
+ case STASIS_UMOS_CHANNEL:
+ json_object = ast_channel_snapshot_to_json(mos->snapshot, sanitize);
+ break;
+ case STASIS_UMOS_BRIDGE:
+ json_object = ast_bridge_snapshot_to_json(mos->snapshot, sanitize);
+ break;
+ case STASIS_UMOS_ENDPOINT:
+ json_object = ast_endpoint_snapshot_to_json(mos->snapshot, sanitize);
+ break;
+ }
+ if (!json_object) {
+ continue;
+ }
+ ast_json_object_set(out, mos->key.name, json_object);
+ ao2_cleanup(mos);
+ }
+ ao2_iterator_destroy(&it_snapshots);
+ //ast_log(LOG_ERROR,"*** '%s'\n",ast_json_dump_string(out));
+ return ast_json_ref(out);
+}
+
+/*! \internal \brief convert a multi object snapshot to ami string */
+static struct ast_str *multi_object_snapshot_to_ami(void *obj)
+{
+ const struct ast_multi_object_snapshot *mos = obj;
+ const char *name = mos->key.name;
+
+ if (!mos) {
+ return NULL;
+ }
+ switch (mos->key.type) {
+ case STASIS_UMOS_CHANNEL:
+ if (ast_begins_with(name, "channel")) {
+ name = name + 7;
+ }
+ return ast_manager_build_channel_state_string_prefix(mos->snapshot, name);
+ case STASIS_UMOS_BRIDGE:
+ if (ast_begins_with(name, "bridge")) {
+ name = name + 6;
+ }
+ return ast_manager_build_bridge_state_string_prefix(mos->snapshot, name);
+ case STASIS_UMOS_ENDPOINT:
+ /* currently not sending endpoint snapshots to AMI */
+ break;
+ }
+ return NULL;
+}
+
+/*! \internal \brief convert multi object blob to ami string */
+static struct ast_str *multi_object_blob_to_ami(void *obj)
+{
+ struct ast_str *ami_str=ast_str_create(64);
+ struct ast_str *ami_snap;
+ const struct ast_multi_object_blob *multi = obj;
+
+ struct ao2_iterator it_snapshots;
+ struct ast_multi_object_snapshot *mos;
+
+ if (!ami_str) {
+ return NULL;
+ }
+ if (!multi) {
+ ast_free_ptr(ami_str);
+ return NULL;
+ }
+
+ it_snapshots = ao2_iterator_init(multi->object_snapshots, 0);
+ while ((mos = ao2_iterator_next(&it_snapshots))) {
+ ami_snap = multi_object_snapshot_to_ami(mos);
+ if (!ami_snap) {
+ continue;
+ }
+ ast_str_append(&ami_str, 0, "%s", ast_str_buffer(ami_snap));
+ ast_free_ptr(ami_snap);
+ ao2_cleanup(mos);
+ }
+ ao2_iterator_destroy(&it_snapshots);
+ return ami_str;
+}
+
+/*! \internal \brief Callback to pass user defined parameters from blob */
+static int userevent_exclusion_cb(const char *key)
+{
+ if (!strcmp("eventname", key)) {
+ return 1;
+ }
+ return 0;
+}
+
+static struct ast_manager_event_blob *multi_user_event_to_ami(
+ struct stasis_message *message)
+{
+ RAII_VAR(struct ast_str *, object_string, NULL, ast_free);
+ RAII_VAR(struct ast_str *, body, NULL, ast_free);
+ struct ast_multi_object_blob *multi = stasis_message_data(message);
+ const char *eventname;
+
+ eventname = ast_json_string_get(ast_json_object_get(multi->blob, "eventname"));
+ body = ast_manager_str_from_json_object(multi->blob, userevent_exclusion_cb);
+ object_string = multi_object_blob_to_ami(multi);
+ if (!object_string || !body) {
+ return NULL;
+ }
+
+ /*** DOCUMENTATION
+ <managerEvent language="en_US" name="UserEvent">
+ <managerEventInstance class="EVENT_FLAG_USER">
+ <synopsis>A user defined event raised from the dialplan.</synopsis>
+ <syntax>
+ <channel_snapshot/>
+ <parameter name="UserEvent">
+ <para>The event name, as specified in the dialplan.</para>
+ </parameter>
+ </syntax>
+ <see-also>
+ <ref type="application">UserEvent</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ ***/
+
+ return ast_manager_event_blob_create(EVENT_FLAG_USER, "UserEvent",
+ "%s"
+ "UserEvent: %s\r\n"
+ "%s",
+ ast_str_buffer(object_string),
+ eventname,
+ ast_str_buffer(body));
+}
+
+
+/*!
+ * @{ \brief Define multi user event message type(s).
+ */
+
+STASIS_MESSAGE_TYPE_DEFN(ast_multi_user_event_type,
+ .to_json = multi_user_event_to_json,
+ .to_ami = multi_user_event_to_ami,
+ );
+
+/*! @} */
+
+/*! \internal \brief Clean up stasis message type(s) that were initialized */
+static void stasis_user_cleanup(void)
+{
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_multi_user_event_type);
+}
+
+/*! \brief Initialize stasis message type(s) */
+int ast_user_stasis_init(void)
+{
+ int res = 0;
+
+ ast_register_cleanup(stasis_user_cleanup);
+
+ res |= STASIS_MESSAGE_TYPE_INIT(ast_multi_user_event_type);
+
+ return res;
+}
Propchange: team/sgriepentrog/12-userevent/main/stasis_user.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/sgriepentrog/12-userevent/main/stasis_user.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/sgriepentrog/12-userevent/main/stasis_user.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the asterisk-commits
mailing list