Merge "ARI: Fix missing dependencies."
[asterisk/asterisk.git] / rest-api-templates / res_ari_resource.c.mustache
1 {{#api_declaration}}
2 /*
3  * Asterisk -- An open source telephony toolkit.
4  *
5  * {{{copyright}}}
6  *
7  * {{{author}}}
8 {{! Template Copyright
9  * Copyright (C) 2013, Digium, Inc.
10  *
11  * David M. Lee, II <dlee@digium.com>
12 }}
13  *
14  * See http://www.asterisk.org for more information about
15  * the Asterisk project. Please do not directly contact
16  * any of the maintainers of this project for assistance;
17  * the project provides a web site, mailing lists and IRC
18  * channels for your use.
19  *
20  * This program is free software, distributed under the terms of
21  * the GNU General Public License Version 2. See the LICENSE file
22  * at the top of the source tree.
23  */
24
25 {{! Template for rendering the res_ module for an HTTP resource. }}
26 /*
27 {{> do-not-edit}}
28  * This file is generated by a mustache template. Please see the original
29  * template in rest-api-templates/res_ari_resource.c.mustache
30  */
31
32 /*! \file
33  *
34  * \brief {{{description}}}
35  *
36  * \author {{{author}}}
37  */
38
39 /*** MODULEINFO
40         <depend type="module">res_ari</depend>
41         <depend type="module">res_ari_model</depend>
42         <depend type="module">res_stasis</depend>
43         <support_level>core</support_level>
44  ***/
45
46 #include "asterisk.h"
47
48 ASTERISK_REGISTER_FILE()
49
50 #include "asterisk/app.h"
51 #include "asterisk/module.h"
52 #include "asterisk/stasis_app.h"
53 #include "ari/resource_{{c_name}}.h"
54 #if defined(AST_DEVMODE)
55 #include "ari/ari_model_validators.h"
56 #endif
57 {{^has_websocket}}
58 {{! Only include http_websocket if necessary. Otherwise we'll do a lot of
59  *  unnecessary optional_api intialization, which makes optional_api harder
60  *  to debug
61  }}
62 #include "asterisk/http_websocket.h"
63 {{/has_websocket}}
64
65 #define MAX_VALS 128
66
67 {{#apis}}
68 {{#operations}}
69 {{#is_req}}
70 {{> body_parsing}}
71 /*!
72  * \brief Parameter parsing callback for {{path}}.
73  * \param get_params GET parameters in the HTTP request.
74  * \param path_vars Path variables extracted from the request.
75  * \param headers HTTP headers.
76  * \param[out] response Response to the HTTP request.
77  */
78 static void ast_ari_{{c_name}}_{{c_nickname}}_cb(
79         struct ast_tcptls_session_instance *ser,
80         struct ast_variable *get_params, struct ast_variable *path_vars,
81         struct ast_variable *headers, struct ast_ari_response *response)
82 {
83         struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
84 {{#has_parameters}}
85         struct ast_variable *i;
86 {{/has_parameters}}
87         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
88 #if defined(AST_DEVMODE)
89         int is_valid;
90         int code;
91 #endif /* AST_DEVMODE */
92
93 {{> param_parsing}}
94         ast_ari_{{c_name}}_{{c_nickname}}(headers, &args, response);
95 #if defined(AST_DEVMODE)
96         code = response->response_code;
97
98         switch (code) {
99         case 0: /* Implementation is still a stub, or the code wasn't set */
100                 is_valid = response->message == NULL;
101                 break;
102         case 500: /* Internal Server Error */
103         case 501: /* Not Implemented */
104 {{#error_responses}}
105         case {{code}}: /* {{{reason}}} */
106 {{/error_responses}}
107                 is_valid = 1;
108                 break;
109         default:
110                 if (200 <= code && code <= 299) {
111 {{#response_class}}
112 {{#is_list}}
113                         is_valid = ast_ari_validate_list(response->message,
114                                 ast_ari_validate_{{c_singular_name}}_fn());
115 {{/is_list}}
116 {{^is_list}}
117                         is_valid = ast_ari_validate_{{c_name}}(
118                                 response->message);
119 {{/is_list}}
120 {{/response_class}}
121                 } else {
122                         ast_log(LOG_ERROR, "Invalid error response %d for {{path}}\n", code);
123                         is_valid = 0;
124                 }
125         }
126
127         if (!is_valid) {
128                 ast_log(LOG_ERROR, "Response validation failed for {{path}}\n");
129                 ast_ari_response_error(response, 500,
130                         "Internal Server Error", "Response validation failed");
131         }
132 #endif /* AST_DEVMODE */
133
134 fin: __attribute__((unused))
135 {{> param_cleanup}}
136         return;
137 }
138 {{/is_req}}
139 {{#is_websocket}}
140 static void ast_ari_{{c_name}}_{{c_nickname}}_ws_cb(struct ast_websocket *ws_session,
141         struct ast_variable *get_params, struct ast_variable *headers)
142 {
143         struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
144 {{#has_parameters}}
145         RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
146         struct ast_variable *i;
147 {{/has_parameters}}
148         RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref);
149         RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup);
150 {{#has_path_parameters}}
151         /* TODO: It's not immediately obvious how to pass path params through
152          * the websocket code to this callback. Not needed right now, so we'll
153          * just punt. */
154         struct ast_variable *path_vars = NULL;
155 {{/has_path_parameters}}
156
157 {{#has_parameters}}
158         response = ast_calloc(1, sizeof(*response));
159         if (!response) {
160                 ast_log(LOG_ERROR, "Failed to create response.\n");
161                 goto fin;
162         }
163 {{/has_parameters}}
164
165 #if defined(AST_DEVMODE)
166         session = ast_ari_websocket_session_create(ws_session,
167                 ast_ari_validate_{{response_class.c_name}}_fn());
168 #else
169         session = ast_ari_websocket_session_create(ws_session, NULL);
170 #endif
171         if (!session) {
172                 ast_log(LOG_ERROR, "Failed to create ARI session\n");
173                 goto fin;
174         }
175
176 {{> param_parsing}}
177
178         ast_ari_websocket_{{c_name}}_{{c_nickname}}(session, headers, &args);
179
180 fin: __attribute__((unused))
181         if (response && response->response_code != 0) {
182                 /* Param parsing failure */
183                 /* TODO - ideally, this would return the error code to the
184                  * HTTP client; but we've already done the WebSocket
185                  * negotiation. Param parsing should happen earlier, but we
186                  * need a way to pass it through the WebSocket code to the
187                  * callback */
188                 RAII_VAR(char *, msg, NULL, ast_json_free);
189                 if (response->message) {
190                         msg = ast_json_dump_string(response->message);
191                 } else {
192                         ast_log(LOG_ERROR, "Missing response message\n");
193                 }
194                 if (msg) {
195                         ast_websocket_write(ws_session,
196                                 AST_WEBSOCKET_OPCODE_TEXT, msg, strlen(msg));
197                 }
198         }
199 {{> param_cleanup}}
200 }
201 {{/is_websocket}}
202 {{/operations}}
203 {{/apis}}
204
205 {{! The rest_handler partial expands to the tree of stasis_rest_handlers }}
206 {{#root_path}}
207 {{> rest_handler}}
208 {{/root_path}}
209
210 static int load_module(void)
211 {
212         int res = 0;
213 {{#apis}}
214 {{#has_websocket}}
215         {{full_name}}.ws_server = ast_websocket_server_create();
216         if (!{{full_name}}.ws_server) {
217                 return AST_MODULE_LOAD_FAILURE;
218         }
219 {{/has_websocket}}
220 {{#operations}}
221 {{#is_websocket}}
222         res |= ast_websocket_server_add_protocol({{full_name}}.ws_server,
223                 "{{websocket_protocol}}", ast_ari_{{c_name}}_{{c_nickname}}_ws_cb);
224 {{/is_websocket}}
225 {{/operations}}
226 {{/apis}}
227         stasis_app_ref();
228         res |= ast_ari_add_handler(&{{root_full_name}});
229         return res;
230 }
231
232 static int unload_module(void)
233 {
234         ast_ari_remove_handler(&{{root_full_name}});
235 {{#apis}}
236 {{#has_websocket}}
237         ao2_cleanup({{full_name}}.ws_server);
238         {{full_name}}.ws_server = NULL;
239 {{/has_websocket}}
240 {{/apis}}
241         stasis_app_unref();
242         return 0;
243 }
244
245 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - {{{description}}}",
246         .support_level = AST_MODULE_SUPPORT_CORE,
247         .load = load_module,
248         .unload = unload_module,
249         .nonoptreq = "res_ari,res_stasis",
250         );
251 {{/api_declaration}}