summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile11
-rw-r--r--include/asterisk/json.h9
-rw-r--r--include/asterisk/stasis_http.h12
-rw-r--r--main/json.c17
-rw-r--r--main/stasis_bridging.c8
-rw-r--r--main/stasis_channels.c141
-rw-r--r--main/stasis_endpoints.c4
-rw-r--r--res/Makefile3
-rw-r--r--res/res_ari_model.c207
-rw-r--r--res/res_ari_model.exports.in6
-rw-r--r--res/res_stasis.c294
-rw-r--r--res/res_stasis_http.c21
-rw-r--r--res/res_stasis_http_asterisk.c35
-rw-r--r--res/res_stasis_http_bridges.c232
-rw-r--r--res/res_stasis_http_channels.c439
-rw-r--r--res/res_stasis_http_endpoints.c99
-rw-r--r--res/res_stasis_http_events.c10
-rw-r--r--res/res_stasis_http_playback.c102
-rw-r--r--res/res_stasis_http_recordings.c370
-rw-r--r--res/res_stasis_http_sounds.c67
-rw-r--r--res/res_stasis_json_asterisk.c59
-rw-r--r--res/res_stasis_json_asterisk.exports.in4
-rw-r--r--res/res_stasis_json_bridges.c59
-rw-r--r--res/res_stasis_json_bridges.exports.in4
-rw-r--r--res/res_stasis_json_channels.c59
-rw-r--r--res/res_stasis_json_channels.exports.in4
-rw-r--r--res/res_stasis_json_endpoints.c59
-rw-r--r--res/res_stasis_json_endpoints.exports.in4
-rw-r--r--res/res_stasis_json_events.c818
-rw-r--r--res/res_stasis_json_events.exports.in25
-rw-r--r--res/res_stasis_json_playback.c59
-rw-r--r--res/res_stasis_json_playback.exports.in4
-rw-r--r--res/res_stasis_json_recordings.c59
-rw-r--r--res/res_stasis_json_recordings.exports.in4
-rw-r--r--res/res_stasis_json_sounds.c59
-rw-r--r--res/res_stasis_json_sounds.exports.in4
-rw-r--r--res/stasis_http/ari_model_validators.c2567
-rw-r--r--res/stasis_http/ari_model_validators.h659
-rw-r--r--res/stasis_http/ari_websockets.c32
-rw-r--r--res/stasis_http/resource_recordings.c4
-rw-r--r--res/stasis_http/resource_recordings.h11
-rw-r--r--res/stasis_json/resource_asterisk.h46
-rw-r--r--res/stasis_json/resource_bridges.h48
-rw-r--r--res/stasis_json/resource_channels.h75
-rw-r--r--res/stasis_json/resource_endpoints.h48
-rw-r--r--res/stasis_json/resource_events.h386
-rw-r--r--res/stasis_json/resource_playback.h47
-rw-r--r--res/stasis_json/resource_recordings.h54
-rw-r--r--res/stasis_json/resource_sounds.h52
-rw-r--r--rest-api-templates/api.wiki.mustache47
-rw-r--r--rest-api-templates/ari_model_validators.c.mustache117
-rw-r--r--rest-api-templates/ari_model_validators.h.mustache159
-rw-r--r--rest-api-templates/asterisk_processor.py87
-rw-r--r--rest-api-templates/event_function_decl.mustache10
-rwxr-xr-xrest-api-templates/make_ari_stubs.py (renamed from rest-api-templates/make_stasis_http_stubs.py)27
-rw-r--r--rest-api-templates/models.wiki.mustache22
-rw-r--r--rest-api-templates/res_stasis_http_resource.c.mustache53
-rw-r--r--rest-api-templates/res_stasis_json_resource.c.mustache151
-rw-r--r--rest-api-templates/res_stasis_json_resource.exports.mustache12
-rw-r--r--rest-api-templates/stasis_json_resource.h.mustache83
-rw-r--r--rest-api-templates/swagger_model.py338
-rw-r--r--rest-api-templates/transform.py15
-rw-r--r--rest-api/api-docs/asterisk.json1
-rw-r--r--rest-api/api-docs/bridges.json52
-rw-r--r--rest-api/api-docs/channels.json114
-rw-r--r--rest-api/api-docs/endpoints.json20
-rw-r--r--rest-api/api-docs/events.json108
-rw-r--r--rest-api/api-docs/playback.json32
-rw-r--r--rest-api/api-docs/recordings.json25
-rw-r--r--rest-api/api-docs/sounds.json2
-rw-r--r--tests/test_ari_model.c431
-rw-r--r--tests/test_res_stasis.c4
-rw-r--r--tests/test_stasis_channels.c12
73 files changed, 6418 insertions, 2904 deletions
diff --git a/Makefile b/Makefile
index 6cca3aafa..a51534424 100644
--- a/Makefile
+++ b/Makefile
@@ -416,6 +416,7 @@ _clean:
rm -f main/version.c
rm -f doc/core-en_US.xml
rm -f doc/full-en_US.xml
+ rm -f docs/rest-api/*.wiki
@$(MAKE) -C menuselect clean
cp -f .cleancount .lastclean
@@ -963,15 +964,15 @@ menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(di
# We don't want to require Python or Pystache for every build, so this is its
# own target.
-stasis-stubs:
+ari-stubs:
ifeq ($(PYTHON),:)
@echo "--------------------------------------------------------------------------"
- @echo "--- Please install python to build Stasis HTTP stubs ---"
+ @echo "--- Please install python to build ARI stubs ---"
@echo "--------------------------------------------------------------------------"
@false
else
- $(PYTHON) rest-api-templates/make_stasis_http_stubs.py \
- rest-api/resources.json res/
+ $(PYTHON) rest-api-templates/make_ari_stubs.py \
+ rest-api/resources.json .
endif
.PHONY: menuselect
@@ -993,7 +994,7 @@ endif
.PHONY: installdirs
.PHONY: validate-docs
.PHONY: _clean
-.PHONY: stasis-stubs
+.PHONY: ari-stubs
.PHONY: $(SUBDIRS_INSTALL)
.PHONY: $(SUBDIRS_DIST_CLEAN)
.PHONY: $(SUBDIRS_CLEAN)
diff --git a/include/asterisk/json.h b/include/asterisk/json.h
index 61685fd9f..0584c99af 100644
--- a/include/asterisk/json.h
+++ b/include/asterisk/json.h
@@ -158,6 +158,15 @@ enum ast_json_type
*/
enum ast_json_type ast_json_typeof(const struct ast_json *value);
+/*!
+ * \brief Get the string name for the given type.
+ * \since 12.0.0
+ * \param type Type to convert to string.
+ * \return Simple string for the type name (object, array, string, etc.)
+ * \return \c "?" for invalid types.
+ */
+const char *ast_json_typename(enum ast_json_type type);
+
/*!@}*/
/*!@{*/
diff --git a/include/asterisk/stasis_http.h b/include/asterisk/stasis_http.h
index 05e9dded7..8d5a74ee7 100644
--- a/include/asterisk/stasis_http.h
+++ b/include/asterisk/stasis_http.h
@@ -33,6 +33,12 @@
#include "asterisk/json.h"
#include "asterisk/http_websocket.h"
+/*!
+ * \brief Configured encoding format for JSON output.
+ * \return JSON output encoding (compact, pretty, etc.)
+ */
+enum ast_json_encoding_format stasis_http_json_format(void);
+
struct stasis_http_response;
/*!
@@ -141,12 +147,16 @@ struct ari_websocket_session;
/*!
* \brief Create an ARI WebSocket session.
*
+ * If \c NULL is given for the validator function, no validation will be
+ * performed.
+ *
* \param ws_session Underlying WebSocket session.
+ * \param validator Function to validate outgoing messages.
* \return New ARI WebSocket session.
* \return \c NULL on error.
*/
struct ari_websocket_session *ari_websocket_session_create(
- struct ast_websocket *ws_session);
+ struct ast_websocket *ws_session, int (*validator)(struct ast_json *));
/*!
* \brief Read a message from an ARI WebSocket.
diff --git a/main/json.c b/main/json.c
index dff35dbab..c185b053f 100644
--- a/main/json.c
+++ b/main/json.c
@@ -103,6 +103,23 @@ enum ast_json_type ast_json_typeof(const struct ast_json *json)
return r;
}
+const char *ast_json_typename(enum ast_json_type type)
+{
+ switch (type) {
+ case AST_JSON_OBJECT: return "object";
+ case AST_JSON_ARRAY: return "array";
+ case AST_JSON_STRING: return "string";
+ case AST_JSON_INTEGER: return "integer";
+ case AST_JSON_REAL: return "real";
+ case AST_JSON_TRUE: return "boolean";
+ case AST_JSON_FALSE: return "boolean";
+ case AST_JSON_NULL: return "null";
+ }
+ ast_assert(0);
+ return "?";
+}
+
+
struct ast_json *ast_json_true(void)
{
return (struct ast_json *)json_true();
diff --git a/main/stasis_bridging.c b/main/stasis_bridging.c
index 39a8ba892..dcf4275ae 100644
--- a/main/stasis_bridging.c
+++ b/main/stasis_bridging.c
@@ -657,10 +657,10 @@ struct ast_json *ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *s
}
json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: o}",
- "bridgeUniqueid", snapshot->uniqueid,
- "bridgeTechnology", snapshot->technology,
- "bridgeType", capability2str(snapshot->capabilities),
- "bridgeClass", snapshot->subclass,
+ "id", snapshot->uniqueid,
+ "technology", snapshot->technology,
+ "bridge_type", capability2str(snapshot->capabilities),
+ "bridge_class", snapshot->subclass,
"channels", json_channels);
if (!json_bridge) {
return NULL;
diff --git a/main/stasis_channels.c b/main/stasis_channels.c
index 6dddb0a5e..d121279d8 100644
--- a/main/stasis_channels.c
+++ b/main/stasis_channels.c
@@ -32,10 +32,11 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-#include "asterisk/stasis.h"
#include "asterisk/astobj2.h"
-#include "asterisk/stasis_channels.h"
+#include "asterisk/json.h"
#include "asterisk/pbx.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_channels.h"
/*** DOCUMENTATION
<managerEvent language="en_US" name="VarSet">
@@ -621,25 +622,25 @@ struct ast_json *ast_channel_snapshot_to_json(const struct ast_channel_snapshot
return NULL;
}
- json_chan = ast_json_pack("{ s: s, s: s, s: s, s: s, s: s, s: s, s: s,"
- " s: s, s: s, s: s, s: s, s: o, s: o, s: o,"
- " s: o"
- "}",
- "name", snapshot->name,
- "state", ast_state2str(snapshot->state),
- "accountcode", snapshot->accountcode,
- "peeraccount", snapshot->peeraccount,
- "userfield", snapshot->userfield,
- "uniqueid", snapshot->uniqueid,
- "linkedid", snapshot->linkedid,
- "parkinglot", snapshot->parkinglot,
- "hangupsource", snapshot->hangupsource,
- "appl", snapshot->appl,
- "data", snapshot->data,
- "dialplan", ast_json_dialplan_cep(snapshot->context, snapshot->exten, snapshot->priority),
- "caller", ast_json_name_number(snapshot->caller_name, snapshot->caller_number),
- "connected", ast_json_name_number(snapshot->connected_name, snapshot->connected_number),
- "creationtime", ast_json_timeval(snapshot->creationtime, NULL));
+ json_chan = ast_json_pack(
+ /* Broken up into groups of three for readability */
+ "{ s: s, s: s, s: s,"
+ " s: o, s: o, s: s,"
+ " s: o, s: o }",
+ /* First line */
+ "id", snapshot->uniqueid,
+ "name", snapshot->name,
+ "state", ast_state2str(snapshot->state),
+ /* Second line */
+ "caller", ast_json_name_number(
+ snapshot->caller_name, snapshot->caller_number),
+ "connected", ast_json_name_number(
+ snapshot->connected_name, snapshot->connected_number),
+ "accountcode", snapshot->accountcode,
+ /* Third line */
+ "dialplan", ast_json_dialplan_cep(
+ snapshot->context, snapshot->exten, snapshot->priority),
+ "creationtime", ast_json_timeval(snapshot->creationtime, NULL));
return ast_json_ref(json_chan);
}
@@ -675,6 +676,91 @@ int ast_channel_snapshot_caller_id_equal(
strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
}
+static struct ast_json *channel_blob_to_json(struct stasis_message *message,
+ const char *type)
+{
+ RAII_VAR(struct ast_json *, out, NULL, ast_json_unref);
+ struct ast_channel_blob *channel_blob = stasis_message_data(message);
+ struct ast_json *blob = channel_blob->blob;
+ struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
+ const struct timeval *tv = stasis_message_timestamp(message);
+ int res = 0;
+
+ if (blob == NULL || ast_json_is_null(blob)) {
+ out = ast_json_object_create();
+ } else {
+ /* blobs are immutable, so shallow copies are fine */
+ out = ast_json_copy(blob);
+ }
+
+ if (!out) {
+ return NULL;
+ }
+
+ res |= ast_json_object_set(out, "type", ast_json_string_create(type));
+ res |= ast_json_object_set(out, "timestamp",
+ ast_json_timeval(*tv, NULL));
+
+ /* For global channel messages, the snapshot is optional */
+ if (snapshot) {
+ res |= ast_json_object_set(out, "channel",
+ ast_channel_snapshot_to_json(snapshot));
+ }
+
+ if (res != 0) {
+ return NULL;
+ }
+
+ return ast_json_ref(out);
+}
+
+static struct ast_json *dtmf_end_to_json(struct stasis_message *message)
+{
+ struct ast_channel_blob *channel_blob = stasis_message_data(message);
+ struct ast_json *blob = channel_blob->blob;
+ struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
+ const char *direction =
+ ast_json_string_get(ast_json_object_get(blob, "direction"));
+ const struct timeval *tv = stasis_message_timestamp(message);
+
+ /* Only present received DTMF end events as JSON */
+ if (strcasecmp("Received", direction) != 0) {
+ return NULL;
+ }
+
+ return ast_json_pack("{s: s, s: o, s: O, s: O, s: o}",
+ "type", "ChannelDtmfReceived",
+ "timestamp", ast_json_timeval(*tv, NULL),
+ "digit", ast_json_object_get(blob, "digit"),
+ "duration_ms", ast_json_object_get(blob, "duration_ms"),
+ "channel", ast_channel_snapshot_to_json(snapshot));
+}
+
+static struct ast_json *user_event_to_json(struct stasis_message *message)
+{
+ struct ast_channel_blob *channel_blob = stasis_message_data(message);
+ struct ast_json *blob = channel_blob->blob;
+ struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
+ const struct timeval *tv = stasis_message_timestamp(message);
+
+ return ast_json_pack("{s: s, s: o, s: O, s: O, s: o}",
+ "type", "ChannelUserevent",
+ "timestamp", ast_json_timeval(*tv, NULL),
+ "eventname", ast_json_object_get(blob, "eventname"),
+ "userevent", blob,
+ "channel", ast_channel_snapshot_to_json(snapshot));
+}
+
+static struct ast_json *varset_to_json(struct stasis_message *message)
+{
+ return channel_blob_to_json(message, "ChannelVarset");
+}
+
+static struct ast_json *hangup_request_to_json(struct stasis_message *message)
+{
+ return channel_blob_to_json(message, "ChannelHangupRequest");
+}
+
/*!
* @{ \brief Define channel message types.
*/
@@ -682,11 +768,18 @@ STASIS_MESSAGE_TYPE_DEFN(ast_channel_snapshot_type);
STASIS_MESSAGE_TYPE_DEFN(ast_channel_dial_type);
STASIS_MESSAGE_TYPE_DEFN(ast_channel_varset_type,
.to_ami = varset_to_ami,
+ .to_json = varset_to_json,
+ );
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_user_event_type,
+ .to_json = user_event_to_json,
+ );
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_request_type,
+ .to_json = hangup_request_to_json,
);
-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);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_end_type,
+ .to_json = dtmf_end_to_json,
+ );
STASIS_MESSAGE_TYPE_DEFN(ast_channel_hold_type);
STASIS_MESSAGE_TYPE_DEFN(ast_channel_unhold_type);
STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_start_type);
diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c
index 90d968567..a6756182c 100644
--- a/main/stasis_endpoints.c
+++ b/main/stasis_endpoints.c
@@ -239,7 +239,7 @@ struct ast_json *ast_endpoint_snapshot_to_json(
"technology", snapshot->tech,
"resource", snapshot->resource,
"state", ast_endpoint_state_to_string(snapshot->state),
- "channels");
+ "channel_ids");
if (json == NULL) {
return NULL;
@@ -253,7 +253,7 @@ struct ast_json *ast_endpoint_snapshot_to_json(
}
}
- channel_array = ast_json_object_get(json, "channels");
+ channel_array = ast_json_object_get(json, "channel_ids");
ast_assert(channel_array != NULL);
for (i = 0; i < snapshot->num_channels; ++i) {
int res = ast_json_array_append(channel_array,
diff --git a/res/Makefile b/res/Makefile
index c69862802..1310dae3a 100644
--- a/res/Makefile
+++ b/res/Makefile
@@ -83,5 +83,8 @@ $(subst .c,.o,$(wildcard parking/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_par
res_stasis_http.so: stasis_http/ari_websockets.o
stasis_http/ari_websockets.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_stasis_http_asterisk)
+res_ari_model.so: stasis_http/ari_model_validators.o
+stasis_http/ari_model_validators.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_model)
+
# Dependencies for res_stasis_http_*.so are generated, so they're in this file
include stasis_http.make
diff --git a/res/res_ari_model.c b/res/res_ari_model.c
new file mode 100644
index 000000000..fd2ec6493
--- /dev/null
+++ b/res/res_ari_model.c
@@ -0,0 +1,207 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@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 Implementation Swagger validators.
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*** MODULEINFO
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "stasis_http/ari_model_validators.h"
+#include "asterisk/logger.h"
+#include "asterisk/module.h"
+#include "asterisk/utils.h"
+
+#include <regex.h>
+
+/* Regex to match date strings */
+static regex_t date_regex;
+
+/* Regex for YYYY-MM-DD */
+#define REGEX_YMD "[0-9]{4}-[01][0-9]-[0-3][0-9]"
+
+/* Regex for hh:mm(:ss(.s)); seconds and subseconds optional
+ * Handles the probably impossible case of a leap second, too */
+#define REGEX_HMS "[0-2][0-9]:[0-5][0-9](:[0-6][0-9](.[0-9]+)?)?"
+
+/* Regex for timezone: (+|-)hh(:mm), with optional colon. */
+#define REGEX_TZ "(Z|[-+][0-2][0-9](:?[0-5][0-9])?)"
+
+/* REGEX for ISO 8601, the time specifier optional */
+#define ISO8601_PATTERN "^" REGEX_YMD "(T" REGEX_HMS REGEX_TZ ")?$"
+
+static int check_type(struct ast_json *json, enum ast_json_type expected)
+{
+ enum ast_json_type actual;
+
+ if (!json) {
+ ast_log(LOG_ERROR, "Expected type %s, was NULL\n",
+ ast_json_typename(expected));
+ return 0;
+ }
+
+ actual = ast_json_typeof(json);
+ if (expected != actual) {
+ ast_log(LOG_ERROR, "Expected type %s, was %s\n",
+ ast_json_typename(expected), ast_json_typename(actual));
+ return 0;
+ }
+ return 1;
+}
+
+static int check_range(intmax_t minval, intmax_t maxval, struct ast_json *json)
+{
+ intmax_t v;
+
+ if (!check_type(json, AST_JSON_INTEGER)) {
+ return 0;
+ }
+
+ v = ast_json_integer_get(json);
+
+ if (v < minval || maxval < v) {
+ ast_log(LOG_ERROR, "Value out of range. Expected %jd <= %jd <= %jd\n", minval, v, maxval);
+ return 0;
+ }
+ return 1;
+}
+
+int ari_validate_void(struct ast_json *json)
+{
+ return check_type(json, AST_JSON_NULL);
+}
+
+int ari_validate_byte(struct ast_json *json)
+{
+ /* Java bytes are signed, which accounts for great fun for all */
+ return check_range(-128, 255, json);
+}
+
+int ari_validate_boolean(struct ast_json *json)
+{
+ enum ast_json_type actual = ast_json_typeof(json);
+ switch (actual) {
+ case AST_JSON_TRUE:
+ case AST_JSON_FALSE:
+ return 1;
+ default:
+ ast_log(LOG_ERROR, "Expected type boolean, was %s\n",
+ ast_json_typename(actual));
+ return 0;
+ }
+}
+
+int ari_validate_int(struct ast_json *json)
+{
+ /* Swagger int's are 32-bit */
+ return check_range(-2147483648, 2147483647, json);
+}
+
+int ari_validate_long(struct ast_json *json)
+{
+ /* All integral values are valid longs. No need for range check. */
+ return check_type(json, AST_JSON_INTEGER);
+}
+
+int ari_validate_float(struct ast_json *json)
+{
+ return check_type(json, AST_JSON_REAL);
+}
+
+int ari_validate_double(struct ast_json *json)
+{
+ return check_type(json, AST_JSON_REAL);
+}
+
+int ari_validate_string(struct ast_json *json)
+{
+ return check_type(json, AST_JSON_STRING);
+}
+
+int ari_validate_date(struct ast_json *json)
+{
+ /* Dates are ISO-8601 strings */
+ const char *str;
+ if (!check_type(json, AST_JSON_STRING)) {
+ return 0;
+ }
+ str = ast_json_string_get(json);
+ ast_assert(str != NULL);
+ if (regexec(&date_regex, str, 0, NULL, 0) != 0) {
+ ast_log(LOG_ERROR, "Date field is malformed: '%s'\n", str);
+ return 0;
+ }
+ return 1;
+}
+
+int ari_validate_list(struct ast_json *json, int (*fn)(struct ast_json *))
+{
+ int res = 1;
+ size_t i;
+
+ if (!check_type(json, AST_JSON_ARRAY)) {
+ return 0;
+ }
+
+ for (i = 0; i < ast_json_array_size(json); ++i) {
+ int member_res;
+ member_res = fn(ast_json_array_get(json, i));
+ if (!member_res) {
+ ast_log(LOG_ERROR,
+ "Array member %zd failed validation\n", i);
+ res = 0;
+ }
+ }
+
+ return res;
+}
+
+static int load_module(void)
+{
+ int res;
+ res = regcomp(&date_regex, ISO8601_PATTERN,
+ REG_EXTENDED | REG_ICASE | REG_NOSUB);
+
+ if (res != 0) {
+ return AST_MODULE_LOAD_FAILURE;
+ }
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ regfree(&date_regex);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY,
+ AST_MODFLAG_LOAD_ORDER | AST_MODFLAG_GLOBAL_SYMBOLS,
+ "ARI Model validators",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_ari_model.exports.in b/res/res_ari_model.exports.in
new file mode 100644
index 000000000..160e23f43
--- /dev/null
+++ b/res/res_ari_model.exports.in
@@ -0,0 +1,6 @@
+{
+ global:
+ LINKER_SYMBOL_PREFIXari_*;
+ local:
+ *;
+};
diff --git a/res/res_stasis.c b/res/res_stasis.c
index de432e409..ed3823051 100644
--- a/res/res_stasis.c
+++ b/res/res_stasis.c
@@ -48,7 +48,6 @@
*/
/*** MODULEINFO
- <depend>res_stasis_json_events</depend>
<support_level>core</support_level>
***/
@@ -66,7 +65,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/strings.h"
#include "stasis/app.h"
#include "stasis/control.h"
-#include "stasis_json/resource_events.h"
/*! Time to wait for a frame in the application */
#define MAX_WAIT_MS 200
@@ -233,28 +231,60 @@ static struct ao2_container *get_apps_watching_channel(const char *uniqueid)
/*! \brief Typedef for callbacks that get called on channel snapshot updates */
typedef struct ast_json *(*channel_snapshot_monitor)(
struct ast_channel_snapshot *old_snapshot,
- struct ast_channel_snapshot *new_snapshot);
+ struct ast_channel_snapshot *new_snapshot,
+ const struct timeval *tv);
+
+static struct ast_json *simple_channel_event(
+ const char *type,
+ struct ast_channel_snapshot *snapshot,
+ const struct timeval *tv)
+{
+ return ast_json_pack("{s: s, s: o, s: o}",
+ "type", type,
+ "timestamp", ast_json_timeval(*tv, NULL),
+ "channel", ast_channel_snapshot_to_json(snapshot));
+}
+
+static struct ast_json *channel_created_event(
+ struct ast_channel_snapshot *snapshot,
+ const struct timeval *tv)
+{
+ return simple_channel_event("ChannelCreated", snapshot, tv);
+}
+
+static struct ast_json *channel_destroyed_event(
+ struct ast_channel_snapshot *snapshot,
+ const struct timeval *tv)
+{
+ return ast_json_pack("{s: s, s: o, s: i, s: s, s: o}",
+ "type", "ChannelDestroyed",
+ "timestamp", ast_json_timeval(*tv, NULL),
+ "cause", snapshot->hangupcause,
+ "cause_txt", ast_cause2str(snapshot->hangupcause),
+ "channel", ast_channel_snapshot_to_json(snapshot));
+}
+
+static struct ast_json *channel_state_change_event(
+ struct ast_channel_snapshot *snapshot,
+ const struct timeval *tv)
+{
+ return simple_channel_event("ChannelStateChange", snapshot, tv);
+}
/*! \brief Handle channel state changes */
static struct ast_json *channel_state(
struct ast_channel_snapshot *old_snapshot,
- struct ast_channel_snapshot *new_snapshot)
+ struct ast_channel_snapshot *new_snapshot,
+ const struct timeval *tv)
{
- RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
struct ast_channel_snapshot *snapshot = new_snapshot ? new_snapshot : old_snapshot;
if (!old_snapshot) {
- return stasis_json_event_channel_created_create(snapshot);
+ return channel_created_event(snapshot, tv);
} else if (!new_snapshot) {
- json = ast_json_pack("{s: i, s: s}",
- "cause", snapshot->hangupcause,
- "cause_txt", ast_cause2str(snapshot->hangupcause));
- if (!json) {
- return NULL;
- }
- return stasis_json_event_channel_destroyed_create(snapshot, json);
+ return channel_destroyed_event(snapshot, tv);
} else if (old_snapshot->state != new_snapshot->state) {
- return stasis_json_event_channel_state_change_create(snapshot);
+ return channel_state_change_event(snapshot, tv);
}
return NULL;
@@ -262,7 +292,8 @@ static struct ast_json *channel_state(
static struct ast_json *channel_dialplan(
struct ast_channel_snapshot *old_snapshot,
- struct ast_channel_snapshot *new_snapshot)
+ struct ast_channel_snapshot *new_snapshot,
+ const struct timeval *tv)
{
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
@@ -280,19 +311,18 @@ static struct ast_json *channel_dialplan(
return NULL;
}
- json = ast_json_pack("{s: s, s: s}",
- "application", new_snapshot->appl,
- "application_data", new_snapshot->data);
- if (!json) {
- return NULL;
- }
-
- return stasis_json_event_channel_dialplan_create(new_snapshot, json);
+ return ast_json_pack("{s: s, s: o, s: s, s: s, s: o}",
+ "type", "ChannelDialplan",
+ "timestamp", ast_json_timeval(*tv, NULL),
+ "dialplan_app", new_snapshot->appl,
+ "dialplan_app_data", new_snapshot->data,
+ "channel", ast_channel_snapshot_to_json(new_snapshot));
}
static struct ast_json *channel_callerid(
struct ast_channel_snapshot *old_snapshot,
- struct ast_channel_snapshot *new_snapshot)
+ struct ast_channel_snapshot *new_snapshot,
+ const struct timeval *tv)
{
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
@@ -305,29 +335,16 @@ static struct ast_json *channel_callerid(
return NULL;
}
- json = ast_json_pack("{s: i, s: s}",
+ return ast_json_pack("{s: s, s: o, s: i, s: s, s: o}",
+ "type", "ChannelCallerId",
+ "timestamp", ast_json_timeval(*tv, NULL),
"caller_presentation", new_snapshot->caller_pres,
- "caller_presentation_txt", ast_describe_caller_presentation(new_snapshot->caller_pres));
- if (!json) {
- return NULL;
- }
-
- return stasis_json_event_channel_caller_id_create(new_snapshot, json);
-}
-
-static struct ast_json *channel_snapshot(
- struct ast_channel_snapshot *old_snapshot,
- struct ast_channel_snapshot *new_snapshot)
-{
- if (!new_snapshot) {
- return NULL;
- }
-
- return stasis_json_event_channel_snapshot_create(new_snapshot);
+ "caller_presentation_txt", ast_describe_caller_presentation(
+ new_snapshot->caller_pres),
+ "channel", ast_channel_snapshot_to_json(new_snapshot));
}
channel_snapshot_monitor channel_monitors[] = {
- channel_snapshot,
channel_state,
channel_dialplan,
channel_callerid
@@ -351,6 +368,9 @@ static void sub_channel_snapshot_handler(void *data,
struct stasis_cache_update *update = stasis_message_data(message);
struct ast_channel_snapshot *new_snapshot = stasis_message_data(update->new_snapshot);
struct ast_channel_snapshot *old_snapshot = stasis_message_data(update->old_snapshot);
+ /* Pull timestamp from the new snapshot, or from the update message
+ * when there isn't one. */
+ const struct timeval *tv = update->new_snapshot ? stasis_message_timestamp(update->new_snapshot) : stasis_message_timestamp(message);
int i;
watching_apps = get_apps_watching_channel(new_snapshot ? new_snapshot->uniqueid : old_snapshot->uniqueid);
@@ -361,7 +381,7 @@ static void sub_channel_snapshot_handler(void *data,
for (i = 0; i < ARRAY_LEN(channel_monitors); ++i) {
RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
- msg = channel_monitors[i](old_snapshot, new_snapshot);
+ msg = channel_monitors[i](old_snapshot, new_snapshot, tv);
if (msg) {
ao2_callback(watching_apps, OBJ_NODATA, app_send_cb, msg);
}
@@ -373,22 +393,26 @@ static void distribute_message(struct ao2_container *apps, struct ast_json *msg)
ao2_callback(apps, OBJ_NODATA, app_send_cb, msg);
}
-static void generic_blob_handler(struct ast_channel_blob *obj, channel_blob_handler_cb handler_cb)
+static void sub_channel_blob_handler(void *data,
+ struct stasis_subscription *sub,
+ struct stasis_topic *topic,
+ struct stasis_message *message)
{
RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
RAII_VAR(struct ao2_container *, watching_apps, NULL, ao2_cleanup);
+ struct ast_channel_blob *obj = stasis_message_data(message);
if (!obj->snapshot) {
return;
}
- watching_apps = get_apps_watching_channel(obj->snapshot->uniqueid);
- if (!watching_apps) {
+ msg = stasis_message_to_json(message);
+ if (!msg) {
return;
}
- msg = handler_cb(obj);
- if (!msg) {
+ watching_apps = get_apps_watching_channel(obj->snapshot->uniqueid);
+ if (!watching_apps) {
return;
}
@@ -446,7 +470,6 @@ int app_send_start_msg(struct app *app, struct ast_channel *chan,
int argc, char *argv[])
{
RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
struct ast_json *json_args;
@@ -460,13 +483,16 @@ int app_send_start_msg(struct app *app, struct ast_channel *chan,
return -1;
}
- blob = ast_json_pack("{s: []}", "args");
- if (!blob) {
+ msg = ast_json_pack("{s: s, s: [], s: o}",
+ "type", "StasisStart",
+ "args",
+ "channel", ast_channel_snapshot_to_json(snapshot));
+ if (!msg) {
return -1;
}
/* Append arguments to args array */
- json_args = ast_json_object_get(blob, "args");
+ json_args = ast_json_object_get(msg, "args");
ast_assert(json_args != NULL);
for (i = 0; i < argc; ++i) {
int r = ast_json_array_append(json_args,
@@ -477,11 +503,6 @@ int app_send_start_msg(struct app *app, struct ast_channel *chan,
}
}
- msg = stasis_json_event_stasis_start_create(snapshot, blob);
- if (!msg) {
- return -1;
- }
-
app_send(app, msg);
return 0;
}
@@ -499,7 +520,9 @@ int app_send_end_msg(struct app *app, struct ast_channel *chan)
return -1;
}
- msg = stasis_json_event_stasis_end_create(snapshot);
+ msg = ast_json_pack("{s: s, s: o}",
+ "type", "StasisEnd",
+ "channel", ast_channel_snapshot_to_json(snapshot));
if (!msg) {
return -1;
}
@@ -633,15 +656,13 @@ int stasis_app_register(const char *app_name, stasis_app_cb handler, void *data)
app = ao2_find(apps_registry, app_name, OBJ_KEY | OBJ_NOLOCK);
if (app) {
- RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
- blob = ast_json_pack("{s: s}", "application", app_name);
- if (blob) {
- msg = stasis_json_event_application_replaced_create(blob);
- if (msg) {
- app_send(app, msg);
- }
+ msg = ast_json_pack("{s: s, s: s}",
+ "type", "ApplicationReplaced",
+ "application", app_name);
+ if (msg) {
+ app_send(app, msg);
}
app_update(app, handler, data);
@@ -665,82 +686,6 @@ void stasis_app_unregister(const char *app_name)
}
}
-static struct ast_json *handle_blob_dtmf(struct ast_channel_blob *obj)
-{
- RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
- const char *direction;
-
- /* To simplify events, we'll only generate on receive */
- direction = ast_json_string_get(
- ast_json_object_get(obj->blob, "direction"));
-
- if (strcmp("Received", direction) != 0) {
- return NULL;
- }
-
- extra = ast_json_pack(
- "{s: o}",
- "digit", ast_json_ref(ast_json_object_get(obj->blob, "digit")));
- if (!extra) {
- return NULL;
- }
-
- return stasis_json_event_channel_dtmf_received_create(obj->snapshot, extra);
-}
-
-/* To simplify events, we'll only generate on DTMF end (dtmf_end type) */
-static void sub_dtmf_handler(void *data,
- struct stasis_subscription *sub,
- struct stasis_topic *topic,
- struct stasis_message *message)
-{
- struct ast_channel_blob *obj = stasis_message_data(message);
- generic_blob_handler(obj, handle_blob_dtmf);
-}
-
-static struct ast_json *handle_blob_userevent(struct ast_channel_blob *obj)
-{
- return stasis_json_event_channel_userevent_create(obj->snapshot, obj->blob);
-}
-
-static void sub_userevent_handler(void *data,
- struct stasis_subscription *sub,
- struct stasis_topic *topic,
- struct stasis_message *message)
-{
- struct ast_channel_blob *obj = stasis_message_data(message);
- generic_blob_handler(obj, handle_blob_userevent);
-}
-
-static struct ast_json *handle_blob_hangup_request(struct ast_channel_blob *obj)
-{
- return stasis_json_event_channel_hangup_request_create(obj->snapshot, obj->blob);
-}
-
-static void sub_hangup_request_handler(void *data,
- struct stasis_subscription *sub,
- struct stasis_topic *topic,
- struct stasis_message *message)
-{
- struct ast_channel_blob *obj = stasis_message_data(message);
- generic_blob_handler(obj, handle_blob_hangup_request);
-}
-
-static struct ast_json *handle_blob_varset(struct ast_channel_blob *obj)
-{
- return stasis_json_event_channel_varset_create(obj->snapshot, obj->blob);
-}
-
-static void sub_varset_handler(void *data,
- struct stasis_subscription *sub,
- struct stasis_topic *topic,
- struct stasis_message *message)
-{
- struct ast_channel_blob *obj = stasis_message_data(message);
- generic_blob_handler(obj, handle_blob_varset);
-}
-
void stasis_app_ref(void)
{
ast_module_ref(ast_module_info->self);
@@ -788,6 +733,30 @@ static int remove_bridge_cb(void *obj, void *arg, int flags)
return 0;
}
+static struct ast_json *simple_bridge_event(
+ const char *type,
+ struct ast_bridge_snapshot *snapshot,
+ const struct timeval *tv)
+{
+ return ast_json_pack("{s: s, s: o, s: o}",
+ "type", type,
+ "timestamp", ast_json_timeval(*tv, NULL),
+ "bridge", ast_bridge_snapshot_to_json(snapshot));
+}
+
+static struct ast_json *simple_bridge_channel_event(
+ const char *type,
+ struct ast_bridge_snapshot *bridge_snapshot,
+ struct ast_channel_snapshot *channel_snapshot,
+ const struct timeval *tv)
+{
+ return ast_json_pack("{s: s, s: o, s: o}",
+ "type", type,
+ "timestamp", ast_json_timeval(*tv, NULL),
+ "bridge", ast_bridge_snapshot_to_json(bridge_snapshot),
+ "channel", ast_channel_snapshot_to_json(channel_snapshot));
+}
+
static void sub_bridge_snapshot_handler(void *data,
struct stasis_subscription *sub,
struct stasis_topic *topic,
@@ -797,6 +766,8 @@ static void sub_bridge_snapshot_handler(void *data,
struct stasis_cache_update *update = stasis_message_data(message);
struct ast_bridge_snapshot *new_snapshot = stasis_message_data(update->new_snapshot);
struct ast_bridge_snapshot *old_snapshot = stasis_message_data(update->old_snapshot);
+ const struct timeval *tv = update->new_snapshot ? stasis_message_timestamp(update->new_snapshot) : stasis_message_timestamp(message);
+
RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
watching_apps = get_apps_watching_bridge(new_snapshot ? new_snapshot->uniqueid : old_snapshot->uniqueid);
@@ -810,11 +781,11 @@ static void sub_bridge_snapshot_handler(void *data,
/* The bridge has gone away. Create the message, make sure no apps are
* watching this bridge anymore, and destroy the bridge's control
* structure */
- msg = stasis_json_event_bridge_destroyed_create(old_snapshot);
+ msg = simple_bridge_event("BridgeDestroyed", old_snapshot, tv);
ao2_callback(watching_apps, OBJ_NODATA, remove_bridge_cb, bridge_id);
stasis_app_bridge_destroy(old_snapshot->uniqueid);
} else if (!old_snapshot) {
- msg = stasis_json_event_bridge_created_create(old_snapshot);
+ msg = simple_bridge_event("BridgeCreated", old_snapshot, tv);
}
if (!msg) {
@@ -865,6 +836,7 @@ static void sub_bridge_merge_handler(void *data,
struct ast_bridge_merge_message *merge = stasis_message_data(message);
RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+ const struct timeval *tv = stasis_message_timestamp(message);
watching_apps_to = get_apps_watching_bridge(merge->to->uniqueid);
if (watching_apps_to) {
@@ -881,16 +853,16 @@ static void sub_bridge_merge_handler(void *data,
return;
}
- /* The secondary bridge has to be packed into JSON by hand because the auto-generated
- * JSON event generator can only handle one instance of a given snapshot type in an
- * elegant way */
- blob = ast_json_pack("{s: o}", "bridge_from", ast_bridge_snapshot_to_json(merge->from));
- if (!blob) {
+ msg = ast_json_pack("{s: s, s: o, s: o, s: o}",
+ "type", "BridgeMerged",
+ "timestamp", ast_json_timeval(*tv, NULL),
+ "bridge", ast_bridge_snapshot_to_json(merge->to),
+ "bridge_from", ast_bridge_snapshot_to_json(merge->from));
+
+ if (!msg) {
return;
}
- msg = stasis_json_event_bridge_merged_create(merge->to, blob);
-
distribute_message(watching_apps_all, msg);
}
@@ -920,7 +892,8 @@ static void sub_bridge_enter_handler(void *data,
return;
}
- msg = stasis_json_event_channel_entered_bridge_create(obj->bridge, obj->channel);
+ msg = simple_bridge_channel_event("ChannelEnteredBridge", obj->bridge,
+ obj->channel, stasis_message_timestamp(message));
distribute_message(watching_apps_all, msg);
}
@@ -939,7 +912,8 @@ static void sub_bridge_leave_handler(void *data,
return;
}
- msg = stasis_json_event_channel_left_bridge_create(obj->bridge, obj->channel);
+ msg = simple_bridge_channel_event("ChannelLeftBridge", obj->bridge,
+ obj->channel, stasis_message_timestamp(message));
distribute_message(watching_apps_bridge, msg);
}
@@ -972,10 +946,16 @@ static int load_module(void)
}
r |= stasis_message_router_add(channel_router, stasis_cache_update_type(), sub_channel_snapshot_handler, NULL);
- r |= stasis_message_router_add(channel_router, ast_channel_user_event_type(), sub_userevent_handler, NULL);
- r |= stasis_message_router_add(channel_router, ast_channel_varset_type(), sub_varset_handler, NULL);
- r |= stasis_message_router_add(channel_router, ast_channel_dtmf_begin_type(), sub_dtmf_handler, NULL);
- r |= stasis_message_router_add(channel_router, ast_channel_hangup_request_type(), sub_hangup_request_handler, NULL);
+ /* TODO: This could be handled a lot better. Instead of subscribing to
+ * the one caching topic and filtering out messages by channel id, we
+ * should have individual caching topics per-channel, with a shared
+ * back-end cache. That would simplify a lot of what's going on right
+ * here.
+ */
+ r |= stasis_message_router_add(channel_router, ast_channel_user_event_type(), sub_channel_blob_handler, NULL);
+ r |= stasis_message_router_add(channel_router, ast_channel_varset_type(), sub_channel_blob_handler, NULL);
+ r |= stasis_message_router_add(channel_router, ast_channel_dtmf_end_type(), sub_channel_blob_handler, NULL);
+ r |= stasis_message_router_add(channel_router, ast_channel_hangup_request_type(), sub_channel_blob_handler, NULL);
if (r) {
return AST_MODULE_LOAD_FAILURE;
}
diff --git a/res/res_stasis_http.c b/res/res_stasis_http.c
index fce108146..3ff6482b5 100644
--- a/res/res_stasis_http.c
+++ b/res/res_stasis_http.c
@@ -324,7 +324,7 @@ void stasis_http_response_ok(struct stasis_http_response *response,
void stasis_http_response_no_content(struct stasis_http_response *response)
{
- response->message = NULL;
+ response->message = ast_json_null();
response->response_code = 204;
response->response_text = "No Content";
}
@@ -386,9 +386,7 @@ static void handle_options(struct stasis_rest_handlers *handler,
/* Regular OPTIONS response */
add_allow_header(handler, response);
- response->response_code = 204;
- response->response_text = "No Content";
- response->message = NULL;
+ stasis_http_response_no_content(response);
/* Parse CORS headers */
for (header = headers; header != NULL; header = header->next) {
@@ -797,6 +795,11 @@ static void process_cors_request(struct ast_variable *headers,
*/
}
+enum ast_json_encoding_format stasis_http_json_format(void)
+{
+ RAII_VAR(struct conf *, cfg, ao2_global_obj_ref(confs), ao2_cleanup);
+ return cfg->global->format;
+}
/*!
* \internal
@@ -819,7 +822,6 @@ static int stasis_http_callback(struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params,
struct ast_variable *headers)
{
- RAII_VAR(struct conf *, cfg, ao2_global_obj_ref(confs), ao2_cleanup);
RAII_VAR(struct ast_str *, response_headers, ast_str_create(40), ast_free);
RAII_VAR(struct ast_str *, response_body, ast_str_create(256), ast_free);
struct stasis_http_response response = {};
@@ -859,11 +861,10 @@ static int stasis_http_callback(struct ast_tcptls_session_instance *ser,
return 0;
}
- /* Leaving message unset is only allowed for 204 (No Content).
- * If you explicitly want to have no content for a different return
- * code, set message to ast_json_null().
+ /* If you explicitly want to have no content, set message to
+ * ast_json_null().
*/
- ast_assert(response.response_code == 204 || response.message != NULL);
+ ast_assert(response.message != NULL);
ast_assert(response.response_code > 0);
ast_str_append(&response_headers, 0, "%s", ast_str_buffer(response.headers));
@@ -874,7 +875,7 @@ static int stasis_http_callback(struct ast_tcptls_session_instance *ser,
if (response.message && !ast_json_is_null(response.message)) {
ast_str_append(&response_headers, 0,
"Content-type: application/json\r\n");
- if (ast_json_dump_str_format(response.message, &response_body, cfg->global->format) != 0) {
+ if (ast_json_dump_str_format(response.message, &response_body, stasis_http_json_format()) != 0) {
/* Error encoding response */
response.response_code = 500;
response.response_text = "Internal Server Error";
diff --git a/res/res_stasis_http_asterisk.c b/res/res_stasis_http_asterisk.c
index 9f4fd63e1..01f082ad6 100644
--- a/res/res_stasis_http_asterisk.c
+++ b/res/res_stasis_http_asterisk.c
@@ -44,6 +44,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/stasis_app.h"
#include "stasis_http/resource_asterisk.h"
+#if defined(AST_DEVMODE)
+#include "stasis_http/ari_model_validators.h"
+#endif
/*!
* \brief Parameter parsing callback for /asterisk/info.
@@ -53,9 +56,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_asterisk_info_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_asterisk_info_args args = {};
struct ast_variable *i;
@@ -66,6 +74,29 @@ static void stasis_http_get_asterisk_info_cb(
{}
}
stasis_http_get_asterisk_info(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_asterisk_info(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/info\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /asterisk/info\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*! \brief REST handler for /api-docs/asterisk.{format} */
diff --git a/res/res_stasis_http_bridges.c b/res/res_stasis_http_bridges.c
index 717b2f83f..a4801df13 100644
--- a/res/res_stasis_http_bridges.c
+++ b/res/res_stasis_http_bridges.c
@@ -44,6 +44,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/stasis_app.h"
#include "stasis_http/resource_bridges.h"
+#if defined(AST_DEVMODE)
+#include "stasis_http/ari_model_validators.h"
+#endif
/*!
* \brief Parameter parsing callback for /bridges.
@@ -53,11 +56,39 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_bridges_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_bridges_args args = {};
stasis_http_get_bridges(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_list(response->message,
+ ari_validate_bridge);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /bridges\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /bridges\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /bridges.
@@ -67,9 +98,14 @@ static void stasis_http_get_bridges_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_new_bridge_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_new_bridge_args args = {};
struct ast_variable *i;
@@ -80,6 +116,29 @@ static void stasis_http_new_bridge_cb(
{}
}
stasis_http_new_bridge(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_bridge(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /bridges\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /bridges\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /bridges/{bridgeId}.
@@ -89,9 +148,14 @@ static void stasis_http_new_bridge_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_bridge_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_bridge_args args = {};
struct ast_variable *i;
@@ -102,6 +166,30 @@ static void stasis_http_get_bridge_cb(
{}
}
stasis_http_get_bridge(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Bridge not found */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_bridge(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /bridges/{bridgeId}.
@@ -111,9 +199,14 @@ static void stasis_http_get_bridge_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_delete_bridge_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_delete_bridge_args args = {};
struct ast_variable *i;
@@ -124,6 +217,30 @@ static void stasis_http_delete_bridge_cb(
{}
}
stasis_http_delete_bridge(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Bridge not found */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /bridges/{bridgeId}/addChannel.
@@ -133,9 +250,14 @@ static void stasis_http_delete_bridge_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_add_channel_to_bridge_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_add_channel_to_bridge_args args = {};
struct ast_variable *i;
@@ -152,6 +274,32 @@ static void stasis_http_add_channel_to_bridge_cb(
{}
}
stasis_http_add_channel_to_bridge(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Bridge not found */
+ case 409: /* Bridge not in Stasis application */
+ case 422: /* Channel not found, or not in Stasis application */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/addChannel\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/addChannel\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /bridges/{bridgeId}/removeChannel.
@@ -161,9 +309,14 @@ static void stasis_http_add_channel_to_bridge_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_remove_channel_from_bridge_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_remove_channel_from_bridge_args args = {};
struct ast_variable *i;
@@ -180,6 +333,29 @@ static void stasis_http_remove_channel_from_bridge_cb(
{}
}
stasis_http_remove_channel_from_bridge(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/removeChannel\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/removeChannel\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /bridges/{bridgeId}/record.
@@ -189,9 +365,14 @@ static void stasis_http_remove_channel_from_bridge_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_record_bridge_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_record_bridge_args args = {};
struct ast_variable *i;
@@ -223,6 +404,29 @@ static void stasis_http_record_bridge_cb(
{}
}
stasis_http_record_bridge(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_live_recording(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/record\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/record\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*! \brief REST handler for /api-docs/bridges.{format} */
diff --git a/res/res_stasis_http_channels.c b/res/res_stasis_http_channels.c
index c865b3931..ebcc9e880 100644
--- a/res/res_stasis_http_channels.c
+++ b/res/res_stasis_http_channels.c
@@ -44,6 +44,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/stasis_app.h"
#include "stasis_http/resource_channels.h"
+#if defined(AST_DEVMODE)
+#include "stasis_http/ari_model_validators.h"
+#endif
/*!
* \brief Parameter parsing callback for /channels.
@@ -53,11 +56,39 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_channels_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_channels_args args = {};
stasis_http_get_channels(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_list(response->message,
+ ari_validate_channel);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /channels.
@@ -67,9 +98,14 @@ static void stasis_http_get_channels_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_originate_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_originate_args args = {};
struct ast_variable *i;
@@ -101,6 +137,29 @@ static void stasis_http_originate_cb(
{}
}
stasis_http_originate(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /channels/{channelId}.
@@ -110,9 +169,14 @@ static void stasis_http_originate_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_channel_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_channel_args args = {};
struct ast_variable *i;
@@ -123,6 +187,30 @@ static void stasis_http_get_channel_cb(
{}
}
stasis_http_get_channel(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Channel not found */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_channel(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /channels/{channelId}.
@@ -132,9 +220,14 @@ static void stasis_http_get_channel_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_delete_channel_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_delete_channel_args args = {};
struct ast_variable *i;
@@ -145,6 +238,30 @@ static void stasis_http_delete_channel_cb(
{}
}
stasis_http_delete_channel(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Channel not found */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /channels/{channelId}/dial.
@@ -154,9 +271,14 @@ static void stasis_http_delete_channel_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_dial_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_dial_args args = {};
struct ast_variable *i;
@@ -182,6 +304,31 @@ static void stasis_http_dial_cb(
{}
}
stasis_http_dial(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Channel not found */
+ case 409: /* Channel not in a Stasis application */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_dialed(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/dial\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/dial\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /channels/{channelId}/continue.
@@ -191,9 +338,14 @@ static void stasis_http_dial_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_continue_in_dialplan_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_continue_in_dialplan_args args = {};
struct ast_variable *i;
@@ -216,6 +368,31 @@ static void stasis_http_continue_in_dialplan_cb(
{}
}
stasis_http_continue_in_dialplan(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Channel not found */
+ case 409: /* Channel not in a Stasis application */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/continue\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/continue\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /channels/{channelId}/answer.
@@ -225,9 +402,14 @@ static void stasis_http_continue_in_dialplan_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_answer_channel_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_answer_channel_args args = {};
struct ast_variable *i;
@@ -238,6 +420,31 @@ static void stasis_http_answer_channel_cb(
{}
}
stasis_http_answer_channel(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Channel not found */
+ case 409: /* Channel not in a Stasis application */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/answer\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/answer\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /channels/{channelId}/mute.
@@ -247,9 +454,14 @@ static void stasis_http_answer_channel_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_mute_channel_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_mute_channel_args args = {};
struct ast_variable *i;
@@ -266,6 +478,31 @@ static void stasis_http_mute_channel_cb(
{}
}
stasis_http_mute_channel(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Channel not found */
+ case 409: /* Channel not in a Stasis application */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/mute\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/mute\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /channels/{channelId}/unmute.
@@ -275,9 +512,14 @@ static void stasis_http_mute_channel_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_unmute_channel_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_unmute_channel_args args = {};
struct ast_variable *i;
@@ -294,6 +536,31 @@ static void stasis_http_unmute_channel_cb(
{}
}
stasis_http_unmute_channel(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Channel not found */
+ case 409: /* Channel not in a Stasis application */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/unmute\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/unmute\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /channels/{channelId}/hold.
@@ -303,9 +570,14 @@ static void stasis_http_unmute_channel_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_hold_channel_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_hold_channel_args args = {};
struct ast_variable *i;
@@ -316,6 +588,31 @@ static void stasis_http_hold_channel_cb(
{}
}
stasis_http_hold_channel(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Channel not found */
+ case 409: /* Channel not in a Stasis application */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/hold\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/hold\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /channels/{channelId}/unhold.
@@ -325,9 +622,14 @@ static void stasis_http_hold_channel_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_unhold_channel_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_unhold_channel_args args = {};
struct ast_variable *i;
@@ -338,6 +640,31 @@ static void stasis_http_unhold_channel_cb(
{}
}
stasis_http_unhold_channel(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Channel not found */
+ case 409: /* Channel not in a Stasis application */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/unhold\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/unhold\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /channels/{channelId}/play.
@@ -347,9 +674,14 @@ static void stasis_http_unhold_channel_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_play_on_channel_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_play_on_channel_args args = {};
struct ast_variable *i;
@@ -375,6 +707,31 @@ static void stasis_http_play_on_channel_cb(
{}
}
stasis_http_play_on_channel(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Channel not found */
+ case 409: /* Channel not in a Stasis application */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_playback(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/play\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/play\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /channels/{channelId}/record.
@@ -384,9 +741,14 @@ static void stasis_http_play_on_channel_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_record_channel_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_record_channel_args args = {};
struct ast_variable *i;
@@ -421,6 +783,31 @@ static void stasis_http_record_channel_cb(
{}
}
stasis_http_record_channel(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 404: /* Channel not found */
+ case 409: /* Channel is not in a Stasis application, or the channel is currently bridged with other channels. */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/record\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/record\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*! \brief REST handler for /api-docs/channels.{format} */
diff --git a/res/res_stasis_http_endpoints.c b/res/res_stasis_http_endpoints.c
index 81cdfeb0f..332333030 100644
--- a/res/res_stasis_http_endpoints.c
+++ b/res/res_stasis_http_endpoints.c
@@ -44,6 +44,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/stasis_app.h"
#include "stasis_http/resource_endpoints.h"
+#if defined(AST_DEVMODE)
+#include "stasis_http/ari_model_validators.h"
+#endif
/*!
* \brief Parameter parsing callback for /endpoints.
@@ -53,11 +56,39 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_endpoints_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_endpoints_args args = {};
stasis_http_get_endpoints(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_list(response->message,
+ ari_validate_endpoint);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /endpoints\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /endpoints\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /endpoints/{tech}.
@@ -67,9 +98,14 @@ static void stasis_http_get_endpoints_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_endpoints_by_tech_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_endpoints_by_tech_args args = {};
struct ast_variable *i;
@@ -80,6 +116,29 @@ static void stasis_http_get_endpoints_by_tech_cb(
{}
}
stasis_http_get_endpoints_by_tech(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_list(response->message,
+ ari_validate_endpoint);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /endpoints/{tech}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /endpoints/{tech}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /endpoints/{tech}/{resource}.
@@ -89,9 +148,14 @@ static void stasis_http_get_endpoints_by_tech_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_endpoint_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_endpoint_args args = {};
struct ast_variable *i;
@@ -105,6 +169,29 @@ static void stasis_http_get_endpoint_cb(
{}
}
stasis_http_get_endpoint(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_endpoint(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /endpoints/{tech}/{resource}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /endpoints/{tech}/{resource}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*! \brief REST handler for /api-docs/endpoints.{format} */
diff --git a/res/res_stasis_http_events.c b/res/res_stasis_http_events.c
index 909c2d659..421726312 100644
--- a/res/res_stasis_http_events.c
+++ b/res/res_stasis_http_events.c
@@ -44,6 +44,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/stasis_app.h"
#include "stasis_http/resource_events.h"
+#if defined(AST_DEVMODE)
+#include "stasis_http/ari_model_validators.h"
+#endif
static void stasis_http_event_websocket_ws_cb(struct ast_websocket *ws_session,
struct ast_variable *get_params, struct ast_variable *headers)
@@ -59,7 +62,12 @@ static void stasis_http_event_websocket_ws_cb(struct ast_websocket *ws_session,
} else
{}
}
- session = ari_websocket_session_create(ws_session);
+#if defined(AST_DEVMODE)
+ session = ari_websocket_session_create(ws_session,
+ ari_validate_event);
+#else
+ session = ari_websocket_session_create(ws_session, NULL);
+#endif
if (!session) {
ast_log(LOG_ERROR, "Failed to create ARI session\n");
return;
diff --git a/res/res_stasis_http_playback.c b/res/res_stasis_http_playback.c
index 4608686bc..0e56e6229 100644
--- a/res/res_stasis_http_playback.c
+++ b/res/res_stasis_http_playback.c
@@ -44,6 +44,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/stasis_app.h"
#include "stasis_http/resource_playback.h"
+#if defined(AST_DEVMODE)
+#include "stasis_http/ari_model_validators.h"
+#endif
/*!
* \brief Parameter parsing callback for /playback/{playbackId}.
@@ -53,9 +56,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_playback_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_playback_args args = {};
struct ast_variable *i;
@@ -66,6 +74,29 @@ static void stasis_http_get_playback_cb(
{}
}
stasis_http_get_playback(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_playback(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /playback/{playbackId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /playback/{playbackId}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /playback/{playbackId}.
@@ -75,9 +106,14 @@ static void stasis_http_get_playback_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_stop_playback_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_stop_playback_args args = {};
struct ast_variable *i;
@@ -88,6 +124,29 @@ static void stasis_http_stop_playback_cb(
{}
}
stasis_http_stop_playback(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_playback(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /playback/{playbackId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /playback/{playbackId}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /playback/{playbackId}/control.
@@ -97,9 +156,14 @@ static void stasis_http_stop_playback_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_control_playback_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_control_playback_args args = {};
struct ast_variable *i;
@@ -116,6 +180,32 @@ static void stasis_http_control_playback_cb(
{}
}
stasis_http_control_playback(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ case 400: /* The provided operation parameter was invalid */
+ case 404: /* The playback cannot be found */
+ case 409: /* The operation cannot be performed in the playback's current state */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_playback(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /playback/{playbackId}/control\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /playback/{playbackId}/control\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*! \brief REST handler for /api-docs/playback.{format} */
diff --git a/res/res_stasis_http_recordings.c b/res/res_stasis_http_recordings.c
index 7d89393bc..4aa43c9be 100644
--- a/res/res_stasis_http_recordings.c
+++ b/res/res_stasis_http_recordings.c
@@ -44,22 +44,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/stasis_app.h"
#include "stasis_http/resource_recordings.h"
+#if defined(AST_DEVMODE)
+#include "stasis_http/ari_model_validators.h"
+#endif
/*!
- * \brief Parameter parsing callback for /recordings.
- * \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 stasis_http_get_recordings_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
-{
- struct ast_get_recordings_args args = {};
- stasis_http_get_recordings(headers, &args, response);
-}
-/*!
* \brief Parameter parsing callback for /recordings/stored.
* \param get_params GET parameters in the HTTP request.
* \param path_vars Path variables extracted from the request.
@@ -67,11 +56,39 @@ static void stasis_http_get_recordings_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_stored_recordings_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_stored_recordings_args args = {};
stasis_http_get_stored_recordings(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_list(response->message,
+ ari_validate_stored_recording);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/stored\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /recordings/stored/{recordingId}.
@@ -81,9 +98,14 @@ static void stasis_http_get_stored_recordings_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_stored_recording_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_stored_recording_args args = {};
struct ast_variable *i;
@@ -94,6 +116,29 @@ static void stasis_http_get_stored_recording_cb(
{}
}
stasis_http_get_stored_recording(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_stored_recording(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored/{recordingId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/stored/{recordingId}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /recordings/stored/{recordingId}.
@@ -103,9 +148,14 @@ static void stasis_http_get_stored_recording_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_delete_stored_recording_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_delete_stored_recording_args args = {};
struct ast_variable *i;
@@ -116,6 +166,29 @@ static void stasis_http_delete_stored_recording_cb(
{}
}
stasis_http_delete_stored_recording(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored/{recordingId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/stored/{recordingId}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /recordings/live.
@@ -125,11 +198,39 @@ static void stasis_http_delete_stored_recording_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_live_recordings_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_live_recordings_args args = {};
stasis_http_get_live_recordings(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_list(response->message,
+ ari_validate_live_recording);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /recordings/live/{recordingId}.
@@ -139,9 +240,14 @@ static void stasis_http_get_live_recordings_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_live_recording_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_live_recording_args args = {};
struct ast_variable *i;
@@ -152,6 +258,29 @@ static void stasis_http_get_live_recording_cb(
{}
}
stasis_http_get_live_recording(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_live_recording(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /recordings/live/{recordingId}.
@@ -161,9 +290,14 @@ static void stasis_http_get_live_recording_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_cancel_recording_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_cancel_recording_args args = {};
struct ast_variable *i;
@@ -174,6 +308,29 @@ static void stasis_http_cancel_recording_cb(
{}
}
stasis_http_cancel_recording(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /recordings/live/{recordingId}/stop.
@@ -183,9 +340,14 @@ static void stasis_http_cancel_recording_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_stop_recording_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_stop_recording_args args = {};
struct ast_variable *i;
@@ -196,6 +358,29 @@ static void stasis_http_stop_recording_cb(
{}
}
stasis_http_stop_recording(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}/stop\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}/stop\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /recordings/live/{recordingId}/pause.
@@ -205,9 +390,14 @@ static void stasis_http_stop_recording_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_pause_recording_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_pause_recording_args args = {};
struct ast_variable *i;
@@ -218,6 +408,29 @@ static void stasis_http_pause_recording_cb(
{}
}
stasis_http_pause_recording(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}/pause\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}/pause\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /recordings/live/{recordingId}/unpause.
@@ -227,9 +440,14 @@ static void stasis_http_pause_recording_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_unpause_recording_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_unpause_recording_args args = {};
struct ast_variable *i;
@@ -240,6 +458,29 @@ static void stasis_http_unpause_recording_cb(
{}
}
stasis_http_unpause_recording(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}/unpause\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}/unpause\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /recordings/live/{recordingId}/mute.
@@ -249,9 +490,14 @@ static void stasis_http_unpause_recording_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_mute_recording_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_mute_recording_args args = {};
struct ast_variable *i;
@@ -262,6 +508,29 @@ static void stasis_http_mute_recording_cb(
{}
}
stasis_http_mute_recording(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}/mute\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}/mute\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /recordings/live/{recordingId}/unmute.
@@ -271,9 +540,14 @@ static void stasis_http_mute_recording_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_unmute_recording_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_unmute_recording_args args = {};
struct ast_variable *i;
@@ -284,6 +558,29 @@ static void stasis_http_unmute_recording_cb(
{}
}
stasis_http_unmute_recording(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}/unmute\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}/unmute\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*! \brief REST handler for /api-docs/recordings.{format} */
@@ -375,7 +672,6 @@ static struct stasis_rest_handlers recordings_live = {
static struct stasis_rest_handlers recordings = {
.path_segment = "recordings",
.callbacks = {
- [AST_HTTP_GET] = stasis_http_get_recordings_cb,
},
.num_children = 2,
.children = { &recordings_stored,&recordings_live, }
diff --git a/res/res_stasis_http_sounds.c b/res/res_stasis_http_sounds.c
index 975ca0388..da0206223 100644
--- a/res/res_stasis_http_sounds.c
+++ b/res/res_stasis_http_sounds.c
@@ -44,6 +44,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/stasis_app.h"
#include "stasis_http/resource_sounds.h"
+#if defined(AST_DEVMODE)
+#include "stasis_http/ari_model_validators.h"
+#endif
/*!
* \brief Parameter parsing callback for /sounds.
@@ -53,9 +56,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_sounds_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_sounds_args args = {};
struct ast_variable *i;
@@ -69,6 +77,29 @@ static void stasis_http_get_sounds_cb(
{}
}
stasis_http_get_sounds(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_list(response->message,
+ ari_validate_sound);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /sounds\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /sounds\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*!
* \brief Parameter parsing callback for /sounds/{soundId}.
@@ -78,9 +109,14 @@ static void stasis_http_get_sounds_cb(
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_get_stored_sound_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
struct ast_get_stored_sound_args args = {};
struct ast_variable *i;
@@ -91,6 +127,29 @@ static void stasis_http_get_stored_sound_cb(
{}
}
stasis_http_get_stored_sound(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ari_validate_sound(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /sounds/{soundId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /sounds/{soundId}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
/*! \brief REST handler for /api-docs/sounds.{format} */
diff --git a/res/res_stasis_json_asterisk.c b/res/res_stasis_json_asterisk.c
deleted file mode 100644
index 830a2cfab..000000000
--- a/res/res_stasis_json_asterisk.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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_stasis_http_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Asterisk resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*** MODULEINFO
- <support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/module.h"
-#include "asterisk/json.h"
-#include "stasis_json/resource_asterisk.h"
-static int load_module(void)
-{
- return 0;
-}
-
-static int unload_module(void)
-{
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis JSON Generators and Validators - Asterisk resources",
- .load = load_module,
- .unload = unload_module,
- .load_pri = AST_MODPRI_DEFAULT,
- );
diff --git a/res/res_stasis_json_asterisk.exports.in b/res/res_stasis_json_asterisk.exports.in
deleted file mode 100644
index 5e767549c..000000000
--- a/res/res_stasis_json_asterisk.exports.in
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- local:
- *;
-};
diff --git a/res/res_stasis_json_bridges.c b/res/res_stasis_json_bridges.c
deleted file mode 100644
index 90977bff4..000000000
--- a/res/res_stasis_json_bridges.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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_stasis_http_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Bridge resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*** MODULEINFO
- <support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/module.h"
-#include "asterisk/json.h"
-#include "stasis_json/resource_bridges.h"
-static int load_module(void)
-{
- return 0;
-}
-
-static int unload_module(void)
-{
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis JSON Generators and Validators - Bridge resources",
- .load = load_module,
- .unload = unload_module,
- .load_pri = AST_MODPRI_DEFAULT,
- );
diff --git a/res/res_stasis_json_bridges.exports.in b/res/res_stasis_json_bridges.exports.in
deleted file mode 100644
index 5e767549c..000000000
--- a/res/res_stasis_json_bridges.exports.in
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- local:
- *;
-};
diff --git a/res/res_stasis_json_channels.c b/res/res_stasis_json_channels.c
deleted file mode 100644
index 3f85736b3..000000000
--- a/res/res_stasis_json_channels.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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_stasis_http_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Channel resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*** MODULEINFO
- <support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/module.h"
-#include "asterisk/json.h"
-#include "stasis_json/resource_channels.h"
-static int load_module(void)
-{
- return 0;
-}
-
-static int unload_module(void)
-{
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis JSON Generators and Validators - Channel resources",
- .load = load_module,
- .unload = unload_module,
- .load_pri = AST_MODPRI_DEFAULT,
- );
diff --git a/res/res_stasis_json_channels.exports.in b/res/res_stasis_json_channels.exports.in
deleted file mode 100644
index 5e767549c..000000000
--- a/res/res_stasis_json_channels.exports.in
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- local:
- *;
-};
diff --git a/res/res_stasis_json_endpoints.c b/res/res_stasis_json_endpoints.c
deleted file mode 100644
index be214e038..000000000
--- a/res/res_stasis_json_endpoints.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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_stasis_http_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Endpoint resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*** MODULEINFO
- <support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/module.h"
-#include "asterisk/json.h"
-#include "stasis_json/resource_endpoints.h"
-static int load_module(void)
-{
- return 0;
-}
-
-static int unload_module(void)
-{
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis JSON Generators and Validators - Endpoint resources",
- .load = load_module,
- .unload = unload_module,
- .load_pri = AST_MODPRI_DEFAULT,
- );
diff --git a/res/res_stasis_json_endpoints.exports.in b/res/res_stasis_json_endpoints.exports.in
deleted file mode 100644
index 5e767549c..000000000
--- a/res/res_stasis_json_endpoints.exports.in
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- local:
- *;
-};
diff --git a/res/res_stasis_json_events.c b/res/res_stasis_json_events.c
deleted file mode 100644
index 4b966e235..000000000
--- a/res/res_stasis_json_events.c
+++ /dev/null
@@ -1,818 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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_stasis_http_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief WebSocket resource
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*** MODULEINFO
- <support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/module.h"
-#include "asterisk/json.h"
-#include "stasis_json/resource_events.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_bridging.h"
-
-struct ast_json *stasis_json_event_channel_userevent_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- struct ast_json *validator;
- int ret;
-
- ast_assert(channel_snapshot != NULL);
- ast_assert(blob != NULL);
- ast_assert(ast_json_object_get(blob, "channel") == NULL);
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-
- validator = ast_json_object_get(blob, "eventname");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- event = ast_json_deep_copy(blob);
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "channel_userevent", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_bridge_created_create(
- struct ast_bridge_snapshot *bridge_snapshot
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- int ret;
-
- ast_assert(bridge_snapshot != NULL);
-
- event = ast_json_object_create();
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "bridge", ast_bridge_snapshot_to_json(bridge_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "bridge_created", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_playback_finished_create(
- struct ast_json *blob
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- struct ast_json *validator;
-
- ast_assert(blob != NULL);
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-
- validator = ast_json_object_get(blob, "playback");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- event = ast_json_deep_copy(blob);
- if (!event) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "playback_finished", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_channel_snapshot_create(
- struct ast_channel_snapshot *channel_snapshot
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- int ret;
-
- ast_assert(channel_snapshot != NULL);
-
- event = ast_json_object_create();
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "channel_snapshot", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_channel_caller_id_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- struct ast_json *validator;
- int ret;
-
- ast_assert(channel_snapshot != NULL);
- ast_assert(blob != NULL);
- ast_assert(ast_json_object_get(blob, "channel") == NULL);
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-
- validator = ast_json_object_get(blob, "caller_presentation_txt");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- validator = ast_json_object_get(blob, "caller_presentation");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- event = ast_json_deep_copy(blob);
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "channel_caller_id", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_playback_started_create(
- struct ast_json *blob
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- struct ast_json *validator;
-
- ast_assert(blob != NULL);
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-
- validator = ast_json_object_get(blob, "playback");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- event = ast_json_deep_copy(blob);
- if (!event) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "playback_started", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_channel_varset_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- struct ast_json *validator;
- int ret;
-
- ast_assert(channel_snapshot != NULL);
- ast_assert(blob != NULL);
- ast_assert(ast_json_object_get(blob, "channel") == NULL);
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-
- validator = ast_json_object_get(blob, "variable");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- validator = ast_json_object_get(blob, "value");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- event = ast_json_deep_copy(blob);
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "channel_varset", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_bridge_destroyed_create(
- struct ast_bridge_snapshot *bridge_snapshot
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- int ret;
-
- ast_assert(bridge_snapshot != NULL);
-
- event = ast_json_object_create();
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "bridge", ast_bridge_snapshot_to_json(bridge_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "bridge_destroyed", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_application_replaced_create(
- struct ast_json *blob
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- struct ast_json *validator;
-
- ast_assert(blob != NULL);
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-
- validator = ast_json_object_get(blob, "application");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- event = ast_json_deep_copy(blob);
- if (!event) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "application_replaced", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_channel_destroyed_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- struct ast_json *validator;
- int ret;
-
- ast_assert(channel_snapshot != NULL);
- ast_assert(blob != NULL);
- ast_assert(ast_json_object_get(blob, "channel") == NULL);
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-
- validator = ast_json_object_get(blob, "cause");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- validator = ast_json_object_get(blob, "cause_txt");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- event = ast_json_deep_copy(blob);
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "channel_destroyed", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_bridge_merged_create(
- struct ast_bridge_snapshot *bridge_snapshot,
- struct ast_json *blob
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- struct ast_json *validator;
- int ret;
-
- ast_assert(bridge_snapshot != NULL);
- ast_assert(blob != NULL);
- ast_assert(ast_json_object_get(blob, "bridge") == NULL);
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-
- validator = ast_json_object_get(blob, "bridge_from");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- event = ast_json_deep_copy(blob);
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "bridge", ast_bridge_snapshot_to_json(bridge_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "bridge_merged", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_channel_left_bridge_create(
- struct ast_bridge_snapshot *bridge_snapshot,
- struct ast_channel_snapshot *channel_snapshot
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- int ret;
-
- ast_assert(channel_snapshot != NULL);
- ast_assert(bridge_snapshot != NULL);
-
- event = ast_json_object_create();
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "bridge", ast_bridge_snapshot_to_json(bridge_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "channel_left_bridge", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_channel_created_create(
- struct ast_channel_snapshot *channel_snapshot
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- int ret;
-
- ast_assert(channel_snapshot != NULL);
-
- event = ast_json_object_create();
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "channel_created", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_stasis_start_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- struct ast_json *validator;
- int ret;
-
- ast_assert(channel_snapshot != NULL);
- ast_assert(blob != NULL);
- ast_assert(ast_json_object_get(blob, "channel") == NULL);
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-
- validator = ast_json_object_get(blob, "args");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- event = ast_json_deep_copy(blob);
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "stasis_start", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_channel_dialplan_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- struct ast_json *validator;
- int ret;
-
- ast_assert(channel_snapshot != NULL);
- ast_assert(blob != NULL);
- ast_assert(ast_json_object_get(blob, "channel") == NULL);
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-
- validator = ast_json_object_get(blob, "application");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- validator = ast_json_object_get(blob, "application_data");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- event = ast_json_deep_copy(blob);
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "channel_dialplan", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_channel_state_change_create(
- struct ast_channel_snapshot *channel_snapshot
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- int ret;
-
- ast_assert(channel_snapshot != NULL);
-
- event = ast_json_object_create();
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "channel_state_change", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_channel_hangup_request_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- struct ast_json *validator;
- int ret;
-
- ast_assert(channel_snapshot != NULL);
- ast_assert(blob != NULL);
- ast_assert(ast_json_object_get(blob, "channel") == NULL);
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-
- validator = ast_json_object_get(blob, "soft");
- if (validator) {
- /* do validation? XXX */
- }
-
- validator = ast_json_object_get(blob, "cause");
- if (validator) {
- /* do validation? XXX */
- }
-
- event = ast_json_deep_copy(blob);
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "channel_hangup_request", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_channel_entered_bridge_create(
- struct ast_bridge_snapshot *bridge_snapshot,
- struct ast_channel_snapshot *channel_snapshot
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- int ret;
-
- ast_assert(channel_snapshot != NULL);
- ast_assert(bridge_snapshot != NULL);
-
- event = ast_json_object_create();
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "bridge", ast_bridge_snapshot_to_json(bridge_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "channel_entered_bridge", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_channel_dtmf_received_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- struct ast_json *validator;
- int ret;
-
- ast_assert(channel_snapshot != NULL);
- ast_assert(blob != NULL);
- ast_assert(ast_json_object_get(blob, "channel") == NULL);
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-
- validator = ast_json_object_get(blob, "digit");
- if (validator) {
- /* do validation? XXX */
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
- }
-
- event = ast_json_deep_copy(blob);
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "channel_dtmf_received", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-struct ast_json *stasis_json_event_stasis_end_create(
- struct ast_channel_snapshot *channel_snapshot
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
- int ret;
-
- ast_assert(channel_snapshot != NULL);
-
- event = ast_json_object_create();
- if (!event) {
- return NULL;
- }
-
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
- message = ast_json_pack("{s: o}", "stasis_end", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-static int load_module(void)
-{
- return 0;
-}
-
-static int unload_module(void)
-{
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis JSON Generators and Validators - WebSocket resource",
- .load = load_module,
- .unload = unload_module,
- .load_pri = AST_MODPRI_DEFAULT,
- );
diff --git a/res/res_stasis_json_events.exports.in b/res/res_stasis_json_events.exports.in
deleted file mode 100644
index 5865c026b..000000000
--- a/res/res_stasis_json_events.exports.in
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- global:
- LINKER_SYMBOL_PREFIXstasis_json_event_channel_userevent_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_bridge_created_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_playback_finished_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_channel_snapshot_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_channel_caller_id_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_playback_started_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_channel_varset_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_bridge_destroyed_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_application_replaced_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_channel_destroyed_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_bridge_merged_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_channel_left_bridge_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_channel_created_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_stasis_start_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_channel_dialplan_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_channel_state_change_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_channel_hangup_request_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_channel_entered_bridge_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_channel_dtmf_received_create;
- LINKER_SYMBOL_PREFIXstasis_json_event_stasis_end_create;
- local:
- *;
-};
diff --git a/res/res_stasis_json_playback.c b/res/res_stasis_json_playback.c
deleted file mode 100644
index 16218c92d..000000000
--- a/res/res_stasis_json_playback.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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_stasis_http_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Playback control resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*** MODULEINFO
- <support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/module.h"
-#include "asterisk/json.h"
-#include "stasis_json/resource_playback.h"
-static int load_module(void)
-{
- return 0;
-}
-
-static int unload_module(void)
-{
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis JSON Generators and Validators - Playback control resources",
- .load = load_module,
- .unload = unload_module,
- .load_pri = AST_MODPRI_DEFAULT,
- );
diff --git a/res/res_stasis_json_playback.exports.in b/res/res_stasis_json_playback.exports.in
deleted file mode 100644
index 5e767549c..000000000
--- a/res/res_stasis_json_playback.exports.in
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- local:
- *;
-};
diff --git a/res/res_stasis_json_recordings.c b/res/res_stasis_json_recordings.c
deleted file mode 100644
index 73935dede..000000000
--- a/res/res_stasis_json_recordings.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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_stasis_http_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Recording resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*** MODULEINFO
- <support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/module.h"
-#include "asterisk/json.h"
-#include "stasis_json/resource_recordings.h"
-static int load_module(void)
-{
- return 0;
-}
-
-static int unload_module(void)
-{
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis JSON Generators and Validators - Recording resources",
- .load = load_module,
- .unload = unload_module,
- .load_pri = AST_MODPRI_DEFAULT,
- );
diff --git a/res/res_stasis_json_recordings.exports.in b/res/res_stasis_json_recordings.exports.in
deleted file mode 100644
index 5e767549c..000000000
--- a/res/res_stasis_json_recordings.exports.in
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- local:
- *;
-};
diff --git a/res/res_stasis_json_sounds.c b/res/res_stasis_json_sounds.c
deleted file mode 100644
index cc6d5ae17..000000000
--- a/res/res_stasis_json_sounds.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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_stasis_http_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Sound resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*** MODULEINFO
- <support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/module.h"
-#include "asterisk/json.h"
-#include "stasis_json/resource_sounds.h"
-static int load_module(void)
-{
- return 0;
-}
-
-static int unload_module(void)
-{
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis JSON Generators and Validators - Sound resources",
- .load = load_module,
- .unload = unload_module,
- .load_pri = AST_MODPRI_DEFAULT,
- );
diff --git a/res/res_stasis_json_sounds.exports.in b/res/res_stasis_json_sounds.exports.in
deleted file mode 100644
index 5e767549c..000000000
--- a/res/res_stasis_json_sounds.exports.in
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- local:
- *;
-};
diff --git a/res/stasis_http/ari_model_validators.c b/res/stasis_http/ari_model_validators.c
new file mode 100644
index 000000000..b41c15473
--- /dev/null
+++ b/res/stasis_http/ari_model_validators.c
@@ -0,0 +1,2567 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * 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 - Build validators for ARI model objects.
+ */
+
+ /*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! DO NOT EDIT !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_model_validators.h.mustache
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/logger.h"
+#include "asterisk/module.h"
+#include "ari_model_validators.h"
+
+int ari_validate_asterisk_info(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ {
+ ast_log(LOG_ERROR,
+ "ARI AsteriskInfo has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ return res;
+}
+
+int ari_validate_endpoint(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_channel_ids = 0;
+ int has_resource = 0;
+ int has_technology = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("channel_ids", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel_ids = 1;
+ prop_is_valid = ari_validate_list(
+ ast_json_object_iter_value(iter),
+ ari_validate_string);
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Endpoint field channel_ids failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("resource", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_resource = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Endpoint field resource failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("state", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Endpoint field state failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("technology", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_technology = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Endpoint field technology failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Endpoint has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_channel_ids) {
+ ast_log(LOG_ERROR, "ARI Endpoint missing required field channel_ids\n");
+ res = 0;
+ }
+
+ if (!has_resource) {
+ ast_log(LOG_ERROR, "ARI Endpoint missing required field resource\n");
+ res = 0;
+ }
+
+ if (!has_technology) {
+ ast_log(LOG_ERROR, "ARI Endpoint missing required field technology\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_caller_id(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_name = 0;
+ int has_number = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_name = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI CallerID field name failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("number", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_number = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI CallerID field number failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI CallerID has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_name) {
+ ast_log(LOG_ERROR, "ARI CallerID missing required field name\n");
+ res = 0;
+ }
+
+ if (!has_number) {
+ ast_log(LOG_ERROR, "ARI CallerID missing required field number\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_channel(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_accountcode = 0;
+ int has_caller = 0;
+ int has_connected = 0;
+ int has_creationtime = 0;
+ int has_dialplan = 0;
+ int has_id = 0;
+ int has_name = 0;
+ int has_state = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("accountcode", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_accountcode = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field accountcode failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("caller", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_caller = 1;
+ prop_is_valid = ari_validate_caller_id(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field caller failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("connected", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_connected = 1;
+ prop_is_valid = ari_validate_caller_id(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field connected failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("creationtime", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_creationtime = 1;
+ prop_is_valid = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field creationtime failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("dialplan", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_dialplan = 1;
+ prop_is_valid = ari_validate_dialplan_cep(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field dialplan failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_id = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field id 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 = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field name failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("state", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_state = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field state failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Channel has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_accountcode) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field accountcode\n");
+ res = 0;
+ }
+
+ if (!has_caller) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field caller\n");
+ res = 0;
+ }
+
+ if (!has_connected) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field connected\n");
+ res = 0;
+ }
+
+ if (!has_creationtime) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field creationtime\n");
+ res = 0;
+ }
+
+ if (!has_dialplan) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field dialplan\n");
+ res = 0;
+ }
+
+ if (!has_id) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field id\n");
+ res = 0;
+ }
+
+ if (!has_name) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field name\n");
+ res = 0;
+ }
+
+ if (!has_state) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field state\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_dialed(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ {
+ ast_log(LOG_ERROR,
+ "ARI Dialed has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ return res;
+}
+
+int ari_validate_dialplan_cep(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_context = 0;
+ int has_exten = 0;
+ int has_priority = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("context", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_context = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI DialplanCEP field context failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("exten", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_exten = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI DialplanCEP field exten failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("priority", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_priority = 1;
+ prop_is_valid = ari_validate_long(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI DialplanCEP field priority failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI DialplanCEP has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_context) {
+ ast_log(LOG_ERROR, "ARI DialplanCEP missing required field context\n");
+ res = 0;
+ }
+
+ if (!has_exten) {
+ ast_log(LOG_ERROR, "ARI DialplanCEP missing required field exten\n");
+ res = 0;
+ }
+
+ if (!has_priority) {
+ ast_log(LOG_ERROR, "ARI DialplanCEP missing required field priority\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_bridge(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_bridge_class = 0;
+ int has_bridge_type = 0;
+ int has_channels = 0;
+ int has_id = 0;
+ int has_technology = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("bridge_class", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge_class = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Bridge field bridge_class failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge_type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Bridge field bridge_type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channels", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channels = 1;
+ prop_is_valid = ari_validate_list(
+ ast_json_object_iter_value(iter),
+ ari_validate_string);
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Bridge field channels failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_id = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Bridge field id failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("technology", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_technology = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Bridge field technology failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Bridge has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_bridge_class) {
+ ast_log(LOG_ERROR, "ARI Bridge missing required field bridge_class\n");
+ res = 0;
+ }
+
+ if (!has_bridge_type) {
+ ast_log(LOG_ERROR, "ARI Bridge missing required field bridge_type\n");
+ res = 0;
+ }
+
+ if (!has_channels) {
+ ast_log(LOG_ERROR, "ARI Bridge missing required field channels\n");
+ res = 0;
+ }
+
+ if (!has_id) {
+ ast_log(LOG_ERROR, "ARI Bridge missing required field id\n");
+ res = 0;
+ }
+
+ if (!has_technology) {
+ ast_log(LOG_ERROR, "ARI Bridge missing required field technology\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_live_recording(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_id = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_id = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI LiveRecording field id failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI LiveRecording has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_id) {
+ ast_log(LOG_ERROR, "ARI LiveRecording missing required field id\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_stored_recording(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_formats = 0;
+ int has_id = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("duration_seconds", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ari_validate_int(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StoredRecording field duration_seconds failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("formats", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_formats = 1;
+ prop_is_valid = ari_validate_list(
+ ast_json_object_iter_value(iter),
+ ari_validate_string);
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StoredRecording field formats failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_id = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StoredRecording field id failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("time", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StoredRecording field time failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI StoredRecording has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_formats) {
+ ast_log(LOG_ERROR, "ARI StoredRecording missing required field formats\n");
+ res = 0;
+ }
+
+ if (!has_id) {
+ ast_log(LOG_ERROR, "ARI StoredRecording missing required field id\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_format_lang_pair(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_format = 0;
+ int has_language = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("format", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_format = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI FormatLangPair field format failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("language", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_language = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI FormatLangPair field language failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI FormatLangPair has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_format) {
+ ast_log(LOG_ERROR, "ARI FormatLangPair missing required field format\n");
+ res = 0;
+ }
+
+ if (!has_language) {
+ ast_log(LOG_ERROR, "ARI FormatLangPair missing required field language\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_sound(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_formats = 0;
+ int has_id = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("formats", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_formats = 1;
+ prop_is_valid = ari_validate_list(
+ ast_json_object_iter_value(iter),
+ ari_validate_format_lang_pair);
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Sound field formats failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_id = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Sound field id failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("text", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Sound field text failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Sound has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_formats) {
+ ast_log(LOG_ERROR, "ARI Sound missing required field formats\n");
+ res = 0;
+ }
+
+ if (!has_id) {
+ ast_log(LOG_ERROR, "ARI Sound missing required field id\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_playback(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_id = 0;
+ int has_media_uri = 0;
+ int has_state = 0;
+ int has_target_uri = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_id = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Playback field id failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("language", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Playback field language failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("media_uri", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_media_uri = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Playback field media_uri failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("state", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_state = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Playback field state failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("target_uri", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_target_uri = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Playback field target_uri failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Playback has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_id) {
+ ast_log(LOG_ERROR, "ARI Playback missing required field id\n");
+ res = 0;
+ }
+
+ if (!has_media_uri) {
+ ast_log(LOG_ERROR, "ARI Playback missing required field media_uri\n");
+ res = 0;
+ }
+
+ if (!has_state) {
+ ast_log(LOG_ERROR, "ARI Playback missing required field state\n");
+ res = 0;
+ }
+
+ if (!has_target_uri) {
+ ast_log(LOG_ERROR, "ARI Playback missing required field target_uri\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_application_replaced(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ApplicationReplaced 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ApplicationReplaced field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ApplicationReplaced field type failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ApplicationReplaced has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ApplicationReplaced missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ApplicationReplaced missing required field type\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_bridge_created(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_bridge = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge = 1;
+ prop_is_valid = ari_validate_bridge(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated field bridge failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI BridgeCreated has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_bridge) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated missing required field bridge\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_bridge_destroyed(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_bridge = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge = 1;
+ prop_is_valid = ari_validate_bridge(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed field bridge failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI BridgeDestroyed has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_bridge) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed missing required field bridge\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_bridge_merged(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_bridge = 0;
+ int has_bridge_from = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge = 1;
+ prop_is_valid = ari_validate_bridge(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged field bridge failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge_from", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge_from = 1;
+ prop_is_valid = ari_validate_bridge(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged field bridge_from failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI BridgeMerged has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_bridge) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged missing required field bridge\n");
+ res = 0;
+ }
+
+ if (!has_bridge_from) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged missing required field bridge_from\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_channel_caller_id(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_caller_presentation = 0;
+ int has_caller_presentation_txt = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("caller_presentation", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_caller_presentation = 1;
+ prop_is_valid = ari_validate_int(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId field caller_presentation failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("caller_presentation_txt", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_caller_presentation_txt = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId field caller_presentation_txt failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelCallerId has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_caller_presentation) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field caller_presentation\n");
+ res = 0;
+ }
+
+ if (!has_caller_presentation_txt) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field caller_presentation_txt\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_channel_created(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelCreated has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_channel_destroyed(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_cause = 0;
+ int has_cause_txt = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("cause", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_cause = 1;
+ prop_is_valid = ari_validate_int(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed field cause failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("cause_txt", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_cause_txt = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed field cause_txt failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelDestroyed has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_cause) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field cause\n");
+ res = 0;
+ }
+
+ if (!has_cause_txt) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field cause_txt\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_channel_dialplan(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_channel = 0;
+ int has_dialplan_app = 0;
+ int has_dialplan_app_data = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("dialplan_app", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_dialplan_app = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan field dialplan_app failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("dialplan_app_data", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_dialplan_app_data = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan field dialplan_app_data failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelDialplan has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field channel\n");
+ res = 0;
+ }
+
+ if (!has_dialplan_app) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field dialplan_app\n");
+ res = 0;
+ }
+
+ if (!has_dialplan_app_data) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field dialplan_app_data\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_channel_dtmf_received(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_channel = 0;
+ int has_digit = 0;
+ int has_duration_ms = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("digit", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_digit = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field digit failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("duration_ms", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_duration_ms = 1;
+ prop_is_valid = ari_validate_int(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field duration_ms failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelDtmfReceived has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field channel\n");
+ res = 0;
+ }
+
+ if (!has_digit) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field digit\n");
+ res = 0;
+ }
+
+ if (!has_duration_ms) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field duration_ms\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_channel_entered_bridge(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_bridge = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge = 1;
+ prop_is_valid = ari_validate_bridge(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field bridge failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelEnteredBridge has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_bridge) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge missing required field bridge\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_channel_hangup_request(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("cause", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ari_validate_int(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest field cause failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("soft", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ari_validate_boolean(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest field soft failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelHangupRequest has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_channel_left_bridge(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_bridge = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge = 1;
+ prop_is_valid = ari_validate_bridge(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge field bridge failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelLeftBridge has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_bridge) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge missing required field bridge\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_channel_state_change(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelStateChange has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_channel_userevent(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_channel = 0;
+ int has_eventname = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("eventname", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_eventname = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent field eventname failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelUserevent has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field channel\n");
+ res = 0;
+ }
+
+ if (!has_eventname) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field eventname\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_channel_varset(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_value = 0;
+ int has_variable = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("value", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_value = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset field value failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("variable", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_variable = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset field variable failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelVarset has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_value) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset missing required field value\n");
+ res = 0;
+ }
+
+ if (!has_variable) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset missing required field variable\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_event(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ const char *discriminator;
+
+ discriminator = ast_json_string_get(ast_json_object_get(json, "type"));
+ if (!discriminator) {
+ ast_log(LOG_ERROR, "ARI Event missing required field type");
+ return 0;
+ }
+
+ if (strcmp("Event", discriminator) == 0) {
+ /* Self type; fall through */
+ } else
+ if (strcmp("ApplicationReplaced", discriminator) == 0) {
+ return ari_validate_application_replaced(json);
+ } else
+ if (strcmp("BridgeCreated", discriminator) == 0) {
+ return ari_validate_bridge_created(json);
+ } else
+ if (strcmp("BridgeDestroyed", discriminator) == 0) {
+ return ari_validate_bridge_destroyed(json);
+ } else
+ if (strcmp("BridgeMerged", discriminator) == 0) {
+ return ari_validate_bridge_merged(json);
+ } else
+ if (strcmp("ChannelCallerId", discriminator) == 0) {
+ return ari_validate_channel_caller_id(json);
+ } else
+ if (strcmp("ChannelCreated", discriminator) == 0) {
+ return ari_validate_channel_created(json);
+ } else
+ if (strcmp("ChannelDestroyed", discriminator) == 0) {
+ return ari_validate_channel_destroyed(json);
+ } else
+ if (strcmp("ChannelDialplan", discriminator) == 0) {
+ return ari_validate_channel_dialplan(json);
+ } else
+ if (strcmp("ChannelDtmfReceived", discriminator) == 0) {
+ return ari_validate_channel_dtmf_received(json);
+ } else
+ if (strcmp("ChannelEnteredBridge", discriminator) == 0) {
+ return ari_validate_channel_entered_bridge(json);
+ } else
+ if (strcmp("ChannelHangupRequest", discriminator) == 0) {
+ return ari_validate_channel_hangup_request(json);
+ } else
+ if (strcmp("ChannelLeftBridge", discriminator) == 0) {
+ return ari_validate_channel_left_bridge(json);
+ } else
+ if (strcmp("ChannelStateChange", discriminator) == 0) {
+ return ari_validate_channel_state_change(json);
+ } else
+ if (strcmp("ChannelUserevent", discriminator) == 0) {
+ return ari_validate_channel_userevent(json);
+ } else
+ if (strcmp("ChannelVarset", discriminator) == 0) {
+ return ari_validate_channel_varset(json);
+ } else
+ if (strcmp("PlaybackFinished", discriminator) == 0) {
+ return ari_validate_playback_finished(json);
+ } else
+ if (strcmp("PlaybackStarted", discriminator) == 0) {
+ return ari_validate_playback_started(json);
+ } else
+ if (strcmp("StasisEnd", discriminator) == 0) {
+ return ari_validate_stasis_end(json);
+ } else
+ if (strcmp("StasisStart", discriminator) == 0) {
+ return ari_validate_stasis_start(json);
+ } else
+ {
+ ast_log(LOG_ERROR, "ARI Event has undocumented subtype %s\n",
+ discriminator);
+ res = 0;
+ }
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Event 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Event field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Event field type failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Event has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI Event missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI Event missing required field type\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_playback_finished(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_playback = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("playback", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_playback = 1;
+ prop_is_valid = ari_validate_playback(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished field playback failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI PlaybackFinished has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_playback) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished missing required field playback\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_playback_started(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_playback = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("playback", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_playback = 1;
+ prop_is_valid = ari_validate_playback(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted field playback failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI PlaybackStarted has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_playback) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted missing required field playback\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_stasis_end(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisEnd 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisEnd field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisEnd field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisEnd field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI StasisEnd has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI StasisEnd missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI StasisEnd missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI StasisEnd missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+int ari_validate_stasis_start(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_application = 0;
+ int has_type = 0;
+ int has_args = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisStart 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 = ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisStart field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisStart field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("args", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_args = 1;
+ prop_is_valid = ari_validate_list(
+ ast_json_object_iter_value(iter),
+ ari_validate_string);
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisStart field args failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisStart field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI StasisStart has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI StasisStart missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI StasisStart missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_args) {
+ ast_log(LOG_ERROR, "ARI StasisStart missing required field args\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI StasisStart missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
diff --git a/res/stasis_http/ari_model_validators.h b/res/stasis_http/ari_model_validators.h
new file mode 100644
index 000000000..c4d0f27c2
--- /dev/null
+++ b/res/stasis_http/ari_model_validators.h
@@ -0,0 +1,659 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * 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 - Build validators for ARI model objects.
+ */
+
+ /*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! DO NOT EDIT !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_model_validators.h.mustache
+ */
+
+#ifndef _ASTERISK_ARI_MODEL_H
+#define _ASTERISK_ARI_MODEL_H
+
+#include "asterisk/json.h"
+
+/*! @{ */
+
+/*!
+ * \brief Validator for native Swagger void.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_void(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger byte.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_byte(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger boolean.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_boolean(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger int.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_int(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger long.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_long(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger float.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_float(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger double.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_double(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger string.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_string(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger date.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_date(struct ast_json *json);
+
+/*!
+ * \brief Validator for a Swagger List[]/JSON array.
+ *
+ * \param json JSON object to validate.
+ * \param fn Validator to call on every element in the array.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_list(struct ast_json *json, int (*fn)(struct ast_json *));
+
+/*! @} */
+
+/*!
+ * \brief Validator for AsteriskInfo.
+ *
+ * Asterisk system information
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_asterisk_info(struct ast_json *json);
+
+/*!
+ * \brief Validator for Endpoint.
+ *
+ * An external device that may offer/accept calls to/from Asterisk.
+ *
+ * Unlike most resources, which have a single unique identifier, an endpoint is uniquely identified by the technology/resource pair.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_endpoint(struct ast_json *json);
+
+/*!
+ * \brief Validator for CallerID.
+ *
+ * Caller identification
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_caller_id(struct ast_json *json);
+
+/*!
+ * \brief Validator for Channel.
+ *
+ * A specific communication connection between Asterisk and an Endpoint.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_channel(struct ast_json *json);
+
+/*!
+ * \brief Validator for Dialed.
+ *
+ * Dialed channel information.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_dialed(struct ast_json *json);
+
+/*!
+ * \brief Validator for DialplanCEP.
+ *
+ * Dialplan location (context/extension/priority)
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_dialplan_cep(struct ast_json *json);
+
+/*!
+ * \brief Validator for Bridge.
+ *
+ * The merging of media from one or more channels.
+ *
+ * Everyone on the bridge receives the same audio.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_bridge(struct ast_json *json);
+
+/*!
+ * \brief Validator for LiveRecording.
+ *
+ * A recording that is in progress
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_live_recording(struct ast_json *json);
+
+/*!
+ * \brief Validator for StoredRecording.
+ *
+ * A past recording that may be played back.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_stored_recording(struct ast_json *json);
+
+/*!
+ * \brief Validator for FormatLangPair.
+ *
+ * Identifies the format and language of a sound file
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_format_lang_pair(struct ast_json *json);
+
+/*!
+ * \brief Validator for Sound.
+ *
+ * A media file that may be played back.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_sound(struct ast_json *json);
+
+/*!
+ * \brief Validator for Playback.
+ *
+ * Object representing the playback of media to a channel
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_playback(struct ast_json *json);
+
+/*!
+ * \brief Validator for ApplicationReplaced.
+ *
+ * Notification that another WebSocket has taken over for an application.
+ *
+ * An application may only be subscribed to by a single WebSocket at a time. If multiple WebSockets attempt to subscribe to the same application, the newer WebSocket wins, and the older one receives this event.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_application_replaced(struct ast_json *json);
+
+/*!
+ * \brief Validator for BridgeCreated.
+ *
+ * Notification that a bridge has been created.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_bridge_created(struct ast_json *json);
+
+/*!
+ * \brief Validator for BridgeDestroyed.
+ *
+ * Notification that a bridge has been destroyed.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_bridge_destroyed(struct ast_json *json);
+
+/*!
+ * \brief Validator for BridgeMerged.
+ *
+ * Notification that one bridge has merged into another.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_bridge_merged(struct ast_json *json);
+
+/*!
+ * \brief Validator for ChannelCallerId.
+ *
+ * Channel changed Caller ID.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_channel_caller_id(struct ast_json *json);
+
+/*!
+ * \brief Validator for ChannelCreated.
+ *
+ * Notification that a channel has been created.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_channel_created(struct ast_json *json);
+
+/*!
+ * \brief Validator for ChannelDestroyed.
+ *
+ * Notification that a channel has been destroyed.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_channel_destroyed(struct ast_json *json);
+
+/*!
+ * \brief Validator for ChannelDialplan.
+ *
+ * Channel changed location in the dialplan.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_channel_dialplan(struct ast_json *json);
+
+/*!
+ * \brief Validator for ChannelDtmfReceived.
+ *
+ * DTMF received on a channel.
+ *
+ * This event is sent when the DTMF ends. There is no notification about the start of DTMF
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_channel_dtmf_received(struct ast_json *json);
+
+/*!
+ * \brief Validator for ChannelEnteredBridge.
+ *
+ * Notification that a channel has entered a bridge.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_channel_entered_bridge(struct ast_json *json);
+
+/*!
+ * \brief Validator for ChannelHangupRequest.
+ *
+ * A hangup was requested on the channel.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_channel_hangup_request(struct ast_json *json);
+
+/*!
+ * \brief Validator for ChannelLeftBridge.
+ *
+ * Notification that a channel has left a bridge.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_channel_left_bridge(struct ast_json *json);
+
+/*!
+ * \brief Validator for ChannelStateChange.
+ *
+ * Notification of a channel's state change.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_channel_state_change(struct ast_json *json);
+
+/*!
+ * \brief Validator for ChannelUserevent.
+ *
+ * User-generated event with additional user-defined fields in the object.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_channel_userevent(struct ast_json *json);
+
+/*!
+ * \brief Validator for ChannelVarset.
+ *
+ * Channel variable changed.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_channel_varset(struct ast_json *json);
+
+/*!
+ * \brief Validator for Event.
+ *
+ * Base type for asynchronous events from Asterisk.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_event(struct ast_json *json);
+
+/*!
+ * \brief Validator for PlaybackFinished.
+ *
+ * Event showing the completion of a media playback operation.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_playback_finished(struct ast_json *json);
+
+/*!
+ * \brief Validator for PlaybackStarted.
+ *
+ * Event showing the start of a media playback operation.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_playback_started(struct ast_json *json);
+
+/*!
+ * \brief Validator for StasisEnd.
+ *
+ * Notification that a channel has left a Stasis appliction.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_stasis_end(struct ast_json *json);
+
+/*!
+ * \brief Validator for StasisStart.
+ *
+ * Notification that a channel has entered a Stasis appliction.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_stasis_start(struct ast_json *json);
+
+/*
+ * JSON models
+ *
+ * AsteriskInfo
+ * Endpoint
+ * - channel_ids: List[string] (required)
+ * - resource: string (required)
+ * - state: string
+ * - technology: string (required)
+ * CallerID
+ * - name: string (required)
+ * - number: string (required)
+ * Channel
+ * - accountcode: string (required)
+ * - caller: CallerID (required)
+ * - connected: CallerID (required)
+ * - creationtime: Date (required)
+ * - dialplan: DialplanCEP (required)
+ * - id: string (required)
+ * - name: string (required)
+ * - state: string (required)
+ * Dialed
+ * DialplanCEP
+ * - context: string (required)
+ * - exten: string (required)
+ * - priority: long (required)
+ * Bridge
+ * - bridge_class: string (required)
+ * - bridge_type: string (required)
+ * - channels: List[string] (required)
+ * - id: string (required)
+ * - technology: string (required)
+ * LiveRecording
+ * - id: string (required)
+ * StoredRecording
+ * - duration_seconds: int
+ * - formats: List[string] (required)
+ * - id: string (required)
+ * - time: Date
+ * FormatLangPair
+ * - format: string (required)
+ * - language: string (required)
+ * Sound
+ * - formats: List[FormatLangPair] (required)
+ * - id: string (required)
+ * - text: string
+ * Playback
+ * - id: string (required)
+ * - language: string
+ * - media_uri: string (required)
+ * - state: string (required)
+ * - target_uri: string (required)
+ * ApplicationReplaced
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * BridgeCreated
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - bridge: Bridge (required)
+ * BridgeDestroyed
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - bridge: Bridge (required)
+ * BridgeMerged
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - bridge: Bridge (required)
+ * - bridge_from: Bridge (required)
+ * ChannelCallerId
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - caller_presentation: int (required)
+ * - caller_presentation_txt: string (required)
+ * - channel: Channel (required)
+ * ChannelCreated
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - channel: Channel (required)
+ * ChannelDestroyed
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - cause: int (required)
+ * - cause_txt: string (required)
+ * - channel: Channel (required)
+ * ChannelDialplan
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - channel: Channel (required)
+ * - dialplan_app: string (required)
+ * - dialplan_app_data: string (required)
+ * ChannelDtmfReceived
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - channel: Channel (required)
+ * - digit: string (required)
+ * - duration_ms: int (required)
+ * ChannelEnteredBridge
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - bridge: Bridge (required)
+ * - channel: Channel
+ * ChannelHangupRequest
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - cause: int
+ * - channel: Channel (required)
+ * - soft: boolean
+ * ChannelLeftBridge
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - bridge: Bridge (required)
+ * - channel: Channel (required)
+ * ChannelStateChange
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - channel: Channel (required)
+ * ChannelUserevent
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - channel: Channel (required)
+ * - eventname: string (required)
+ * ChannelVarset
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - channel: Channel
+ * - value: string (required)
+ * - variable: string (required)
+ * Event
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * PlaybackFinished
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - playback: Playback (required)
+ * PlaybackStarted
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - playback: Playback (required)
+ * StasisEnd
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - channel: Channel (required)
+ * StasisStart
+ * - application: string (required)
+ * - timestamp: Date
+ * - type: string (required)
+ * - args: List[string] (required)
+ * - channel: Channel (required)
+ */
+
+#endif /* _ASTERISK_ARI_MODEL_H */
diff --git a/res/stasis_http/ari_websockets.c b/res/stasis_http/ari_websockets.c
index e6b316b57..60a184657 100644
--- a/res/stasis_http/ari_websockets.c
+++ b/res/stasis_http/ari_websockets.c
@@ -31,6 +31,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
struct ari_websocket_session {
struct ast_websocket *ws_session;
+ int (*validator)(struct ast_json *);
};
static void websocket_session_dtor(void *obj)
@@ -41,8 +42,16 @@ static void websocket_session_dtor(void *obj)
session->ws_session = NULL;
}
+/*!
+ * \brief Validator that always succeeds.
+ */
+static int null_validator(struct ast_json *json)
+{
+ return 1;
+}
+
struct ari_websocket_session *ari_websocket_session_create(
- struct ast_websocket *ws_session)
+ struct ast_websocket *ws_session, int (*validator)(struct ast_json *))
{
RAII_VAR(struct ari_websocket_session *, session, NULL, ao2_cleanup);
@@ -50,6 +59,10 @@ struct ari_websocket_session *ari_websocket_session_create(
return NULL;
}
+ if (validator == NULL) {
+ validator = null_validator;
+ }
+
if (ast_websocket_set_nonblock(ws_session) != 0) {
ast_log(LOG_ERROR,
"Stasis web socket failed to set nonblock; closing\n");
@@ -63,6 +76,7 @@ struct ari_websocket_session *ari_websocket_session_create(
ao2_ref(ws_session, +1);
session->ws_session = ws_session;
+ session->validator = validator;
ao2_ref(session, +1);
return session;
@@ -109,10 +123,24 @@ struct ast_json *ari_websocket_session_read(
return ast_json_ref(message);
}
+#define VALIDATION_FAILED \
+ "{ \"error\": \"Outgoing message failed validation\" }"
+
int ari_websocket_session_write(struct ari_websocket_session *session,
struct ast_json *message)
{
- RAII_VAR(char *, str, ast_json_dump_string(message), ast_free);
+ RAII_VAR(char *, str, NULL, ast_free);
+
+#ifdef AST_DEVMODE
+ if (!session->validator(message)) {
+ ast_log(LOG_ERROR, "Outgoing message failed validation\n");
+ return ast_websocket_write(session->ws_session,
+ AST_WEBSOCKET_OPCODE_TEXT, VALIDATION_FAILED,
+ strlen(VALIDATION_FAILED));
+ }
+#endif
+
+ str = ast_json_dump_string_format(message, stasis_http_json_format());
if (str == NULL) {
ast_log(LOG_ERROR, "Failed to encode JSON object\n");
diff --git a/res/stasis_http/resource_recordings.c b/res/stasis_http/resource_recordings.c
index 2400a6876..7d31c42aa 100644
--- a/res/stasis_http/resource_recordings.c
+++ b/res/stasis_http/resource_recordings.c
@@ -29,10 +29,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "resource_recordings.h"
-void stasis_http_get_recordings(struct ast_variable *headers, struct ast_get_recordings_args *args, struct stasis_http_response *response)
-{
- ast_log(LOG_ERROR, "TODO: stasis_http_get_recordings\n");
-}
void stasis_http_get_stored_recordings(struct ast_variable *headers, struct ast_get_stored_recordings_args *args, struct stasis_http_response *response)
{
ast_log(LOG_ERROR, "TODO: stasis_http_get_stored_recordings\n");
diff --git a/res/stasis_http/resource_recordings.h b/res/stasis_http/resource_recordings.h
index ee48e43b7..acccc124b 100644
--- a/res/stasis_http/resource_recordings.h
+++ b/res/stasis_http/resource_recordings.h
@@ -39,17 +39,6 @@
#include "asterisk/stasis_http.h"
-/*! \brief Argument struct for stasis_http_get_recordings() */
-struct ast_get_recordings_args {
-};
-/*!
- * \brief List all recordings.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void stasis_http_get_recordings(struct ast_variable *headers, struct ast_get_recordings_args *args, struct stasis_http_response *response);
/*! \brief Argument struct for stasis_http_get_stored_recordings() */
struct ast_get_stored_recordings_args {
};
diff --git a/res/stasis_json/resource_asterisk.h b/res/stasis_json/resource_asterisk.h
deleted file mode 100644
index 5a717d005..000000000
--- a/res/stasis_json/resource_asterisk.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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/stasis_json/resource_asterisk.c
- *
- * Asterisk resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!! DO NOT EDIT !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/stasis_http_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_ASTERISK_H
-#define _ASTERISK_RESOURCE_ASTERISK_H
-
-/*
- * JSON models
- *
- * AsteriskInfo
- */
-
-#endif /* _ASTERISK_RESOURCE_ASTERISK_H */
diff --git a/res/stasis_json/resource_bridges.h b/res/stasis_json/resource_bridges.h
deleted file mode 100644
index cf2d03dc7..000000000
--- a/res/stasis_json/resource_bridges.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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/stasis_json/resource_bridges.c
- *
- * Bridge resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!! DO NOT EDIT !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/stasis_http_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_BRIDGES_H
-#define _ASTERISK_RESOURCE_BRIDGES_H
-
-/*
- * JSON models
- *
- * Bridge
- * - channels: List[string] (required)
- * - bridgeType: string (required)
- */
-
-#endif /* _ASTERISK_RESOURCE_BRIDGES_H */
diff --git a/res/stasis_json/resource_channels.h b/res/stasis_json/resource_channels.h
deleted file mode 100644
index c98743c36..000000000
--- a/res/stasis_json/resource_channels.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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/stasis_json/resource_channels.c
- *
- * Channel resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!! DO NOT EDIT !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/stasis_http_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_CHANNELS_H
-#define _ASTERISK_RESOURCE_CHANNELS_H
-
-/*
- * JSON models
- *
- * DialplanCEP
- * - priority: long (required)
- * - exten: string (required)
- * - context: string (required)
- * Playback
- * - language: string
- * - media_uri: string (required)
- * - id: string (required)
- * - target_uri: string (required)
- * - state: string (required)
- * Channel
- * - accountcode: string (required)
- * - linkedid: string (required)
- * - name: string (required)
- * - userfield: string (required)
- * - caller: CallerID (required)
- * - creationtime: Date (required)
- * - state: string (required)
- * - parkinglot: string (required)
- * - peeraccount: string (required)
- * - appl: string (required)
- * - connected: CallerID (required)
- * - uniqueid: string (required)
- * - hangupsource: string (required)
- * - dialplan: DialplanCEP (required)
- * - data: string (required)
- * CallerID
- * - name: string (required)
- * - number: string (required)
- * Dialed
- */
-
-#endif /* _ASTERISK_RESOURCE_CHANNELS_H */
diff --git a/res/stasis_json/resource_endpoints.h b/res/stasis_json/resource_endpoints.h
deleted file mode 100644
index 7f2e4233c..000000000
--- a/res/stasis_json/resource_endpoints.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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/stasis_json/resource_endpoints.c
- *
- * Endpoint resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!! DO NOT EDIT !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/stasis_http_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_ENDPOINTS_H
-#define _ASTERISK_RESOURCE_ENDPOINTS_H
-
-/*
- * JSON models
- *
- * Endpoint
- * - resource: string (required)
- * - technology: string (required)
- */
-
-#endif /* _ASTERISK_RESOURCE_ENDPOINTS_H */
diff --git a/res/stasis_json/resource_events.h b/res/stasis_json/resource_events.h
deleted file mode 100644
index a2af30daa..000000000
--- a/res/stasis_json/resource_events.h
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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/stasis_json/resource_events.c
- *
- * WebSocket resource
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!! DO NOT EDIT !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/stasis_http_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_EVENTS_H
-#define _ASTERISK_RESOURCE_EVENTS_H
-
-struct ast_channel_snapshot;
-struct ast_bridge_snapshot;
-
-/*!
- * \brief User-generated event with additional user-defined fields in the object.
- *
- * \param channel The channel that signaled the user event.
- * \param blob JSON blob containing the following parameters:
- * - eventname: string - The name of the user event. (required)
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_channel_userevent_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- );
-
-/*!
- * \brief Notification that a bridge has been created.
- *
- * \param bridge The bridge to be used to generate this event
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_bridge_created_create(
- struct ast_bridge_snapshot *bridge_snapshot
- );
-
-/*!
- * \brief Event showing the completion of a media playback operation.
- *
- * \param blob JSON blob containing the following parameters:
- * - playback: Playback - Playback control object (required)
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_playback_finished_create(
- struct ast_json *blob
- );
-
-/*!
- * \brief Some part of channel state changed.
- *
- * \param channel The channel to be used to generate this event
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_channel_snapshot_create(
- struct ast_channel_snapshot *channel_snapshot
- );
-
-/*!
- * \brief Channel changed Caller ID.
- *
- * \param channel The channel that changed Caller ID.
- * \param blob JSON blob containing the following parameters:
- * - caller_presentation_txt: string - The text representation of the Caller Presentation value. (required)
- * - caller_presentation: integer - The integer representation of the Caller Presentation value. (required)
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_channel_caller_id_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- );
-
-/*!
- * \brief Event showing the start of a media playback operation.
- *
- * \param blob JSON blob containing the following parameters:
- * - playback: Playback - Playback control object (required)
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_playback_started_create(
- struct ast_json *blob
- );
-
-/*!
- * \brief Channel variable changed.
- *
- * \param channel The channel on which the variable was set.
- * \param blob JSON blob containing the following parameters:
- * - variable: string - The variable that changed. (required)
- * - value: string - The new value of the variable. (required)
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_channel_varset_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- );
-
-/*!
- * \brief Notification that a bridge has been destroyed.
- *
- * \param bridge The bridge to be used to generate this event
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_bridge_destroyed_create(
- struct ast_bridge_snapshot *bridge_snapshot
- );
-
-/*!
- * \brief Notification that another WebSocket has taken over for an application.
- *
- * \param blob JSON blob containing the following parameters:
- * - application: string (required)
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_application_replaced_create(
- struct ast_json *blob
- );
-
-/*!
- * \brief Notification that a channel has been destroyed.
- *
- * \param channel The channel to be used to generate this event
- * \param blob JSON blob containing the following parameters:
- * - cause: integer - Integer representation of the cause of the hangup (required)
- * - cause_txt: string - Text representation of the cause of the hangup (required)
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_channel_destroyed_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- );
-
-/*!
- * \brief Notification that one bridge has merged into another.
- *
- * \param bridge The bridge to be used to generate this event
- * \param blob JSON blob containing the following parameters:
- * - bridge_from: Bridge (required)
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_bridge_merged_create(
- struct ast_bridge_snapshot *bridge_snapshot,
- struct ast_json *blob
- );
-
-/*!
- * \brief Notification that a channel has left a bridge.
- *
- * \param channel The channel to be used to generate this event
- * \param bridge The bridge to be used to generate this event
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_channel_left_bridge_create(
- struct ast_bridge_snapshot *bridge_snapshot,
- struct ast_channel_snapshot *channel_snapshot
- );
-
-/*!
- * \brief Notification that a channel has been created.
- *
- * \param channel The channel to be used to generate this event
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_channel_created_create(
- struct ast_channel_snapshot *channel_snapshot
- );
-
-/*!
- * \brief Notification that a channel has entered a Stasis appliction.
- *
- * \param channel The channel to be used to generate this event
- * \param blob JSON blob containing the following parameters:
- * - args: List[string] - Arguments to the application (required)
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_stasis_start_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- );
-
-/*!
- * \brief Channel changed location in the dialplan.
- *
- * \param channel The channel that changed dialplan location.
- * \param blob JSON blob containing the following parameters:
- * - application: string - The application that the channel is currently in. (required)
- * - application_data: string - The data that was passed to the application when it was invoked. (required)
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_channel_dialplan_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- );
-
-/*!
- * \brief Notification of a channel's state change.
- *
- * \param channel The channel to be used to generate this event
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_channel_state_change_create(
- struct ast_channel_snapshot *channel_snapshot
- );
-
-/*!
- * \brief A hangup was requested on the channel.
- *
- * \param channel The channel on which the hangup was requested.
- * \param blob JSON blob containing the following parameters:
- * - soft: boolean - Whether the hangup request was a soft hangup request.
- * - cause: integer - Integer representation of the cause of the hangup.
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_channel_hangup_request_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- );
-
-/*!
- * \brief Notification that a channel has entered a bridge.
- *
- * \param channel The channel to be used to generate this event
- * \param bridge The bridge to be used to generate this event
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_channel_entered_bridge_create(
- struct ast_bridge_snapshot *bridge_snapshot,
- struct ast_channel_snapshot *channel_snapshot
- );
-
-/*!
- * \brief DTMF received on a channel.
- *
- * \param channel The channel on which DTMF was received
- * \param blob JSON blob containing the following parameters:
- * - digit: string - DTMF digit received (0-9, A-E, # or *) (required)
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_channel_dtmf_received_create(
- struct ast_channel_snapshot *channel_snapshot,
- struct ast_json *blob
- );
-
-/*!
- * \brief Notification that a channel has left a Stasis appliction.
- *
- * \param channel The channel to be used to generate this event
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-struct ast_json *stasis_json_event_stasis_end_create(
- struct ast_channel_snapshot *channel_snapshot
- );
-
-/*
- * JSON models
- *
- * ChannelUserevent
- * - eventname: string (required)
- * BridgeCreated
- * PlaybackFinished
- * - playback: Playback (required)
- * ChannelSnapshot
- * ChannelCallerId
- * - caller_presentation_txt: string (required)
- * - caller_presentation: integer (required)
- * PlaybackStarted
- * - playback: Playback (required)
- * ChannelVarset
- * - variable: string (required)
- * - value: string (required)
- * BridgeDestroyed
- * ApplicationReplaced
- * - application: string (required)
- * ChannelDestroyed
- * - cause: integer (required)
- * - cause_txt: string (required)
- * BridgeMerged
- * - bridge_from: Bridge (required)
- * ChannelLeftBridge
- * ChannelCreated
- * StasisStart
- * - args: List[string] (required)
- * ChannelDialplan
- * - application: string (required)
- * - application_data: string (required)
- * ChannelStateChange
- * ChannelHangupRequest
- * - soft: boolean
- * - cause: integer
- * ChannelEnteredBridge
- * ChannelDtmfReceived
- * - digit: string (required)
- * Event
- * - channel_varset: ChannelVarset
- * - channel_created: ChannelCreated
- * - channel_destroyed: ChannelDestroyed
- * - channel_entered_bridge: ChannelEnteredBridge
- * - channel_left_bridge: ChannelLeftBridge
- * - bridge_merged: BridgeMerged
- * - channel_dialplan: ChannelDialplan
- * - application_replaced: ApplicationReplaced
- * - channel_state_change: ChannelStateChange
- * - bridge_created: BridgeCreated
- * - application: string (required)
- * - channel_hangup_request: ChannelHangupRequest
- * - channel_userevent: ChannelUserevent
- * - stasis_start: StasisStart
- * - channel_snapshot: ChannelSnapshot
- * - channel_dtmf_received: ChannelDtmfReceived
- * - channel_caller_id: ChannelCallerId
- * - bridge_destroyed: BridgeDestroyed
- * - playback_started: PlaybackStarted
- * - playback_finished: PlaybackFinished
- * - stasis_end: StasisEnd
- * StasisEnd
- */
-
-#endif /* _ASTERISK_RESOURCE_EVENTS_H */
diff --git a/res/stasis_json/resource_playback.h b/res/stasis_json/resource_playback.h
deleted file mode 100644
index e84e6de0d..000000000
--- a/res/stasis_json/resource_playback.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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/stasis_json/resource_playback.c
- *
- * Playback control resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!! DO NOT EDIT !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/stasis_http_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_PLAYBACK_H
-#define _ASTERISK_RESOURCE_PLAYBACK_H
-
-/*
- * JSON models
- *
- * Playback
- * - id: string (required)
- */
-
-#endif /* _ASTERISK_RESOURCE_PLAYBACK_H */
diff --git a/res/stasis_json/resource_recordings.h b/res/stasis_json/resource_recordings.h
deleted file mode 100644
index b460fb769..000000000
--- a/res/stasis_json/resource_recordings.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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/stasis_json/resource_recordings.c
- *
- * Recording resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!! DO NOT EDIT !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/stasis_http_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_RECORDINGS_H
-#define _ASTERISK_RESOURCE_RECORDINGS_H
-
-/*
- * JSON models
- *
- * Recording
- * - id: string (required)
- * StoredRecording
- * - durationSeconds: int
- * - time: Date
- * - id: string (required)
- * - formats: List[string] (required)
- * LiveRecording
- * - id: string (required)
- */
-
-#endif /* _ASTERISK_RESOURCE_RECORDINGS_H */
diff --git a/res/stasis_json/resource_sounds.h b/res/stasis_json/resource_sounds.h
deleted file mode 100644
index d7f8714e6..000000000
--- a/res/stasis_json/resource_sounds.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee@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/stasis_json/resource_sounds.c
- *
- * Sound resources
- *
- * \author David M. Lee, II <dlee@digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!! DO NOT EDIT !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/stasis_http_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_SOUNDS_H
-#define _ASTERISK_RESOURCE_SOUNDS_H
-
-/*
- * JSON models
- *
- * Sound
- * - text: string
- * - id: string (required)
- * - formats: List[FormatLangPair] (required)
- * FormatLangPair
- * - language: string (required)
- * - format: string (required)
- */
-
-#endif /* _ASTERISK_RESOURCE_SOUNDS_H */
diff --git a/rest-api-templates/api.wiki.mustache b/rest-api-templates/api.wiki.mustache
new file mode 100644
index 000000000..c70e58fc3
--- /dev/null
+++ b/rest-api-templates/api.wiki.mustache
@@ -0,0 +1,47 @@
+{{#api_declaration}}
+h1. {{name_title}}
+
+|| Method || Path || Return Model || Summary ||
+{{#apis}}
+{{#operations}}
+| {{http_method}} | [{{wiki_path}}|#{{nickname}}] | {{#response_class}}{{#is_primitive}}{{name}}{{/is_primitive}}{{^is_primitive}}[{{wiki_name}}|{{wiki_prefix}} REST Data Models#{{singular_name}}]{{/is_primitive}}{{/response_class}} | {{summary}} |
+{{/operations}}
+{{/apis}}
+{{#apis}}
+{{#operations}}
+
+{anchor:{{nickname}}}
+h2. {{http_method}} {{wiki_path}}
+
+{{{summary}}}{{#notes}} {{{notes}}}{{/notes}}
+{{#has_path_parameters}}
+
+h3. Path parameters
+{{#path_parameters}}
+* {{name}}: {{data_type}}{{#default_value}} = {{default_value}}{{/default_value}} - {{description}}
+{{/path_parameters}}
+{{/has_path_parameters}}
+{{#has_query_parameters}}
+
+h3. Query parameters
+{{#query_parameters}}
+* {{name}}: {{data_type}}{{#default_value}} = {{default_value}}{{/default_value}} -{{#required}} *(required)*{{/required}} {{description}}
+{{/query_parameters}}
+{{/has_query_parameters}}
+{{#has_header_parameters}}
+
+h3. Header parameters
+{{#header_parameters}}
+* {{name}}: {{data_type}}{{#default_value}} = {{default_value}}{{/default_value}} -{{#required}} *(required)*{{/required}} {{description}}
+{{/header_parameters}}
+{{/has_header_parameters}}
+{{#has_error_responses}}
+
+h3. Error Responses
+{{#error_responses}}
+* {{code}} - {{{reason}}}
+{{/error_responses}}
+{{/has_error_responses}}
+{{/operations}}
+{{/apis}}
+{{/api_declaration}}
diff --git a/rest-api-templates/ari_model_validators.c.mustache b/rest-api-templates/ari_model_validators.c.mustache
new file mode 100644
index 000000000..0e87f8e24
--- /dev/null
+++ b/rest-api-templates/ari_model_validators.c.mustache
@@ -0,0 +1,117 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * 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 - Build validators for ARI model objects.
+ */
+
+ /*
+{{> do-not-edit}}
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_model_validators.h.mustache
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/logger.h"
+#include "asterisk/module.h"
+#include "ari_model_validators.h"
+{{#apis}}
+{{#api_declaration}}
+{{#models}}
+
+int ari_validate_{{c_id}}(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+{{#properties}}
+{{#required}}
+ int has_{{name}} = 0;
+{{/required}}
+{{/properties}}
+{{#has_subtypes}}
+ const char *discriminator;
+
+ discriminator = ast_json_string_get(ast_json_object_get(json, "{{discriminator.name}}"));
+ if (!discriminator) {
+ ast_log(LOG_ERROR, "ARI {{id}} missing required field {{discriminator.name}}");
+ return 0;
+ }
+
+ if (strcmp("{{id}}", discriminator) == 0) {
+ /* Self type; fall through */
+ } else
+{{#subtypes}}
+ if (strcmp("{{id}}", discriminator) == 0) {
+ return ari_validate_{{c_id}}(json);
+ } else
+{{/subtypes}}
+ {
+ ast_log(LOG_ERROR, "ARI {{id}} has undocumented subtype %s\n",
+ discriminator);
+ res = 0;
+ }
+{{/has_subtypes}}
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+{{#properties}}
+ if (strcmp("{{name}}", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+{{#required}}
+ has_{{name}} = 1;
+{{/required}}
+{{#type}}
+{{#is_list}}
+ prop_is_valid = ari_validate_list(
+ ast_json_object_iter_value(iter),
+ ari_validate_{{c_singular_name}});
+{{/is_list}}
+{{^is_list}}
+ prop_is_valid = ari_validate_{{c_name}}(
+ ast_json_object_iter_value(iter));
+{{/is_list}}
+{{/type}}
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI {{id}} field {{name}} failed validation\n");
+ res = 0;
+ }
+ } else
+{{/properties}}
+ {
+ ast_log(LOG_ERROR,
+ "ARI {{id}} has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+{{#properties}}
+{{#required}}
+ if (!has_{{name}}) {
+ ast_log(LOG_ERROR, "ARI {{id}} missing required field {{name}}\n");
+ res = 0;
+ }
+
+{{/required}}
+{{/properties}}
+ return res;
+}
+{{/models}}
+{{/api_declaration}}
+{{/apis}}
diff --git a/rest-api-templates/ari_model_validators.h.mustache b/rest-api-templates/ari_model_validators.h.mustache
new file mode 100644
index 000000000..65efbbd85
--- /dev/null
+++ b/rest-api-templates/ari_model_validators.h.mustache
@@ -0,0 +1,159 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * 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 - Build validators for ARI model objects.
+ */
+
+ /*
+{{> do-not-edit}}
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_model_validators.h.mustache
+ */
+
+#ifndef _ASTERISK_ARI_MODEL_H
+#define _ASTERISK_ARI_MODEL_H
+
+#include "asterisk/json.h"
+
+/*! @{ */
+
+/*!
+ * \brief Validator for native Swagger void.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_void(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger byte.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_byte(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger boolean.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_boolean(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger int.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_int(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger long.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_long(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger float.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_float(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger double.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_double(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger string.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_string(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger date.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_date(struct ast_json *json);
+
+/*!
+ * \brief Validator for a Swagger List[]/JSON array.
+ *
+ * \param json JSON object to validate.
+ * \param fn Validator to call on every element in the array.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_list(struct ast_json *json, int (*fn)(struct ast_json *));
+
+/*! @} */
+{{#apis}}
+{{#api_declaration}}
+{{#models}}
+
+/*!
+ * \brief Validator for {{id}}.
+ *
+ * {{{description_dox}}}
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ari_validate_{{c_id}}(struct ast_json *json);
+{{/models}}
+{{/api_declaration}}
+{{/apis}}
+
+/*
+ * JSON models
+ *
+{{#apis}}
+{{#api_declaration}}
+{{#models}}
+ * {{id}}
+{{#properties}}
+ * - {{name}}: {{type.name}}{{#required}} (required){{/required}}
+{{/properties}}
+{{/models}}
+{{/api_declaration}}
+{{/apis}} */
+
+#endif /* _ASTERISK_ARI_MODEL_H */
diff --git a/rest-api-templates/asterisk_processor.py b/rest-api-templates/asterisk_processor.py
index af5f5bdfe..0260b6b55 100644
--- a/rest-api-templates/asterisk_processor.py
+++ b/rest-api-templates/asterisk_processor.py
@@ -24,6 +24,11 @@ import re
from swagger_model import *
+try:
+ from collections import OrderedDict
+except ImportError:
+ from odict import OrderedDict
+
def simple_name(name):
"""Removes the {markers} from a path segement.
@@ -35,6 +40,14 @@ def simple_name(name):
return name
+def wikify(str):
+ """Escapes a string for the wiki.
+
+ @param str: String to escape
+ """
+ return re.sub(r'([{}\[\]])', r'\\\1', str)
+
+
def snakify(name):
"""Helper to take a camelCase or dash-seperated name and make it
snake_case.
@@ -107,6 +120,7 @@ class PathSegment(Stringify):
"""
return len(self.__children)
+
class AsteriskProcessor(SwaggerPostProcessor):
"""A SwaggerPostProcessor which adds fields needed to generate Asterisk
RESTful HTTP binding code.
@@ -131,12 +145,17 @@ class AsteriskProcessor(SwaggerPostProcessor):
'double': 'atof',
}
- def process_api(self, resource_api, context):
+ def __init__(self, wiki_prefix):
+ self.wiki_prefix = wiki_prefix
+
+ def process_resource_api(self, resource_api, context):
+ resource_api.wiki_prefix = self.wiki_prefix
# Derive a resource name from the API declaration's filename
resource_api.name = re.sub('\..*', '',
os.path.basename(resource_api.path))
- # Now in all caps, from include guard
+ # Now in all caps, for include guard
resource_api.name_caps = resource_api.name.upper()
+ resource_api.name_title = resource_api.name.capitalize()
# Construct the PathSegement tree for the API.
if resource_api.api_declaration:
resource_api.root_path = PathSegment('', None)
@@ -145,17 +164,6 @@ class AsteriskProcessor(SwaggerPostProcessor):
for operation in api.operations:
segment.operations.append(operation)
api.full_name = segment.full_name
- resource_api.api_declaration.has_events = False
- for model in resource_api.api_declaration.models:
- if model.id == "Event":
- resource_api.api_declaration.has_events = True
- break
- if resource_api.api_declaration.has_events:
- resource_api.api_declaration.events = \
- [self.process_model(model, context) for model in \
- resource_api.api_declaration.models if model.id != "Event"]
- else:
- resource_api.api_declaration.events = []
# Since every API path should start with /[resource], root should
# have exactly one child.
@@ -169,6 +177,9 @@ class AsteriskProcessor(SwaggerPostProcessor):
"API declaration name should match", context)
resource_api.root_full_name = resource_api.root_path.full_name
+ def process_api(self, api, context):
+ api.wiki_path = wikify(api.path)
+
def process_operation(self, operation, context):
# Nicknames are camelcase, Asterisk coding is snake case
operation.c_nickname = snakify(operation.nickname)
@@ -179,7 +190,7 @@ class AsteriskProcessor(SwaggerPostProcessor):
def process_parameter(self, parameter, context):
if not parameter.data_type in self.type_mapping:
raise SwaggerError(
- "Invalid parameter type %s" % paramter.data_type, context)
+ "Invalid parameter type %s" % parameter.data_type, context)
# Parameter names are camelcase, Asterisk convention is snake case
parameter.c_name = snakify(parameter.name)
parameter.c_data_type = self.type_mapping[parameter.data_type]
@@ -191,41 +202,19 @@ class AsteriskProcessor(SwaggerPostProcessor):
parameter.c_space = ' '
def process_model(self, model, context):
+ model.description_dox = model.description.replace('\n', '\n * ')
+ model.description_dox = re.sub(' *\n', '\n', model.description_dox)
model.c_id = snakify(model.id)
- model.channel = False
- model.channel_desc = ""
- model.bridge = False
- model.bridge_desc = ""
- model.properties = [self.process_property(model, prop, context) for prop in model.properties]
- model.properties = [prop for prop in model.properties if prop]
- model.has_properties = (len(model.properties) != 0)
return model
- def process_property(self, model, prop, context):
- # process channel separately since it will be pulled out
- if prop.name == 'channel' and prop.type == 'Channel':
- model.channel = True
- model.channel_desc = prop.description or ""
- return None
-
- # process bridge separately since it will be pulled out
- if prop.name == 'bridge' and prop.type == 'Bridge':
- model.bridge = True
- model.bridge_desc = prop.description or ""
- return None
-
- prop.c_name = snakify(prop.name)
- if prop.type in self.type_mapping:
- prop.c_type = self.type_mapping[prop.type]
- prop.c_convert = self.convert_mapping[prop.c_type]
- else:
- prop.c_type = "Property type %s not mappable to a C type" % (prop.type)
- prop.c_convert = "Property type %s not mappable to a C conversion" % (prop.type)
- #raise SwaggerError(
- # "Invalid property type %s" % prop.type, context)
- # You shouldn't put a space between 'char *' and the variable
- if prop.c_type.endswith('*'):
- prop.c_space = ''
- else:
- prop.c_space = ' '
- return prop
+ def process_property(self, prop, context):
+ if "-" in prop.name:
+ raise SwaggerError("Property names cannot have dashes", context)
+ if prop.name != prop.name.lower():
+ raise SwaggerError("Property name should be all lowercase",
+ context)
+
+ def process_type(self, swagger_type, context):
+ swagger_type.c_name = snakify(swagger_type.name)
+ swagger_type.c_singular_name = snakify(swagger_type.singular_name)
+ swagger_type.wiki_name = wikify(swagger_type.name)
diff --git a/rest-api-templates/event_function_decl.mustache b/rest-api-templates/event_function_decl.mustache
deleted file mode 100644
index fd2c7eb5b..000000000
--- a/rest-api-templates/event_function_decl.mustache
+++ /dev/null
@@ -1,10 +0,0 @@
-struct ast_json *stasis_json_event_{{c_id}}_create(
-{{#bridge}}
- struct ast_bridge_snapshot *bridge_snapshot{{#channel}},{{/channel}}{{^channel}}{{#has_properties}},{{/has_properties}}{{/channel}}
-{{/bridge}}
-{{#channel}}
- struct ast_channel_snapshot *channel_snapshot{{#has_properties}},{{/has_properties}}
-{{/channel}}
-{{#has_properties}}
- struct ast_json *blob
-{{/has_properties}}
diff --git a/rest-api-templates/make_stasis_http_stubs.py b/rest-api-templates/make_ari_stubs.py
index 1114ea46e..6f59e3813 100755
--- a/rest-api-templates/make_stasis_http_stubs.py
+++ b/rest-api-templates/make_ari_stubs.py
@@ -22,7 +22,6 @@ except ImportError:
print >> sys.stderr, "Pystache required. Please sudo pip install pystache."
import os.path
-import pystache
import sys
from asterisk_processor import AsteriskProcessor
@@ -40,23 +39,27 @@ def rel(file):
"""
return os.path.join(TOPDIR, file)
+WIKI_PREFIX = 'Asterisk 12'
+
API_TRANSFORMS = [
+ Transform(rel('api.wiki.mustache'),
+ 'doc/rest-api/%s {{name_title}} REST API.wiki' % WIKI_PREFIX),
Transform(rel('res_stasis_http_resource.c.mustache'),
- 'res_stasis_http_{{name}}.c'),
+ 'res/res_stasis_http_{{name}}.c'),
Transform(rel('stasis_http_resource.h.mustache'),
- 'stasis_http/resource_{{name}}.h'),
+ 'res/stasis_http/resource_{{name}}.h'),
Transform(rel('stasis_http_resource.c.mustache'),
- 'stasis_http/resource_{{name}}.c', False),
- Transform(rel('res_stasis_json_resource.c.mustache'),
- 'res_stasis_json_{{name}}.c'),
- Transform(rel('res_stasis_json_resource.exports.mustache'),
- 'res_stasis_json_{{name}}.exports.in'),
- Transform(rel('stasis_json_resource.h.mustache'),
- 'stasis_json/resource_{{name}}.h'),
+ 'res/stasis_http/resource_{{name}}.c', overwrite=False),
]
RESOURCES_TRANSFORMS = [
- Transform(rel('stasis_http.make.mustache'), 'stasis_http.make'),
+ Transform(rel('models.wiki.mustache'),
+ 'doc/rest-api/%s REST Data Models.wiki' % WIKI_PREFIX),
+ Transform(rel('stasis_http.make.mustache'), 'res/stasis_http.make'),
+ Transform(rel('ari_model_validators.h.mustache'),
+ 'res/stasis_http/ari_model_validators.h'),
+ Transform(rel('ari_model_validators.c.mustache'),
+ 'res/stasis_http/ari_model_validators.c'),
]
@@ -71,7 +74,7 @@ def main(argv):
source = args[1]
dest_dir = args[2]
renderer = pystache.Renderer(search_dirs=[TOPDIR], missing_tags='strict')
- processor = AsteriskProcessor()
+ processor = AsteriskProcessor(wiki_prefix=WIKI_PREFIX)
# Build the models
base_dir = os.path.dirname(source)
diff --git a/rest-api-templates/models.wiki.mustache b/rest-api-templates/models.wiki.mustache
new file mode 100644
index 000000000..e3d3eb95c
--- /dev/null
+++ b/rest-api-templates/models.wiki.mustache
@@ -0,0 +1,22 @@
+{toc}
+
+{{#apis}}
+{{#api_declaration}}
+{{#models}}
+h1. {{id}}
+{{#extends}}Base type: [{{extends}}|#{{extends}}]{{/extends}}
+{{#has_subtypes}}Subtypes:{{#subtypes}} [{{id}}|#{{id}}]{{/subtypes}}{{/has_subtypes}}
+{{#description}}
+
+{{{description}}}
+{{/description}}
+{code:language=javascript|collapse=true}
+{{{model_json}}}
+{code}
+{{#properties}}
+* {{name}}: {{#type}}{{#is_primitive}}{{wiki_name}}{{/is_primitive}}{{^is_primitive}}[{{wiki_name}}|#{{singular_name}}]{{/is_primitive}}{{/type}}{{^required}} _(optional)_{{/required}}{{#description}} - {{{description}}}{{/description}}
+{{/properties}}
+
+{{/models}}
+{{/api_declaration}}
+{{/apis}}
diff --git a/rest-api-templates/res_stasis_http_resource.c.mustache b/rest-api-templates/res_stasis_http_resource.c.mustache
index 0bdc1d014..0f0535bcf 100644
--- a/rest-api-templates/res_stasis_http_resource.c.mustache
+++ b/rest-api-templates/res_stasis_http_resource.c.mustache
@@ -49,6 +49,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/stasis_app.h"
#include "stasis_http/resource_{{name}}.h"
+#if defined(AST_DEVMODE)
+#include "stasis_http/ari_model_validators.h"
+#endif
{{#apis}}
{{#operations}}
@@ -61,11 +64,50 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
* \param[out] response Response to the HTTP request.
*/
static void stasis_http_{{c_nickname}}_cb(
- struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct stasis_http_response *response)
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct stasis_http_response *response)
{
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
{{> param_parsing}}
stasis_http_{{c_nickname}}(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 500: /* Internal server error */
+{{#error_responses}}
+ case {{code}}: /* {{{reason}}} */
+{{/error_responses}}
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+{{#response_class}}
+{{#is_list}}
+ is_valid = ari_validate_list(response->message,
+ ari_validate_{{c_singular_name}});
+{{/is_list}}
+{{^is_list}}
+ is_valid = ari_validate_{{c_name}}(
+ response->message);
+{{/is_list}}
+{{/response_class}}
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for {{path}}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for {{path}}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
}
{{/is_req}}
{{#is_websocket}}
@@ -81,7 +123,12 @@ static void stasis_http_{{c_nickname}}_ws_cb(struct ast_websocket *ws_session,
struct ast_variable *path_vars = NULL;
{{/has_path_parameters}}
{{> param_parsing}}
- session = ari_websocket_session_create(ws_session);
+#if defined(AST_DEVMODE)
+ session = ari_websocket_session_create(ws_session,
+ ari_validate_{{response_class.c_name}});
+#else
+ session = ari_websocket_session_create(ws_session, NULL);
+#endif
if (!session) {
ast_log(LOG_ERROR, "Failed to create ARI session\n");
return;
diff --git a/rest-api-templates/res_stasis_json_resource.c.mustache b/rest-api-templates/res_stasis_json_resource.c.mustache
deleted file mode 100644
index a25bdc228..000000000
--- a/rest-api-templates/res_stasis_json_resource.c.mustache
+++ /dev/null
@@ -1,151 +0,0 @@
-{{#api_declaration}}
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * {{{copyright}}}
- *
- * {{{author}}}
-{{! Template Copyright
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kinsey Moore <kmoore@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.
- */
-
-{{! Template for rendering the res_ module for an HTTP resource. }}
-/*
-{{> do-not-edit}}
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_stasis_http_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief {{{description}}}
- *
- * \author {{{author}}}
- */
-
-/*** MODULEINFO
- <support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/module.h"
-#include "asterisk/json.h"
-#include "stasis_json/resource_{{name}}.h"
-{{#has_events}}
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_bridging.h"
-
-{{#events}}
-{{> event_function_decl}}
- )
-{
- RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
- RAII_VAR(struct ast_json *, event, NULL, ast_json_unref);
-{{#has_properties}}
- struct ast_json *validator;
-{{/has_properties}}
-{{#channel}}
- int ret;
-{{/channel}}
-{{#bridge}}
-{{^channel}}
- int ret;
-{{/channel}}
-{{/bridge}}
-
-{{#channel}}
- ast_assert(channel_snapshot != NULL);
-{{/channel}}
-{{#bridge}}
- ast_assert(bridge_snapshot != NULL);
-{{/bridge}}
-{{#has_properties}}
- ast_assert(blob != NULL);
-{{#channel}}
- ast_assert(ast_json_object_get(blob, "channel") == NULL);
-{{/channel}}
-{{#bridge}}
- ast_assert(ast_json_object_get(blob, "bridge") == NULL);
-{{/bridge}}
- ast_assert(ast_json_object_get(blob, "type") == NULL);
-{{#properties}}
-
- validator = ast_json_object_get(blob, "{{name}}");
- if (validator) {
- /* do validation? XXX */
-{{#required}}
- } else {
- /* fail message generation if the required parameter doesn't exist */
- return NULL;
-{{/required}}
- }
-{{/properties}}
-
- event = ast_json_deep_copy(blob);
-{{/has_properties}}
-{{^has_properties}}
-
- event = ast_json_object_create();
-{{/has_properties}}
- if (!event) {
- return NULL;
- }
-
-{{#channel}}
- ret = ast_json_object_set(event,
- "channel", ast_channel_snapshot_to_json(channel_snapshot));
- if (ret) {
- return NULL;
- }
-
-{{/channel}}
-{{#bridge}}
- ret = ast_json_object_set(event,
- "bridge", ast_bridge_snapshot_to_json(bridge_snapshot));
- if (ret) {
- return NULL;
- }
-
-{{/bridge}}
- message = ast_json_pack("{s: o}", "{{c_id}}", ast_json_ref(event));
- if (!message) {
- return NULL;
- }
-
- return ast_json_ref(message);
-}
-
-{{/events}}
-{{/has_events}}
-static int load_module(void)
-{
- return 0;
-}
-
-static int unload_module(void)
-{
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis JSON Generators and Validators - {{{description}}}",
- .load = load_module,
- .unload = unload_module,
- .load_pri = AST_MODPRI_DEFAULT,
- );
-{{/api_declaration}}
diff --git a/rest-api-templates/res_stasis_json_resource.exports.mustache b/rest-api-templates/res_stasis_json_resource.exports.mustache
deleted file mode 100644
index 0f958fa04..000000000
--- a/rest-api-templates/res_stasis_json_resource.exports.mustache
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-{{#api_declaration}}
-{{#has_events}}
- global:
-{{#events}}
- LINKER_SYMBOL_PREFIXstasis_json_event_{{c_id}}_create;
-{{/events}}
-{{/has_events}}
-{{/api_declaration}}
- local:
- *;
-};
diff --git a/rest-api-templates/stasis_json_resource.h.mustache b/rest-api-templates/stasis_json_resource.h.mustache
deleted file mode 100644
index 8cfd2c1f7..000000000
--- a/rest-api-templates/stasis_json_resource.h.mustache
+++ /dev/null
@@ -1,83 +0,0 @@
-{{#api_declaration}}
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * {{{copyright}}}
- *
- * {{{author}}}
- *
- * 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/stasis_json/resource_{{name}}.c
- *
- * {{{description}}}
- *
- * \author {{{author}}}
- */
-
-/*
-{{> do-not-edit}}
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/stasis_http_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_{{name_caps}}_H
-#define _ASTERISK_RESOURCE_{{name_caps}}_H
-
-{{#has_events}}
-struct ast_channel_snapshot;
-struct ast_bridge_snapshot;
-
-{{#events}}
-/*!
- * \brief {{description}}
-{{#notes}}
- *
- * {{{notes}}}
-{{/notes}}
- *
-{{#channel}}
- * \param channel {{#channel_desc}}{{channel_desc}}{{/channel_desc}}{{^channel_desc}}The channel to be used to generate this event{{/channel_desc}}
-{{/channel}}
-{{#bridge}}
- * \param bridge {{#bridge_desc}}{{bridge_desc}}{{/bridge_desc}}{{^bridge_desc}}The bridge to be used to generate this event{{/bridge_desc}}
-{{/bridge}}
-{{#has_properties}}
- * \param blob JSON blob containing the following parameters:
-{{/has_properties}}
-{{#properties}}
- * - {{name}}: {{type}} {{#description}}- {{description}}{{/description}}{{#required}} (required){{/required}}
-{{/properties}}
- *
- * \retval NULL on error
- * \retval JSON (ast_json) describing the event
- */
-{{> event_function_decl}}
- );
-
-{{/events}}
-{{/has_events}}
-/*
- * JSON models
- *
-{{#models}}
- * {{id}}
-{{#properties}}
- * - {{name}}: {{type}}{{#required}} (required){{/required}}
-{{/properties}}
-{{/models}} */
-
-#endif /* _ASTERISK_RESOURCE_{{name_caps}}_H */
-{{/api_declaration}}
diff --git a/rest-api-templates/swagger_model.py b/rest-api-templates/swagger_model.py
index 47461b406..2907688c5 100644
--- a/rest-api-templates/swagger_model.py
+++ b/rest-api-templates/swagger_model.py
@@ -29,16 +29,101 @@ See https://github.com/wordnik/swagger-core/wiki/API-Declaration for the spec.
import json
import os.path
import pprint
+import re
import sys
import traceback
-try:
- from collections import OrderedDict
-except ImportError:
- from odict import OrderedDict
+# I'm not quite sure what was in Swagger 1.2, but apparently I missed it
+SWAGGER_VERSIONS = ["1.1", "1.3"]
+SWAGGER_PRIMITIVES = [
+ 'void',
+ 'string',
+ 'boolean',
+ 'number',
+ 'int',
+ 'long',
+ 'double',
+ 'float',
+ 'Date',
+]
-SWAGGER_VERSION = "1.1"
+
+class Stringify(object):
+ """Simple mix-in to make the repr of the model classes more meaningful.
+ """
+ def __repr__(self):
+ return "%s(%s)" % (self.__class__, pprint.saferepr(self.__dict__))
+
+
+def compare_versions(lhs, rhs):
+ '''Performs a lexicographical comparison between two version numbers.
+
+ This properly handles simple major.minor.whatever.sure.why.not version
+ numbers, but fails miserably if there's any letters in there.
+
+ For reference:
+ 1.0 == 1.0
+ 1.0 < 1.0.1
+ 1.2 < 1.10
+
+ @param lhs Left hand side of the comparison
+ @param rhs Right hand side of the comparison
+ @return < 0 if lhs < rhs
+ @return == 0 if lhs == rhs
+ @return > 0 if lhs > rhs
+ '''
+ lhs = [int(v) for v in lhs.split('.')]
+ rhs = [int(v) for v in rhs.split('.')]
+ return cmp(lhs, rhs)
+
+
+class ParsingContext(object):
+ """Context information for parsing.
+
+ This object is immutable. To change contexts (like adding an item to the
+ stack), use the next() and next_stack() functions to build a new one.
+ """
+
+ def __init__(self, swagger_version, stack):
+ self.__swagger_version = swagger_version
+ self.__stack = stack
+
+ def __repr__(self):
+ return "ParsingContext(swagger_version=%s, stack=%s)" % (
+ self.swagger_version, self.stack)
+
+ def get_swagger_version(self):
+ return self.__swagger_version
+
+ def get_stack(self):
+ return self.__stack
+
+ swagger_version = property(get_swagger_version)
+
+ stack = property(get_stack)
+
+ def version_less_than(self, ver):
+ return compare_versions(self.swagger_version, ver) < 0
+
+ def next_stack(self, json, id_field):
+ """Returns a new item pushed to the stack.
+
+ @param json: Current JSON object.
+ @param id_field: Field identifying this object.
+ @return New context with additional item in the stack.
+ """
+ if not id_field in json:
+ raise SwaggerError("Missing id_field: %s" % id_field, self)
+ new_stack = self.stack + ['%s=%s' % (id_field, str(json[id_field]))]
+ return ParsingContext(self.swagger_version, new_stack)
+
+ def next(self, version=None, stack=None):
+ if version is None:
+ version = self.version
+ if stack is None:
+ stack = self.stack
+ return ParsingContext(version, stack)
class SwaggerError(Exception):
@@ -50,7 +135,7 @@ class SwaggerError(Exception):
"""Ctor.
@param msg: String message for the error.
- @param context: Array of strings for current context in the API.
+ @param context: ParsingContext object
@param cause: Optional exception that caused this one.
"""
super(Exception, self).__init__(msg, context, cause)
@@ -61,7 +146,7 @@ class SwaggerPostProcessor(object):
fields to model objects for additional information to use in the
templates.
"""
- def process_api(self, resource_api, context):
+ def process_resource_api(self, resource_api, context):
"""Post process a ResourceApi object.
@param resource_api: ResourceApi object.
@@ -69,6 +154,14 @@ class SwaggerPostProcessor(object):
"""
pass
+ def process_api(self, api, context):
+ """Post process an Api object.
+
+ @param api: Api object.
+ @param context: Current context in the API.
+ """
+ pass
+
def process_operation(self, operation, context):
"""Post process a Operation object.
@@ -85,12 +178,37 @@ class SwaggerPostProcessor(object):
"""
pass
+ def process_model(self, model, context):
+ """Post process a Model object.
-class Stringify(object):
- """Simple mix-in to make the repr of the model classes more meaningful.
- """
- def __repr__(self):
- return "%s(%s)" % (self.__class__, pprint.saferepr(self.__dict__))
+ @param model: Model object.
+ @param context: Current context in the API.
+ """
+ pass
+
+ def process_property(self, property, context):
+ """Post process a Property object.
+
+ @param property: Property object.
+ @param context: Current context in the API.
+ """
+ pass
+
+ def process_type(self, swagger_type, context):
+ """Post process a SwaggerType object.
+
+ @param swagger_type: ResourceListing object.
+ @param context: Current context in the API.
+ """
+ pass
+
+ def process_resource_listing(self, resource_listing, context):
+ """Post process the overall ResourceListing object.
+
+ @param resource_listing: ResourceListing object.
+ @param context: Current context in the API.
+ """
+ pass
class AllowableRange(Stringify):
@@ -158,17 +276,22 @@ class Parameter(Stringify):
self.allow_multiple = None
def load(self, parameter_json, processor, context):
- context = add_context(context, parameter_json, 'name')
+ context = context.next_stack(parameter_json, 'name')
validate_required_fields(parameter_json, self.required_fields, context)
self.name = parameter_json.get('name')
self.param_type = parameter_json.get('paramType')
self.description = parameter_json.get('description') or ''
self.data_type = parameter_json.get('dataType')
self.required = parameter_json.get('required') or False
+ self.default_value = parameter_json.get('defaultValue')
self.allowable_values = load_allowable_values(
parameter_json.get('allowableValues'), context)
self.allow_multiple = parameter_json.get('allowMultiple') or False
processor.process_parameter(self, context)
+ if parameter_json.get('allowedValues'):
+ raise SwaggerError(
+ "Field 'allowedValues' invalid; use 'allowableValues'",
+ context)
return self
def is_type(self, other_type):
@@ -188,13 +311,41 @@ class ErrorResponse(Stringify):
self.reason = None
def load(self, err_json, processor, context):
- context = add_context(context, err_json, 'code')
+ context = context.next_stack(err_json, 'code')
validate_required_fields(err_json, self.required_fields, context)
self.code = err_json.get('code')
self.reason = err_json.get('reason')
return self
+class SwaggerType(Stringify):
+ """Model of a data type.
+ """
+
+ def __init__(self):
+ self.name = None
+ self.is_discriminator = None
+ self.is_list = None
+ self.singular_name = None
+ self.is_primitive = None
+
+ def load(self, type_name, processor, context):
+ # Some common errors
+ if type_name == 'integer':
+ raise SwaggerError("The type for integer should be 'int'", context)
+
+ self.name = type_name
+ type_param = get_list_parameter_type(self.name)
+ self.is_list = type_param is not None
+ if self.is_list:
+ self.singular_name = type_param
+ else:
+ self.singular_name = self.name
+ self.is_primitive = self.singular_name in SWAGGER_PRIMITIVES
+ processor.process_type(self, context)
+ return self
+
+
class Operation(Stringify):
"""Model of an operation on an API
@@ -213,11 +364,14 @@ class Operation(Stringify):
self.error_responses = []
def load(self, op_json, processor, context):
- context = add_context(context, op_json, 'nickname')
+ context = context.next_stack(op_json, 'nickname')
validate_required_fields(op_json, self.required_fields, context)
self.http_method = op_json.get('httpMethod')
self.nickname = op_json.get('nickname')
- self.response_class = op_json.get('responseClass')
+ response_class = op_json.get('responseClass')
+ self.response_class = response_class and SwaggerType().load(
+ response_class, processor, context)
+
# Specifying WebSocket URL's is our own extension
self.is_websocket = op_json.get('upgrade') == 'websocket'
self.is_req = not self.is_websocket
@@ -247,6 +401,7 @@ class Operation(Stringify):
err_json = op_json.get('errorResponses') or []
self.error_responses = [
ErrorResponse().load(j, processor, context) for j in err_json]
+ self.has_error_responses = self.error_responses != []
processor.process_operation(self, context)
return self
@@ -265,7 +420,7 @@ class Api(Stringify):
self.operations = []
def load(self, api_json, processor, context):
- context = add_context(context, api_json, 'path')
+ context = context.next_stack(api_json, 'path')
validate_required_fields(api_json, self.required_fields, context)
self.path = api_json.get('path')
self.description = api_json.get('description')
@@ -274,9 +429,20 @@ class Api(Stringify):
Operation().load(j, processor, context) for j in op_json]
self.has_websocket = \
filter(lambda op: op.is_websocket, self.operations) != []
+ processor.process_api(self, context)
return self
+def get_list_parameter_type(type_string):
+ """Returns the type parameter if the given type_string is List[].
+
+ @param type_string: Type string to parse
+ @returns Type parameter of the list, or None if not a List.
+ """
+ list_match = re.match('^List\[(.*)\]$', type_string)
+ return list_match and list_match.group(1)
+
+
class Property(Stringify):
"""Model of a Swagger property.
@@ -293,9 +459,15 @@ class Property(Stringify):
def load(self, property_json, processor, context):
validate_required_fields(property_json, self.required_fields, context)
- self.type = property_json.get('type')
+ # Bit of a hack, but properties do not self-identify
+ context = context.next_stack({'name': self.name}, 'name')
self.description = property_json.get('description') or ''
self.required = property_json.get('required') or False
+
+ type = property_json.get('type')
+ self.type = type and SwaggerType().load(type, processor, context)
+
+ processor.process_property(self, context)
return self
@@ -305,24 +477,95 @@ class Model(Stringify):
See https://github.com/wordnik/swagger-core/wiki/datatypes
"""
+ required_fields = ['description', 'properties']
+
def __init__(self):
self.id = None
+ self.extends = None
+ self.extends_type = None
self.notes = None
self.description = None
- self.properties = None
+ self.__properties = None
+ self.__discriminator = None
+ self.__subtypes = []
def load(self, id, model_json, processor, context):
- context = add_context(context, model_json, 'id')
- # This arrangement is required by the Swagger API spec
+ context = context.next_stack(model_json, 'id')
+ validate_required_fields(model_json, self.required_fields, context)
+ # The duplication of the model's id is required by the Swagger spec.
self.id = model_json.get('id')
if id != self.id:
- raise SwaggerError("Model id doesn't match name", c)
+ raise SwaggerError("Model id doesn't match name", context)
+ self.extends = model_json.get('extends')
+ if self.extends and context.version_less_than("1.3"):
+ raise SwaggerError("Type extension support added in Swagger 1.3",
+ context)
self.description = model_json.get('description')
props = model_json.get('properties').items() or []
- self.properties = [
+ self.__properties = [
Property(k).load(j, processor, context) for (k, j) in props]
+ self.__properties = sorted(self.__properties, key=lambda p: p.name)
+
+ discriminator = model_json.get('discriminator')
+
+ if discriminator:
+ if context.version_less_than("1.3"):
+ raise SwaggerError("Discriminator support added in Swagger 1.3",
+ context)
+
+ discr_props = [p for p in self.__properties if p.name == discriminator]
+ if not discr_props:
+ raise SwaggerError(
+ "Discriminator '%s' does not name a property of '%s'" % (
+ discriminator, self.id),
+ context)
+
+ self.__discriminator = discr_props[0]
+
+ self.model_json = json.dumps(model_json,
+ indent=2, separators=(',', ': '))
+
+ processor.process_model(self, context)
return self
+ def add_subtype(self, subtype):
+ """Add subtype to this model.
+
+ @param subtype: Model instance for the subtype.
+ """
+ self.__subtypes.append(subtype)
+
+ def set_extends_type(self, extends_type):
+ self.extends_type = extends_type
+
+ def discriminator(self):
+ """Returns the discriminator, digging through base types if needed.
+ """
+ return self.__discriminator or \
+ self.extends_type and self.extends_type.discriminator()
+
+ def properties(self):
+ base_props = []
+ if self.extends_type:
+ base_props = self.extends_type.properties()
+ return base_props + self.__properties
+
+ def has_properties(self):
+ return len(self.properties()) > 0
+
+ def subtypes(self):
+ """Returns the full list of all subtypes.
+ """
+ res = self.__subtypes + \
+ [subsubtypes for subtype in self.__subtypes
+ for subsubtypes in subtype.subtypes()]
+ return sorted(res, key=lambda m: m.id)
+
+ def has_subtypes(self):
+ """Returns True if type has any subtypes.
+ """
+ return len(self.subtypes()) > 0
+
class ApiDeclaration(Stringify):
"""Model class for an API Declaration.
@@ -345,8 +588,8 @@ class ApiDeclaration(Stringify):
self.apis = []
self.models = []
- def load_file(self, api_declaration_file, processor, context=[]):
- context = context + [api_declaration_file]
+ def load_file(self, api_declaration_file, processor):
+ context = ParsingContext(None, [api_declaration_file])
try:
return self.__load_file(api_declaration_file, processor, context)
except SwaggerError:
@@ -376,9 +619,10 @@ class ApiDeclaration(Stringify):
"""
# If the version doesn't match, all bets are off.
self.swagger_version = api_decl_json.get('swaggerVersion')
- if self.swagger_version != SWAGGER_VERSION:
+ context = context.next(version=self.swagger_version)
+ if not self.swagger_version in SWAGGER_VERSIONS:
raise SwaggerError(
- "Unsupported Swagger version %s" % swagger_version, context)
+ "Unsupported Swagger version %s" % self.swagger_version, context)
validate_required_fields(api_decl_json, self.required_fields, context)
@@ -391,9 +635,19 @@ class ApiDeclaration(Stringify):
self.apis = [
Api().load(j, processor, context) for j in api_json]
models = api_decl_json.get('models').items() or []
- self.models = [
- Model().load(k, j, processor, context) for (k, j) in models]
-
+ self.models = [Model().load(id, json, processor, context)
+ for (id, json) in models]
+ self.models = sorted(self.models, key=lambda m: m.id)
+ # Now link all base/extended types
+ model_dict = dict((m.id, m) for m in self.models)
+ for m in self.models:
+ if m.extends:
+ extends_type = model_dict.get(m.extends)
+ if not extends_type:
+ raise SwaggerError("%s extends non-existing model %s",
+ m.id, m.extends)
+ extends_type.add_subtype(m)
+ m.set_extends_type(extends_type)
return self
@@ -409,20 +663,20 @@ class ResourceApi(Stringify):
self.api_declaration = None
def load(self, api_json, processor, context):
- context = add_context(context, api_json, 'path')
+ context = context.next_stack(api_json, 'path')
validate_required_fields(api_json, self.required_fields, context)
self.path = api_json['path']
self.description = api_json['description']
if not self.path or self.path[0] != '/':
raise SwaggerError("Path must start with /", context)
- processor.process_api(self, context)
+ processor.process_resource_api(self, context)
return self
def load_api_declaration(self, base_dir, processor):
self.file = (base_dir + self.path).replace('{format}', 'json')
self.api_declaration = ApiDeclaration().load_file(self.file, processor)
- processor.process_api(self, [self.file])
+ processor.process_resource_api(self, [self.file])
class ResourceListing(Stringify):
@@ -438,7 +692,7 @@ class ResourceListing(Stringify):
self.apis = None
def load_file(self, resource_file, processor):
- context = [resource_file]
+ context = ParsingContext(None, [resource_file])
try:
return self.__load_file(resource_file, processor, context)
except SwaggerError:
@@ -455,7 +709,7 @@ class ResourceListing(Stringify):
def load(self, resources_json, processor, context):
# If the version doesn't match, all bets are off.
self.swagger_version = resources_json.get('swaggerVersion')
- if self.swagger_version != SWAGGER_VERSION:
+ if not self.swagger_version in SWAGGER_VERSIONS:
raise SwaggerError(
"Unsupported Swagger version %s" % swagger_version, context)
@@ -465,6 +719,7 @@ class ResourceListing(Stringify):
apis_json = resources_json['apis']
self.apis = [
ResourceApi().load(j, processor, context) for j in apis_json]
+ processor.process_resource_listing(self, context)
return self
@@ -482,16 +737,3 @@ def validate_required_fields(json, required_fields, context):
if missing_fields:
raise SwaggerError(
"Missing fields: %s" % ', '.join(missing_fields), context)
-
-
-def add_context(context, json, id_field):
- """Returns a new context with a new item added to it.
-
- @param context: Old context.
- @param json: Current JSON object.
- @param id_field: Field identifying this object.
- @return New context with additional item.
- """
- if not id_field in json:
- raise SwaggerError("Missing id_field: %s" % id_field, context)
- return context + ['%s=%s' % (id_field, str(json[id_field]))]
diff --git a/rest-api-templates/transform.py b/rest-api-templates/transform.py
index d0ef3c4a1..fc12efe85 100644
--- a/rest-api-templates/transform.py
+++ b/rest-api-templates/transform.py
@@ -16,8 +16,11 @@
# at the top of the source tree.
#
+import filecmp
import os.path
import pystache
+import shutil
+import tempfile
class Transform(object):
@@ -46,8 +49,14 @@ class Transform(object):
"""
dest_file = pystache.render(self.dest_file_template, model)
dest_file = os.path.join(dest_dir, dest_file)
- if os.path.exists(dest_file) and not self.overwrite:
+ dest_exists = os.path.exists(dest_file)
+ if dest_exists and not self.overwrite:
return
- print "Rendering %s" % dest_file
- with open(dest_file, "w") as out:
+ tmp_file = tempfile.mkstemp()
+ with tempfile.NamedTemporaryFile() as out:
out.write(renderer.render(self.template, model))
+ out.flush()
+
+ if not dest_exists or not filecmp.cmp(out.name, dest_file):
+ print "Writing %s" % dest_file
+ shutil.copyfile(out.name, dest_file)
diff --git a/rest-api/api-docs/asterisk.json b/rest-api/api-docs/asterisk.json
index ef6c7b864..8ee88e439 100644
--- a/rest-api/api-docs/asterisk.json
+++ b/rest-api/api-docs/asterisk.json
@@ -41,6 +41,7 @@
"models": {
"AsteriskInfo": {
"id": "AsteriskInfo",
+ "description": "Asterisk system information",
"properties": {}
}
}
diff --git a/rest-api/api-docs/bridges.json b/rest-api/api-docs/bridges.json
index 5b0cf6298..87d5b3d4f 100644
--- a/rest-api/api-docs/bridges.json
+++ b/rest-api/api-docs/bridges.json
@@ -31,8 +31,8 @@
"required": false,
"allowMultiple": false,
"dataType": "string",
- "allowedValues": {
- "type": "LIST",
+ "allowableValues": {
+ "valueType": "LIST",
"values": [
"mixing",
"holding"
@@ -61,6 +61,12 @@
"allowMultiple": false,
"dataType": "string"
}
+ ],
+ "errorResponses": [
+ {
+ "code": 404,
+ "reason": "Bridge not found"
+ }
]
},
{
@@ -78,6 +84,12 @@
"allowMultiple": false,
"dataType": "string"
}
+ ],
+ "errorResponses": [
+ {
+ "code": 404,
+ "reason": "Bridge not found"
+ }
]
}
]
@@ -108,6 +120,20 @@
"allowMultiple": true,
"dataType": "string"
}
+ ],
+ "errorResponses": [
+ {
+ "code": 404,
+ "reason": "Bridge not found"
+ },
+ {
+ "code": 409,
+ "reason": "Bridge not in Stasis application"
+ },
+ {
+ "code": 422,
+ "reason": "Channel not found, or not in Stasis application"
+ }
]
}
]
@@ -231,19 +257,35 @@
"models": {
"Bridge": {
"id": "Bridge",
+ "description": "The merging of media from one or more channels.\n\nEveryone on the bridge receives the same audio.",
"properties": {
- "bridgeType": {
+ "id": {
+ "type": "string",
+ "description": "Unique identifier for this bridge",
+ "required": true
+ },
+ "technology": {
+ "type": "string",
+ "description": "Name of the current bridging technology",
+ "required": true
+ },
+ "bridge_type": {
"type": "string",
"description": "Type of bridge technology",
"required": true,
- "allowedValues": {
- "type": "LIST",
+ "allowableValues": {
+ "valueType": "LIST",
"values": [
"mixing",
"holding"
]
}
},
+ "bridge_class": {
+ "type": "string",
+ "description": "Bridging class",
+ "required": true
+ },
"channels": {
"type": "List[string]",
"description": "Id's of channels participating in this bridge",
diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json
index 623cb17bb..f013ef641 100644
--- a/rest-api/api-docs/channels.json
+++ b/rest-api/api-docs/channels.json
@@ -286,6 +286,10 @@
{
"code": 404,
"reason": "Channel not found"
+ },
+ {
+ "code": 409,
+ "reason": "Channel not in a Stasis application"
}
]
}
@@ -616,11 +620,7 @@
},
{
"code": 409,
- "reason": "Channel is not in a Stasis application."
- },
- {
- "code": 409,
- "reason": "The channel is currently bridged with other channels."
+ "reason": "Channel is not in a Stasis application, or the channel is currently bridged with other channels."
}
]
}
@@ -630,10 +630,12 @@
"models": {
"Dialed": {
"id": "Dialed",
+ "description": "Dialed channel information.",
"properties": {}
},
"DialplanCEP": {
"id": "DialplanCEP",
+ "description": "Dialplan location (context/extension/priority)",
"properties": {
"context": {
"required": true,
@@ -654,6 +656,7 @@
},
"CallerID": {
"id": "CallerID",
+ "description": "Caller identification",
"properties": {
"name": {
"required": true,
@@ -667,11 +670,12 @@
},
"Channel": {
"id": "Channel",
+ "description": "A specific communication connection between Asterisk and an Endpoint.",
"properties": {
- "uniqueid": {
+ "id": {
"required": true,
"type": "string",
- "description": "Unique identifier of the channel"
+ "description": "Unique identifier of the channel.\n\nThis is the same as the Uniqueid field in AMI."
},
"name": {
"required": true,
@@ -680,99 +684,47 @@
},
"state": {
"required": true,
- "type": "string"
- },
- "accountcode": {
- "required": true,
- "type": "string"
- },
- "peeraccount": {
- "required": true,
- "type": "string"
- },
- "userfield": {
- "required": true,
- "type": "string"
+ "type": "string",
+ "allowableValues": {
+ "valueType": "LIST",
+ "values": [
+ "Down",
+ "Rsrved",
+ "OffHook",
+ "Dialing",
+ "Ring",
+ "Ringing",
+ "Up",
+ "Busy",
+ "Dialing Offhook",
+ "Pre-ring",
+ "Unknown"
+ ]
+ }
},
- "linkedid": {
+ "caller": {
"required": true,
- "type": "string"
+ "type": "CallerID"
},
- "parkinglot": {
+ "connected": {
"required": true,
- "type": "string"
+ "type": "CallerID"
},
- "hangupsource": {
+ "accountcode": {
"required": true,
"type": "string"
},
- "appl": {
- "required": true,
- "type": "string",
- "description": "Currently executing dialplan application"
- },
- "data": {
- "required": true,
- "type": "string",
- "description": "Arguments passed to appl"
- },
"dialplan": {
"required": true,
"type": "DialplanCEP",
"description": "Current location in the dialplan"
},
- "caller": {
- "required": true,
- "type": "CallerID"
- },
- "connected": {
- "required": true,
- "type": "CallerID"
- },
"creationtime": {
"required": true,
"type": "Date",
"description": "Timestamp when channel was created"
}
}
- },
- "Playback": {
- "id": "Playback",
- "description": "Object representing the playback of media to a channel",
- "properties": {
- "id": {
- "type": "string",
- "description": "ID for this playback operation",
- "required": true
- },
- "media_uri": {
- "type": "string",
- "description": "URI for the media to play back.",
- "required": true
- },
- "target_uri": {
- "type": "string",
- "description": "URI for the channel or bridge to play the media on",
- "required": true
- },
- "language": {
- "type": "string",
- "description": "For media types that support multiple languages, the language requested for playback."
- },
- "state": {
- "type": "string",
- "description": "Current state of the playback operation.",
- "required": true,
- "allowableValues": {
- "valueType": "LIST",
- "values": [
- "queued",
- "playing",
- "complete"
- ]
- }
- }
- }
}
}
}
diff --git a/rest-api/api-docs/endpoints.json b/rest-api/api-docs/endpoints.json
index d3d77d84a..9d0ff1840 100644
--- a/rest-api/api-docs/endpoints.json
+++ b/rest-api/api-docs/endpoints.json
@@ -69,7 +69,7 @@
"models": {
"Endpoint": {
"id": "Endpoint",
- "description": "A snapshot of an endpoint. Unlike most resources, which have a single unique identifier, an endpoint is uniquely identified by the technology/resource pair.",
+ "description": "An external device that may offer/accept calls to/from Asterisk.\n\nUnlike most resources, which have a single unique identifier, an endpoint is uniquely identified by the technology/resource pair.",
"properties": {
"technology": {
"type": "string",
@@ -80,6 +80,24 @@
"type": "string",
"description": "Identifier of the endpoint, specific to the given technology.",
"required": true
+ },
+ "state": {
+ "type": "string",
+ "description": "Endpoint's state",
+ "required": false,
+ "allowableValues": {
+ "valueType": "LIST",
+ "values": [
+ "unknown",
+ "offline",
+ "online"
+ ]
+ }
+ },
+ "channel_ids": {
+ "type": "List[string]",
+ "description": "Id's of channels associated with this endpoint",
+ "required": true
}
}
}
diff --git a/rest-api/api-docs/events.json b/rest-api/api-docs/events.json
index 56a05e4ee..79908eff7 100644
--- a/rest-api/api-docs/events.json
+++ b/rest-api/api-docs/events.json
@@ -3,7 +3,7 @@
"_author": "David M. Lee, II <dlee@digium.com>",
"_svn_revision": "$Revision$",
"apiVersion": "0.0.1",
- "swaggerVersion": "1.1",
+ "swaggerVersion": "1.3",
"basePath": "http://localhost:8088/stasis",
"resourcePath": "/api-docs/events.{format}",
"apis": [
@@ -35,37 +35,29 @@
"models": {
"Event": {
"id": "Event",
- "description": "Asynchronous events from Asterisk. The non-required fields of this object are mutually exclusive.",
+ "description": "Base type for asynchronous events from Asterisk.",
+ "discriminator": "type",
"properties": {
+ "type": {
+ "type": "string",
+ "required": true,
+ "description": "Indicates the type of this event."
+ },
"application": {
"type": "string",
"description": "Name of the application receiving the event.",
"required": true
},
- "application_replaced": { "type": "ApplicationReplaced" },
- "bridge_created": { "type": "BridgeCreated" },
- "bridge_destroyed": { "type": "BridgeDestroyed" },
- "bridge_merged": { "type": "BridgeMerged" },
- "channel_created": { "type": "ChannelCreated" },
- "channel_destroyed": { "type": "ChannelDestroyed" },
- "channel_snapshot": { "type": "ChannelSnapshot" },
- "channel_entered_bridge": { "type": "ChannelEnteredBridge" },
- "channel_left_bridge": { "type": "ChannelLeftBridge" },
- "channel_state_change": { "type": "ChannelStateChange" },
- "channel_dtmf_received": { "type": "ChannelDtmfReceived" },
- "channel_dialplan": { "type": "ChannelDialplan" },
- "channel_caller_id": { "type": "ChannelCallerId" },
- "channel_userevent": { "type": "ChannelUserevent" },
- "channel_hangup_request": { "type": "ChannelHangupRequest" },
- "channel_varset": { "type": "ChannelVarset" },
- "stasis_end": { "type": "StasisEnd" },
- "stasis_start": { "type": "StasisStart" },
- "playback_started": { "type": "PlaybackStarted" },
- "playback_finished": { "type": "PlaybackFinished" }
+ "timestamp": {
+ "type": "Date",
+ "description": "Time at which this event was created.",
+ "required": false
+ }
}
},
"PlaybackStarted": {
"id": "PlaybackStarted",
+ "extends": "Event",
"description": "Event showing the start of a media playback operation.",
"properties": {
"playback": {
@@ -77,6 +69,7 @@
},
"PlaybackFinished": {
"id": "PlaybackFinished",
+ "extends": "Event",
"description": "Event showing the completion of a media playback operation.",
"properties": {
"playback": {
@@ -88,17 +81,13 @@
},
"ApplicationReplaced": {
"id": "ApplicationReplaced",
- "description": "Notification that another WebSocket has taken over for an application.",
- "notes": "An application may only be subscribed to by a single WebSocket at a time. If multiple WebSockets attempt to subscribe to the same application, the newer WebSocket wins, and the older one receives this event.",
- "properties": {
- "application": {
- "required": true,
- "type": "string"
- }
- }
+ "extends": "Event",
+ "description": "Notification that another WebSocket has taken over for an application.\n\nAn application may only be subscribed to by a single WebSocket at a time. If multiple WebSockets attempt to subscribe to the same application, the newer WebSocket wins, and the older one receives this event.",
+ "properties": {}
},
"BridgeCreated": {
"id": "BridgeCreated",
+ "extends": "Event",
"description": "Notification that a bridge has been created.",
"properties": {
"bridge": {
@@ -109,6 +98,7 @@
},
"BridgeDestroyed": {
"id": "BridgeDestroyed",
+ "extends": "Event",
"description": "Notification that a bridge has been destroyed.",
"properties": {
"bridge": {
@@ -119,6 +109,7 @@
},
"BridgeMerged": {
"id": "BridgeMerged",
+ "extends": "Event",
"description": "Notification that one bridge has merged into another.",
"properties": {
"bridge": {
@@ -133,6 +124,7 @@
},
"ChannelCreated": {
"id": "ChannelCreated",
+ "extends": "Event",
"description": "Notification that a channel has been created.",
"properties": {
"channel": {
@@ -141,24 +133,15 @@
}
}
},
- "ChannelSnapshot": {
- "id": "ChannelSnapshot",
- "description": "Some part of channel state changed.",
- "properties": {
- "channel": {
- "required": true,
- "type": "Channel"
- }
- }
- },
"ChannelDestroyed": {
"id": "ChannelDestroyed",
+ "extends": "Event",
"description": "Notification that a channel has been destroyed.",
"properties": {
"cause": {
"required": true,
"description": "Integer representation of the cause of the hangup",
- "type": "integer"
+ "type": "int"
},
"cause_txt": {
"required": true,
@@ -173,6 +156,7 @@
},
"ChannelEnteredBridge": {
"id": "ChannelEnteredBridge",
+ "extends": "Event",
"description": "Notification that a channel has entered a bridge.",
"properties": {
"bridge": {
@@ -186,6 +170,7 @@
},
"ChannelLeftBridge": {
"id": "ChannelLeftBridge",
+ "extends": "Event",
"description": "Notification that a channel has left a bridge.",
"properties": {
"bridge": {
@@ -200,6 +185,7 @@
},
"ChannelStateChange": {
"id": "ChannelStateChange",
+ "extends": "Event",
"description": "Notification of a channel's state change.",
"properties": {
"channel": {
@@ -210,14 +196,19 @@
},
"ChannelDtmfReceived": {
"id": "ChannelDtmfReceived",
- "description": "DTMF received on a channel.",
- "notes": "This event is sent when the DTMF ends. There is no notification about the start of DTMF",
+ "extends": "Event",
+ "description": "DTMF received on a channel.\n\nThis event is sent when the DTMF ends. There is no notification about the start of DTMF",
"properties": {
"digit": {
"required": true,
"type": "string",
"description": "DTMF digit received (0-9, A-E, # or *)"
},
+ "duration_ms": {
+ "required": true,
+ "type": "int",
+ "description": "Number of milliseconds DTMF was received"
+ },
"channel": {
"required": true,
"type": "Channel",
@@ -227,32 +218,34 @@
},
"ChannelDialplan": {
"id": "ChannelDialplan",
+ "extends": "Event",
"description": "Channel changed location in the dialplan.",
"properties": {
- "application": {
+ "channel": {
"required": true,
- "type": "string",
- "description": "The application that the channel is currently in."
+ "type": "Channel",
+ "description": "The channel that changed dialplan location."
},
- "application_data": {
+ "dialplan_app": {
"required": true,
"type": "string",
- "description": "The data that was passed to the application when it was invoked."
+ "description": "The application about to be executed."
},
- "channel": {
+ "dialplan_app_data": {
"required": true,
- "type": "Channel",
- "description": "The channel that changed dialplan location."
+ "type": "string",
+ "description": "The data to be passed to the application."
}
}
},
"ChannelCallerId": {
"id": "ChannelCallerId",
+ "extends": "Event",
"description": "Channel changed Caller ID.",
"properties": {
"caller_presentation": {
"required": true,
- "type": "integer",
+ "type": "int",
"description": "The integer representation of the Caller Presentation value."
},
"caller_presentation_txt": {
@@ -269,6 +262,7 @@
},
"ChannelUserevent": {
"id": "ChannelUserevent",
+ "extends": "Event",
"description": "User-generated event with additional user-defined fields in the object.",
"properties": {
"eventname": {
@@ -285,10 +279,11 @@
},
"ChannelHangupRequest": {
"id": "ChannelHangupRequest",
+ "extends": "Event",
"description": "A hangup was requested on the channel.",
"properties": {
"cause": {
- "type": "integer",
+ "type": "int",
"description": "Integer representation of the cause of the hangup."
},
"soft": {
@@ -304,6 +299,7 @@
},
"ChannelVarset": {
"id": "ChannelVarset",
+ "extends": "Event",
"description": "Channel variable changed.",
"properties": {
"variable": {
@@ -317,14 +313,15 @@
"description": "The new value of the variable."
},
"channel": {
- "required": true,
+ "required": false,
"type": "Channel",
- "description": "The channel on which the variable was set."
+ "description": "The channel on which the variable was set.\n\nIf missing, the variable is a global variable."
}
}
},
"StasisEnd": {
"id": "StasisEnd",
+ "extends": "Event",
"description": "Notification that a channel has left a Stasis appliction.",
"properties": {
"channel": {
@@ -335,6 +332,7 @@
},
"StasisStart": {
"id": "StasisStart",
+ "extends": "Event",
"description": "Notification that a channel has entered a Stasis appliction.",
"properties": {
"args": {
diff --git a/rest-api/api-docs/playback.json b/rest-api/api-docs/playback.json
index 38ca5e1a7..884c0db26 100644
--- a/rest-api/api-docs/playback.json
+++ b/rest-api/api-docs/playback.json
@@ -103,11 +103,39 @@
"models": {
"Playback": {
"id": "Playback",
+ "description": "Object representing the playback of media to a channel",
"properties": {
"id": {
+ "type": "string",
+ "description": "ID for this playback operation",
+ "required": true
+ },
+ "media_uri": {
+ "type": "string",
+ "description": "URI for the media to play back.",
+ "required": true
+ },
+ "target_uri": {
+ "type": "string",
+ "description": "URI for the channel or bridge to play the media on",
+ "required": true
+ },
+ "language": {
+ "type": "string",
+ "description": "For media types that support multiple languages, the language requested for playback."
+ },
+ "state": {
+ "type": "string",
+ "description": "Current state of the playback operation.",
"required": true,
- "description": "Playback's identifier.",
- "type": "string"
+ "allowableValues": {
+ "valueType": "LIST",
+ "values": [
+ "queued",
+ "playing",
+ "complete"
+ ]
+ }
}
}
}
diff --git a/rest-api/api-docs/recordings.json b/rest-api/api-docs/recordings.json
index 2f5f92a08..ce11d17c2 100644
--- a/rest-api/api-docs/recordings.json
+++ b/rest-api/api-docs/recordings.json
@@ -8,18 +8,6 @@
"resourcePath": "/api-docs/recordings.{format}",
"apis": [
{
- "path": "/recordings",
- "description": "Recordings",
- "operations": [
- {
- "httpMethod": "GET",
- "summary": "List all recordings.",
- "nickname": "getRecordings",
- "responseClass": "List[Recording]"
- }
- ]
- },
- {
"path": "/recordings/stored",
"description": "Recordings",
"operations": [
@@ -226,17 +214,9 @@
}
],
"models": {
- "Recording": {
- "id": "Recording",
- "properties": {
- "id": {
- "required": true,
- "type": "string"
- }
- }
- },
"StoredRecording": {
"id": "StoredRecording",
+ "description": "A past recording that may be played back.",
"properties": {
"id": {
"required": true,
@@ -246,7 +226,7 @@
"required": true,
"type": "List[string]"
},
- "durationSeconds": {
+ "duration_seconds": {
"required": false,
"type": "int"
},
@@ -259,6 +239,7 @@
},
"LiveRecording": {
"id": "LiveRecording",
+ "description": "A recording that is in progress",
"properties": {
"id": {
"required": true,
diff --git a/rest-api/api-docs/sounds.json b/rest-api/api-docs/sounds.json
index 06d84ea7e..103738c45 100644
--- a/rest-api/api-docs/sounds.json
+++ b/rest-api/api-docs/sounds.json
@@ -60,6 +60,7 @@
"models": {
"FormatLangPair": {
"id": "FormatLangPair",
+ "description": "Identifies the format and language of a sound file",
"properties": {
"language": {
"required": true,
@@ -73,6 +74,7 @@
},
"Sound": {
"id": "Sound",
+ "description": "A media file that may be played back.",
"properties": {
"id": {
"required": true,
diff --git a/tests/test_ari_model.c b/tests/test_ari_model.c
new file mode 100644
index 000000000..21ad80ab5
--- /dev/null
+++ b/tests/test_ari_model.c
@@ -0,0 +1,431 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@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 Test the native ARI JSON validators.
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*** MODULEINFO
+ <depend>TEST_FRAMEWORK</depend>
+ <depend>res_ari_model</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/utils.h"
+#include "asterisk/module.h"
+#include "asterisk/test.h"
+#include "../res/stasis_http/ari_model_validators.h"
+
+AST_TEST_DEFINE(validate_byte)
+{
+ RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
+ RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
+ int res;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/ari/validators/";
+ info->summary = "Test byte validation";
+ info->description =
+ "Test byte validation";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ uut = ast_json_integer_create(-128);
+ ast_test_validate(test, NULL != uut);
+ ast_test_validate(test, ari_validate_byte(uut));
+
+ res = ast_json_integer_set(uut, 0);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, ari_validate_byte(uut));
+
+ res = ast_json_integer_set(uut, 255);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, ari_validate_byte(uut));
+
+ res = ast_json_integer_set(uut, -129);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, !ari_validate_byte(uut));
+
+ res = ast_json_integer_set(uut, 256);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, !ari_validate_byte(uut));
+
+ str = ast_json_string_create("not a byte");
+ ast_test_validate(test, NULL != str);
+ ast_test_validate(test, !ari_validate_byte(str));
+
+ /* Even if the string has an integral value */
+ res = ast_json_string_set(str, "0");
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, !ari_validate_byte(str));
+
+ ast_test_validate(test, !ari_validate_byte(ast_json_null()));
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(validate_boolean)
+{
+ RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
+ int res;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/ari/validators/";
+ info->summary = "Test byte validation";
+ info->description =
+ "Test byte validation";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ ast_test_validate(test, ari_validate_boolean(ast_json_true()));
+ ast_test_validate(test, ari_validate_boolean(ast_json_false()));
+
+ str = ast_json_string_create("not a bool");
+ ast_test_validate(test, NULL != str);
+ ast_test_validate(test, !ari_validate_boolean(str));
+
+ /* Even if the string has a boolean value */
+ res = ast_json_string_set(str, "true");
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, !ari_validate_boolean(str));
+
+ /* Even if the string has a boolean text in it */
+ res = ast_json_string_set(str, "true");
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, !ari_validate_boolean(str));
+
+ ast_test_validate(test, !ari_validate_boolean(ast_json_null()));
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(validate_int)
+{
+ RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
+ RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
+ int res;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/ari/validators/";
+ info->summary = "Test int validation";
+ info->description =
+ "Test int validation";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ uut = ast_json_integer_create(-2147483648);
+ ast_test_validate(test, NULL != uut);
+ ast_test_validate(test, ari_validate_int(uut));
+
+ res = ast_json_integer_set(uut, 0);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, ari_validate_int(uut));
+
+ res = ast_json_integer_set(uut, 2147483647);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, ari_validate_int(uut));
+
+ res = ast_json_integer_set(uut, -2147483649LL);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, !ari_validate_int(uut));
+
+ res = ast_json_integer_set(uut, 2147483648LL);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, !ari_validate_int(uut));
+
+ str = ast_json_string_create("not a int");
+ ast_test_validate(test, NULL != str);
+ ast_test_validate(test, !ari_validate_int(str));
+
+ /* Even if the string has an integral value */
+ res = ast_json_string_set(str, "0");
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, !ari_validate_int(str));
+
+ ast_test_validate(test, !ari_validate_int(ast_json_null()));
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(validate_long)
+{
+ RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
+ RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
+ int res;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/ari/validators/";
+ info->summary = "Test long validation";
+ info->description =
+ "Test long validation";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ uut = ast_json_integer_create(0);
+ ast_test_validate(test, NULL != uut);
+ ast_test_validate(test, ari_validate_long(uut));
+
+ str = ast_json_string_create("not a long");
+ ast_test_validate(test, NULL != str);
+ ast_test_validate(test, !ari_validate_long(str));
+
+ /* Even if the string has an integral value */
+ res = ast_json_string_set(str, "0");
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, !ari_validate_long(str));
+
+ ast_test_validate(test, !ari_validate_long(ast_json_null()));
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(validate_string)
+{
+ RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
+ RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
+ int res;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/ari/validators/";
+ info->summary = "Test string validation";
+ info->description =
+ "Test string validation";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ uut = ast_json_string_create("text");
+ ast_test_validate(test, NULL != uut);
+ ast_test_validate(test, ari_validate_string(uut));
+
+ res = ast_json_string_set(uut, "");
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, ari_validate_string(uut));
+
+ ast_test_validate(test, !ari_validate_string(ast_json_null()));
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(validate_date)
+{
+ RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
+ RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
+ enum ast_test_result_state test_res;
+ int res;
+ int i;
+ const char *valid_dates[] = {
+ /* Time is optional */
+ "2013-06-17",
+ /* Seconds are optional */
+ "2013-06-17T23:59Z",
+ /* Subseconds are optional */
+ "2013-06-17T23:59:59Z",
+ /* Leap seconds are valid */
+ "2013-06-30T23:59:61Z",
+ /* Subseconds are allowed */
+ "2013-06-17T23:59:59.999999Z",
+ /* Now with -06:00 for the timezone */
+ "2013-06-17T23:59-06:00",
+ "2013-06-17T23:59:59-06:00",
+ "2013-06-30T23:59:61-06:00",
+ "2013-06-17T23:59:59.999999-06:00",
+ /* Again, with +06:30 for the timezone */
+ "2013-06-17T23:59+06:30",
+ "2013-06-17T23:59:59+06:30",
+ "2013-06-30T23:59:61+06:30",
+ "2013-06-17T23:59:59.999999+06:30",
+ /* So the colon in the timezone is optional */
+ "2013-06-17T23:59-0600",
+ "2013-06-17T23:59:59-0600",
+ "2013-06-30T23:59:61-0600",
+ "2013-06-17T23:59:59.999999-0600",
+ /* Sure, why not */
+ "2013-06-17T23:59+0630",
+ "2013-06-17T23:59:59+0630",
+ "2013-06-30T23:59:61+0630",
+ "2013-06-17T23:59:59.999999+0630",
+ "9999-12-31T23:59:61.999999Z",
+ /* In fact, you don't even have to specify minutes */
+ "2013-06-17T23:59-06",
+ "2013-06-17T23:59:59-06",
+ "2013-06-30T23:59:61-06",
+ "2013-06-17T23:59:59.999999-06",
+ };
+
+ /* There are lots of invalid dates that the validator lets through.
+ * Those would be strings properly formatted as a ridiculous date. Such
+ * as 0000-00-00, or 9999-19-39. Those are harder to catch with a regex,
+ * and actually aren't as important. So long as the valid dates pass the
+ * validator, and poorly formatted dates are rejected, it's fine.
+ * Catching the occasional ridiculous date is just bonus.
+ */
+ const char *invalid_dates[] = {
+ "",
+ "Not a date",
+ "2013-06-17T", /* Missing time, but has T */
+ "2013-06-17T23:59:59.Z", /* Missing subsecond, but has dot */
+ "2013-06-17T23:59", /* Missing timezone, but has time */
+ "2013-06-17T23:59:59.999999", /* Missing timezone */
+ "9999-99-31T23:59:61.999999Z", /* Invalid month */
+ "9999-12-99T23:59:61.999999Z", /* Invalid day */
+ "9999-12-31T99:59:61.999999Z", /* Invalid hour */
+ "9999-12-31T23:99:61.999999Z", /* Invalid minute */
+ "9999-12-31T23:59:99.999999Z", /* Invalid second */
+ "2013-06-17T23:59:59.999999-99:00", /* Invalid timezone */
+ "2013-06-17T23:59:59.999999-06:99", /* Invalid timezone */
+ "2013-06-17T23:59:59.999999-06:", /* Invalid timezone */
+ "2013-06-17T23:59:59.999999-06:0", /* Invalid timezone */
+ "2013-06-17T23:59:59.999999-060", /* Invalid timezone */
+ };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/ari/validators/";
+ info->summary = "Test date validation";
+ info->description =
+ "Test date validation";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ uut = ast_json_string_create("");
+ ast_test_validate(test, NULL != uut);
+
+ /* Instead of using ast_test_validate, we'll collect the results from
+ * several test cases, since we have so many */
+ test_res = AST_TEST_PASS;
+ for (i = 0; i < ARRAY_LEN(valid_dates); ++i) {
+ res = ast_json_string_set(uut, valid_dates[i]);
+ ast_test_validate(test, 0 == res);
+ if (!ari_validate_date(uut)) {
+ ast_test_status_update(test,
+ "Expected '%s' to be a valid date\n",
+ valid_dates[i]);
+ test_res = AST_TEST_FAIL;
+ }
+ }
+
+ for (i = 0; i < ARRAY_LEN(invalid_dates); ++i) {
+ res = ast_json_string_set(uut, invalid_dates[i]);
+ ast_test_validate(test, 0 == res);
+ if (ari_validate_date(uut)) {
+ ast_test_status_update(test,
+ "Expected '%s' to be an invalid date\n",
+ invalid_dates[i]);
+ test_res = AST_TEST_FAIL;
+ }
+ }
+
+ ast_test_validate(test, !ari_validate_string(ast_json_null()));
+
+ return test_res;
+}
+
+AST_TEST_DEFINE(validate_list)
+{
+ RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
+ RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
+ int res;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/ari/validators/";
+ info->summary = "Test list validation";
+ info->description =
+ "Test list validation";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ uut = ast_json_array_create();
+ ast_test_validate(test, NULL != uut);
+ ast_test_validate(test, ari_validate_list(uut, ari_validate_string));
+ ast_test_validate(test, ari_validate_list(uut, ari_validate_int));
+
+ res = ast_json_array_append(uut, ast_json_string_create(""));
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, ari_validate_list(uut, ari_validate_string));
+ ast_test_validate(test, !ari_validate_list(uut, ari_validate_int));
+
+ res = ast_json_array_append(uut, ast_json_integer_create(0));
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, !ari_validate_list(uut, ari_validate_string));
+ ast_test_validate(test, !ari_validate_list(uut, ari_validate_int));
+
+ ast_test_validate(test,
+ !ari_validate_list(ast_json_null(), ari_validate_string));
+
+ return AST_TEST_PASS;
+}
+
+static int unload_module(void)
+{
+ AST_TEST_UNREGISTER(validate_byte);
+ AST_TEST_UNREGISTER(validate_boolean);
+ AST_TEST_UNREGISTER(validate_int);
+ AST_TEST_UNREGISTER(validate_long);
+ AST_TEST_UNREGISTER(validate_string);
+ AST_TEST_UNREGISTER(validate_date);
+ AST_TEST_UNREGISTER(validate_list);
+ return 0;
+}
+
+static int load_module(void)
+{
+ AST_TEST_REGISTER(validate_byte);
+ AST_TEST_REGISTER(validate_boolean);
+ AST_TEST_REGISTER(validate_int);
+ AST_TEST_REGISTER(validate_long);
+ AST_TEST_REGISTER(validate_string);
+ AST_TEST_REGISTER(validate_date);
+ AST_TEST_REGISTER(validate_list);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Skeleton (sample) Test");
diff --git a/tests/test_res_stasis.c b/tests/test_res_stasis.c
index 321f40f3d..5865f0951 100644
--- a/tests/test_res_stasis.c
+++ b/tests/test_res_stasis.c
@@ -157,7 +157,9 @@ AST_TEST_DEFINE(app_replaced)
stasis_app_register(app_name, test_handler, app_data1);
stasis_app_register(app_name, test_handler, app_data2);
- expected_message1 = ast_json_pack("[{s: {s: s}}]", "application_replaced", "application", app_name);
+ expected_message1 = ast_json_pack("[{s: s, s: s}]",
+ "type", "ApplicationReplaced",
+ "application", app_name);
message = ast_json_pack("{ s: o }", "test-message", ast_json_null());
expected_message2 = ast_json_pack("[o]", ast_json_ref(message));
diff --git a/tests/test_stasis_channels.c b/tests/test_stasis_channels.c
index 214d77396..a3f882819 100644
--- a/tests/test_stasis_channels.c
+++ b/tests/test_stasis_channels.c
@@ -256,8 +256,7 @@ AST_TEST_DEFINE(channel_snapshot_json)
ast_test_validate(test, NULL != snapshot);
actual = ast_channel_snapshot_to_json(snapshot);
- expected = ast_json_pack("{ s: s, s: s, s: s, s: s, s: s, s: s, s: s,"
- " s: s, s: s, s: s, s: s,"
+ expected = ast_json_pack("{ s: s, s: s, s: s, s: s,"
" s: { s: s, s: s, s: i },"
" s: { s: s, s: s },"
" s: { s: s, s: s },"
@@ -266,14 +265,7 @@ AST_TEST_DEFINE(channel_snapshot_json)
"name", "TEST/name",
"state", "Down",
"accountcode", "acctcode",
- "peeraccount", "",
- "userfield", "",
- "uniqueid", ast_channel_uniqueid(chan),
- "linkedid", ast_channel_uniqueid(chan),
- "parkinglot", "",
- "hangupsource", "",
- "appl", "",
- "data", "",
+ "id", ast_channel_uniqueid(chan),
"dialplan",
"context", "context",
"exten", "exten",