def generateServiceMappings(svc_cfg, registry_path=forms.DEFAULT_REGISTRY_PATH): """ Utility function that reads the services config and generates URL mappings to service classes. """ services = [] ## Generate service mappings in tuple(<invocation_url>, <classpath>) format for service, cfg in svc_cfg['services'].items(): if cfg['enabled'] == True: services.append( ('/'.join(svc_cfg['config']['url_prefix'].split('/') + [service]), cfg['service'])) services = protorpc._normalize_services(services) mapping = [] registry_map = {} if registry_path is not None: registry_service = registry.RegistryService.new_factory(registry_map) services = list(services) + [(registry_path, registry_service)] forms_handler = forms.FormsHandler(registry_path=registry_path) mapping.append((registry_path + r'/form(?:/)?', forms_handler)) mapping.append((registry_path + r'/form/(.+)', forms.ResourceHandler)) paths = set() for path, service in services: service_class = getattr(service, 'service_class', service) if not path: path = '/' + service_class.definition_name().replace('.', '/') if path in paths: raise service_handlers.ServiceConfigurationError( 'Path %r is already defined in service mapping' % path.encode('utf-8')) else: paths.add(path) # Create service mapping for webapp2. new_mapping = RemoteServiceHandlerFactory.default(service).mapping( path) mapping.append(new_mapping) # Update registry with service class. registry_map[path] = service_class return mapping
def service_mapping(services, registry_path=forms.DEFAULT_REGISTRY_PATH): """Create a services mapping for use with webapp2. Creates basic default configuration and registration for ProtoRPC services. Each service listed in the service mapping has a standard service handler factory created for it. The list of mappings can either be an explicit path to service mapping or just services. If mappings are just services, they will automatically be mapped to their default name. For example:: from protorpc import messages from protorpc import remote import webapp2 from webapp2_extras import protorpc class HelloRequest(messages.Message): my_name = messages.StringField(1, required=True) class HelloResponse(messages.Message): hello = messages.StringField(1, required=True) class HelloService(remote.Service): @remote.method(HelloRequest, HelloResponse) def hello(self, request): return HelloResponse(hello='Hello there, %s!' % request.my_name) service_mappings = protorpc.service_mapping([ ('/hello', HelloService), ]) app = webapp2.WSGIApplication(routes=service_mappings) def main(): app.run() if __name__ == '__main__': main() Specifying a service mapping: Normally services are mapped to URL paths by specifying a tuple (path, service): - path: The path the service resides on. - service: The service class or service factory for creating new instances of the service. For more information about service factories, please see remote.Service.new_factory. If no tuple is provided, and therefore no path specified, a default path is calculated by using the fully qualified service name using a URL path separator for each of its components instead of a '.'. :param services: Can be service type, service factory or string definition name of service being mapped or list of tuples (path, service): - path: Path on server to map service to. - service: Service type, service factory or string definition name of service being mapped. Can also be a dict. If so, the keys are treated as the path and values as the service. :param registry_path: Path to give to registry service. Use None to disable registry service. :returns: List of tuples defining a mapping of request handlers compatible with a webapp2 application. :raises: ServiceConfigurationError when duplicate paths are provided. """ # TODO: clean the convoluted API? Accept services as tuples only, or # make different functions to accept different things. # For now we are just following the same API from protorpc. services = _normalize_services(services) mapping = [] registry_map = {} if registry_path is not None: registry_service = registry.RegistryService.new_factory(registry_map) services = list(services) + [(registry_path, registry_service)] forms_handler = forms.FormsHandler(registry_path=registry_path) mapping.append((registry_path + r'/form(?:/)?', forms_handler)) mapping.append((registry_path + r'/form/(.+)', forms.ResourceHandler)) paths = set() for path, service in services: service_class = getattr(service, 'service_class', service) if not path: path = '/' + service_class.definition_name().replace('.', '/') if path in paths: raise service_handlers.ServiceConfigurationError( 'Path %r is already defined in service mapping' % path.encode('utf-8')) else: paths.add(path) # Create service mapping for webapp2. new_mapping = ServiceHandlerFactory.default(service).mapping(path) mapping.append(new_mapping) # Update registry with service class. registry_map[path] = service_class return mapping