[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