app_chanspy: reduce audio loss on the spying channel.
[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 int ast_ari_{{c_name}}_{{c_nickname}}_ws_attempted_cb(struct ast_tcptls_session_instance *ser,
141         struct ast_variable *get_params, struct ast_variable *headers, const char *session_id)
142 {
143         struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
144 {{#has_parameters}}
145         int res = 0;
146         RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
147         struct ast_variable *i;
148 {{/has_parameters}}
149
150 {{#has_parameters}}
151         response = ast_calloc(1, sizeof(*response));
152         if (!response) {
153                 ast_log(LOG_ERROR, "Failed to create response.\n");
154                 goto fin;
155         }
156 {{/has_parameters}}
157
158 {{> param_parsing}}
159
160         res = ast_ari_websocket_{{c_name}}_{{c_nickname}}_attempted(ser, headers, &args, session_id);
161
162 fin: __attribute__((unused))
163         if (!response) {
164                 ast_http_error(ser, 500, "Server Error", "Memory allocation error");
165                 res = -1;
166         } else if (response->response_code != 0) {
167                 /* Param parsing failure */
168                 RAII_VAR(char *, msg, NULL, ast_json_free);
169                 if (response->message) {
170                         msg = ast_json_dump_string(response->message);
171                 } else {
172                         ast_log(LOG_ERROR, "Missing response message\n");
173                 }
174
175                 if (msg) {
176                         ast_http_error(ser, response->response_code, response->response_text, msg);
177                 }
178                 res = -1;
179         }
180 {{> param_cleanup}}
181 {{#has_parameters}}
182         return res;
183 {{/has_parameters}}
184 }
185
186 static void ast_ari_{{c_name}}_{{c_nickname}}_ws_established_cb(struct ast_websocket *ws_session,
187         struct ast_variable *get_params, struct ast_variable *headers)
188 {
189         struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
190 {{#has_parameters}}
191         RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
192         struct ast_variable *i;
193 {{/has_parameters}}
194         RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref);
195         RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup);
196 {{#has_path_parameters}}
197         /* TODO: It's not immediately obvious how to pass path params through
198          * the websocket code to this callback. Not needed right now, so we'll
199          * just punt. */
200         struct ast_variable *path_vars = NULL;
201 {{/has_path_parameters}}
202
203 {{#has_parameters}}
204         response = ast_calloc(1, sizeof(*response));
205         if (!response) {
206                 ast_log(LOG_ERROR, "Failed to create response.\n");
207                 goto fin;
208         }
209 {{/has_parameters}}
210
211 #if defined(AST_DEVMODE)
212         session = ast_ari_websocket_session_create(ws_session,
213                 ast_ari_validate_{{response_class.c_name}}_fn());
214 #else
215         session = ast_ari_websocket_session_create(ws_session, NULL);
216 #endif
217         if (!session) {
218                 ast_log(LOG_ERROR, "Failed to create ARI session\n");
219                 goto fin;
220         }
221
222 {{> param_parsing}}
223
224         ast_ari_websocket_{{c_name}}_{{c_nickname}}_established(session, headers, &args);
225
226 fin: __attribute__((unused))
227         if (response && response->response_code != 0) {
228                 /* Param parsing failure */
229                 RAII_VAR(char *, msg, NULL, ast_json_free);
230                 if (response->message) {
231                         msg = ast_json_dump_string(response->message);
232                 } else {
233                         ast_log(LOG_ERROR, "Missing response message\n");
234                 }
235                 if (msg) {
236                         ast_websocket_write(ws_session,
237                                 AST_WEBSOCKET_OPCODE_TEXT, msg, strlen(msg));
238                 }
239         }
240 {{> param_cleanup}}
241 }
242 {{/is_websocket}}
243 {{/operations}}
244 {{/apis}}
245
246 {{! The rest_handler partial expands to the tree of stasis_rest_handlers }}
247 {{#root_path}}
248 {{> rest_handler}}
249 {{/root_path}}
250
251 static int load_module(void)
252 {
253         int res = 0;
254 {{#apis}}
255 {{#operations}}
256 {{#has_websocket}}
257         struct ast_websocket_protocol *protocol;
258
259         if (ast_ari_websocket_{{c_name}}_{{c_nickname}}_init() == -1) {
260                 return AST_MODULE_LOAD_FAILURE;
261         }
262
263         {{full_name}}.ws_server = ast_websocket_server_create();
264         if (!{{full_name}}.ws_server) {
265                 return AST_MODULE_LOAD_FAILURE;
266         }
267
268         protocol = ast_websocket_sub_protocol_alloc("{{websocket_protocol}}");
269         if (!protocol) {
270                 ao2_ref({{full_name}}.ws_server, -1);
271                 {{full_name}}.ws_server = NULL;
272                 return AST_MODULE_LOAD_FAILURE;
273         }
274         protocol->session_attempted = ast_ari_{{c_name}}_{{c_nickname}}_ws_attempted_cb;
275         protocol->session_established = ast_ari_{{c_name}}_{{c_nickname}}_ws_established_cb;
276 {{/has_websocket}}
277 {{#is_websocket}}
278         res |= ast_websocket_server_add_protocol2({{full_name}}.ws_server, protocol);
279 {{/is_websocket}}
280 {{/operations}}
281 {{/apis}}
282         stasis_app_ref();
283         res |= ast_ari_add_handler(&{{root_full_name}});
284         return res;
285 }
286
287 static int unload_module(void)
288 {
289         ast_ari_remove_handler(&{{root_full_name}});
290 {{#apis}}
291 {{#has_websocket}}
292         ao2_cleanup({{full_name}}.ws_server);
293         {{full_name}}.ws_server = NULL;
294         ast_ari_websocket_events_event_websocket_dtor();
295 {{/has_websocket}}
296 {{/apis}}
297         stasis_app_unref();
298         return 0;
299 }
300
301 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - {{{description}}}",
302         .support_level = AST_MODULE_SUPPORT_CORE,
303         .load = load_module,
304         .unload = unload_module,
305         .nonoptreq = "res_ari,res_stasis",
306 );
307 {{/api_declaration}}