res_ari_resource.c.mustache 8.1 KB

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