Merge "astobj2: Create function to copy weak proxied objects from container."
[asterisk/asterisk.git] / rest-api-templates / res_ari_resource.c.mustache
index 7d138b7..85948fb 100644 (file)
        <depend type="module">res_ari</depend>
        <depend type="module">res_ari_model</depend>
        <depend type="module">res_stasis</depend>
+{{#requires_modules}}
+       <depend type="module">{{.}}</depend>
+{{/requires_modules}}
        <support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_REGISTER_FILE()
-
 #include "asterisk/app.h"
 #include "asterisk/module.h"
 #include "asterisk/stasis_app.h"
@@ -54,7 +55,7 @@ ASTERISK_REGISTER_FILE()
 #if defined(AST_DEVMODE)
 #include "ari/ari_model_validators.h"
 #endif
-{{^has_websocket}}
+{{#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
@@ -78,20 +79,24 @@ ASTERISK_REGISTER_FILE()
 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_ari_response *response)
+       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}}
-       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #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;
 
@@ -114,8 +119,14 @@ static void ast_ari_{{c_name}}_{{c_nickname}}_cb(
                                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 {
@@ -137,7 +148,53 @@ 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, 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 = {};
@@ -175,16 +232,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);
@@ -207,45 +259,65 @@ fin: __attribute__((unused))
 {{> 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}}
-{{#has_websocket}}
+{{#operations}}
+{{#is_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) {
-               return AST_MODULE_LOAD_FAILURE;
+               ast_ari_websocket_events_event_websocket_dtor();
+               return AST_MODULE_LOAD_DECLINE;
        }
-{{/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);
+
+       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;
+       res |= ast_websocket_server_add_protocol2({{full_name}}.ws_server, protocol);
 {{/is_websocket}}
 {{/operations}}
 {{/apis}}
-       stasis_app_ref();
+
        res |= ast_ari_add_handler(&{{root_full_name}});
-       return res;
-}
+       if (res) {
+               unload_module();
+               return AST_MODULE_LOAD_DECLINE;
+       }
 
-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;
-{{/has_websocket}}
-{{/apis}}
-       stasis_app_unref();
-       return 0;
+       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,
-       .nonoptreq = "res_ari,res_stasis",
+       .requires = "res_ari,res_ari_model,res_stasis{{#requires_modules}},{{.}}{{/requires_modules}}",
 );
 {{/api_declaration}}