[asterisk-commits] kmoore: branch kmoore/stasis-channel_events r383923 - in /team/kmoore/stasis-...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Mar 26 15:40:47 CDT 2013


Author: kmoore
Date: Tue Mar 26 15:40:38 2013
New Revision: 383923

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383923
Log:
Generate channel events in a more generic way

Expose channel blob message creation with a snapshot instead of a
channel

Separate channel AMI event creation and publication from snapshot
difference analysis using Stasis as an intermediary. This allows
messages like hangup, newstate, etc. to be sent over AMI or pushed to
an app_stasis application (like res_stasis_websocket) with relative
ease instead of having all that generic logic being locked away behind
AMI.

Modified:
    team/kmoore/stasis-channel_events/include/asterisk/channel.h
    team/kmoore/stasis-channel_events/main/channel.c
    team/kmoore/stasis-channel_events/main/manager_channels.c

Modified: team/kmoore/stasis-channel_events/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-channel_events/include/asterisk/channel.h?view=diff&rev=383923&r1=383922&r2=383923
==============================================================================
--- team/kmoore/stasis-channel_events/include/asterisk/channel.h (original)
+++ team/kmoore/stasis-channel_events/include/asterisk/channel.h Tue Mar 26 15:40:38 2013
@@ -4257,6 +4257,22 @@
 
 /*!
  * \since 12
+ * \brief Creates a \ref ast_channel_blob message from an existing snapshot.
+ *
+ * The \a blob JSON object requires a \c "type" field describing the blob. It
+ * should also be treated as immutable and not modified after it is put into the
+ * message.
+ *
+ * \param snapshot Snapshot of channel blob is associated with.
+ * \param blob JSON object representing the data.
+ * \return \ref ast_channel_blob message.
+ * \return \c NULL on error
+ */
+struct stasis_message *ast_channel_blob_create_from_snapshot(struct ast_channel_snapshot *snapshot,
+					       struct ast_json *blob);
+
+/*!
+ * \since 12
  * \brief Creates a \ref ast_channel_blob message.
  *
  * The \a blob JSON object requires a \c "type" field describing the blob. It

Modified: team/kmoore/stasis-channel_events/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-channel_events/main/channel.c?view=diff&rev=383923&r1=383922&r2=383923
==============================================================================
--- team/kmoore/stasis-channel_events/main/channel.c (original)
+++ team/kmoore/stasis-channel_events/main/channel.c Tue Mar 26 15:40:38 2013
@@ -264,17 +264,15 @@
 	ast_json_unref(event->blob);
 }
 
-struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
-					       struct ast_json *blob)
+struct stasis_message *ast_channel_blob_create_from_snapshot(struct ast_channel_snapshot *snapshot,
+	struct ast_json *blob)
 {
 	RAII_VAR(struct ast_channel_blob *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct ast_json *type;
+	struct stasis_message *msg;
 
 	ast_assert(blob != NULL);
 
-	type = ast_json_object_get(blob, "type");
-	if (type == NULL) {
+	if (!ast_json_object_get(blob, "type")) {
 		ast_log(LOG_ERROR, "Invalid ast_channel_blob; missing type field");
 		return NULL;
 	}
@@ -284,11 +282,9 @@
 		return NULL;
 	}
 
-	if (chan) {
-		obj->snapshot = ast_channel_snapshot_create(chan);
-		if (obj->snapshot == NULL) {
-			return NULL;
-		}
+	if (snapshot) {
+		obj->snapshot = snapshot;
+		ao2_ref(snapshot, +1);
 	}
 
 	obj->blob = ast_json_ref(blob);
@@ -298,8 +294,22 @@
 		return NULL;
 	}
 
-	ao2_ref(msg, +1);
 	return msg;
+}
+
+struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
+					       struct ast_json *blob)
+{
+	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+
+	if (chan) {
+		snapshot = ast_channel_snapshot_create(chan);
+		if (!snapshot) {
+			return NULL;
+		}
+	}
+
+	return ast_channel_blob_create_from_snapshot(snapshot, blob);
 }
 
 const char *ast_channel_blob_type(struct ast_channel_blob *obj)
@@ -320,7 +330,7 @@
 	ast_assert(value != NULL);
 
 	blob = ast_json_pack("{s: s, s: s, s: s}",
-			     "type", "varset",
+			     "type", "VarSet",
 			     "variable", name,
 			     "value", value);
 	publish_channel_blob(chan, blob);

Modified: team/kmoore/stasis-channel_events/main/manager_channels.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-channel_events/main/manager_channels.c?view=diff&rev=383923&r1=383922&r2=383923
==============================================================================
--- team/kmoore/stasis-channel_events/main/manager_channels.c (original)
+++ team/kmoore/stasis-channel_events/main/manager_channels.c Tue Mar 26 15:40:38 2013
@@ -154,6 +154,20 @@
 				<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
 				<parameter name="CID-CallingPres">
 					<para>A description of the Caller ID presentation.</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	</managerEvent>
+	<managerEvent language="en_US" name="VarSet">
+		<managerEventInstance class="EVENT_FLAG_DIALPLAN">
+			<synopsis>Raised when a variable is set to a particular value.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+				<parameter name="Variable">
+					<para>The variable being set.</para>
+				</parameter>
+				<parameter name="Value">
+					<para>The new value of the variable.</para>
 				</parameter>
 			</syntax>
 		</managerEventInstance>
@@ -220,86 +234,32 @@
 	return out;
 }
 
-/*! \brief Struct containing info for an AMI channel event to send out. */
-struct snapshot_manager_event {
-	/*! event_flags manager_event() flags parameter. */
-	int event_flags;
-	/*!  manager_event manager_event() category. */
-	const char *manager_event;
-	AST_DECLARE_STRING_FIELDS(
-		/* extra fields to include in the event. */
-		AST_STRING_FIELD(extra_fields);
-		);
-};
-
-static void snapshot_manager_event_dtor(void *obj)
-{
-	struct snapshot_manager_event *ev = obj;
-	ast_string_field_free_memory(ev);
-}
-
-/*!
- * \brief Construct a \ref snapshot_manager_event.
- * \param event_flags manager_event() flags parameter.
- * \param manager_event manager_event() category.
- * \param extra_fields_fmt Format string for extra fields to include.
- *                         Or NO_EXTRA_FIELDS for no extra fields.
- * \return New \ref snapshot_manager_event object.
- * \return \c NULL on error.
- */
-static struct snapshot_manager_event *
-__attribute__((format(printf, 3, 4)))
-snapshot_manager_event_create(
-	int event_flags,
-	const char *manager_event,
-	const char *extra_fields_fmt,
-	...)
-{
-	RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
-	va_list argp;
-
-	ast_assert(extra_fields_fmt != NULL);
-	ast_assert(manager_event != NULL);
-
-	ev = ao2_alloc(sizeof(*ev), snapshot_manager_event_dtor);
-	if (!ev) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(ev, 20)) {
-		return NULL;
-	}
-
-	ev->manager_event = manager_event;
-	ev->event_flags = event_flags;
-
-	va_start(argp, extra_fields_fmt);
-	ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt,
-				      argp);
-	va_end(argp);
-
-	ao2_ref(ev, +1);
-	return ev;
-}
-
-/*! GCC warns about blank or NULL format strings. So, shenanigans! */
-#define NO_EXTRA_FIELDS "%s", ""
-
-/*! \brief Typedef for callbacks that get called on channel snapshot updates */
-typedef struct snapshot_manager_event *(*snapshot_monitor)(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot);
+static void publish_channel_blob(struct ast_channel_snapshot *snapshot, struct ast_json *blob)
+{
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+
+	if (!blob) {
+		return;
+	}
+
+	msg = ast_channel_blob_create_from_snapshot(snapshot, blob);
+	if (!msg) {
+		return;
+	}
+
+	stasis_publish(ast_channel_topic_by_uniqueid(snapshot->uniqueid), msg);
+}
 
 /*! \brief Handle channel state changes */
-static struct snapshot_manager_event *channel_state_change(
+static void channel_generate_state_change(
 	struct ast_channel_snapshot *old_snapshot,
 	struct ast_channel_snapshot *new_snapshot)
 {
-	int is_hungup, was_hungup;
+	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 
 	if (!new_snapshot) {
 		/* Ignore cache clearing events; we'll see the hangup first */
-		return NULL;
+		return;
 	}
 
 	/* The Newchannel, Newstate and Hangup events are closely related, in
@@ -308,29 +268,19 @@
 	 */
 
 	if (!old_snapshot) {
-		return snapshot_manager_event_create(
-			EVENT_FLAG_CALL, "Newchannel", NO_EXTRA_FIELDS);
-	}
-
-	was_hungup = ast_test_flag(&old_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
-	is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
-
-	if (!was_hungup && is_hungup) {
-		return snapshot_manager_event_create(
-			EVENT_FLAG_CALL, "Hangup",
-			"Cause: %d\r\n"
-			"Cause-txt: %s\r\n",
-			new_snapshot->hangupcause,
-			ast_cause2str(new_snapshot->hangupcause));
-	}
-
-	if (old_snapshot->state != new_snapshot->state) {
-		return snapshot_manager_event_create(
-			EVENT_FLAG_CALL, "Newstate", NO_EXTRA_FIELDS);
-	}
-
-	/* No event */
-	return NULL;
+		blob = ast_json_pack("{s: s}",
+			"type", "Newchannel");
+	} else if (!ast_test_flag(&old_snapshot->flags, AST_FLAG_ZOMBIE) && ast_test_flag(&new_snapshot->flags, AST_FLAG_ZOMBIE)) {
+		blob = ast_json_pack("{s: s, s: i, s: s}",
+			"type", "Hangup",
+			"Cause", new_snapshot->hangupcause,
+			"Cause-txt", ast_cause2str(new_snapshot->hangupcause));
+	} else if (old_snapshot->state != new_snapshot->state) {
+		blob = ast_json_pack("{s: s}",
+			"type", "Newstate");
+	}
+
+	publish_channel_blob(new_snapshot, blob);
 }
 
 /*!
@@ -361,33 +311,32 @@
 		strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
 }
 
-static struct snapshot_manager_event *channel_newexten(
+static void channel_generate_newexten(
 	struct ast_channel_snapshot *old_snapshot,
 	struct ast_channel_snapshot *new_snapshot)
 {
+	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+
 	/* No Newexten event on cache clear */
 	if (!new_snapshot) {
-		return NULL;
+		return;
 	}
 
 	/* Empty application is not valid for a Newexten event */
 	if (ast_strlen_zero(new_snapshot->appl)) {
-		return NULL;
+		return;
 	}
 
 	if (old_snapshot && cep_equal(old_snapshot, new_snapshot)) {
-		return NULL;
-	}
-
-	/* DEPRECATED: Extension field deprecated in 12; remove in 14 */
-	return snapshot_manager_event_create(
-		EVENT_FLAG_CALL, "Newexten",
-		"Extension: %s\r\n"
-		"Application: %s\r\n"
-		"AppData: %s\r\n",
-		new_snapshot->exten,
-		new_snapshot->appl,
-		new_snapshot->data);
+		return;
+	}
+
+	blob = ast_json_pack("{s: s, s: s, s: s}",
+		"type", "Newexten",
+		"Application", new_snapshot->appl,
+		"AppData", new_snapshot->data);
+
+	publish_channel_blob(new_snapshot, blob);
 }
 
 /*!
@@ -407,37 +356,48 @@
 		strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
 }
 
-static struct snapshot_manager_event *channel_new_callerid(
+static void channel_generate_newcallerid(
 	struct ast_channel_snapshot *old_snapshot,
 	struct ast_channel_snapshot *new_snapshot)
 {
+	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+	RAII_VAR(struct ast_str *, calling_pres, ast_str_create(32), ast_free);
+
 	/* No NewCallerid event on cache clear or first event */
 	if (!old_snapshot || !new_snapshot) {
-		return NULL;
+		return;
 	}
 
 	if (caller_id_equal(old_snapshot, new_snapshot)) {
-		return NULL;
-	}
-
-	return snapshot_manager_event_create(
-		EVENT_FLAG_CALL, "NewCallerid",
-		"CID-CallingPres: %d (%s)\r\n",
+		return;
+	}
+
+	ast_str_set(&calling_pres, 0, "%d (%s)",
 		new_snapshot->caller_pres,
 		ast_describe_caller_presentation(new_snapshot->caller_pres));
-}
+
+	blob = ast_json_pack("{s: s, s: s}",
+		"type", "NewCallerid",
+		"CID-CallingPres", ast_str_buffer(calling_pres));
+
+	publish_channel_blob(new_snapshot, blob);
+}
+
+/*! \brief Typedef for callbacks that get called on channel snapshot updates */
+typedef void (*snapshot_monitor)(
+	struct ast_channel_snapshot *old_snapshot,
+	struct ast_channel_snapshot *new_snapshot);
 
 snapshot_monitor monitors[] = {
-	channel_state_change,
-	channel_newexten,
-	channel_new_callerid
+	channel_generate_state_change,
+	channel_generate_newexten,
+	channel_generate_newcallerid
 };
 
 static void channel_snapshot_update(void *data, struct stasis_subscription *sub,
 				    struct stasis_topic *topic,
 				    struct stasis_message *message)
 {
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
 	struct stasis_cache_update *update;
 	struct ast_channel_snapshot *old_snapshot;
 	struct ast_channel_snapshot *new_snapshot;
@@ -453,25 +413,7 @@
 	new_snapshot = stasis_message_data(update->new_snapshot);
 
 	for (i = 0; i < ARRAY_LEN(monitors); ++i) {
-		RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
-		ev = monitors[i](old_snapshot, new_snapshot);
-
-		if (!ev) {
-			continue;
-		}
-
-		/* If we haven't already, build the channel event string */
-		if (!channel_event_string) {
-			channel_event_string =
-				manager_build_channel_state_string(new_snapshot);
-			if (!channel_event_string) {
-				return;
-			}
-		}
-
-		manager_event(ev->event_flags, ev->manager_event, "%s%s",
-			ast_str_buffer(channel_event_string),
-			ev->extra_fields);
+		monitors[i](old_snapshot, new_snapshot);
 	}
 }
 
@@ -518,7 +460,7 @@
 	return output_str;
 }
 
-static void channel_varset(struct ast_channel_blob *obj)
+static void channel_manager_generic(struct ast_channel_blob *obj, int manager_flag)
 {
 	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
 	RAII_VAR(struct ast_str *, blob_str, manager_str_from_blob(obj->blob), ast_free);
@@ -532,32 +474,17 @@
 			    "Uniqueid: none\r\n");
 	}
 
-	if (!channel_event_string) {
-		return;
-	}
-
-	/*** DOCUMENTATION
-		<managerEventInstance>
-			<synopsis>Raised when a variable is set to a particular value.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
-				<parameter name="Variable">
-					<para>The variable being set.</para>
-				</parameter>
-				<parameter name="Value">
-					<para>The new value of the variable.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	***/
-	manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
+	if (!channel_event_string || !blob_str) {
+		return;
+	}
+
+	manager_event(manager_flag, ast_channel_blob_type(obj),
 		      "%s"
 		      "%s",
 		      ast_str_buffer(channel_event_string),
 		      ast_str_buffer(blob_str));
 }
 
-
 static int userevent_exclusion_cb(const char *key)
 {
 	if (!strcmp("type", key)) {
@@ -569,7 +496,7 @@
 	return 0;
 }
 
-static void channel_userevent(struct ast_channel_blob *obj)
+static void channel_userevent(struct ast_channel_blob *obj, int manager_flag)
 {
 	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
 	RAII_VAR(struct ast_str *, body, manager_str_from_blob_exclusion(obj->blob, userevent_exclusion_cb), ast_free);
@@ -603,7 +530,7 @@
 		      ast_str_buffer(channel_event_string), eventname, ast_str_buffer(body));
 }
 
-static void channel_hangup_request(struct ast_channel_blob *obj)
+static void channel_hangup_request(struct ast_channel_blob *obj, int manager_flag)
 {
 	RAII_VAR(struct ast_str *, extra, NULL, ast_free);
 	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
@@ -640,10 +567,32 @@
 		      ast_str_buffer(extra));
 }
 
-typedef void (*blob_handler_cb)(struct ast_channel_blob *obj);
+static void channel_newexten(struct ast_channel_blob *obj, int manager_flag)
+{
+	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+	RAII_VAR(struct ast_str *, blob_str, manager_str_from_blob(obj->blob), ast_free);
+
+	channel_event_string = manager_build_channel_state_string(obj->snapshot);
+
+	if (!channel_event_string || !blob_str) {
+		return;
+	}
+
+	/* DEPRECATED: Extension field deprecated in 12; remove in 14 */
+	manager_event(manager_flag, ast_channel_blob_type(obj),
+		"%s"
+		"%s"
+		"Extension: %s\r\n",
+		ast_str_buffer(channel_event_string),
+		ast_str_buffer(blob_str),
+		obj->snapshot->exten);
+}
+
+typedef void (*blob_handler_cb)(struct ast_channel_blob *obj, int manager_flag);
 
 struct blob_handler {
 	char *type;
+	int flag;
 	blob_handler_cb handler_cb;
 };
 
@@ -653,7 +602,7 @@
 	ast_free(handler->type);
 }
 
-static void register_blob_handler(char *type, blob_handler_cb handler_cb)
+static void register_blob_handler(char *type, int flag, blob_handler_cb handler_cb)
 {
 	RAII_VAR(struct blob_handler *, handler, ao2_alloc(sizeof(*handler), blob_handler_destroy), ao2_cleanup);
 
@@ -668,17 +617,8 @@
 	}
 
 	handler->handler_cb = handler_cb;
+	handler->flag = flag;
 	ao2_link(channel_blob_handlers, handler);
-}
-
-static blob_handler_cb get_blob_handler(const char *type)
-{
-	RAII_VAR(struct blob_handler *, handler, ao2_find(channel_blob_handlers, type, OBJ_KEY), ao2_cleanup);
-	if (!handler) {
-		return NULL;
-	}
-
-	return handler->handler_cb;
 }
 
 /*!
@@ -689,10 +629,10 @@
 			    struct stasis_message *message)
 {
 	struct ast_channel_blob *obj = stasis_message_data(message);
-	blob_handler_cb handler = get_blob_handler(ast_channel_blob_type(obj));
+	RAII_VAR(struct blob_handler *, handler, ao2_find(channel_blob_handlers, ast_channel_blob_type(obj), OBJ_KEY), ao2_cleanup);
 
 	if (handler) {
-		handler(obj);
+		handler->handler_cb(obj, handler->flag);
 	}
 }
 
@@ -760,9 +700,14 @@
 		return -1;
 	}
 
-	register_blob_handler("varset", channel_varset);
-	register_blob_handler("userevent", channel_userevent);
-	register_blob_handler("hangup_request", channel_hangup_request);
+	register_blob_handler("userevent", EVENT_FLAG_USER, channel_userevent);
+	register_blob_handler("hangup_request", EVENT_FLAG_CALL, channel_hangup_request);
+	register_blob_handler("Newexten", EVENT_FLAG_CALL, channel_newexten);
+	register_blob_handler("VarSet", EVENT_FLAG_DIALPLAN, channel_manager_generic);
+	register_blob_handler("NewCallerid", EVENT_FLAG_CALL, channel_manager_generic);
+	register_blob_handler("Newchannel", EVENT_FLAG_CALL, channel_manager_generic);
+	register_blob_handler("Newstate", EVENT_FLAG_CALL, channel_manager_generic);
+	register_blob_handler("Hangup", EVENT_FLAG_CALL, channel_manager_generic);
 
 	return 0;
 }




More information about the asterisk-commits mailing list