mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	Shuffle RESTful URL's around.
This patch moves the RESTful URL's around to more appropriate locations for release. The /stasis URL's are moved to /ari, since Asterisk REST Interface was a more appropriate name than Stasis-HTTP. (Most of the code still has stasis_http references, but they will be cleaned up after there are no more outstanding branches that would have merge conflicts with such a change). A larger change was moving the ARI events WebSocket off of the shared /ws URL to its permanent home on /ari/events. The Swagger code generator was extended to handle "upgrade: websocket" and "websocketProtocol:" attributes on an operation. The WebSocket module was modified to better handle WebSocket servers that have a single registered protocol handler. If a client connections does not specify the Sec-WebSocket-Protocol header, and the server has a single protocol handler registered, the WebSocket server will go ahead and accept the client for that subprotocol. (closes issue ASTERISK-21857) Review: https://reviewboard.asterisk.org/r/2621/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393528 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		| @@ -144,6 +144,7 @@ class AsteriskProcessor(SwaggerPostProcessor): | ||||
|                 segment = resource_api.root_path.get_child(api.path.split('/')) | ||||
|                 for operation in api.operations: | ||||
|                     segment.operations.append(operation) | ||||
|                 api.full_name = segment.full_name | ||||
|             resource_api.api_declaration.has_events = False | ||||
|             for model in resource_api.api_declaration.models: | ||||
|                 if model.id == "Event": | ||||
|   | ||||
							
								
								
									
										45
									
								
								rest-api-templates/param_parsing.mustache
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								rest-api-templates/param_parsing.mustache
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| {{! | ||||
|  * Asterisk -- An open source telephony toolkit. | ||||
|  * | ||||
|  * Copyright (C) 2013, Digium, Inc. | ||||
|  * | ||||
|  * David M. Lee, II <dlee@digium.com> | ||||
|  * | ||||
|  * See http://www.asterisk.org for more information about | ||||
|  * the Asterisk project. Please do not directly contact | ||||
|  * any of the maintainers of this project for assistance; | ||||
|  * the project provides a web site, mailing lists and IRC | ||||
|  * channels for your use. | ||||
|  * | ||||
|  * This program is free software, distributed under the terms of | ||||
|  * the GNU General Public License Version 2. See the LICENSE file | ||||
|  * at the top of the source tree. | ||||
| }} | ||||
| {{! | ||||
|  * Snippet for decoding parameters into an _args struct. | ||||
| }} | ||||
| 	struct ast_{{c_nickname}}_args args = {}; | ||||
| {{#has_parameters}} | ||||
| 	struct ast_variable *i; | ||||
|  | ||||
| {{#has_query_parameters}} | ||||
| 	for (i = get_params; i; i = i->next) { | ||||
| {{#query_parameters}} | ||||
| 		if (strcmp(i->name, "{{name}}") == 0) { | ||||
| 			args.{{c_name}} = {{c_convert}}(i->value); | ||||
| 		} else | ||||
| {{/query_parameters}} | ||||
| 		{} | ||||
| 	} | ||||
| {{/has_query_parameters}} | ||||
| {{#has_path_parameters}} | ||||
| 	for (i = path_vars; i; i = i->next) { | ||||
| {{#path_parameters}} | ||||
| 		if (strcmp(i->name, "{{name}}") == 0) { | ||||
| 			args.{{c_name}} = {{c_convert}}(i->value); | ||||
| 		} else | ||||
| {{/path_parameters}} | ||||
| 		{} | ||||
| 	} | ||||
| {{/has_path_parameters}} | ||||
| {{/has_parameters}} | ||||
| @@ -52,6 +52,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | ||||
|  | ||||
| {{#apis}} | ||||
| {{#operations}} | ||||
| {{#is_req}} | ||||
| /*! | ||||
|  * \brief Parameter parsing callback for {{path}}. | ||||
|  * \param get_params GET parameters in the HTTP request. | ||||
| @@ -63,33 +64,31 @@ static void stasis_http_{{c_nickname}}_cb( | ||||
|     struct ast_variable *get_params, struct ast_variable *path_vars, | ||||
|     struct ast_variable *headers, struct stasis_http_response *response) | ||||
| { | ||||
| 	struct ast_{{c_nickname}}_args args = {}; | ||||
| {{#has_parameters}} | ||||
| 	struct ast_variable *i; | ||||
|  | ||||
| {{#has_query_parameters}} | ||||
| 	for (i = get_params; i; i = i->next) { | ||||
| {{#query_parameters}} | ||||
| 		if (strcmp(i->name, "{{name}}") == 0) { | ||||
| 			args.{{c_name}} = {{c_convert}}(i->value); | ||||
| 		} else | ||||
| {{/query_parameters}} | ||||
| 		{} | ||||
| 	} | ||||
| {{/has_query_parameters}} | ||||
| {{#has_path_parameters}} | ||||
| 	for (i = path_vars; i; i = i->next) { | ||||
| {{#path_parameters}} | ||||
| 		if (strcmp(i->name, "{{name}}") == 0) { | ||||
| 			args.{{c_name}} = {{c_convert}}(i->value); | ||||
| 		} else | ||||
| {{/path_parameters}} | ||||
| 		{} | ||||
| 	} | ||||
| {{/has_path_parameters}} | ||||
| {{/has_parameters}} | ||||
| {{> param_parsing}} | ||||
| 	stasis_http_{{c_nickname}}(headers, &args, response); | ||||
| } | ||||
| {{/is_req}} | ||||
| {{#is_websocket}} | ||||
| static void stasis_http_{{c_nickname}}_ws_cb(struct ast_websocket *ws_session, | ||||
| 	struct ast_variable *get_params, struct ast_variable *headers) | ||||
| { | ||||
| 	RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref); | ||||
| 	RAII_VAR(struct ari_websocket_session *, session, NULL, ao2_cleanup); | ||||
| {{#has_path_parameters}} | ||||
| 	/* TODO: It's not immediately obvious how to pass path params through | ||||
| 	 * the websocket code to this callback. Not needed right now, so we'll | ||||
| 	 * just punt. */ | ||||
| 	struct ast_variable *path_vars = NULL; | ||||
| {{/has_path_parameters}} | ||||
| {{> param_parsing}} | ||||
| 	session = ari_websocket_session_create(ws_session); | ||||
| 	if (!session) { | ||||
| 		ast_log(LOG_ERROR, "Failed to create ARI session\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 	ari_websocket_{{c_nickname}}(session, headers, &args); | ||||
| } | ||||
| {{/is_websocket}} | ||||
| {{/operations}} | ||||
| {{/apis}} | ||||
|  | ||||
| @@ -100,13 +99,35 @@ static void stasis_http_{{c_nickname}}_cb( | ||||
|  | ||||
| static int load_module(void) | ||||
| { | ||||
| 	int res = 0; | ||||
| {{#apis}} | ||||
| {{#has_websocket}} | ||||
| 	{{full_name}}.ws_server = ast_websocket_server_create(); | ||||
| 	if (!{{full_name}}.ws_server) { | ||||
| 		return AST_MODULE_LOAD_FAILURE; | ||||
| 	} | ||||
| {{/has_websocket}} | ||||
| {{#operations}} | ||||
| {{#is_websocket}} | ||||
| 	res |= ast_websocket_server_add_protocol({{full_name}}.ws_server, | ||||
| 		"{{websocket_protocol}}", stasis_http_{{c_nickname}}_ws_cb); | ||||
| {{/is_websocket}} | ||||
| {{/operations}} | ||||
| {{/apis}} | ||||
| 	stasis_app_ref(); | ||||
| 	return stasis_http_add_handler(&{{root_full_name}}); | ||||
| 	res |= stasis_http_add_handler(&{{root_full_name}}); | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| static int unload_module(void) | ||||
| { | ||||
| 	stasis_http_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; | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| {{! -*- C -*- | ||||
| {{! | ||||
|  * Asterisk -- An open source telephony toolkit. | ||||
|  * | ||||
|  * Copyright (C) 2013, Digium, Inc. | ||||
| @@ -30,7 +30,9 @@ static struct stasis_rest_handlers {{full_name}} = { | ||||
| {{/is_wildcard}} | ||||
| 	.callbacks = { | ||||
| {{#operations}} | ||||
| {{#is_req}} | ||||
| 		[{{c_http_method}}] = stasis_http_{{c_nickname}}_cb, | ||||
| {{/is_req}} | ||||
| {{/operations}} | ||||
| 	}, | ||||
| 	.num_children = {{num_children}}, | ||||
|   | ||||
| @@ -32,10 +32,22 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | ||||
|  | ||||
| {{#apis}} | ||||
| {{#operations}} | ||||
| void stasis_http_{{c_nickname}}(struct ast_variable *headers, struct ast_{{c_nickname}}_args *args, struct stasis_http_response *response) | ||||
| {{#is_req}} | ||||
| void stasis_http_{{c_nickname}}(struct ast_variable *headers, | ||||
| 	struct ast_{{c_nickname}}_args *args, | ||||
| 	struct stasis_http_response *response) | ||||
| { | ||||
| 	ast_log(LOG_ERROR, "TODO: stasis_http_{{c_nickname}}\n"); | ||||
| } | ||||
| {{/is_req}} | ||||
| {{#is_websocket}} | ||||
| void ari_websocket_{{c_nickname}}(struct ari_websocket_session *session, | ||||
| 	struct ast_variable *headers, | ||||
| 	struct ast_{{c_nickname}}_args *args) | ||||
| { | ||||
| 	ast_log(LOG_ERROR, "TODO: ari_websocket_{{c_nickname}}\n"); | ||||
| } | ||||
| {{/is_websocket}} | ||||
| {{/operations}} | ||||
| {{/apis}} | ||||
| {{/api_declaration}} | ||||
|   | ||||
| @@ -49,6 +49,7 @@ struct ast_{{c_nickname}}_args { | ||||
| 	{{c_data_type}}{{c_space}}{{c_name}}; | ||||
| {{/parameters}} | ||||
| }; | ||||
| {{#is_req}} | ||||
| /*! | ||||
|  * \brief {{summary}} | ||||
| {{#notes}} | ||||
| @@ -61,6 +62,21 @@ struct ast_{{c_nickname}}_args { | ||||
|  * \param[out] response HTTP response | ||||
|  */ | ||||
| void stasis_http_{{c_nickname}}(struct ast_variable *headers, struct ast_{{c_nickname}}_args *args, struct stasis_http_response *response); | ||||
| {{/is_req}} | ||||
| {{#is_websocket}} | ||||
| /*! | ||||
|  * \brief {{summary}} | ||||
| {{#notes}} | ||||
|  * | ||||
|  * {{{notes}}} | ||||
| {{/notes}} | ||||
|  * | ||||
|  * \param session ARI WebSocket. | ||||
|  * \param headers HTTP headers. | ||||
|  * \param args Swagger parameters. | ||||
|  */ | ||||
| void ari_websocket_{{c_nickname}}(struct ari_websocket_session *session, struct ast_variable *headers, struct ast_{{c_nickname}}_args *args); | ||||
| {{/is_websocket}} | ||||
| {{/operations}} | ||||
| {{/apis}} | ||||
|  | ||||
|   | ||||
| @@ -218,6 +218,16 @@ class Operation(Stringify): | ||||
|         self.http_method = op_json.get('httpMethod') | ||||
|         self.nickname = op_json.get('nickname') | ||||
|         self.response_class = op_json.get('responseClass') | ||||
|         # Specifying WebSocket URL's is our own extension | ||||
|         self.is_websocket = op_json.get('upgrade') == 'websocket' | ||||
|         self.is_req = not self.is_websocket | ||||
|  | ||||
|         if self.is_websocket: | ||||
|             self.websocket_protocol = op_json.get('websocketProtocol') | ||||
|             if self.http_method != 'GET': | ||||
|                 raise ValueError( | ||||
|                     "upgrade: websocket is only valid on GET operations") | ||||
|  | ||||
|         params_json = op_json.get('parameters') or [] | ||||
|         self.parameters = [ | ||||
|             Parameter().load(j, processor, context) for j in params_json] | ||||
| @@ -262,6 +272,8 @@ class Api(Stringify): | ||||
|         op_json = api_json.get('operations') | ||||
|         self.operations = [ | ||||
|             Operation().load(j, processor, context) for j in op_json] | ||||
|         self.has_websocket = \ | ||||
|             filter(lambda op: op.is_websocket, self.operations) != [] | ||||
|         return self | ||||
|  | ||||
|  | ||||
| @@ -353,7 +365,8 @@ class ApiDeclaration(Stringify): | ||||
|             .replace(".json", ".{format}") | ||||
|  | ||||
|         if self.resource_path != expected_resource_path: | ||||
|             print "%s != %s" % (self.resource_path, expected_resource_path) | ||||
|             print >> sys.stderr, \ | ||||
|                 "%s != %s" % (self.resource_path, expected_resource_path) | ||||
|             raise SwaggerError("resourcePath has incorrect value", context) | ||||
|  | ||||
|         return self | ||||
|   | ||||
		Reference in New Issue
	
	Block a user