[asterisk-commits] mjordan: branch 12 r400522 - in /branches/12: include/asterisk/ main/ res/ re...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Oct 4 10:55:04 CDT 2013


Author: mjordan
Date: Fri Oct  4 10:54:57 2013
New Revision: 400522

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=400522
Log:
ARI: Add subscription support

This patch adds an /applications API to ARI, allowing explicit management of
Stasis applications.

 * GET /applications - list current applications
 * GET /applications/{applicationName} - get details of a specific application
 * POST /applications/{applicationName}/subscription - explicitly subscribe to
   a channel, bridge or endpoint
 * DELETE /applications/{applicationName}/subscription - explicitly unsubscribe
   from a channel, bridge or endpoint

Subscriptions work by a reference counting mechanism: if you subscript to an
event source X number of times, you must unsubscribe X number of times to stop
receiveing events for that event source.

Review: https://reviewboard.asterisk.org/r/2862

(issue ASTERISK-22451)
Reported by: Matt Jordan



Added:
    branches/12/res/ari/resource_applications.c   (with props)
    branches/12/res/ari/resource_applications.h   (with props)
    branches/12/res/res_ari_applications.c   (with props)
Modified:
    branches/12/include/asterisk/_private.h
    branches/12/include/asterisk/endpoints.h
    branches/12/include/asterisk/stasis_app.h
    branches/12/main/asterisk.c
    branches/12/main/endpoints.c
    branches/12/main/json.c
    branches/12/res/ari.make
    branches/12/res/ari/ari_model_validators.c
    branches/12/res/ari/ari_model_validators.h
    branches/12/res/ari/resource_endpoints.h
    branches/12/res/res_ari_model.c
    branches/12/res/res_stasis.c
    branches/12/res/stasis/app.c
    branches/12/res/stasis/app.h
    branches/12/rest-api-templates/ari_model_validators.h.mustache
    branches/12/rest-api/api-docs/endpoints.json
    branches/12/rest-api/api-docs/events.json
    branches/12/rest-api/resources.json

Modified: branches/12/include/asterisk/_private.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/_private.h?view=diff&rev=400522&r1=400521&r2=400522
==============================================================================
--- branches/12/include/asterisk/_private.h (original)
+++ branches/12/include/asterisk/_private.h Fri Oct  4 10:54:57 2013
@@ -142,4 +142,12 @@
 
 /*! \brief initialize the sounds index */
 int ast_sounds_index_init(void);
+
+/*!
+ * \brief Endpoint support initialization.
+ * \return 0 on success.
+ * \return Non-zero on error.
+ */
+int ast_endpoint_init(void);
+
 #endif /* _ASTERISK__PRIVATE_H */

Modified: branches/12/include/asterisk/endpoints.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/endpoints.h?view=diff&rev=400522&r1=400521&r2=400522
==============================================================================
--- branches/12/include/asterisk/endpoints.h (original)
+++ branches/12/include/asterisk/endpoints.h Fri Oct  4 10:54:57 2013
@@ -77,6 +77,19 @@
 struct ast_endpoint;
 
 /*!
+ * \brief Finds the endpoint with the given tech/resource id.
+ *
+ * Endpoints are refcounted, so ao2_cleanup() when you're done.
+ *
+ * \param id Tech/resource id to look for.
+ * \return Associated endpoint.
+ * \return \c NULL if not found.
+ *
+ * \since 12
+ */
+struct ast_endpoint *ast_endpoint_find_by_id(const char *id);
+
+/*!
  * \brief Create an endpoint struct.
  *
  * The endpoint is created with a state of UNKNOWN and max_channels of -1
@@ -126,6 +139,18 @@
 const char *ast_endpoint_get_resource(const struct ast_endpoint *endpoint);
 
 /*!
+ * \brief Gets the tech/resource id of the given endpoint.
+ *
+ * This is unique across all endpoints, and immutable.
+ *
+ * \param endpoint The endpoint.
+ * \return Tech/resource id of the endpoint.
+ * \return \c NULL if endpoint is \c NULL.
+ * \since 12
+ */
+const char *ast_endpoint_get_id(const struct ast_endpoint *endpoint);
+
+/*!
  * \brief Updates the state of the given endpoint.
  *
  * \param endpoint Endpoint to modify.

Modified: branches/12/include/asterisk/stasis_app.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/stasis_app.h?view=diff&rev=400522&r1=400521&r2=400522
==============================================================================
--- branches/12/include/asterisk/stasis_app.h (original)
+++ branches/12/include/asterisk/stasis_app.h Fri Oct  4 10:54:57 2013
@@ -69,6 +69,14 @@
 	struct ast_json *message);
 
 /*!
+ * \brief Gets the names of all registered Stasis applications.
+ *
+ * \return \c ast_str_container of container names.
+ * \return \c NULL on error.
+ */
+struct ao2_container *stasis_app_get_all(void);
+
+/*!
  * \brief Register a new Stasis application.
  *
  * If an application is already registered with the given name, the old
@@ -77,6 +85,7 @@
  * \param app_name Name of this application.
  * \param handler Callback for application messages.
  * \param data Data blob to pass to the callback. Must be AO2 managed.
+ *
  * \return 0 for success
  * \return -1 for error.
  */
@@ -96,10 +105,60 @@
  *
  * \param app_name Name of the application to invoke.
  * \param message Message to send (borrowed reference)
+ *
  * \return 0 for success.
  * \return -1 for error.
  */
 int stasis_app_send(const char *app_name, struct ast_json *message);
+
+/*!
+ * \brief Return the JSON representation of a Stasis application.
+ *
+ * \param app_name Name of the application.
+ *
+ * \return JSON representation of app with given name.
+ * \return \c NULL on error.
+ */
+struct ast_json *stasis_app_to_json(const char *app_name);
+
+/*! \brief Return code for stasis_app_[un]subscribe */
+enum stasis_app_subscribe_res {
+	STASIS_ASR_OK,
+	STASIS_ASR_APP_NOT_FOUND,
+	STASIS_ASR_EVENT_SOURCE_NOT_FOUND,
+	STASIS_ASR_EVENT_SOURCE_BAD_SCHEME,
+	STASIS_ASR_INTERNAL_ERROR,
+};
+
+/*!
+ * \brief Subscribes an application to a list of event sources.
+ *
+ * \param app_name Name of the application to subscribe.
+ * \param event_source_uris URIs for the event sources to subscribe to.
+ * \param event_sources_count Array size of event_source_uris.
+ * \param json Optional output pointer for JSON representation of the app
+ *             after adding the subscription.
+ *
+ * \return \ref stasis_app_subscribe_res return code.
+ */
+enum stasis_app_subscribe_res stasis_app_subscribe(const char *app_name,
+	const char **event_source_uris, int event_sources_count,
+	struct ast_json **json);
+
+/*!
+ * \brief Unsubscribes an application from a list of event sources.
+ *
+ * \param app_name Name of the application to subscribe.
+ * \param event_source_uris URIs for the event sources to subscribe to.
+ * \param event_sources_count Array size of event_source_uris.
+ * \param json Optional output pointer for JSON representation of the app
+ *             after adding the subscription.
+ *
+ * \return \ref stasis_app_subscribe_res return code.
+ */
+enum stasis_app_subscribe_res stasis_app_unsubscribe(const char *app_name,
+	const char **event_source_uris, int event_sources_count,
+	struct ast_json **json);
 
 /*! @} */
 
@@ -111,6 +170,7 @@
 /*!
  * \brief Returns the handler for the given channel.
  * \param chan Channel to handle.
+ *
  * \return NULL channel not in Stasis application.
  * \return Pointer to \c res_stasis handler.
  */
@@ -120,6 +180,7 @@
 /*!
  * \brief Returns the handler for the channel with the given id.
  * \param channel_id Uniqueid of the channel.
+ *
  * \return NULL channel not in Stasis application, or channel does not exist.
  * \return Pointer to \c res_stasis handler.
  */
@@ -153,6 +214,7 @@
  * \brief Returns the uniqueid of the channel associated with this control
  *
  * \param control Control object.
+ *
  * \return Uniqueid of the associate channel.
  * \return \c NULL if \a control is \c NULL.
  */
@@ -245,6 +307,7 @@
  * \brief Get the value of a variable on the channel associated with this control.
  * \param control Control for \c res_stasis.
  * \param variable The name of the variable.
+ *
  * \return The value of the variable.  The returned variable must be freed.
  */
 char *stasis_app_control_get_channel_var(struct stasis_app_control *control, const char *variable);
@@ -291,6 +354,7 @@
  * The returned pointer is AO2 managed, so ao2_cleanup() when you're done.
  *
  * \param control Control for \c res_stasis.
+ *
  * \return Most recent snapshot. ao2_cleanup() when done.
  * \return \c NULL if channel isn't in cache.
  */
@@ -331,6 +395,7 @@
 /*!
  * \brief Returns the bridge with the given id.
  * \param bridge_id Uniqueid of the bridge.
+ *
  * \return NULL bridge not created by a Stasis application, or bridge does not exist.
  * \return Pointer to bridge.
  */
@@ -364,6 +429,7 @@
  *
  * \param control Control whose channel should be added to the bridge
  * \param bridge Pointer to the bridge
+ *
  * \return non-zero on failure
  * \return zero on success
  */
@@ -375,6 +441,7 @@
  *
  * \param control Control whose channel should be removed from the bridge
  * \param bridge Pointer to the bridge
+ *
  * \return non-zero on failure
  * \return zero on success
  */
@@ -386,6 +453,7 @@
  * \brief Gets the bridge currently associated with a control object.
  *
  * \param control Control object for the channel to query.
+ *
  * \return Associated \ref ast_bridge.
  * \return \c NULL if not associated with a bridge.
  */

Modified: branches/12/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/asterisk.c?view=diff&rev=400522&r1=400521&r2=400522
==============================================================================
--- branches/12/main/asterisk.c (original)
+++ branches/12/main/asterisk.c Fri Oct  4 10:54:57 2013
@@ -247,6 +247,7 @@
 #include "asterisk/stasis_endpoints.h"
 #include "asterisk/stasis_system.h"
 #include "asterisk/security_events.h"
+#include "asterisk/endpoints.h"
 
 #include "../defaults.h"
 
@@ -4340,6 +4341,11 @@
 
 	ast_channels_init();
 
+	if (ast_endpoint_init()) {
+		printf ("%s", term_quit());
+		exit(1);
+	}
+
 	if ((moduleresult = load_modules(1))) {		/* Load modules, pre-load only */
 		printf("%s", term_quit());
 		exit(moduleresult == -2 ? 2 : 1);

Modified: branches/12/main/endpoints.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/endpoints.c?view=diff&rev=400522&r1=400521&r2=400522
==============================================================================
--- branches/12/main/endpoints.c (original)
+++ branches/12/main/endpoints.c Fri Oct  4 10:54:57 2013
@@ -38,9 +38,15 @@
 #include "asterisk/stasis_endpoints.h"
 #include "asterisk/stasis_message_router.h"
 #include "asterisk/stringfields.h"
+#include "asterisk/_private.h"
 
 /*! Buckets for endpoint->channel mappings. Keep it prime! */
+#define ENDPOINT_CHANNEL_BUCKETS 127
+
+/*! Buckets for endpoint hash. Keep it prime! */
 #define ENDPOINT_BUCKETS 127
+
+static struct ao2_container *endpoints;
 
 struct ast_endpoint {
 	AST_DECLARE_STRING_FIELDS(
@@ -65,6 +71,59 @@
 	struct ao2_container *channel_ids;
 };
 
+static int endpoint_hash(const void *obj, int flags)
+{
+	const struct ast_endpoint *endpoint;
+	const char *key;
+
+	switch (flags & OBJ_SEARCH_MASK) {
+	case OBJ_SEARCH_KEY:
+		key = obj;
+		return ast_str_hash(key);
+	case OBJ_SEARCH_OBJECT:
+		endpoint = obj;
+		return ast_str_hash(endpoint->id);
+	default:
+		/* Hash can only work on something with a full key. */
+		ast_assert(0);
+		return 0;
+	}
+}
+
+static int endpoint_cmp(void *obj, void *arg, int flags)
+{
+	const struct ast_endpoint *left = obj;
+	const struct ast_endpoint *right = arg;
+	const char *right_key = arg;
+	int cmp;
+
+	switch (flags & OBJ_SEARCH_MASK) {
+	case OBJ_SEARCH_OBJECT:
+		right_key = right->id;
+		/* Fall through */
+	case OBJ_SEARCH_KEY:
+		cmp = strcmp(left->id, right_key);
+		break;
+	case OBJ_SEARCH_PARTIAL_KEY:
+		cmp = strncmp(left->id, right_key, strlen(right_key));
+		break;
+	default:
+		ast_assert(0);
+		cmp = 0;
+		break;
+	}
+	if (cmp) {
+		return 0;
+	}
+
+	return CMP_MATCH;
+}
+
+struct ast_endpoint *ast_endpoint_find_by_id(const char *id)
+{
+	return ao2_find(endpoints, id, OBJ_KEY);
+}
+
 struct stasis_topic *ast_endpoint_topic(struct ast_endpoint *endpoint)
 {
 	if (!endpoint) {
@@ -218,7 +277,7 @@
 	/* All access to channel_ids should be covered by the endpoint's
 	 * lock; no extra lock needed. */
 	endpoint->channel_ids = ast_str_container_alloc_options(
-		AO2_ALLOC_OPT_LOCK_NOLOCK, ENDPOINT_BUCKETS);
+		AO2_ALLOC_OPT_LOCK_NOLOCK, ENDPOINT_CHANNEL_BUCKETS);
 	if (!endpoint->channel_ids) {
 		return NULL;
 	}
@@ -241,14 +300,10 @@
 
 	endpoint_publish_snapshot(endpoint);
 
+	ao2_link(endpoints, endpoint);
+
 	ao2_ref(endpoint, +1);
 	return endpoint;
-}
-
-const char *ast_endpoint_get_tech(const struct ast_endpoint *endpoint)
-{
-	ast_assert(endpoint != NULL);
-	return endpoint->tech;
 }
 
 static struct stasis_message *create_endpoint_snapshot_message(struct ast_endpoint *endpoint)
@@ -269,6 +324,8 @@
 	if (endpoint == NULL) {
 		return;
 	}
+
+	ao2_unlink(endpoints, endpoint);
 
 	clear_msg = create_endpoint_snapshot_message(endpoint);
 	if (clear_msg) {
@@ -284,9 +341,28 @@
 	stasis_message_router_unsubscribe(endpoint->router);
 }
 
+const char *ast_endpoint_get_tech(const struct ast_endpoint *endpoint)
+{
+	if (!endpoint) {
+		return NULL;
+	}
+	return endpoint->tech;
+}
+
 const char *ast_endpoint_get_resource(const struct ast_endpoint *endpoint)
 {
+	if (!endpoint) {
+		return NULL;
+	}
 	return endpoint->resource;
+}
+
+const char *ast_endpoint_get_id(const struct ast_endpoint *endpoint)
+{
+	if (!endpoint) {
+		return NULL;
+	}
+	return endpoint->id;
 }
 
 void ast_endpoint_set_state(struct ast_endpoint *endpoint,
@@ -354,3 +430,23 @@
 	ao2_ref(snapshot, +1);
 	return snapshot;
 }
+
+static void endpoint_cleanup(void)
+{
+	ao2_cleanup(endpoints);
+	endpoints = NULL;
+}
+
+int ast_endpoint_init(void)
+{
+	ast_register_cleanup(endpoint_cleanup);
+
+	endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, endpoint_hash,
+		endpoint_cmp);
+
+	if (!endpoints) {
+		return -1;
+	}
+
+	return 0;
+}

Modified: branches/12/main/json.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/json.c?view=diff&rev=400522&r1=400521&r2=400522
==============================================================================
--- branches/12/main/json.c (original)
+++ branches/12/main/json.c Fri Oct  4 10:54:57 2013
@@ -686,9 +686,15 @@
 }
 struct ast_json *ast_json_vpack(char const *format, va_list ap)
 {
+	json_error_t error;
 	struct ast_json *r = NULL;
 	if (format) {
-		r = (struct ast_json *)json_vpack_ex(NULL, 0, format, ap);
+		r = (struct ast_json *)json_vpack_ex(&error, 0, format, ap);
+		if (!r) {
+			ast_log(LOG_ERROR,
+				"Error building JSON from '%s': %s.\n",
+				format, error.text);
+		}
 	}
 	return r;
 }

Modified: branches/12/res/ari.make
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/ari.make?view=diff&rev=400522&r1=400521&r2=400522
==============================================================================
--- branches/12/res/ari.make (original)
+++ branches/12/res/ari.make Fri Oct  4 10:54:57 2013
@@ -49,3 +49,7 @@
 
 ari/resource_events.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_events)
 
+res_ari_applications.so: ari/resource_applications.o
+
+ari/resource_applications.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_applications)
+

Modified: branches/12/res/ari/ari_model_validators.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/ari/ari_model_validators.c?view=diff&rev=400522&r1=400521&r2=400522
==============================================================================
--- branches/12/res/ari/ari_model_validators.c (original)
+++ branches/12/res/ari/ari_model_validators.c Fri Oct  4 10:54:57 2013
@@ -2530,6 +2530,7 @@
 	int has_application = 0;
 	int has_channel = 0;
 	int has_eventname = 0;
+	int has_userevent = 0;
 
 	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
 		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
@@ -2581,6 +2582,16 @@
 				res = 0;
 			}
 		} else
+		if (strcmp("userevent", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_userevent = 1;
+			prop_is_valid = ast_ari_validate_object(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelUserevent field userevent failed validation\n");
+				res = 0;
+			}
+		} else
 		{
 			ast_log(LOG_ERROR,
 				"ARI ChannelUserevent has undocumented field %s\n",
@@ -2606,6 +2617,11 @@
 
 	if (!has_eventname) {
 		ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field eventname\n");
+		res = 0;
+	}
+
+	if (!has_userevent) {
+		ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field userevent\n");
 		res = 0;
 	}
 
@@ -2721,6 +2737,85 @@
 	return ast_ari_validate_channel_varset;
 }
 
+int ast_ari_validate_endpoint_state_change(struct ast_json *json)
+{
+	int res = 1;
+	struct ast_json_iter *iter;
+	int has_type = 0;
+	int has_application = 0;
+	int has_endpoint = 0;
+
+	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_type = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI EndpointStateChange field type failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_application = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI EndpointStateChange field application failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			prop_is_valid = ast_ari_validate_date(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI EndpointStateChange field timestamp failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("endpoint", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_endpoint = 1;
+			prop_is_valid = ast_ari_validate_endpoint(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI EndpointStateChange field endpoint failed validation\n");
+				res = 0;
+			}
+		} else
+		{
+			ast_log(LOG_ERROR,
+				"ARI EndpointStateChange has undocumented field %s\n",
+				ast_json_object_iter_key(iter));
+			res = 0;
+		}
+	}
+
+	if (!has_type) {
+		ast_log(LOG_ERROR, "ARI EndpointStateChange missing required field type\n");
+		res = 0;
+	}
+
+	if (!has_application) {
+		ast_log(LOG_ERROR, "ARI EndpointStateChange missing required field application\n");
+		res = 0;
+	}
+
+	if (!has_endpoint) {
+		ast_log(LOG_ERROR, "ARI EndpointStateChange missing required field endpoint\n");
+		res = 0;
+	}
+
+	return res;
+}
+
+ari_validator ast_ari_validate_endpoint_state_change_fn(void)
+{
+	return ast_ari_validate_endpoint_state_change;
+}
+
 int ast_ari_validate_event(struct ast_json *json)
 {
 	int res = 1;
@@ -2783,6 +2878,9 @@
 	if (strcmp("ChannelVarset", discriminator) == 0) {
 		return ast_ari_validate_channel_varset(json);
 	} else
+	if (strcmp("EndpointStateChange", discriminator) == 0) {
+		return ast_ari_validate_endpoint_state_change(json);
+	} else
 	if (strcmp("PlaybackFinished", discriminator) == 0) {
 		return ast_ari_validate_playback_finished(json);
 	} else
@@ -2918,6 +3016,9 @@
 	if (strcmp("ChannelVarset", discriminator) == 0) {
 		return ast_ari_validate_channel_varset(json);
 	} else
+	if (strcmp("EndpointStateChange", discriminator) == 0) {
+		return ast_ari_validate_endpoint_state_change(json);
+	} else
 	if (strcmp("Event", discriminator) == 0) {
 		return ast_ari_validate_event(json);
 	} else
@@ -3361,3 +3462,92 @@
 {
 	return ast_ari_validate_stasis_start;
 }
+
+int ast_ari_validate_application(struct ast_json *json)
+{
+	int res = 1;
+	struct ast_json_iter *iter;
+	int has_bridge_ids = 0;
+	int has_channel_ids = 0;
+	int has_endpoint_ids = 0;
+	int has_name = 0;
+
+	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+		if (strcmp("bridge_ids", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_bridge_ids = 1;
+			prop_is_valid = ast_ari_validate_list(
+				ast_json_object_iter_value(iter),
+				ast_ari_validate_string);
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Application field bridge_ids failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("channel_ids", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_channel_ids = 1;
+			prop_is_valid = ast_ari_validate_list(
+				ast_json_object_iter_value(iter),
+				ast_ari_validate_string);
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Application field channel_ids failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("endpoint_ids", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_endpoint_ids = 1;
+			prop_is_valid = ast_ari_validate_list(
+				ast_json_object_iter_value(iter),
+				ast_ari_validate_string);
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Application field endpoint_ids failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_name = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Application field name failed validation\n");
+				res = 0;
+			}
+		} else
+		{
+			ast_log(LOG_ERROR,
+				"ARI Application has undocumented field %s\n",
+				ast_json_object_iter_key(iter));
+			res = 0;
+		}
+	}
+
+	if (!has_bridge_ids) {
+		ast_log(LOG_ERROR, "ARI Application missing required field bridge_ids\n");
+		res = 0;
+	}
+
+	if (!has_channel_ids) {
+		ast_log(LOG_ERROR, "ARI Application missing required field channel_ids\n");
+		res = 0;
+	}
+
+	if (!has_endpoint_ids) {
+		ast_log(LOG_ERROR, "ARI Application missing required field endpoint_ids\n");
+		res = 0;
+	}
+
+	if (!has_name) {
+		ast_log(LOG_ERROR, "ARI Application missing required field name\n");
+		res = 0;
+	}
+
+	return res;
+}
+
+ari_validator ast_ari_validate_application_fn(void)
+{
+	return ast_ari_validate_application;
+}

Modified: branches/12/res/ari/ari_model_validators.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/ari/ari_model_validators.h?view=diff&rev=400522&r1=400521&r2=400522
==============================================================================
--- branches/12/res/ari/ari_model_validators.h (original)
+++ branches/12/res/ari/ari_model_validators.h Fri Oct  4 10:54:57 2013
@@ -55,6 +55,15 @@
 int ast_ari_validate_void(struct ast_json *json);
 
 /*!
+ * \brief Validator for native Swagger object.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_object(struct ast_json *json);
+
+/*!
  * \brief Validator for native Swagger byte.
  *
  * \param json JSON object to validate.
@@ -746,6 +755,24 @@
 ari_validator ast_ari_validate_channel_varset_fn(void);
 
 /*!
+ * \brief Validator for EndpointStateChange.
+ *
+ * Endpoint state changed.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_endpoint_state_change(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_endpoint_state_change().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_endpoint_state_change_fn(void);
+
+/*!
  * \brief Validator for Event.
  *
  * Base type for asynchronous events from Asterisk.
@@ -870,6 +897,24 @@
  * See \ref ast_ari_model_validators.h for more details.
  */
 ari_validator ast_ari_validate_stasis_start_fn(void);
+
+/*!
+ * \brief Validator for Application.
+ *
+ * Details of a Stasis application
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_application(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_application().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_application_fn(void);
 
 /*
  * JSON models
@@ -1035,6 +1080,7 @@
  * - timestamp: Date
  * - channel: Channel (required)
  * - eventname: string (required)
+ * - userevent: object (required)
  * ChannelVarset
  * - type: string (required)
  * - application: string (required)
@@ -1042,6 +1088,11 @@
  * - channel: Channel
  * - value: string (required)
  * - variable: string (required)
+ * EndpointStateChange
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - endpoint: Endpoint (required)
  * Event
  * - type: string (required)
  * - application: string (required)
@@ -1072,6 +1123,11 @@
  * - timestamp: Date
  * - args: List[string] (required)
  * - channel: Channel (required)
+ * Application
+ * - bridge_ids: List[string] (required)
+ * - channel_ids: List[string] (required)
+ * - endpoint_ids: List[string] (required)
+ * - name: string (required)
  */
 
 #endif /* _ASTERISK_ARI_MODEL_H */

Added: branches/12/res/ari/resource_applications.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/ari/resource_applications.c?view=auto&rev=400522
==============================================================================
--- branches/12/res/ari/resource_applications.c (added)
+++ branches/12/res/ari/resource_applications.c Fri Oct  4 10:54:57 2013
@@ -1,0 +1,173 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee 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 /api-docs/applications.{format} implementation - Stasis application
+ * resources
+ *
+ * \author David M. Lee, II <dlee at digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/stasis_app.h"
+#include "resource_applications.h"
+
+static int append_json(void *obj, void *arg, int flags)
+{
+	const char *app = obj;
+	struct ast_json *array = arg;
+
+	ast_json_array_append(array, stasis_app_to_json(app));
+
+	return 0;
+}
+
+void ast_ari_get_applications(struct ast_variable *headers,
+	struct ast_get_applications_args *args,
+	struct ast_ari_response *response)
+{
+	RAII_VAR(struct ao2_container *, apps, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+	size_t count;
+
+	apps = stasis_app_get_all();
+	json = ast_json_array_create();
+	if (!apps || !json) {
+		ast_ari_response_error(response, 500, "Internal Server Error",
+			"Allocation failed");
+		return;
+	}
+
+	ao2_lock(apps);
+	count = ao2_container_count(apps);
+	ao2_callback(apps, OBJ_NOLOCK | OBJ_NODATA, append_json, json);
+	ao2_lock(apps);
+
+	if (count != ast_json_array_size(json)) {
+		ast_ari_response_error(response, 500, "Internal Server Error",
+			"Allocation failed");
+		return;
+	}
+
+
+	ast_ari_response_ok(response, json);
+}
+
+void ast_ari_get_application(struct ast_variable *headers,
+	struct ast_get_application_args *args,
+	struct ast_ari_response *response)
+{
+	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+
+	json = stasis_app_to_json(args->application_name);
+
+	if (!json) {
+		ast_ari_response_error(response, 404, "Not Found",
+			"Application not found");
+		return;
+	}
+
+	ast_ari_response_ok(response, json);
+}
+
+void ast_ari_application_subscribe(struct ast_variable *headers,
+	struct ast_application_subscribe_args *args,
+	struct ast_ari_response *response)
+{
+	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+	enum stasis_app_subscribe_res res;
+
+	if (args->event_source_count <= 0) {
+		ast_ari_response_error(response, 400, "Bad Request",
+			"Missing parameter eventSource");
+		return;
+	}
+
+	if (ast_strlen_zero(args->application_name)) {
+		ast_ari_response_error(response, 400, "Bad Request",
+			"Missing parameter applicationName");
+		return;
+	}
+
+	res = stasis_app_subscribe(args->application_name, args->event_source,
+		args->event_source_count, &json);
+
+	switch (res) {
+	case STASIS_ASR_OK:
+		ast_ari_response_ok(response, json);
+		break;
+	case STASIS_ASR_APP_NOT_FOUND:
+		ast_ari_response_error(response, 404, "Not Found",
+			"Application not found");
+		break;
+	case STASIS_ASR_EVENT_SOURCE_NOT_FOUND:
+		ast_ari_response_error(response, 422, "Unprocessable Entity",
+			"Event source does not exist");
+		break;
+	case STASIS_ASR_EVENT_SOURCE_BAD_SCHEME:
+		ast_ari_response_error(response, 400, "Bad Request",
+			"Invalid event source URI scheme");
+		break;
+	case STASIS_ASR_INTERNAL_ERROR:
+		ast_ari_response_error(response, 500, "Internal Server Error",
+			"Error processing request");
+		break;
+	}
+}
+
+void ast_ari_application_unsubscribe(struct ast_variable *headers,
+	struct ast_application_unsubscribe_args *args,
+	struct ast_ari_response *response)
+{
+	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+	enum stasis_app_subscribe_res res;
+
+	if (args->event_source_count == 0) {
+		ast_ari_response_error(response, 400, "Bad Request",
+			"Missing parameter eventSource");
+		return;
+	}
+
+	res = stasis_app_unsubscribe(args->application_name, args->event_source,
+		args->event_source_count, &json);
+
+	switch (res) {
+	case STASIS_ASR_OK:
+		ast_ari_response_ok(response, json);
+		break;
+	case STASIS_ASR_APP_NOT_FOUND:
+		ast_ari_response_error(response, 404, "Not Found",
+			"Application not found");
+		break;
+	case STASIS_ASR_EVENT_SOURCE_NOT_FOUND:
+		ast_ari_response_error(response, 422, "Unprocessable Entity",
+			"Event source was not subscribed to");
+		break;
+	case STASIS_ASR_EVENT_SOURCE_BAD_SCHEME:
+		ast_ari_response_error(response, 400, "Bad Request",
+			"Invalid event source URI scheme");
+		break;
+	case STASIS_ASR_INTERNAL_ERROR:
+		ast_ari_response_error(response, 500, "Internal Server Error",
+			"Error processing request");
+	}
+}

Propchange: branches/12/res/ari/resource_applications.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: branches/12/res/ari/resource_applications.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: branches/12/res/ari/resource_applications.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: branches/12/res/ari/resource_applications.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/ari/resource_applications.h?view=auto&rev=400522
==============================================================================
--- branches/12/res/ari/resource_applications.h (added)
+++ branches/12/res/ari/resource_applications.h Fri Oct  4 10:54:57 2013
@@ -1,0 +1,109 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee 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 Generated file - declares stubs to be implemented in
+ * res/ari/resource_applications.c
+ *
+ * Stasis application resources
+ *
+ * \author David M. Lee, II <dlee at digium.com>
+ */
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!!                               DO NOT EDIT                        !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_resource.h.mustache
+ */
+
+#ifndef _ASTERISK_RESOURCE_APPLICATIONS_H
+#define _ASTERISK_RESOURCE_APPLICATIONS_H
+
+#include "asterisk/ari.h"
+
+/*! \brief Argument struct for ast_ari_get_applications() */
+struct ast_get_applications_args {
+};
+/*!
+ * \brief List all applications.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_applications(struct ast_variable *headers, struct ast_get_applications_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_get_application() */
+struct ast_get_application_args {
+	/*! \brief Application's name */
+	const char *application_name;
+};
+/*!
+ * \brief Get details of an application.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_application(struct ast_variable *headers, struct ast_get_application_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_application_subscribe() */
+struct ast_application_subscribe_args {
+	/*! \brief Application's name */
+	const char *application_name;
+	/*! \brief Array of URI for event source (channel:{channelId}, bridge:{bridgeId}, endpoint:{tech}/{resource} */
+	const char **event_source;
+	/*! \brief Length of event_source array. */
+	size_t event_source_count;
+	/*! \brief Parsing context for event_source. */
+	char *event_source_parse;
+};
+/*!
+ * \brief Subscribe an application to a event source.
+ *
+ * Returns the state of the application after the subscriptions have changed
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_application_subscribe(struct ast_variable *headers, struct ast_application_subscribe_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_application_unsubscribe() */
+struct ast_application_unsubscribe_args {
+	/*! \brief Application's name */
+	const char *application_name;
+	/*! \brief Array of URI for event source (channel:{channelId}, bridge:{bridgeId}, endpoint:{tech}/{resource} */
+	const char **event_source;
+	/*! \brief Length of event_source array. */
+	size_t event_source_count;
+	/*! \brief Parsing context for event_source. */
+	char *event_source_parse;
+};
+/*!
+ * \brief Unsubscribe an application from an event source.
+ *
+ * Returns the state of the application after the subscriptions have changed
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_application_unsubscribe(struct ast_variable *headers, struct ast_application_unsubscribe_args *args, struct ast_ari_response *response);
+
+#endif /* _ASTERISK_RESOURCE_APPLICATIONS_H */

Propchange: branches/12/res/ari/resource_applications.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: branches/12/res/ari/resource_applications.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: branches/12/res/ari/resource_applications.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: branches/12/res/ari/resource_endpoints.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/ari/resource_endpoints.h?view=diff&rev=400522&r1=400521&r2=400522
==============================================================================
--- branches/12/res/ari/resource_endpoints.h (original)
+++ branches/12/res/ari/resource_endpoints.h Fri Oct  4 10:54:57 2013
@@ -43,7 +43,7 @@
 struct ast_get_endpoints_args {
 };
 /*!
- * \brief List all endoints.
+ * \brief List all endpoints.
  *
  * \param headers HTTP headers
  * \param args Swagger parameters

Added: branches/12/res/res_ari_applications.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_ari_applications.c?view=auto&rev=400522
==============================================================================
--- branches/12/res/res_ari_applications.c (added)
+++ branches/12/res/res_ari_applications.c Fri Oct  4 10:54:57 2013
@@ -1,0 +1,425 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee 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.
+ */
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!!                               DO NOT EDIT                        !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/res_ari_resource.c.mustache
+ */
+
+/*! \file
+ *
+ * \brief Stasis application resources
+ *
+ * \author David M. Lee, II <dlee at digium.com>
+ */
+
+/*** MODULEINFO
+	<depend type="module">res_ari</depend>
+	<depend type="module">res_stasis</depend>
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/app.h"
+#include "asterisk/module.h"
+#include "asterisk/stasis_app.h"
+#include "ari/resource_applications.h"
+#if defined(AST_DEVMODE)
+#include "ari/ari_model_validators.h"
+#endif
+
+#define MAX_VALS 128
+
+/*!
+ * \brief Parameter parsing callback for /applications.
+ * \param get_params GET parameters in the HTTP request.
+ * \param path_vars Path variables extracted from the request.
+ * \param headers HTTP headers.
+ * \param[out] response Response to the HTTP request.
+ */
+static void ast_ari_get_applications_cb(
+	struct ast_variable *get_params, struct ast_variable *path_vars,
+	struct ast_variable *headers, struct ast_ari_response *response)
+{
+	struct ast_get_applications_args args = {};
+#if defined(AST_DEVMODE)
+	int is_valid;
+	int code;
+#endif /* AST_DEVMODE */
+
+	ast_ari_get_applications(headers, &args, response);
+#if defined(AST_DEVMODE)
+	code = response->response_code;
+
+	switch (code) {
+	case 0: /* Implementation is still a stub, or the code wasn't set */
+		is_valid = response->message == NULL;
+		break;
+	case 500: /* Internal Server Error */
+	case 501: /* Not Implemented */
+		is_valid = 1;
+		break;
+	default:
+		if (200 <= code && code <= 299) {
+			is_valid = ast_ari_validate_list(response->message,
+				ast_ari_validate_application_fn());
+		} else {
+			ast_log(LOG_ERROR, "Invalid error response %d for /applications\n", code);
+			is_valid = 0;
+		}
+	}
+
+	if (!is_valid) {
+		ast_log(LOG_ERROR, "Response validation failed for /applications\n");
+		ast_ari_response_error(response, 500,
+			"Internal Server Error", "Response validation failed");
+	}
+#endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
+}
+/*!

[... 1096 lines stripped ...]



More information about the asterisk-commits mailing list