mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	Remove required type field from channel blobs
When we first introduced the channel blob types, the JSON blobs were self identifying by a required "type" field in the JSON object itself. This, as it turns out, was a bad idea. When we introduced the message router, it was useless for routing based on the JSON type. And messages had two type fields to check: the stasis_message_type() of the message itself, plus the type field in the JSON blob (but only if it was a blob message). This patch corrects that mistake by removing the required type field from JSON blobs, and introducing first class stasis_message_type objects for the actual message type. Since we now will have a proliferation of message types, I introduced a few macros to help reduce the amount of boilerplate necessary to set them up. Review: https://reviewboard.asterisk.org/r/2509 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@388005 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		| @@ -93,7 +93,6 @@ static int userevent_exec(struct ast_channel *chan, const char *data) | ||||
| 	} | ||||
|  | ||||
| 	blob = ast_json_pack("{s: s, s: s, s: s}", | ||||
| 			     "type", "userevent", | ||||
| 			     "eventname", args.eventname, | ||||
| 			     "body", ast_str_buffer(body)); | ||||
| 	if (!blob) { | ||||
| @@ -101,7 +100,8 @@ static int userevent_exec(struct ast_channel *chan, const char *data) | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	msg = ast_channel_blob_create(chan, blob); | ||||
| 	msg = ast_channel_blob_create( | ||||
| 		chan, ast_channel_user_event_type(), blob); | ||||
| 	if (!msg) { | ||||
| 		return -1; | ||||
| 	} | ||||
|   | ||||
| @@ -542,6 +542,43 @@ struct ao2_container *stasis_cache_dump(struct stasis_caching_topic *caching_top | ||||
|  | ||||
| /*! @{ */ | ||||
|  | ||||
| /*! | ||||
|  * \brief Boiler-plate removing macro for defining message types. | ||||
|  * | ||||
|  * \param name Name of message type. | ||||
|  * \since 12 | ||||
|  */ | ||||
| #define STASIS_MESSAGE_TYPE_DEFN(name)				\ | ||||
| 	static struct stasis_message_type *__ ## name;	\ | ||||
| 	struct stasis_message_type *name(void) {	\ | ||||
| 		ast_assert(__ ## name != NULL);		\ | ||||
| 		return __ ## name;			\ | ||||
| 	} | ||||
|  | ||||
| /*! | ||||
|  * \brief Boiler-plate removing macro for initializing message types. | ||||
|  * | ||||
|  * \param name Name of message type. | ||||
|  * \return 0 if initialization is successful. | ||||
|  * \return Non-zero on failure. | ||||
|  * \since 12 | ||||
|  */ | ||||
| #define STASIS_MESSAGE_TYPE_INIT(name)				\ | ||||
| 	({						\ | ||||
| 	__ ## name = stasis_message_type_create(#name);	\ | ||||
| 	__ ## name ? 0 : -1;				\ | ||||
| 	}) | ||||
|  | ||||
| #define STASIS_MESSAGE_TYPE_CLEANUP(name)		\ | ||||
| 	({					\ | ||||
| 		ao2_cleanup(__ ## name);	\ | ||||
| 		__ ## name = NULL;		\ | ||||
| 	}) | ||||
|  | ||||
| /*! @} */ | ||||
|  | ||||
| /*! @{ */ | ||||
|  | ||||
| /*! | ||||
|  * \brief Initialize the Stasis subsystem | ||||
|  * \return 0 on success. | ||||
|   | ||||
| @@ -70,8 +70,7 @@ struct ast_channel_snapshot { | ||||
|  * \since 12 | ||||
|  * \brief Blob of data associated with a channel. | ||||
|  * | ||||
|  * The \c blob is actually a JSON object of structured data. It has a "type" field | ||||
|  * which contains the type string describing this blob. | ||||
|  * This blob is actually shared amongst several \ref stasis_message_type's. | ||||
|  */ | ||||
| struct ast_channel_blob { | ||||
| 	/*! Channel blob is associated with (or NULL for global/all channels) */ | ||||
| @@ -110,14 +109,6 @@ struct stasis_caching_topic *ast_channel_topic_all_cached(void); | ||||
|  */ | ||||
| struct stasis_message_type *ast_channel_snapshot_type(void); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Message type for \ref ast_channel_blob messages. | ||||
|  * | ||||
|  * \retval Message type for \ref ast_channel_blob messages. | ||||
|  */ | ||||
| struct stasis_message_type *ast_channel_blob_type(void); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Generate a snapshot of the channel state. This is an ao2 object, so | ||||
| @@ -128,44 +119,35 @@ struct stasis_message_type *ast_channel_blob_type(void); | ||||
|  * \retval pointer on success (must be ast_freed) | ||||
|  * \retval NULL on error | ||||
|  */ | ||||
| struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan); | ||||
| struct ast_channel_snapshot *ast_channel_snapshot_create( | ||||
| 	struct ast_channel *chan); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Creates a \ref ast_channel_blob message. | ||||
|  * | ||||
|  * 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. | ||||
|  * The given \a blob should be treated as immutable and not modified after it is | ||||
|  * put into the message. | ||||
|  * | ||||
|  * \param chan Channel blob is associated with, or \c NULL for global/all channels. | ||||
|  * \param type Message type for this blob. | ||||
|  * \param blob JSON object representing the data, or \c NULL for no data. If | ||||
|  *             \c NULL, ast_json_null() is put into the object. | ||||
|  * | ||||
|  * \param chan Channel blob is associated with, or NULL for global/all channels. | ||||
|  * \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(struct ast_channel *chan, | ||||
| 					       struct ast_json *blob); | ||||
| 	struct stasis_message_type *type, struct ast_json *blob); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Extracts the type field from a \ref ast_channel_blob. | ||||
|  * Returned \c char* is still owned by \a obj | ||||
|  * \param obj Channel blob object. | ||||
|  * \return Type field value from the blob. | ||||
|  * \return \c NULL on error. | ||||
|  */ | ||||
| const char *ast_channel_blob_json_type(struct ast_channel_blob *obj); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Create a \ref ast_multi_channel_blob suitable for a \ref stasis_message | ||||
|  * \brief Create a \ref ast_multi_channel_blob suitable for a \ref stasis_message. | ||||
|  * | ||||
|  * \note Similar to a \ref ast_channel_blob, the \ref ast_multi_channel_blob requires | ||||
|  * a \a blob JSON object containing a \c "type" field describing the blob. It | ||||
|  * should also be treated as immutable and not modified after it is put into the | ||||
|  * message. | ||||
|  * The given \a blob should be treated as immutable and not modified after it is | ||||
|  * put into the message. | ||||
|  * | ||||
|  * \param blob The JSON blob that defines the type of this \ref ast_multi_channel_blob | ||||
|  * \param blob The JSON blob that defines the data of this \ref ast_multi_channel_blob | ||||
|  * | ||||
|  * \return \ref ast_multi_channel_blob object | ||||
|  * \return \c NULL on error | ||||
| @@ -189,8 +171,7 @@ struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *bl | ||||
|  * \retval NULL on error or not found for the role specified | ||||
|  */ | ||||
| struct ast_channel_snapshot *ast_multi_channel_blob_get_channel( | ||||
| 					       struct ast_multi_channel_blob *obj, | ||||
| 					       const char *role); | ||||
| 	struct ast_multi_channel_blob *obj, const char *role); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
| @@ -212,8 +193,7 @@ struct ast_channel_snapshot *ast_multi_channel_blob_get_channel( | ||||
|  * \retval NULL on error or not found for the role specified | ||||
|  */ | ||||
| struct ao2_container *ast_multi_channel_blob_get_channels( | ||||
| 					       struct ast_multi_channel_blob *obj, | ||||
| 					       const char *role); | ||||
| 	struct ast_multi_channel_blob *obj, const char *role); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
| @@ -226,17 +206,6 @@ struct ao2_container *ast_multi_channel_blob_get_channels( | ||||
|  */ | ||||
| struct ast_json *ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Extracts the type field from a \ref ast_multi_channel_blob. | ||||
|  * Returned \c char* is still owned by \a obj | ||||
|  * | ||||
|  * \param obj Channel blob object. | ||||
|  * \return Type field value from the blob. | ||||
|  * \return \c NULL on error. | ||||
|  */ | ||||
| const char *ast_multi_channel_blob_get_type(struct ast_multi_channel_blob *obj); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Add a \ref ast_channel_snapshot to a \ref ast_multi_channel_blob object | ||||
| @@ -250,8 +219,7 @@ const char *ast_multi_channel_blob_get_type(struct ast_multi_channel_blob *obj); | ||||
|  * \ref ast_multi_channel_blob object | ||||
|  */ | ||||
| void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, | ||||
| 					       const char *role, | ||||
| 					       struct ast_channel_snapshot *snapshot); | ||||
| 	const char *role, struct ast_channel_snapshot *snapshot); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
| @@ -272,6 +240,46 @@ void ast_channel_publish_varset(struct ast_channel *chan, | ||||
|  */ | ||||
| struct stasis_message_type *ast_channel_dial_type(void); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Message type for when a variable is set on a channel. | ||||
|  * | ||||
|  * \retval A stasis message type | ||||
|  */ | ||||
| struct stasis_message_type *ast_channel_varset_type(void); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Message type for when a custom user event is sent on a channel. | ||||
|  * | ||||
|  * \retval A stasis message type | ||||
|  */ | ||||
| struct stasis_message_type *ast_channel_user_event_type(void); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Message type for when a hangup is requested on a channel. | ||||
|  * | ||||
|  * \retval A stasis message type | ||||
|  */ | ||||
| struct stasis_message_type *ast_channel_hangup_request_type(void); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Message type for when DTMF begins on a channel. | ||||
|  * | ||||
|  * \retval A stasis message type | ||||
|  */ | ||||
| struct stasis_message_type *ast_channel_dtmf_begin_type(void); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Message type for when DTMF ends on a channel. | ||||
|  * | ||||
|  * \retval A stasis message type | ||||
|  */ | ||||
| struct stasis_message_type *ast_channel_dtmf_end_type(void); | ||||
|  | ||||
| /*! | ||||
|  * \since 12 | ||||
|  * \brief Publish in the \ref ast_channel_topic or \ref ast_channel_topic_all | ||||
|   | ||||
| @@ -1368,11 +1368,12 @@ int ast_queue_frame_head(struct ast_channel *chan, struct ast_frame *fin) | ||||
| } | ||||
|  | ||||
| /*! \internal \brief Publish a channel blob message */ | ||||
| static void publish_channel_blob(struct ast_channel *chan, struct ast_json *blob) | ||||
| static void publish_channel_blob(struct ast_channel *chan, | ||||
| 	struct stasis_message_type *type, struct ast_json *blob) | ||||
| { | ||||
| 	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup); | ||||
| 	if (blob) { | ||||
| 		message = ast_channel_blob_create(chan, blob); | ||||
| 		message = ast_channel_blob_create(chan, type, blob); | ||||
| 	} | ||||
| 	if (message) { | ||||
| 		stasis_publish(ast_channel_topic(chan), message); | ||||
| @@ -1382,7 +1383,6 @@ static void publish_channel_blob(struct ast_channel *chan, struct ast_json *blob | ||||
| /*! \brief Queue a hangup frame for channel */ | ||||
| int ast_queue_hangup(struct ast_channel *chan) | ||||
| { | ||||
| 	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); | ||||
| 	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup); | ||||
| 	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HANGUP }; | ||||
| 	int res; | ||||
| @@ -1390,8 +1390,7 @@ int ast_queue_hangup(struct ast_channel *chan) | ||||
| 	/* Yeah, let's not change a lock-critical value without locking */ | ||||
| 	ast_channel_lock(chan); | ||||
| 	ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_DEV); | ||||
| 	blob = ast_json_pack("{s: s}", "type", "hangup_request"); | ||||
| 	publish_channel_blob(chan, blob); | ||||
| 	publish_channel_blob(chan, ast_channel_hangup_request_type(), NULL); | ||||
|  | ||||
| 	res = ast_queue_frame(chan, &f); | ||||
| 	ast_channel_unlock(chan); | ||||
| @@ -1416,10 +1415,9 @@ int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause) | ||||
| 	if (cause < 0) { | ||||
| 		f.data.uint32 = ast_channel_hangupcause(chan); | ||||
| 	} | ||||
| 	blob = ast_json_pack("{s: s, s: i}", | ||||
| 			     "type", "hangup_request", | ||||
| 	blob = ast_json_pack("{s: i}", | ||||
| 			     "cause", cause); | ||||
| 	publish_channel_blob(chan, blob); | ||||
| 	publish_channel_blob(chan, ast_channel_hangup_request_type(), blob); | ||||
|  | ||||
| 	res = ast_queue_frame(chan, &f); | ||||
| 	ast_channel_unlock(chan); | ||||
| @@ -2727,11 +2725,10 @@ int ast_softhangup(struct ast_channel *chan, int cause) | ||||
|  | ||||
| 	ast_channel_lock(chan); | ||||
| 	res = ast_softhangup_nolock(chan, cause); | ||||
| 	blob = ast_json_pack("{s: s, s: i, s: b}", | ||||
| 			     "type", "hangup_request", | ||||
| 	blob = ast_json_pack("{s: i, s: b}", | ||||
| 			     "cause", cause, | ||||
| 			     "soft", 1); | ||||
| 	publish_channel_blob(chan, blob); | ||||
| 	publish_channel_blob(chan, ast_channel_hangup_request_type(), blob); | ||||
| 	ast_channel_unlock(chan); | ||||
|  | ||||
| 	return res; | ||||
| @@ -3737,15 +3734,14 @@ static void send_dtmf_begin_event(struct ast_channel *chan, | ||||
| 	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); | ||||
| 	char digit_str[] = { digit, '\0' }; | ||||
|  | ||||
| 	blob = ast_json_pack("{ s: s, s: s, s: s }", | ||||
| 		"type", "dtmf_begin", | ||||
| 	blob = ast_json_pack("{ s: s, s: s }", | ||||
| 		"digit", digit_str, | ||||
| 		"direction", dtmf_direction_to_string(direction)); | ||||
| 	if (!blob) { | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	publish_channel_blob(chan, blob); | ||||
| 	publish_channel_blob(chan, ast_channel_dtmf_begin_type(), blob); | ||||
| } | ||||
|  | ||||
| static void send_dtmf_end_event(struct ast_channel *chan, | ||||
| @@ -3754,8 +3750,7 @@ static void send_dtmf_end_event(struct ast_channel *chan, | ||||
| 	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); | ||||
| 	char digit_str[] = { digit, '\0' }; | ||||
|  | ||||
| 	blob = ast_json_pack("{ s: s, s: s, s: s, s: i }", | ||||
| 		"type", "dtmf_end", | ||||
| 	blob = ast_json_pack("{ s: s, s: s, s: i }", | ||||
| 		"digit", digit_str, | ||||
| 		"direction", dtmf_direction_to_string(direction), | ||||
| 		"duration_ms", duration_ms); | ||||
| @@ -3763,7 +3758,7 @@ static void send_dtmf_end_event(struct ast_channel *chan, | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	publish_channel_blob(chan, blob); | ||||
| 	publish_channel_blob(chan, ast_channel_dtmf_end_type(), blob); | ||||
| } | ||||
|  | ||||
| static void ast_read_generator_actions(struct ast_channel *chan, struct ast_frame *f) | ||||
|   | ||||
| @@ -544,8 +544,10 @@ static void channel_snapshot_update(void *data, struct stasis_subscription *sub, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void channel_varset(struct ast_channel_blob *obj) | ||||
| static void channel_varset_cb(void *data, struct stasis_subscription *sub, | ||||
| 	struct stasis_topic *topic, struct stasis_message *message) | ||||
| { | ||||
| 	struct ast_channel_blob *obj = stasis_message_data(message); | ||||
| 	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free); | ||||
| 	const char *variable = ast_json_string_get(ast_json_object_get(obj->blob, "variable")); | ||||
| 	const char *value = ast_json_string_get(ast_json_object_get(obj->blob, "value")); | ||||
| @@ -585,8 +587,10 @@ static void channel_varset(struct ast_channel_blob *obj) | ||||
| 		      variable, value); | ||||
| } | ||||
|  | ||||
| static void channel_userevent(struct ast_channel_blob *obj) | ||||
| static void channel_user_event_cb(void *data, struct stasis_subscription *sub, | ||||
| 	struct stasis_topic *topic, struct stasis_message *message) | ||||
| { | ||||
| 	struct ast_channel_blob *obj = stasis_message_data(message); | ||||
| 	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free); | ||||
| 	const char *eventname; | ||||
| 	const char *body; | ||||
| @@ -620,8 +624,11 @@ static void channel_userevent(struct ast_channel_blob *obj) | ||||
| 		      ast_str_buffer(channel_event_string), eventname, body); | ||||
| } | ||||
|  | ||||
| static void channel_hangup_request(struct ast_channel_blob *obj) | ||||
| static void channel_hangup_request_cb(void *data, | ||||
| 	struct stasis_subscription *sub, struct stasis_topic *topic, | ||||
| 	struct stasis_message *message) | ||||
| { | ||||
| 	struct ast_channel_blob *obj = stasis_message_data(message); | ||||
| 	RAII_VAR(struct ast_str *, extra, NULL, ast_free); | ||||
| 	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free); | ||||
| 	struct ast_json *cause; | ||||
| @@ -657,8 +664,10 @@ static void channel_hangup_request(struct ast_channel_blob *obj) | ||||
| 		      ast_str_buffer(extra)); | ||||
| } | ||||
|  | ||||
| static void channel_dtmf_begin(struct ast_channel_blob *obj) | ||||
| static void channel_dtmf_begin_cb(void *data, struct stasis_subscription *sub, | ||||
| 	struct stasis_topic *topic, struct stasis_message *message) | ||||
| { | ||||
| 	struct ast_channel_blob *obj = stasis_message_data(message); | ||||
| 	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free); | ||||
| 	const char *digit = | ||||
| 		ast_json_string_get(ast_json_object_get(obj->blob, "digit")); | ||||
| @@ -696,8 +705,10 @@ static void channel_dtmf_begin(struct ast_channel_blob *obj) | ||||
| 		digit, direction); | ||||
| } | ||||
|  | ||||
| static void channel_dtmf_end(struct ast_channel_blob *obj) | ||||
| static void channel_dtmf_end_cb(void *data, struct stasis_subscription *sub, | ||||
| 	struct stasis_topic *topic, struct stasis_message *message) | ||||
| { | ||||
| 	struct ast_channel_blob *obj = stasis_message_data(message); | ||||
| 	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free); | ||||
| 	const char *digit = | ||||
| 		ast_json_string_get(ast_json_object_get(obj->blob, "digit")); | ||||
| @@ -741,34 +752,11 @@ static void channel_dtmf_end(struct ast_channel_blob *obj) | ||||
| 		digit, duration_ms, direction); | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief Callback processing messages on the channel topic. | ||||
|  */ | ||||
| static void channel_blob_cb(void *data, struct stasis_subscription *sub, | ||||
| 			    struct stasis_topic *topic, | ||||
| 			    struct stasis_message *message) | ||||
| { | ||||
| 	struct ast_channel_blob *obj = stasis_message_data(message); | ||||
|  | ||||
| 	if (strcmp("varset", ast_channel_blob_json_type(obj)) == 0) { | ||||
| 		channel_varset(obj); | ||||
| 	} else if (strcmp("userevent", ast_channel_blob_json_type(obj)) == 0) { | ||||
| 		channel_userevent(obj); | ||||
| 	} else if (strcmp("hangup_request", ast_channel_blob_json_type(obj)) == 0) { | ||||
| 		channel_hangup_request(obj); | ||||
| 	} else if (strcmp("dtmf_begin", ast_channel_blob_json_type(obj)) == 0) { | ||||
| 		channel_dtmf_begin(obj); | ||||
| 	} else if (strcmp("dtmf_end", ast_channel_blob_json_type(obj)) == 0) { | ||||
| 		channel_dtmf_end(obj); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief Callback processing messages for channel dialing | ||||
|  */ | ||||
| static void channel_dial_cb(void *data, struct stasis_subscription *sub, | ||||
| 				struct stasis_topic *topic, | ||||
| 				struct stasis_message *message) | ||||
| 	struct stasis_topic *topic, struct stasis_message *message) | ||||
| { | ||||
| 	struct ast_multi_channel_blob *obj = stasis_message_data(message); | ||||
| 	const char *dialstatus; | ||||
| @@ -778,11 +766,6 @@ static void channel_dial_cb(void *data, struct stasis_subscription *sub, | ||||
| 	RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free); | ||||
| 	RAII_VAR(struct ast_str *, peer_event_string, NULL, ast_free); | ||||
|  | ||||
| 	if (strcmp("dial", ast_multi_channel_blob_get_type(obj))) { | ||||
| 		ast_assert(0); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	caller = ast_multi_channel_blob_get_channel(obj, "caller"); | ||||
| 	peer = ast_multi_channel_blob_get_channel(obj, "peer"); | ||||
|  | ||||
| @@ -852,8 +835,28 @@ int manager_channels_init(void) | ||||
| 					 NULL); | ||||
|  | ||||
| 	ret |= stasis_message_router_add(channel_state_router, | ||||
| 					 ast_channel_blob_type(), | ||||
| 					 channel_blob_cb, | ||||
| 					 ast_channel_varset_type(), | ||||
| 					 channel_varset_cb, | ||||
| 					 NULL); | ||||
|  | ||||
| 	ret |= stasis_message_router_add(channel_state_router, | ||||
| 					 ast_channel_user_event_type(), | ||||
| 					 channel_user_event_cb, | ||||
| 					 NULL); | ||||
|  | ||||
| 	ret |= stasis_message_router_add(channel_state_router, | ||||
| 					 ast_channel_dtmf_begin_type(), | ||||
| 					 channel_dtmf_begin_cb, | ||||
| 					 NULL); | ||||
|  | ||||
| 	ret |= stasis_message_router_add(channel_state_router, | ||||
| 					 ast_channel_dtmf_end_type(), | ||||
| 					 channel_dtmf_end_cb, | ||||
| 					 NULL); | ||||
|  | ||||
| 	ret |= stasis_message_router_add(channel_state_router, | ||||
| 					 ast_channel_hangup_request_type(), | ||||
| 					 channel_hangup_request_cb, | ||||
| 					 NULL); | ||||
|  | ||||
| 	ret |= stasis_message_router_add(channel_state_router, | ||||
|   | ||||
| @@ -38,14 +38,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | ||||
|  | ||||
| #define NUM_MULTI_CHANNEL_BLOB_BUCKETS 7 | ||||
|  | ||||
| /*! \brief Message type for channel snapshot messages */ | ||||
| static struct stasis_message_type *channel_snapshot_type; | ||||
|  | ||||
| /*! \brief Message type for channel blob messages */ | ||||
| static struct stasis_message_type *channel_blob_type; | ||||
|  | ||||
| /*! \brief Message type for channel dial messages */ | ||||
| static struct stasis_message_type *channel_dial_type; | ||||
| /*! | ||||
|  * @{ \brief Define channel message types. | ||||
|  */ | ||||
| STASIS_MESSAGE_TYPE_DEFN(ast_channel_snapshot_type); | ||||
| STASIS_MESSAGE_TYPE_DEFN(ast_channel_dial_type); | ||||
| STASIS_MESSAGE_TYPE_DEFN(ast_channel_varset_type); | ||||
| STASIS_MESSAGE_TYPE_DEFN(ast_channel_user_event_type); | ||||
| STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_request_type); | ||||
| STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_begin_type); | ||||
| STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_end_type); | ||||
| /*! @} */ | ||||
|  | ||||
| /*! \brief Topic for all channels */ | ||||
| struct stasis_topic *channel_topic_all; | ||||
| @@ -53,21 +56,6 @@ struct stasis_topic *channel_topic_all; | ||||
| /*! \brief Caching topic for all channels */ | ||||
| struct stasis_caching_topic *channel_topic_all_cached; | ||||
|  | ||||
| struct stasis_message_type *ast_channel_dial_type(void) | ||||
| { | ||||
| 	return channel_dial_type; | ||||
| } | ||||
|  | ||||
| struct stasis_message_type *ast_channel_blob_type(void) | ||||
| { | ||||
| 	return channel_blob_type; | ||||
| } | ||||
|  | ||||
| struct stasis_message_type *ast_channel_snapshot_type(void) | ||||
| { | ||||
| 	return channel_snapshot_type; | ||||
| } | ||||
|  | ||||
| struct stasis_topic *ast_channel_topic_all(void) | ||||
| { | ||||
| 	return channel_topic_all; | ||||
| @@ -221,18 +209,13 @@ void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *pe | ||||
| } | ||||
|  | ||||
| struct stasis_message *ast_channel_blob_create(struct ast_channel *chan, | ||||
| 					       struct ast_json *blob) | ||||
| 	struct stasis_message_type *type, 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; | ||||
|  | ||||
| 	ast_assert(blob != NULL); | ||||
|  | ||||
| 	type = ast_json_object_get(blob, "type"); | ||||
| 	if (type == NULL) { | ||||
| 		ast_log(LOG_ERROR, "Invalid ast_channel_blob; missing type field\n"); | ||||
| 		return NULL; | ||||
| 	if (blob == NULL) { | ||||
| 		blob = ast_json_null(); | ||||
| 	} | ||||
|  | ||||
| 	obj = ao2_alloc(sizeof(*obj), channel_blob_dtor); | ||||
| @@ -249,7 +232,7 @@ struct stasis_message *ast_channel_blob_create(struct ast_channel *chan, | ||||
|  | ||||
| 	obj->blob = ast_json_ref(blob); | ||||
|  | ||||
| 	msg = stasis_message_create(ast_channel_blob_type(), obj); | ||||
| 	msg = stasis_message_create(type, obj); | ||||
| 	if (!msg) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| @@ -258,15 +241,6 @@ struct stasis_message *ast_channel_blob_create(struct ast_channel *chan, | ||||
| 	return msg; | ||||
| } | ||||
|  | ||||
| const char *ast_channel_blob_json_type(struct ast_channel_blob *obj) | ||||
| { | ||||
| 	if (obj == NULL) { | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	return ast_json_string_get(ast_json_object_get(obj->blob, "type")); | ||||
| } | ||||
|  | ||||
| /*! \brief A channel snapshot wrapper object used in \ref ast_multi_channel_blob objects */ | ||||
| struct channel_role_snapshot { | ||||
| 	struct ast_channel_snapshot *snapshot;	/*!< A channel snapshot */ | ||||
| @@ -319,7 +293,6 @@ struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *bl | ||||
| 	RAII_VAR(struct ast_multi_channel_blob *, obj, | ||||
| 			ao2_alloc(sizeof(*obj), multi_channel_blob_dtor), | ||||
| 			ao2_cleanup); | ||||
| 	struct ast_json *type; | ||||
|  | ||||
| 	ast_assert(blob != NULL); | ||||
|  | ||||
| @@ -327,12 +300,6 @@ struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *bl | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	type = ast_json_object_get(blob, "type"); | ||||
| 	if (type == NULL) { | ||||
| 		ast_log(LOG_ERROR, "Invalid ast_multi_channel_blob; missing type field\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	obj->channel_snapshots = ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS, | ||||
| 			channel_role_hash_cb, channel_role_single_cmp_cb); | ||||
| 	if (!obj->channel_snapshots) { | ||||
| @@ -423,15 +390,6 @@ struct ast_json *ast_multi_channel_blob_get_json(struct ast_multi_channel_blob * | ||||
| 	return obj->blob; | ||||
| } | ||||
|  | ||||
| const char *ast_multi_channel_blob_get_type(struct ast_multi_channel_blob *obj) | ||||
| { | ||||
| 	if (!obj) { | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	return ast_json_string_get(ast_json_object_get(obj->blob, "type")); | ||||
| } | ||||
|  | ||||
| void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value) | ||||
| { | ||||
| 	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); | ||||
| @@ -449,7 +407,8 @@ void ast_channel_publish_varset(struct ast_channel *chan, const char *name, cons | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	msg = ast_channel_blob_create(chan, ast_json_ref(blob)); | ||||
| 	msg = ast_channel_blob_create(chan, ast_channel_varset_type(), | ||||
| 		ast_json_ref(blob)); | ||||
|  | ||||
| 	if (!msg) { | ||||
| 		return; | ||||
| @@ -491,12 +450,13 @@ struct ast_json *ast_channel_snapshot_to_json(const struct ast_channel_snapshot | ||||
|  | ||||
| void ast_stasis_channels_shutdown(void) | ||||
| { | ||||
| 	ao2_cleanup(channel_snapshot_type); | ||||
| 	channel_snapshot_type = NULL; | ||||
| 	ao2_cleanup(channel_blob_type); | ||||
| 	channel_blob_type = NULL; | ||||
| 	ao2_cleanup(channel_dial_type); | ||||
| 	channel_dial_type = NULL; | ||||
| 	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_snapshot_type); | ||||
| 	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dial_type); | ||||
| 	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_varset_type); | ||||
| 	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_user_event_type); | ||||
| 	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_request_type); | ||||
| 	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_begin_type); | ||||
| 	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_end_type); | ||||
| 	ao2_cleanup(channel_topic_all); | ||||
| 	channel_topic_all = NULL; | ||||
| 	channel_topic_all_cached = stasis_caching_unsubscribe(channel_topic_all_cached); | ||||
| @@ -504,9 +464,14 @@ void ast_stasis_channels_shutdown(void) | ||||
|  | ||||
| void ast_stasis_channels_init(void) | ||||
| { | ||||
| 	channel_snapshot_type = stasis_message_type_create("ast_channel_snapshot"); | ||||
| 	channel_blob_type = stasis_message_type_create("ast_channel_blob"); | ||||
| 	channel_dial_type = stasis_message_type_create("ast_channel_dial"); | ||||
| 	STASIS_MESSAGE_TYPE_INIT(ast_channel_snapshot_type); | ||||
| 	STASIS_MESSAGE_TYPE_INIT(ast_channel_dial_type); | ||||
| 	STASIS_MESSAGE_TYPE_INIT(ast_channel_varset_type); | ||||
| 	STASIS_MESSAGE_TYPE_INIT(ast_channel_user_event_type); | ||||
| 	STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_request_type); | ||||
| 	STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_begin_type); | ||||
| 	STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_end_type); | ||||
|  | ||||
| 	channel_topic_all = stasis_topic_create("ast_channel_topic_all"); | ||||
| 	channel_topic_all_cached = stasis_caching_topic_create(channel_topic_all, channel_snapshot_get_id); | ||||
| } | ||||
|   | ||||
| @@ -470,19 +470,17 @@ static void dtmf_handler(struct app *app, struct ast_channel_blob *obj) | ||||
| 	app_send(app, msg); | ||||
| } | ||||
|  | ||||
| static void blob_handler(struct app *app, struct ast_channel_blob *blob) | ||||
| { | ||||
| 	/* To simplify events, we'll only generate on DTMF end */ | ||||
| 	if (strcmp(ast_channel_blob_json_type(blob), "dtmf_end") == 0) { | ||||
| 		dtmf_handler(app, blob); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void sub_handler(void *data, struct stasis_subscription *sub, | ||||
| 			struct stasis_topic *topic, | ||||
| 			struct stasis_message *message) | ||||
| { | ||||
| 	struct app *app = data; | ||||
|  | ||||
| 	if (stasis_subscription_final_message(sub, message)) { | ||||
| 		ao2_cleanup(data); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (ast_channel_snapshot_type() == stasis_message_type(message)) { | ||||
| 		RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref); | ||||
| 		struct ast_channel_snapshot *snapshot = | ||||
| @@ -493,13 +491,12 @@ static void sub_handler(void *data, struct stasis_subscription *sub, | ||||
| 			return; | ||||
| 		} | ||||
| 		app_send(app, msg); | ||||
| 	} else if (ast_channel_blob_type() == stasis_message_type(message)) { | ||||
| 	} else if (ast_channel_dtmf_end_type() == stasis_message_type(message)) { | ||||
| 		/* To simplify events, we'll only generate on DTMF end */ | ||||
| 		struct ast_channel_blob *blob = stasis_message_data(message); | ||||
| 		blob_handler(app, blob); | ||||
| 	} | ||||
| 	if (stasis_subscription_final_message(sub, message)) { | ||||
| 		ao2_cleanup(data); | ||||
| 		dtmf_handler(app, blob); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| /*! | ||||
|   | ||||
| @@ -54,6 +54,7 @@ static void safe_channel_release(struct ast_channel *chan) | ||||
| AST_TEST_DEFINE(channel_blob_create) | ||||
| { | ||||
| 	struct ast_channel_blob *blob; | ||||
| 	RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup); | ||||
| 	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); | ||||
| 	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release); | ||||
| 	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); | ||||
| @@ -70,36 +71,71 @@ AST_TEST_DEFINE(channel_blob_create) | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	type = stasis_message_type_create("test-type"); | ||||
| 	chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, "TEST/Alice"); | ||||
| 	json = ast_json_pack("{s: s}", | ||||
| 		     "type", "test"); | ||||
| 	bad_json = ast_json_pack("{s: s}", | ||||
| 		     "bad_key", "test"); | ||||
| 		     "foo", "bar"); | ||||
|  | ||||
| 	/* Off nominal creation */ | ||||
| 	ast_test_validate(test, NULL == ast_channel_blob_create(NULL, bad_json)); | ||||
| 	ast_test_validate(test, NULL == ast_channel_blob_create(chan, bad_json)); | ||||
| 	ast_test_validate(test, NULL == ast_channel_blob_create(chan, NULL, json)); | ||||
|  | ||||
| 	/* Test for single channel */ | ||||
| 	msg = ast_channel_blob_create(chan, json); | ||||
| 	msg = ast_channel_blob_create(chan, type, json); | ||||
| 	ast_test_validate(test, NULL != msg); | ||||
| 	blob = stasis_message_data(msg); | ||||
| 	ast_test_validate(test, NULL != blob); | ||||
| 	ast_test_validate(test, NULL != blob->snapshot); | ||||
| 	ast_test_validate(test, NULL != blob->blob); | ||||
| 	ast_test_validate(test, 0 == strcmp(ast_channel_blob_json_type(blob), "test")); | ||||
| 	ast_test_validate(test, type == stasis_message_type(msg)); | ||||
|  | ||||
| 	ast_test_validate(test, 1 == ao2_ref(msg, 0)); | ||||
| 	ao2_cleanup(msg); | ||||
|  | ||||
| 	/* Test for global channels */ | ||||
| 	msg = ast_channel_blob_create(NULL, json); | ||||
| 	msg = ast_channel_blob_create(NULL, type, json); | ||||
| 	ast_test_validate(test, NULL != msg); | ||||
| 	blob = stasis_message_data(msg); | ||||
| 	ast_test_validate(test, NULL != blob); | ||||
| 	ast_test_validate(test, NULL == blob->snapshot); | ||||
| 	ast_test_validate(test, NULL != blob->blob); | ||||
| 	ast_test_validate(test, 0 == strcmp(ast_channel_blob_json_type(blob), "test")); | ||||
| 	ast_test_validate(test, type == stasis_message_type(msg)); | ||||
|  | ||||
| 	return AST_TEST_PASS; | ||||
| } | ||||
|  | ||||
| AST_TEST_DEFINE(null_blob) | ||||
| { | ||||
| 	struct ast_channel_blob *blob; | ||||
| 	RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup); | ||||
| 	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); | ||||
| 	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release); | ||||
| 	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); | ||||
| 	RAII_VAR(struct ast_json *, bad_json, NULL, ast_json_unref); | ||||
|  | ||||
| 	switch (cmd) { | ||||
| 	case TEST_INIT: | ||||
| 		info->name = __func__; | ||||
| 		info->category = test_category; | ||||
| 		info->summary = "Test creation of ast_channel_blob objects"; | ||||
| 		info->description = "Test creation of ast_channel_blob objects"; | ||||
| 		return AST_TEST_NOT_RUN; | ||||
| 	case TEST_EXECUTE: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	type = stasis_message_type_create("test-type"); | ||||
| 	chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, "TEST/Alice"); | ||||
| 	json = ast_json_pack("{s: s}", | ||||
| 		     "foo", "bar"); | ||||
|  | ||||
| 	/* Test for single channel */ | ||||
| 	msg = ast_channel_blob_create(chan, type, NULL); | ||||
| 	ast_test_validate(test, NULL != msg); | ||||
| 	blob = stasis_message_data(msg); | ||||
| 	ast_test_validate(test, NULL != blob); | ||||
| 	ast_test_validate(test, NULL != blob->snapshot); | ||||
| 	ast_test_validate(test, ast_json_null() == blob->blob); | ||||
| 	ast_test_validate(test, type == stasis_message_type(msg)); | ||||
|  | ||||
| 	return AST_TEST_PASS; | ||||
| } | ||||
| @@ -122,17 +158,11 @@ AST_TEST_DEFINE(multi_channel_blob_create) | ||||
| 	} | ||||
|  | ||||
| 	json = ast_json_pack("{s: s}", | ||||
| 		     "type", "test"); | ||||
| 	bad_json = ast_json_pack("{s: s}", | ||||
| 		     "bad_key", "test"); | ||||
|  | ||||
| 	/* Off nominal creation */ | ||||
| 	ast_test_validate(test, NULL == ast_multi_channel_blob_create(bad_json)); | ||||
| 		     "foo", "bar"); | ||||
|  | ||||
| 	/* Test for single channel */ | ||||
| 	blob = ast_multi_channel_blob_create(json); | ||||
| 	ast_test_validate(test, NULL != blob); | ||||
| 	ast_test_validate(test, 0 == strcmp(ast_multi_channel_blob_get_type(blob), "test")); | ||||
| 	ast_test_validate(test, NULL != ast_multi_channel_blob_get_json(blob)); | ||||
|  | ||||
| 	return AST_TEST_PASS; | ||||
| @@ -266,6 +296,7 @@ AST_TEST_DEFINE(channel_snapshot_json) | ||||
| static int unload_module(void) | ||||
| { | ||||
| 	AST_TEST_UNREGISTER(channel_blob_create); | ||||
| 	AST_TEST_UNREGISTER(null_blob); | ||||
| 	AST_TEST_UNREGISTER(multi_channel_blob_create); | ||||
| 	AST_TEST_UNREGISTER(multi_channel_blob_snapshots); | ||||
| 	AST_TEST_UNREGISTER(channel_snapshot_json); | ||||
| @@ -276,6 +307,7 @@ static int unload_module(void) | ||||
| static int load_module(void) | ||||
| { | ||||
| 	AST_TEST_REGISTER(channel_blob_create); | ||||
| 	AST_TEST_REGISTER(null_blob); | ||||
| 	AST_TEST_REGISTER(multi_channel_blob_create); | ||||
| 	AST_TEST_REGISTER(multi_channel_blob_snapshots); | ||||
| 	AST_TEST_REGISTER(channel_snapshot_json); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user