Add missing OPTIONAL_API and ARI dependences.
[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 {{#requires_modules}}
44         <depend type="module">{{.}}</depend>
45 {{/requires_modules}}
46         <support_level>core</support_level>
47  ***/
48
49 #include "asterisk.h"
50
51 #include "asterisk/app.h"
52 #include "asterisk/module.h"
53 #include "asterisk/stasis_app.h"
54 #include "ari/resource_{{c_name}}.h"
55 #if defined(AST_DEVMODE)
56 #include "ari/ari_model_validators.h"
57 #endif
58 {{^has_websocket}}
59 {{! Only include http_websocket if necessary. Otherwise we'll do a lot of
60  *  unnecessary optional_api intialization, which makes optional_api harder
61  *  to debug
62  }}
63 #include "asterisk/http_websocket.h"
64 {{/has_websocket}}
65
66 #define MAX_VALS 128
67
68 {{#apis}}
69 {{#operations}}
70 {{#is_req}}
71 {{> body_parsing}}
72 /*!
73  * \brief Parameter parsing callback for {{path}}.
74  * \param get_params GET parameters in the HTTP request.
75  * \param path_vars Path variables extracted from the request.
76  * \param headers HTTP headers.
77  * \param[out] response Response to the HTTP request.
78  */
79 static void ast_ari_{{c_name}}_{{c_nickname}}_cb(
80         struct ast_tcptls_session_instance *ser,
81         struct ast_variable *get_params, struct ast_variable *path_vars,
82         struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
83 {
84         struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
85 {{#has_parameters}}
86         struct ast_variable *i;
87 {{/has_parameters}}
88 #if defined(AST_DEVMODE)
89         int is_valid;
90         int code;
91 #endif /* AST_DEVMODE */
92
93 {{> param_parsing}}
94 {{^is_binary_response}}
95         ast_ari_{{c_name}}_{{c_nickname}}(headers, &args, response);
96 {{/is_binary_response}}
97 {{#is_binary_response}}
98         ast_ari_{{c_name}}_{{c_nickname}}(ser, headers, &args, response);
99 {{/is_binary_response}}
100 #if defined(AST_DEVMODE)
101         code = response->response_code;
102
103         switch (code) {
104         case 0: /* Implementation is still a stub, or the code wasn't set */
105                 is_valid = response->message == NULL;
106                 break;
107         case 500: /* Internal Server Error */
108         case 501: /* Not Implemented */
109 {{#error_responses}}
110         case {{code}}: /* {{{reason}}} */
111 {{/error_responses}}
112                 is_valid = 1;
113                 break;
114         default:
115                 if (200 <= code && code <= 299) {
116 {{#response_class}}
117 {{#is_list}}
118                         is_valid = ast_ari_validate_list(response->message,
119                                 ast_ari_validate_{{c_singular_name}}_fn());
120 {{/is_list}}
121 {{^is_list}}
122 {{^is_binary_response}}
123                         is_valid = ast_ari_validate_{{c_name}}(
124                                 response->message);
125 {{/is_binary_response}}
126 {{#is_binary_response}}
127                         /* No validation on a raw binary response */
128                         is_valid = 1;
129 {{/is_binary_response}}
130 {{/is_list}}
131 {{/response_class}}
132                 } else {
133                         ast_log(LOG_ERROR, "Invalid error response %d for {{path}}\n", code);
134                         is_valid = 0;
135                 }
136         }
137
138         if (!is_valid) {
139                 ast_log(LOG_ERROR, "Response validation failed for {{path}}\n");
140                 ast_ari_response_error(response, 500,
141                         "Internal Server Error", "Response validation failed");
142         }
143 #endif /* AST_DEVMODE */
144
145 fin: __attribute__((unused))
146 {{> param_cleanup}}
147         return;
148 }
149 {{/is_req}}
150 {{#is_websocket}}
151 static int ast_ari_{{c_name}}_{{c_nickname}}_ws_attempted_cb(struct ast_tcptls_session_instance *ser,
152         struct ast_variable *get_params, struct ast_variable *headers, const char *session_id)
153 {
154         struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
155 {{#has_parameters}}
156         int res = 0;
157         RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
158         struct ast_variable *i;
159 {{/has_parameters}}
160
161 {{#has_parameters}}
162         response = ast_calloc(1, sizeof(*response));
163         if (!response) {
164                 ast_log(LOG_ERROR, "Failed to create response.\n");
165                 goto fin;
166         }
167 {{/has_parameters}}
168
169 {{> param_parsing}}
170
171         res = ast_ari_websocket_{{c_name}}_{{c_nickname}}_attempted(ser, headers, &args, session_id);
172
173 fin: __attribute__((unused))
174         if (!response) {
175                 ast_http_error(ser, 500, "Server Error", "Memory allocation error");
176                 res = -1;
177         } else if (response->response_code != 0) {
178                 /* Param parsing failure */
179                 RAII_VAR(char *, msg, NULL, ast_json_free);
180                 if (response->message) {
181                         msg = ast_json_dump_string(response->message);
182                 } else {
183                         ast_log(LOG_ERROR, "Missing response message\n");
184                 }
185
186                 if (msg) {
187                         ast_http_error(ser, response->response_code, response->response_text, msg);
188                 }
189                 res = -1;
190         }
191 {{> param_cleanup}}
192 {{#has_parameters}}
193         return res;
194 {{/has_parameters}}
195 }
196
197 static void ast_ari_{{c_name}}_{{c_nickname}}_ws_established_cb(struct ast_websocket *ws_session,
198         struct ast_variable *get_params, struct ast_variable *headers)
199 {
200         struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
201 {{#has_parameters}}
202         RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
203         struct ast_variable *i;
204 {{/has_parameters}}
205         RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref);
206         RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup);
207 {{#has_path_parameters}}
208         /* TODO: It's not immediately obvious how to pass path params through
209          * the websocket code to this callback. Not needed right now, so we'll
210          * just punt. */
211         struct ast_variable *path_vars = NULL;
212 {{/has_path_parameters}}
213
214 {{#has_parameters}}
215         response = ast_calloc(1, sizeof(*response));
216         if (!response) {
217                 ast_log(LOG_ERROR, "Failed to create response.\n");
218                 goto fin;
219         }
220 {{/has_parameters}}
221
222 #if defined(AST_DEVMODE)
223         session = ast_ari_websocket_session_create(ws_session,
224                 ast_ari_validate_{{response_class.c_name}}_fn());
225 #else
226         session = ast_ari_websocket_session_create(ws_session, NULL);
227 #endif
228         if (!session) {
229                 ast_log(LOG_ERROR, "Failed to create ARI session\n");
230                 goto fin;
231         }
232
233 {{> param_parsing}}
234
235         ast_ari_websocket_{{c_name}}_{{c_nickname}}_established(session, headers, &args);
236
237 fin: __attribute__((unused))
238         if (response && response->response_code != 0) {
239                 /* Param parsing failure */
240                 RAII_VAR(char *, msg, NULL, ast_json_free);
241                 if (response->message) {
242                         msg = ast_json_dump_string(response->message);
243                 } else {
244                         ast_log(LOG_ERROR, "Missing response message\n");
245                 }
246                 if (msg) {
247                         ast_websocket_write(ws_session,
248                                 AST_WEBSOCKET_OPCODE_TEXT, msg, strlen(msg));
249                 }
250         }
251 {{> param_cleanup}}
252 }
253 {{/is_websocket}}
254 {{/operations}}
255 {{/apis}}
256
257 {{! The rest_handler partial expands to the tree of stasis_rest_handlers }}
258 {{#root_path}}
259 {{> rest_handler}}
260 {{/root_path}}
261
262 static int unload_module(void)
263 {
264         ast_ari_remove_handler(&{{root_full_name}});
265 {{#apis}}
266 {{#has_websocket}}
267         ao2_cleanup({{full_name}}.ws_server);
268         {{full_name}}.ws_server = NULL;
269         ast_ari_websocket_events_event_websocket_dtor();
270 {{/has_websocket}}
271 {{/apis}}
272         stasis_app_unref();
273         return 0;
274 }
275
276 static int load_module(void)
277 {
278         int res = 0;
279
280         CHECK_ARI_MODULE_LOADED();
281
282 {{#apis}}
283 {{#operations}}
284 {{#has_websocket}}
285         /* This is scoped to not conflict with CHECK_ARI_MODULE_LOADED */
286         {
287                 struct ast_websocket_protocol *protocol;
288
289                 if (ast_ari_websocket_{{c_name}}_{{c_nickname}}_init() == -1) {
290                         return AST_MODULE_LOAD_DECLINE;
291                 }
292
293                 {{full_name}}.ws_server = ast_websocket_server_create();
294                 if (!{{full_name}}.ws_server) {
295                         ast_ari_websocket_events_event_websocket_dtor();
296                         return AST_MODULE_LOAD_DECLINE;
297                 }
298
299                 protocol = ast_websocket_sub_protocol_alloc("{{websocket_protocol}}");
300                 if (!protocol) {
301                         ao2_ref({{full_name}}.ws_server, -1);
302                         {{full_name}}.ws_server = NULL;
303                         ast_ari_websocket_events_event_websocket_dtor();
304                         return AST_MODULE_LOAD_DECLINE;
305                 }
306                 protocol->session_attempted = ast_ari_{{c_name}}_{{c_nickname}}_ws_attempted_cb;
307                 protocol->session_established = ast_ari_{{c_name}}_{{c_nickname}}_ws_established_cb;
308 {{/has_websocket}}
309 {{#is_websocket}}
310                 res |= ast_websocket_server_add_protocol2({{full_name}}.ws_server, protocol);
311         }
312 {{/is_websocket}}
313 {{/operations}}
314 {{/apis}}
315
316         stasis_app_ref();
317         res |= ast_ari_add_handler(&{{root_full_name}});
318         if (res) {
319                 unload_module();
320                 return AST_MODULE_LOAD_DECLINE;
321         }
322
323         return AST_MODULE_LOAD_SUCCESS;
324 }
325
326 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - {{{description}}}",
327         .support_level = AST_MODULE_SUPPORT_CORE,
328         .load = load_module,
329         .unload = unload_module,
330         .requires = "res_ari,res_ari_model,res_stasis{{#requires_modules}},{{.}}{{/requires_modules}}",
331 );
332 {{/api_declaration}}