ARI Outbound Websockets

Asterisk can now establish websocket sessions _to_ your ARI applications
as well as accepting websocket sessions _from_ them.
Full details: http://s.asterisk.net/ari-outbound-ws

Code change summary:
* Added an ast_vector_string_join() function,
* Added ApplicationRegistered and ApplicationUnregistered ARI events.
* Converted res/ari/config.c to use sorcery to process ari.conf.
* Added the "outbound-websocket" ARI config object.
* Refactored res/ari/ari_websockets.c to handle outbound websockets.
* Refactored res/ari/cli.c for the sorcery changeover.
* Updated res/res_stasis.c for the sorcery changeover.
* Updated apps/app_stasis.c to allow initiating per-call outbound websockets.
* Added CLI commands to manage ARI websockets.
* Added the new "outbound-websocket" object to ari.conf.sample.
* Moved the ARI XML documentation out of res_ari.c into res/ari/ari_doc.xml

UserNote: Asterisk can now establish websocket sessions _to_ your ARI applications
as well as accepting websocket sessions _from_ them.
Full details: http://s.asterisk.net/ari-outbound-ws
This commit is contained in:
George Joseph
2025-03-28 06:54:21 -06:00
parent 831c961a63
commit 65199303b9
15 changed files with 2948 additions and 963 deletions

View File

@@ -2610,6 +2610,85 @@ ari_validator ast_ari_validate_application_move_failed_fn(void)
return ast_ari_validate_application_move_failed;
}
int ast_ari_validate_application_registered(struct ast_json *json)
{
int res = 1;
struct ast_json_iter *iter;
int has_type = 0;
int has_application = 0;
int has_timestamp = 0;
for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
if (strcmp("asterisk_id", 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 ApplicationRegistered field asterisk_id 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 = ast_ari_validate_string(
ast_json_object_iter_value(iter));
if (!prop_is_valid) {
ast_log(LOG_ERROR, "ARI ApplicationRegistered 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 ApplicationRegistered field application failed validation\n");
res = 0;
}
} else
if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
int prop_is_valid;
has_timestamp = 1;
prop_is_valid = ast_ari_validate_date(
ast_json_object_iter_value(iter));
if (!prop_is_valid) {
ast_log(LOG_ERROR, "ARI ApplicationRegistered field timestamp failed validation\n");
res = 0;
}
} else
{
ast_log(LOG_ERROR,
"ARI ApplicationRegistered has undocumented field %s\n",
ast_json_object_iter_key(iter));
res = 0;
}
}
if (!has_type) {
ast_log(LOG_ERROR, "ARI ApplicationRegistered missing required field type\n");
res = 0;
}
if (!has_application) {
ast_log(LOG_ERROR, "ARI ApplicationRegistered missing required field application\n");
res = 0;
}
if (!has_timestamp) {
ast_log(LOG_ERROR, "ARI ApplicationRegistered missing required field timestamp\n");
res = 0;
}
return res;
}
ari_validator ast_ari_validate_application_registered_fn(void)
{
return ast_ari_validate_application_registered;
}
int ast_ari_validate_application_replaced(struct ast_json *json)
{
int res = 1;
@@ -2689,6 +2768,85 @@ ari_validator ast_ari_validate_application_replaced_fn(void)
return ast_ari_validate_application_replaced;
}
int ast_ari_validate_application_unregistered(struct ast_json *json)
{
int res = 1;
struct ast_json_iter *iter;
int has_type = 0;
int has_application = 0;
int has_timestamp = 0;
for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
if (strcmp("asterisk_id", 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 ApplicationUnregistered field asterisk_id 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 = ast_ari_validate_string(
ast_json_object_iter_value(iter));
if (!prop_is_valid) {
ast_log(LOG_ERROR, "ARI ApplicationUnregistered 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 ApplicationUnregistered field application failed validation\n");
res = 0;
}
} else
if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
int prop_is_valid;
has_timestamp = 1;
prop_is_valid = ast_ari_validate_date(
ast_json_object_iter_value(iter));
if (!prop_is_valid) {
ast_log(LOG_ERROR, "ARI ApplicationUnregistered field timestamp failed validation\n");
res = 0;
}
} else
{
ast_log(LOG_ERROR,
"ARI ApplicationUnregistered has undocumented field %s\n",
ast_json_object_iter_key(iter));
res = 0;
}
}
if (!has_type) {
ast_log(LOG_ERROR, "ARI ApplicationUnregistered missing required field type\n");
res = 0;
}
if (!has_application) {
ast_log(LOG_ERROR, "ARI ApplicationUnregistered missing required field application\n");
res = 0;
}
if (!has_timestamp) {
ast_log(LOG_ERROR, "ARI ApplicationUnregistered missing required field timestamp\n");
res = 0;
}
return res;
}
ari_validator ast_ari_validate_application_unregistered_fn(void)
{
return ast_ari_validate_application_unregistered;
}
int ast_ari_validate_bridge_attended_transfer(struct ast_json *json)
{
int res = 1;
@@ -6085,9 +6243,15 @@ int ast_ari_validate_event(struct ast_json *json)
if (strcmp("ApplicationMoveFailed", discriminator) == 0) {
return ast_ari_validate_application_move_failed(json);
} else
if (strcmp("ApplicationRegistered", discriminator) == 0) {
return ast_ari_validate_application_registered(json);
} else
if (strcmp("ApplicationReplaced", discriminator) == 0) {
return ast_ari_validate_application_replaced(json);
} else
if (strcmp("ApplicationUnregistered", discriminator) == 0) {
return ast_ari_validate_application_unregistered(json);
} else
if (strcmp("BridgeAttendedTransfer", discriminator) == 0) {
return ast_ari_validate_bridge_attended_transfer(json);
} else
@@ -6301,9 +6465,15 @@ int ast_ari_validate_message(struct ast_json *json)
if (strcmp("ApplicationMoveFailed", discriminator) == 0) {
return ast_ari_validate_application_move_failed(json);
} else
if (strcmp("ApplicationRegistered", discriminator) == 0) {
return ast_ari_validate_application_registered(json);
} else
if (strcmp("ApplicationReplaced", discriminator) == 0) {
return ast_ari_validate_application_replaced(json);
} else
if (strcmp("ApplicationUnregistered", discriminator) == 0) {
return ast_ari_validate_application_unregistered(json);
} else
if (strcmp("BridgeAttendedTransfer", discriminator) == 0) {
return ast_ari_validate_bridge_attended_transfer(json);
} else