]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
ARI: Add events for Contact and Peer Status changes 95/1295/1
authorMatt Jordan <mjordan@digium.com>
Fri, 4 Sep 2015 02:19:21 +0000 (21:19 -0500)
committerMatt Jordan <mjordan@digium.com>
Mon, 21 Sep 2015 13:21:58 +0000 (08:21 -0500)
This patch adds support for receiving events regarding Peer status changes
and Contact status changes. This is particularly useful in scenarios where
we are subscribed to all endpoints and channels, where we often want to know
more about the state of channel technology specific items than a single
endpoint's state.

ASTERISK-24870

Change-Id: I6137459cdc25ce27efc134ad58abf065653da4e9

CHANGES
main/stasis_endpoints.c
res/ari/ari_model_validators.c
res/ari/ari_model_validators.h
rest-api-templates/ari_model_validators.c.mustache
rest-api/api-docs/events.json

diff --git a/CHANGES b/CHANGES
index 8c8329cb0cb8aa77f9382bf5f55c242b7404110c..9d599f432d90ea67350e52f36aa44a8aad69200e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -189,6 +189,26 @@ Dialplan Functions
    return the SIP Call-ID associated with the INVITE request that established
    the PJSIP channel.
 
+ARI
+------------------
+ * Two new endpoint related events are now available: PeerStatusChange and
+   ContactStatusChange. In particular, these events are useful when subscribing
+   to all event sources, as they provide additional endpoint related
+   information beyond the addition/removal of channels from an endpoint.
+
+ * Added the ability to subscribe to all ARI events in Asterisk, regardless
+   of whether the application 'controls' the resource. This is useful for
+   scenarios where an ARI application merely wants to observe the system,
+   as opposed to control it. There are two ways to accomplish this:
+   (1) Via the WebSocket connection URI. A new query paramter, 'subscribeAll',
+       has been added that, when present and True, will subscribe all
+       specified applications to all ARI event sources in Asterisk.
+   (2) Via the applications resource. An ARI client can, at any time, subscribe
+       to all resources in an event source merely by not providing an explicit
+       resource. For example, subscribing to an event source of 'channels:'
+       as opposed to 'channels:12345' will subscribe the application to all
+       channels.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 13.4.0 to Asterisk 13.5.0 ------------
 ------------------------------------------------------------------------------
index da6505355139377d524acd332fa4c7e652307447..f44ce4229065c65cbb26c07cde3586f7126b654e 100644 (file)
@@ -124,12 +124,7 @@ struct stasis_topic *ast_endpoint_topic_all_cached(void)
        return stasis_cp_all_topic_cached(endpoint_cache_all);
 }
 
-static struct ast_manager_event_blob *peerstatus_to_ami(struct stasis_message *msg);
-
 STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_snapshot_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_state_type,
-       .to_ami = peerstatus_to_ami,
-);
 
 static struct ast_manager_event_blob *peerstatus_to_ami(struct stasis_message *msg)
 {
@@ -166,10 +161,44 @@ static struct ast_manager_event_blob *peerstatus_to_ami(struct stasis_message *m
                ast_str_buffer(peerstatus_event_string));
 }
 
-static struct ast_manager_event_blob *contactstatus_to_ami(struct stasis_message *msg);
+static struct ast_json *peerstatus_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)
+{
+       struct ast_endpoint_blob *obj = stasis_message_data(msg);
+       struct ast_json *json_endpoint;
+       struct ast_json *json_peer;
+       struct ast_json *json_final;
+       const struct timeval *tv = stasis_message_timestamp(msg);
 
-STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_contact_state_type,
-       .to_ami = contactstatus_to_ami,
+       json_endpoint = ast_endpoint_snapshot_to_json(obj->snapshot, NULL);
+       if (!json_endpoint) {
+               return NULL;
+       }
+
+       json_peer = ast_json_object_create();
+       if (!json_peer) {
+               ast_json_unref(json_endpoint);
+               return NULL;
+       }
+
+       /* Copy all fields from the blob */
+       ast_json_object_update(json_peer, obj->blob);
+
+       json_final = ast_json_pack("{s: s, s: o, s: o, s: o }",
+               "type", "PeerStatusChange",
+               "timestamp", ast_json_timeval(*tv, NULL),
+               "endpoint", json_endpoint,
+               "peer", json_peer);
+       if (!json_final) {
+               ast_json_unref(json_endpoint);
+               ast_json_unref(json_peer);
+       }
+
+       return json_final;
+}
+
+STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_state_type,
+       .to_ami = peerstatus_to_ami,
+       .to_json = peerstatus_to_json,
 );
 
 static struct ast_manager_event_blob *contactstatus_to_ami(struct stasis_message *msg)
@@ -206,6 +235,39 @@ static struct ast_manager_event_blob *contactstatus_to_ami(struct stasis_message
                "%s", ast_str_buffer(contactstatus_event_string));
 }
 
+static struct ast_json *contactstatus_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)
+{
+       struct ast_endpoint_blob *obj = stasis_message_data(msg);
+       struct ast_json *json_endpoint;
+       struct ast_json *json_final;
+       const struct timeval *tv = stasis_message_timestamp(msg);
+
+       json_endpoint = ast_endpoint_snapshot_to_json(obj->snapshot, NULL);
+       if (!json_endpoint) {
+               return NULL;
+       }
+
+       json_final = ast_json_pack("{s: s, s: o, s: o, s: { s: s, s: s, s: s } } ",
+               "type", "ContactStatusChange",
+               "timestamp", ast_json_timeval(*tv, NULL),
+               "endpoint", json_endpoint,
+               "contact_info",
+               "uri", ast_json_string_get(ast_json_object_get(obj->blob, "uri")),
+               "contact_status", ast_json_string_get(ast_json_object_get(obj->blob, "contact_status")),
+               "aor", ast_json_string_get(ast_json_object_get(obj->blob, "aor")),
+               "roundtrip_usec", ast_json_string_get(ast_json_object_get(obj->blob, "roundtrip_usec")));
+       if (!json_final) {
+               ast_json_unref(json_endpoint);
+       }
+
+       return json_final;
+}
+
+STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_contact_state_type,
+       .to_ami = contactstatus_to_ami,
+       .to_json = contactstatus_to_json
+);
+
 static void endpoint_blob_dtor(void *obj)
 {
        struct ast_endpoint_blob *event = obj;
index 0a5c7606f3b85e523cf4663604290b231f60f686..623d5b54162be5f3c637bf0b84c60c79112633b2 100644 (file)
@@ -4180,6 +4180,180 @@ ari_validator ast_ari_validate_channel_varset_fn(void)
        return ast_ari_validate_channel_varset;
 }
 
+int ast_ari_validate_contact_info(struct ast_json *json)
+{
+       int res = 1;
+       struct ast_json_iter *iter;
+       int has_aor = 0;
+       int has_contact_status = 0;
+       int has_uri = 0;
+
+       for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+               if (strcmp("aor", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_aor = 1;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI ContactInfo field aor failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("contact_status", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_contact_status = 1;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI ContactInfo field contact_status failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("roundtrip_usec", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI ContactInfo field roundtrip_usec failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("uri", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_uri = 1;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI ContactInfo field uri failed validation\n");
+                               res = 0;
+                       }
+               } else
+               {
+                       ast_log(LOG_ERROR,
+                               "ARI ContactInfo has undocumented field %s\n",
+                               ast_json_object_iter_key(iter));
+                       res = 0;
+               }
+       }
+
+       if (!has_aor) {
+               ast_log(LOG_ERROR, "ARI ContactInfo missing required field aor\n");
+               res = 0;
+       }
+
+       if (!has_contact_status) {
+               ast_log(LOG_ERROR, "ARI ContactInfo missing required field contact_status\n");
+               res = 0;
+       }
+
+       if (!has_uri) {
+               ast_log(LOG_ERROR, "ARI ContactInfo missing required field uri\n");
+               res = 0;
+       }
+
+       return res;
+}
+
+ari_validator ast_ari_validate_contact_info_fn(void)
+{
+       return ast_ari_validate_contact_info;
+}
+
+int ast_ari_validate_contact_status_change(struct ast_json *json)
+{
+       int res = 1;
+       struct ast_json_iter *iter;
+       int has_type = 0;
+       int has_application = 0;
+       int has_contact_info = 0;
+       int has_endpoint = 0;
+
+       for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+               if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_type = 1;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI ContactStatusChange field type failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_application = 1;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI ContactStatusChange field application failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       prop_is_valid = ast_ari_validate_date(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI ContactStatusChange field timestamp failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("contact_info", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_contact_info = 1;
+                       prop_is_valid = ast_ari_validate_contact_info(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI ContactStatusChange field contact_info failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("endpoint", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_endpoint = 1;
+                       prop_is_valid = ast_ari_validate_endpoint(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI ContactStatusChange field endpoint failed validation\n");
+                               res = 0;
+                       }
+               } else
+               {
+                       ast_log(LOG_ERROR,
+                               "ARI ContactStatusChange has undocumented field %s\n",
+                               ast_json_object_iter_key(iter));
+                       res = 0;
+               }
+       }
+
+       if (!has_type) {
+               ast_log(LOG_ERROR, "ARI ContactStatusChange missing required field type\n");
+               res = 0;
+       }
+
+       if (!has_application) {
+               ast_log(LOG_ERROR, "ARI ContactStatusChange missing required field application\n");
+               res = 0;
+       }
+
+       if (!has_contact_info) {
+               ast_log(LOG_ERROR, "ARI ContactStatusChange missing required field contact_info\n");
+               res = 0;
+       }
+
+       if (!has_endpoint) {
+               ast_log(LOG_ERROR, "ARI ContactStatusChange missing required field endpoint\n");
+               res = 0;
+       }
+
+       return res;
+}
+
+ari_validator ast_ari_validate_contact_status_change_fn(void)
+{
+       return ast_ari_validate_contact_status_change;
+}
+
 int ast_ari_validate_device_state_changed(struct ast_json *json)
 {
        int res = 1;
@@ -4479,7 +4653,7 @@ int ast_ari_validate_event(struct ast_json *json)
 
        discriminator = ast_json_string_get(ast_json_object_get(json, "type"));
        if (!discriminator) {
-               ast_log(LOG_ERROR, "ARI Event missing required field type");
+               ast_log(LOG_ERROR, "ARI Event missing required field type\n");
                return 0;
        }
 
@@ -4552,6 +4726,9 @@ int ast_ari_validate_event(struct ast_json *json)
        if (strcmp("ChannelVarset", discriminator) == 0) {
                return ast_ari_validate_channel_varset(json);
        } else
+       if (strcmp("ContactStatusChange", discriminator) == 0) {
+               return ast_ari_validate_contact_status_change(json);
+       } else
        if (strcmp("DeviceStateChanged", discriminator) == 0) {
                return ast_ari_validate_device_state_changed(json);
        } else
@@ -4561,6 +4738,9 @@ int ast_ari_validate_event(struct ast_json *json)
        if (strcmp("EndpointStateChange", discriminator) == 0) {
                return ast_ari_validate_endpoint_state_change(json);
        } else
+       if (strcmp("PeerStatusChange", discriminator) == 0) {
+               return ast_ari_validate_peer_status_change(json);
+       } else
        if (strcmp("PlaybackFinished", discriminator) == 0) {
                return ast_ari_validate_playback_finished(json);
        } else
@@ -4656,7 +4836,7 @@ int ast_ari_validate_message(struct ast_json *json)
 
        discriminator = ast_json_string_get(ast_json_object_get(json, "type"));
        if (!discriminator) {
-               ast_log(LOG_ERROR, "ARI Message missing required field type");
+               ast_log(LOG_ERROR, "ARI Message missing required field type\n");
                return 0;
        }
 
@@ -4729,6 +4909,9 @@ int ast_ari_validate_message(struct ast_json *json)
        if (strcmp("ChannelVarset", discriminator) == 0) {
                return ast_ari_validate_channel_varset(json);
        } else
+       if (strcmp("ContactStatusChange", discriminator) == 0) {
+               return ast_ari_validate_contact_status_change(json);
+       } else
        if (strcmp("DeviceStateChanged", discriminator) == 0) {
                return ast_ari_validate_device_state_changed(json);
        } else
@@ -4744,6 +4927,9 @@ int ast_ari_validate_message(struct ast_json *json)
        if (strcmp("MissingParams", discriminator) == 0) {
                return ast_ari_validate_missing_params(json);
        } else
+       if (strcmp("PeerStatusChange", discriminator) == 0) {
+               return ast_ari_validate_peer_status_change(json);
+       } else
        if (strcmp("PlaybackFinished", discriminator) == 0) {
                return ast_ari_validate_playback_finished(json);
        } else
@@ -4861,6 +5047,175 @@ ari_validator ast_ari_validate_missing_params_fn(void)
        return ast_ari_validate_missing_params;
 }
 
+int ast_ari_validate_peer(struct ast_json *json)
+{
+       int res = 1;
+       struct ast_json_iter *iter;
+       int has_peer_status = 0;
+
+       for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+               if (strcmp("address", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI Peer field address failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("cause", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI Peer field cause failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("peer_status", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_peer_status = 1;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI Peer field peer_status failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("port", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI Peer field port failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("time", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI Peer field time failed validation\n");
+                               res = 0;
+                       }
+               } else
+               {
+                       ast_log(LOG_ERROR,
+                               "ARI Peer has undocumented field %s\n",
+                               ast_json_object_iter_key(iter));
+                       res = 0;
+               }
+       }
+
+       if (!has_peer_status) {
+               ast_log(LOG_ERROR, "ARI Peer missing required field peer_status\n");
+               res = 0;
+       }
+
+       return res;
+}
+
+ari_validator ast_ari_validate_peer_fn(void)
+{
+       return ast_ari_validate_peer;
+}
+
+int ast_ari_validate_peer_status_change(struct ast_json *json)
+{
+       int res = 1;
+       struct ast_json_iter *iter;
+       int has_type = 0;
+       int has_application = 0;
+       int has_endpoint = 0;
+       int has_peer = 0;
+
+       for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+               if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_type = 1;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI PeerStatusChange field type failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_application = 1;
+                       prop_is_valid = ast_ari_validate_string(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI PeerStatusChange field application failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       prop_is_valid = ast_ari_validate_date(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI PeerStatusChange field timestamp failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("endpoint", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_endpoint = 1;
+                       prop_is_valid = ast_ari_validate_endpoint(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI PeerStatusChange field endpoint failed validation\n");
+                               res = 0;
+                       }
+               } else
+               if (strcmp("peer", ast_json_object_iter_key(iter)) == 0) {
+                       int prop_is_valid;
+                       has_peer = 1;
+                       prop_is_valid = ast_ari_validate_peer(
+                               ast_json_object_iter_value(iter));
+                       if (!prop_is_valid) {
+                               ast_log(LOG_ERROR, "ARI PeerStatusChange field peer failed validation\n");
+                               res = 0;
+                       }
+               } else
+               {
+                       ast_log(LOG_ERROR,
+                               "ARI PeerStatusChange has undocumented field %s\n",
+                               ast_json_object_iter_key(iter));
+                       res = 0;
+               }
+       }
+
+       if (!has_type) {
+               ast_log(LOG_ERROR, "ARI PeerStatusChange missing required field type\n");
+               res = 0;
+       }
+
+       if (!has_application) {
+               ast_log(LOG_ERROR, "ARI PeerStatusChange missing required field application\n");
+               res = 0;
+       }
+
+       if (!has_endpoint) {
+               ast_log(LOG_ERROR, "ARI PeerStatusChange missing required field endpoint\n");
+               res = 0;
+       }
+
+       if (!has_peer) {
+               ast_log(LOG_ERROR, "ARI PeerStatusChange missing required field peer\n");
+               res = 0;
+       }
+
+       return res;
+}
+
+ari_validator ast_ari_validate_peer_status_change_fn(void)
+{
+       return ast_ari_validate_peer_status_change;
+}
+
 int ast_ari_validate_playback_finished(struct ast_json *json)
 {
        int res = 1;
index 1803f57c9ef1764e32def4174ab584e01f7426ed..0bcdb0fa211a13426913427c7a53532900ac290d 100644 (file)
@@ -1006,6 +1006,42 @@ int ast_ari_validate_channel_varset(struct ast_json *json);
  */
 ari_validator ast_ari_validate_channel_varset_fn(void);
 
+/*!
+ * \brief Validator for ContactInfo.
+ *
+ * Detailed information about a contact on an endpoint.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_contact_info(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_contact_info().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_contact_info_fn(void);
+
+/*!
+ * \brief Validator for ContactStatusChange.
+ *
+ * The state of a contact on an endpoint has changed.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_contact_status_change(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_contact_status_change().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_contact_status_change_fn(void);
+
 /*!
  * \brief Validator for DeviceStateChanged.
  *
@@ -1114,6 +1150,42 @@ int ast_ari_validate_missing_params(struct ast_json *json);
  */
 ari_validator ast_ari_validate_missing_params_fn(void);
 
+/*!
+ * \brief Validator for Peer.
+ *
+ * Detailed information about a remote peer that communicates with Asterisk.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_peer(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_peer().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_peer_fn(void);
+
+/*!
+ * \brief Validator for PeerStatusChange.
+ *
+ * The state of a peer associated with an endpoint has changed.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_peer_status_change(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_peer_status_change().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_peer_status_change_fn(void);
+
 /*!
  * \brief Validator for PlaybackFinished.
  *
@@ -1546,6 +1618,17 @@ ari_validator ast_ari_validate_application_fn(void);
  * - channel: Channel
  * - value: string (required)
  * - variable: string (required)
+ * ContactInfo
+ * - aor: string (required)
+ * - contact_status: string (required)
+ * - roundtrip_usec: string
+ * - uri: string (required)
+ * ContactStatusChange
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - contact_info: ContactInfo (required)
+ * - endpoint: Endpoint (required)
  * DeviceStateChanged
  * - type: string (required)
  * - application: string (required)
@@ -1575,6 +1658,18 @@ ari_validator ast_ari_validate_application_fn(void);
  * MissingParams
  * - type: string (required)
  * - params: List[string] (required)
+ * Peer
+ * - address: string
+ * - cause: string
+ * - peer_status: string (required)
+ * - port: string
+ * - time: string
+ * PeerStatusChange
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - endpoint: Endpoint (required)
+ * - peer: Peer (required)
  * PlaybackFinished
  * - type: string (required)
  * - application: string (required)
index 0ca3d26ca3fb1eb0fefe41622df6fd048ef8a0ad..78f19bf6697a6daec39f648cb6086f6a6a57e3bb 100644 (file)
@@ -50,7 +50,7 @@ int ast_ari_validate_{{c_id}}(struct ast_json *json)
 
        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}}");
+               ast_log(LOG_ERROR, "ARI {{id}} missing required field {{discriminator.name}}\n");
                return 0;
        }
 
index 392b0ac706f389ad660a82ef535b12033c96c505..54269a407bfc92dc212f45308186cd576e0f545e 100644 (file)
                                "ChannelTalkingFinished",
                                "ChannelHold",
                                "ChannelUnhold",
+                               "ContactStatusChange",
                                "EndpointStateChange",
                                "Dial",
                                "StasisEnd",
                                "StasisStart",
                                "TextMessageReceived",
-                               "ChannelConnectedLine"
+                               "ChannelConnectedLine",
+                               "PeerStatusChange"
                        ]
                },
+               "ContactInfo": {
+                       "id": "ContactInfo",
+                       "description": "Detailed information about a contact on an endpoint.",
+                       "properties": {
+                               "uri": {
+                                       "type": "string",
+                                       "description": "The location of the contact.",
+                                       "required": true
+                               },
+                               "contact_status": {
+                                       "type": "string",
+                                       "description": "The current status of the contact.",
+                                       "required": true,
+                                       "allowableValues": {
+                                               "valueType": "LIST",
+                                               "values": [
+                                                       "Unreachable",
+                                                       "Reachable",
+                                                       "Unknown",
+                                                       "Created",
+                                                       "Removed"
+                                               ]
+                                       }
+                               },
+                               "aor": {
+                                       "type": "string",
+                                       "description": "The Address of Record this contact belongs to.",
+                                       "required": true
+                               },
+                               "roundtrip_usec": {
+                                       "type": "string",
+                                       "description": "Current round trip time, in microseconds, for the contact.",
+                                       "required": false
+                               }
+                       }
+               },
+               "Peer": {
+                       "id": "Peer",
+                       "description": "Detailed information about a remote peer that communicates with Asterisk.",
+                       "properties": {
+                               "peer_status": {
+                                       "type": "string",
+                                       "description": "The current state of the peer. Note that the values of the status are dependent on the underlying peer technology.",
+                                       "required": true
+                               },
+                               "cause": {
+                                       "type": "string",
+                                       "description": "An optional reason associated with the change in peer_status.",
+                                       "required": false
+                               },
+                               "address": {
+                                       "type": "string",
+                                       "description": "The IP address of the peer.",
+                                       "required": false
+                               },
+                               "port": {
+                                       "type": "string",
+                                       "description": "The port of the peer.",
+                                       "required": false
+                               },
+                               "time": {
+                                       "type": "string",
+                                       "description": "The last known time the peer was contacted.",
+                                       "required": false
+                               }
+                       }
+               },
                "DeviceStateChanged": {
                        "id": "DeviceStateChanged",
                        "description": "Notification that a device state has changed.",
                                }
                        }
                },
+               "ContactStatusChange": {
+                       "id": "ContactStatusChange",
+                       "description": "The state of a contact on an endpoint has changed.",
+                       "properties": {
+                               "endpoint": {
+                                       "required": true,
+                                       "type": "Endpoint"
+                               },
+                               "contact_info": {
+                                       "required": true,
+                                       "type": "ContactInfo"
+                               }
+                       }
+               },
+               "PeerStatusChange": {
+                       "id": "PeerStatusChange",
+                       "description": "The state of a peer associated with an endpoint has changed.",
+                       "properties": {
+                               "endpoint": {
+                                       "required": true,
+                                       "type": "Endpoint"
+                               },
+                               "peer": {
+                                       "required": true,
+                                       "type": "Peer"
+                               }
+                       }
+               },
                "EndpointStateChange": {
                        "id": "EndpointStateChange",
                        "description": "Endpoint state changed.",