{{#api_declaration}} /* * Asterisk -- An open source telephony toolkit. * * {{{copyright}}} * * {{{author}}} {{! Template Copyright * Copyright (C) 2013, Digium, Inc. * * David M. Lee, II }} * * 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_ari_resource.c.mustache */ /*! \file * * \brief {{{description}}} * * \author {{{author}}} */ /*** MODULEINFO res_ari res_ari_model res_stasis {{#requires_modules}} {{.}} {{/requires_modules}} core ***/ #include "asterisk.h" #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" #include "ari/resource_{{c_name}}.h" #if defined(AST_DEVMODE) #include "ari/ari_model_validators.h" #endif {{^has_websocket}} {{! Only include http_websocket if necessary. Otherwise we'll do a lot of * unnecessary optional_api intialization, which makes optional_api harder * to debug }} #include "asterisk/http_websocket.h" {{/has_websocket}} #define MAX_VALS 128 {{#apis}} {{#operations}} {{#is_req}} {{> body_parsing}} /*! * \brief Parameter parsing callback for {{path}}. * \param get_params GET parameters in the HTTP request. * \param path_vars Path variables extracted from the request. * \param headers HTTP headers. * \param[out] response Response to the HTTP request. */ static void ast_ari_{{c_name}}_{{c_nickname}}_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {}; {{#has_parameters}} struct ast_variable *i; {{/has_parameters}} #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ {{> param_parsing}} {{^is_binary_response}} ast_ari_{{c_name}}_{{c_nickname}}(headers, &args, response); {{/is_binary_response}} {{#is_binary_response}} ast_ari_{{c_name}}_{{c_nickname}}(ser, headers, &args, response); {{/is_binary_response}} #if defined(AST_DEVMODE) code = response->response_code; switch (code) { case 0: /* Implementation is still a stub, or the code wasn't set */ is_valid = response->message == NULL; break; case 500: /* Internal Server Error */ case 501: /* Not Implemented */ {{#error_responses}} case {{code}}: /* {{{reason}}} */ {{/error_responses}} is_valid = 1; break; default: if (200 <= code && code <= 299) { {{#response_class}} {{#is_list}} is_valid = ast_ari_validate_list(response->message, ast_ari_validate_{{c_singular_name}}_fn()); {{/is_list}} {{^is_list}} {{^is_binary_response}} is_valid = ast_ari_validate_{{c_name}}( response->message); {{/is_binary_response}} {{#is_binary_response}} /* No validation on a raw binary response */ is_valid = 1; {{/is_binary_response}} {{/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"); ast_ari_response_error(response, 500, "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ fin: __attribute__((unused)) {{> param_cleanup}} return; } {{/is_req}} {{#is_websocket}} 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, const char *session_id) { 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, session_id); 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 = {}; {{#has_parameters}} RAII_VAR(struct ast_ari_response *, response, NULL, ast_free); struct ast_variable *i; {{/has_parameters}} RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref); RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup); {{#has_path_parameters}} /* TODO: It's not immediately obvious how to pass path params through * the websocket code to this callback. Not needed right now, so we'll * just punt. */ struct ast_variable *path_vars = NULL; {{/has_path_parameters}} {{#has_parameters}} response = ast_calloc(1, sizeof(*response)); if (!response) { ast_log(LOG_ERROR, "Failed to create response.\n"); goto fin; } {{/has_parameters}} #if defined(AST_DEVMODE) session = ast_ari_websocket_session_create(ws_session, ast_ari_validate_{{response_class.c_name}}_fn()); #else session = ast_ari_websocket_session_create(ws_session, NULL); #endif if (!session) { ast_log(LOG_ERROR, "Failed to create ARI session\n"); goto fin; } {{> param_parsing}} ast_ari_websocket_{{c_name}}_{{c_nickname}}_established(session, headers, &args); fin: __attribute__((unused)) if (response && 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_websocket_write(ws_session, AST_WEBSOCKET_OPCODE_TEXT, msg, strlen(msg)); } } {{> param_cleanup}} } {{/is_websocket}} {{/operations}} {{/apis}} {{! The rest_handler partial expands to the tree of stasis_rest_handlers }} {{#root_path}} {{> rest_handler}} {{/root_path}} static int unload_module(void) { ast_ari_remove_handler(&{{root_full_name}}); {{#apis}} {{#has_websocket}} ao2_cleanup({{full_name}}.ws_server); {{full_name}}.ws_server = NULL; ast_ari_websocket_events_event_websocket_dtor(); {{/has_websocket}} {{/apis}} return 0; } static int load_module(void) { int res = 0; {{#apis}} {{#operations}} {{#has_websocket}} struct ast_websocket_protocol *protocol; if (ast_ari_websocket_{{c_name}}_{{c_nickname}}_init() == -1) { return AST_MODULE_LOAD_DECLINE; } {{full_name}}.ws_server = ast_websocket_server_create(); if (!{{full_name}}.ws_server) { ast_ari_websocket_events_event_websocket_dtor(); return AST_MODULE_LOAD_DECLINE; } protocol = ast_websocket_sub_protocol_alloc("{{websocket_protocol}}"); if (!protocol) { ao2_ref({{full_name}}.ws_server, -1); {{full_name}}.ws_server = NULL; ast_ari_websocket_events_event_websocket_dtor(); return AST_MODULE_LOAD_DECLINE; } 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}} {{#is_websocket}} res |= ast_websocket_server_add_protocol2({{full_name}}.ws_server, protocol); {{/is_websocket}} {{/operations}} {{/apis}} res |= ast_ari_add_handler(&{{root_full_name}}); if (res) { unload_module(); return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - {{{description}}}", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .requires = "res_ari,res_ari_model,res_stasis{{#requires_modules}},{{.}}{{/requires_modules}}", ); {{/api_declaration}}