mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-02 10:22:46 +00:00
Merge "res/ari: Register Stasis application on WebSocket attempt" into 13
This commit is contained in:
@@ -119,6 +119,10 @@ static void app_handler(void *data, const char *app_name,
|
||||
const char *msg_application = S_OR(
|
||||
ast_json_string_get(ast_json_object_get(message, "application")),
|
||||
"");
|
||||
|
||||
if (!session) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Determine if we've been replaced */
|
||||
if (strcmp(msg_type, "ApplicationReplaced") == 0 &&
|
||||
@@ -168,7 +172,40 @@ static int session_register_app(struct event_session *session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ast_ari_websocket_events_event_websocket(struct ast_ari_websocket_session *ws_session,
|
||||
int ast_ari_websocket_events_event_websocket_attempted(struct ast_tcptls_session_instance *ser,
|
||||
struct ast_variable *headers,
|
||||
struct ast_ari_events_event_websocket_args *args)
|
||||
{
|
||||
int res = 0;
|
||||
size_t i, j;
|
||||
|
||||
ast_debug(3, "/events WebSocket attempted\n");
|
||||
|
||||
if (args->app_count == 0) {
|
||||
ast_http_error(ser, 400, "Bad Request", "Missing param 'app'");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < args->app_count; ++i) {
|
||||
if (ast_strlen_zero(args->app[i])) {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
res |= stasis_app_register(args->app[i], app_handler, NULL);
|
||||
}
|
||||
|
||||
if (res) {
|
||||
for (j = 0; j < i; ++j) {
|
||||
stasis_app_unregister(args->app[j]);
|
||||
}
|
||||
ast_http_error(ser, 400, "Bad Request", "Invalid application provided in param 'app'.");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void ast_ari_websocket_events_event_websocket_established(struct ast_ari_websocket_session *ws_session,
|
||||
struct ast_variable *headers,
|
||||
struct ast_ari_events_event_websocket_args *args)
|
||||
{
|
||||
|
@@ -48,6 +48,19 @@ struct ast_ari_events_event_websocket_args {
|
||||
/*! Parsing context for app. */
|
||||
char *app_parse;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief WebSocket connection for events.
|
||||
*
|
||||
* \param ser HTTP TCP/TLS Server Session
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval non-zero error
|
||||
*/
|
||||
int ast_ari_websocket_events_event_websocket_attempted(struct ast_tcptls_session_instance *ser, struct ast_variable *headers, struct ast_ari_events_event_websocket_args *args);
|
||||
|
||||
/*!
|
||||
* \brief WebSocket connection for events.
|
||||
*
|
||||
@@ -55,7 +68,7 @@ struct ast_ari_events_event_websocket_args {
|
||||
* \param headers HTTP headers.
|
||||
* \param args Swagger parameters.
|
||||
*/
|
||||
void ast_ari_websocket_events_event_websocket(struct ast_ari_websocket_session *session, struct ast_variable *headers, struct ast_ari_events_event_websocket_args *args);
|
||||
void ast_ari_websocket_events_event_websocket_established(struct ast_ari_websocket_session *session, struct ast_variable *headers, struct ast_ari_events_event_websocket_args *args);
|
||||
/*! Argument struct for ast_ari_events_user_event() */
|
||||
struct ast_ari_events_user_event_args {
|
||||
/*! Event name */
|
||||
|
@@ -53,7 +53,92 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#define MAX_VALS 128
|
||||
|
||||
static void ast_ari_events_event_websocket_ws_cb(struct ast_websocket *ws_session,
|
||||
static int ast_ari_events_event_websocket_ws_attempted_cb(struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *headers)
|
||||
{
|
||||
struct ast_ari_events_event_websocket_args args = {};
|
||||
int res = 0;
|
||||
RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
|
||||
struct ast_variable *i;
|
||||
|
||||
response = ast_calloc(1, sizeof(*response));
|
||||
if (!response) {
|
||||
ast_log(LOG_ERROR, "Failed to create response.\n");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
for (i = get_params; i; i = i->next) {
|
||||
if (strcmp(i->name, "app") == 0) {
|
||||
/* Parse comma separated list */
|
||||
char *vals[MAX_VALS];
|
||||
size_t j;
|
||||
|
||||
args.app_parse = ast_strdup(i->value);
|
||||
if (!args.app_parse) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if (strlen(args.app_parse) == 0) {
|
||||
/* ast_app_separate_args can't handle "" */
|
||||
args.app_count = 1;
|
||||
vals[0] = args.app_parse;
|
||||
} else {
|
||||
args.app_count = ast_app_separate_args(
|
||||
args.app_parse, ',', vals,
|
||||
ARRAY_LEN(vals));
|
||||
}
|
||||
|
||||
if (args.app_count == 0) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if (args.app_count >= MAX_VALS) {
|
||||
ast_ari_response_error(response, 400,
|
||||
"Bad Request",
|
||||
"Too many values for app");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
args.app = ast_malloc(sizeof(*args.app) * args.app_count);
|
||||
if (!args.app) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
goto fin;
|
||||
}
|
||||
|
||||
for (j = 0; j < args.app_count; ++j) {
|
||||
args.app[j] = (vals[j]);
|
||||
}
|
||||
} else
|
||||
{}
|
||||
}
|
||||
|
||||
res = ast_ari_websocket_events_event_websocket_attempted(ser, headers, &args);
|
||||
|
||||
fin: __attribute__((unused))
|
||||
if (!response) {
|
||||
ast_http_error(ser, 500, "Server Error", "Memory allocation error");
|
||||
res = -1;
|
||||
} else if (response->response_code != 0) {
|
||||
/* Param parsing failure */
|
||||
RAII_VAR(char *, msg, NULL, ast_json_free);
|
||||
if (response->message) {
|
||||
msg = ast_json_dump_string(response->message);
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Missing response message\n");
|
||||
}
|
||||
|
||||
if (msg) {
|
||||
ast_http_error(ser, response->response_code, response->response_text, msg);
|
||||
}
|
||||
res = -1;
|
||||
}
|
||||
ast_free(args.app_parse);
|
||||
ast_free(args.app);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void ast_ari_events_event_websocket_ws_established_cb(struct ast_websocket *ws_session,
|
||||
struct ast_variable *get_params, struct ast_variable *headers)
|
||||
{
|
||||
struct ast_ari_events_event_websocket_args args = {};
|
||||
@@ -126,16 +211,11 @@ static void ast_ari_events_event_websocket_ws_cb(struct ast_websocket *ws_sessio
|
||||
{}
|
||||
}
|
||||
|
||||
ast_ari_websocket_events_event_websocket(session, headers, &args);
|
||||
ast_ari_websocket_events_event_websocket_established(session, headers, &args);
|
||||
|
||||
fin: __attribute__((unused))
|
||||
if (response && response->response_code != 0) {
|
||||
/* Param parsing failure */
|
||||
/* TODO - ideally, this would return the error code to the
|
||||
* HTTP client; but we've already done the WebSocket
|
||||
* negotiation. Param parsing should happen earlier, but we
|
||||
* need a way to pass it through the WebSocket code to the
|
||||
* callback */
|
||||
RAII_VAR(char *, msg, NULL, ast_json_free);
|
||||
if (response->message) {
|
||||
msg = ast_json_dump_string(response->message);
|
||||
@@ -351,12 +431,22 @@ static struct stasis_rest_handlers events = {
|
||||
static int load_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_websocket_protocol *protocol;
|
||||
|
||||
events.ws_server = ast_websocket_server_create();
|
||||
if (!events.ws_server) {
|
||||
return AST_MODULE_LOAD_FAILURE;
|
||||
}
|
||||
res |= ast_websocket_server_add_protocol(events.ws_server,
|
||||
"ari", ast_ari_events_event_websocket_ws_cb);
|
||||
|
||||
protocol = ast_websocket_sub_protocol_alloc("ari");
|
||||
if (!protocol) {
|
||||
ao2_ref(events.ws_server, -1);
|
||||
events.ws_server = NULL;
|
||||
return AST_MODULE_LOAD_FAILURE;
|
||||
}
|
||||
protocol->session_attempted = ast_ari_events_event_websocket_ws_attempted_cb;
|
||||
protocol->session_established = ast_ari_events_event_websocket_ws_established_cb;
|
||||
res |= ast_websocket_server_add_protocol2(events.ws_server, protocol);
|
||||
stasis_app_ref();
|
||||
res |= ast_ari_add_handler(&events);
|
||||
return res;
|
||||
|
@@ -871,8 +871,7 @@ struct stasis_app *app_create(const char *name, stasis_app_cb handler, void *dat
|
||||
|
||||
strncpy(app->name, name, size - sizeof(*app));
|
||||
app->handler = handler;
|
||||
ao2_ref(data, +1);
|
||||
app->data = data;
|
||||
app->data = ao2_bump(data);
|
||||
|
||||
ao2_ref(app, +1);
|
||||
return app;
|
||||
@@ -950,7 +949,7 @@ void app_update(struct stasis_app *app, stasis_app_cb handler, void *data)
|
||||
{
|
||||
SCOPED_AO2LOCK(lock, app);
|
||||
|
||||
if (app->handler) {
|
||||
if (app->handler && app->data) {
|
||||
RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
|
||||
|
||||
ast_verb(1, "Replacing Stasis app '%s'\n", app->name);
|
||||
|
@@ -89,6 +89,23 @@ int ast_ari_{{c_name}}_{{c_nickname}}_parse_body(
|
||||
void ast_ari_{{c_name}}_{{c_nickname}}(struct ast_variable *headers, struct ast_ari_{{c_name}}_{{c_nickname}}_args *args, struct ast_ari_response *response);
|
||||
{{/is_req}}
|
||||
{{#is_websocket}}
|
||||
|
||||
/*!
|
||||
* \brief {{summary}}
|
||||
{{#notes}}
|
||||
*
|
||||
* {{{notes}}}
|
||||
{{/notes}}
|
||||
*
|
||||
* \param ser HTTP TCP/TLS Server Session
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval non-zero error
|
||||
*/
|
||||
int ast_ari_websocket_{{c_name}}_{{c_nickname}}_attempted(struct ast_tcptls_session_instance *ser, struct ast_variable *headers, struct ast_ari_{{c_name}}_{{c_nickname}}_args *args);
|
||||
|
||||
/*!
|
||||
* \brief {{summary}}
|
||||
{{#notes}}
|
||||
@@ -100,7 +117,7 @@ void ast_ari_{{c_name}}_{{c_nickname}}(struct ast_variable *headers, struct ast_
|
||||
* \param headers HTTP headers.
|
||||
* \param args Swagger parameters.
|
||||
*/
|
||||
void ast_ari_websocket_{{c_name}}_{{c_nickname}}(struct ast_ari_websocket_session *session, struct ast_variable *headers, struct ast_ari_{{c_name}}_{{c_nickname}}_args *args);
|
||||
void ast_ari_websocket_{{c_name}}_{{c_nickname}}_established(struct ast_ari_websocket_session *session, struct ast_variable *headers, struct ast_ari_{{c_name}}_{{c_nickname}}_args *args);
|
||||
{{/is_websocket}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
|
@@ -137,7 +137,52 @@ fin: __attribute__((unused))
|
||||
}
|
||||
{{/is_req}}
|
||||
{{#is_websocket}}
|
||||
static void ast_ari_{{c_name}}_{{c_nickname}}_ws_cb(struct ast_websocket *ws_session,
|
||||
static int ast_ari_{{c_name}}_{{c_nickname}}_ws_attempted_cb(struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *headers)
|
||||
{
|
||||
struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
|
||||
{{#has_parameters}}
|
||||
int res = 0;
|
||||
RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
|
||||
struct ast_variable *i;
|
||||
{{/has_parameters}}
|
||||
|
||||
{{#has_parameters}}
|
||||
response = ast_calloc(1, sizeof(*response));
|
||||
if (!response) {
|
||||
ast_log(LOG_ERROR, "Failed to create response.\n");
|
||||
goto fin;
|
||||
}
|
||||
{{/has_parameters}}
|
||||
|
||||
{{> param_parsing}}
|
||||
|
||||
res = ast_ari_websocket_{{c_name}}_{{c_nickname}}_attempted(ser, headers, &args);
|
||||
|
||||
fin: __attribute__((unused))
|
||||
if (!response) {
|
||||
ast_http_error(ser, 500, "Server Error", "Memory allocation error");
|
||||
res = -1;
|
||||
} else if (response->response_code != 0) {
|
||||
/* Param parsing failure */
|
||||
RAII_VAR(char *, msg, NULL, ast_json_free);
|
||||
if (response->message) {
|
||||
msg = ast_json_dump_string(response->message);
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Missing response message\n");
|
||||
}
|
||||
|
||||
if (msg) {
|
||||
ast_http_error(ser, response->response_code, response->response_text, msg);
|
||||
}
|
||||
res = -1;
|
||||
}
|
||||
{{> param_cleanup}}
|
||||
{{#has_parameters}}
|
||||
return res;
|
||||
{{/has_parameters}}
|
||||
}
|
||||
|
||||
static void ast_ari_{{c_name}}_{{c_nickname}}_ws_established_cb(struct ast_websocket *ws_session,
|
||||
struct ast_variable *get_params, struct ast_variable *headers)
|
||||
{
|
||||
struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
|
||||
@@ -175,16 +220,11 @@ static void ast_ari_{{c_name}}_{{c_nickname}}_ws_cb(struct ast_websocket *ws_ses
|
||||
|
||||
{{> param_parsing}}
|
||||
|
||||
ast_ari_websocket_{{c_name}}_{{c_nickname}}(session, headers, &args);
|
||||
ast_ari_websocket_{{c_name}}_{{c_nickname}}_established(session, headers, &args);
|
||||
|
||||
fin: __attribute__((unused))
|
||||
if (response && response->response_code != 0) {
|
||||
/* Param parsing failure */
|
||||
/* TODO - ideally, this would return the error code to the
|
||||
* HTTP client; but we've already done the WebSocket
|
||||
* negotiation. Param parsing should happen earlier, but we
|
||||
* need a way to pass it through the WebSocket code to the
|
||||
* callback */
|
||||
RAII_VAR(char *, msg, NULL, ast_json_free);
|
||||
if (response->message) {
|
||||
msg = ast_json_dump_string(response->message);
|
||||
@@ -211,16 +251,26 @@ static int load_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
{{#has_websocket}}
|
||||
struct ast_websocket_protocol *protocol;
|
||||
|
||||
{{full_name}}.ws_server = ast_websocket_server_create();
|
||||
if (!{{full_name}}.ws_server) {
|
||||
return AST_MODULE_LOAD_FAILURE;
|
||||
}
|
||||
|
||||
protocol = ast_websocket_sub_protocol_alloc("{{websocket_protocol}}");
|
||||
if (!protocol) {
|
||||
ao2_ref({{full_name}}.ws_server, -1);
|
||||
{{full_name}}.ws_server = NULL;
|
||||
return AST_MODULE_LOAD_FAILURE;
|
||||
}
|
||||
protocol->session_attempted = ast_ari_{{c_name}}_{{c_nickname}}_ws_attempted_cb;
|
||||
protocol->session_established = ast_ari_{{c_name}}_{{c_nickname}}_ws_established_cb;
|
||||
{{/has_websocket}}
|
||||
{{#operations}}
|
||||
{{#is_websocket}}
|
||||
res |= ast_websocket_server_add_protocol({{full_name}}.ws_server,
|
||||
"{{websocket_protocol}}", ast_ari_{{c_name}}_{{c_nickname}}_ws_cb);
|
||||
res |= ast_websocket_server_add_protocol2({{full_name}}.ws_server, protocol);
|
||||
{{/is_websocket}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
|
Reference in New Issue
Block a user