def create(transport, path, config): # get source for file serving (either a directory, or a Python package) # static_options = config.get('options', {}) if 'directory' in config: static_dir = os.path.abspath(os.path.join(transport.cbdir, config['directory'])) elif 'package' in config: if 'resource' not in config: raise ApplicationError(u"crossbar.error.invalid_configuration", "missing resource") try: importlib.import_module(config['package']) except ImportError as e: emsg = "Could not import resource {} from package {}: {}".format(config['resource'], config['package'], e) raise ApplicationError(u"crossbar.error.invalid_configuration", emsg) else: try: static_dir = os.path.abspath(pkg_resources.resource_filename(config['package'], config['resource'])) except Exception as e: emsg = "Could not import resource {} from package {}: {}".format(config['resource'], config['package'], e) raise ApplicationError(u"crossbar.error.invalid_configuration", emsg) else: raise ApplicationError(u"crossbar.error.invalid_configuration", "missing web spec") static_dir = static_dir.encode('ascii', 'ignore') # http://stackoverflow.com/a/20433918/884770 # create resource for file system hierarchy # if static_options.get('enable_directory_listing', False): static_resource_class = StaticResource else: static_resource_class = StaticResourceNoListing cache_timeout = static_options.get('cache_timeout', DEFAULT_CACHE_TIMEOUT) allow_cross_origin = static_options.get('allow_cross_origin', True) resource = static_resource_class(static_dir, cache_timeout=cache_timeout, allow_cross_origin=allow_cross_origin) # set extra MIME types # resource.contentTypes.update(EXTRA_MIME_TYPES) if 'mime_types' in static_options: resource.contentTypes.update(static_options['mime_types']) # render 404 page on any concrete path not found # fallback = static_options.get('default_file') if fallback: resource.childNotFound = ResourceFallback(path, config) else: resource.childNotFound = Resource404(transport.templates, static_dir) return RouterWebServiceStatic(transport, path, config, resource)
def stop_web_transport_service(self, transport_id, path, details=None): """ Stop a service on a Web transport. :param transport_id: The ID of the transport to stop the Web transport service on. :type transport_id: str :param path: The path (absolute URL, eg "/myservice1") of the service to stop. :type path: str :param details: Call details. :type details: :class:`autobahn.wamp.types.CallDetails` """ self.log.info('{func}(transport_id={transport_id}, path="{path}")', func=hltype(self.stop_web_transport_service), transport_id=hlid(transport_id), path=hlval(path)) transport = self.transports.get(transport_id, None) if not transport or \ not isinstance(transport, self.personality.RouterWebTransport) or \ transport.state != self.personality.RouterTransport.STATE_STARTED: emsg = "Cannot stop service on Web transport: no transport with ID '{}' or transport is not a Web transport".format( transport_id) self.log.error(emsg) raise ApplicationError('crossbar.error.not_running', emsg) if path not in transport.root: emsg = "Cannot stop service on Web transport {}: no service running on path '{}'".format( transport_id, path) self.log.error(emsg) raise ApplicationError('crossbar.error.not_running', emsg) caller = details.caller if details else None self.publish(self._uri_prefix + '.on_web_transport_service_stopping', transport_id, path, options=PublishOptions(exclude=caller)) # now actually remove the web service. note: currently this is NOT async, but direct/sync. # FIXME: check that the underlying Twisted Web resource doesn't need any stopping too! del transport.root[path] on_web_transport_service_stopped = { 'transport_id': transport_id, 'path': path, } caller = details.caller if details else None self.publish(self._uri_prefix + '.on_web_transport_service_stopped', transport_id, path, on_web_transport_service_stopped, options=PublishOptions(exclude=caller)) return on_web_transport_service_stopped
async def validate(self, _raise=False, **kwargs): result = [] for name, field in self.fields_map_required.items(): if field.pk or hasattr(field, 'relation_field'): continue if name in kwargs: if type(field) == BackwardFKRelation: if isinstance(kwargs[name], dict): relation = field.model_class() fk_res = await relation.validate(**kwargs[name]) if fk_res: result.append("'{}' {}".format(name, fk_res)) else: result.append("'{}' Invalid type".format(name)) elif type(kwargs[name]) != field.field_type: result.append("'{}' Invalid type".format(name)) if field.unique: obj = await self.model.filter(**{ name: kwargs[name] }).first() if obj: result.append("'{}' must be unique".format(name)) else: if not isinstance(field, ForeignKeyFieldInstance): result.append("'{}' required".format(name)) continue if _raise and result: raise ApplicationError(ApplicationError.INVALID_ARGUMENT, ', '.join(result)) return result
def create(transport, path, config): personality = transport.worker.personality personality.WEB_SERVICE_CHECKERS['wsgi'](personality, config) reactor = transport.worker.components_shared['reactor'] if 'module' not in config: raise ApplicationError('crossbar.error.invalid_configuration', 'missing WSGI app module') if 'object' not in config: raise ApplicationError('crossbar.error.invalid_configuration', 'missing WSGI app object') # import WSGI app module and object mod_name = config['module'] try: mod = importlib.import_module(mod_name) except ImportError as e: raise ApplicationError( 'crossbar.error.invalid_configuration', 'WSGI app module "{}" import failed: {} - Python search path was {}'.format(mod_name, e, sys.path)) obj_name = config['object'] if obj_name not in mod.__dict__: raise ApplicationError('crossbar.error.invalid_configuration', 'WSGI app object "{}" not in module "{}"'.format(obj_name, mod_name)) else: app = getattr(mod, obj_name) # Create a thread-pool for running the WSGI requests in pool = ThreadPool(maxthreads=config.get('maxthreads', 20), minthreads=config.get('minthreads', 0), name='crossbar_wsgi_threadpool') reactor.addSystemEventTrigger('before', 'shutdown', pool.stop) pool.start() # Create a Twisted Web WSGI resource from the user's WSGI application object try: resource = WSGIResource(reactor, pool, app) if path == '/': resource = WSGIRootResource(resource, {}) except Exception as e: raise ApplicationError('crossbar.error.invalid_configuration', 'could not instantiate WSGI resource: {}'.format(e)) else: return RouterWebServiceWsgi(transport, path, config, resource)
def get_web_transport_service(self, transport_id, path, details=None): self.log.debug('{func}(transport_id={transport_id}, path="{path}")', func=hltype(self.get_web_transport_service), transport_id=hlid(transport_id), path=hlval(path)) transport = self.transports.get(transport_id, None) if not transport or \ not isinstance(transport, self.personality.RouterWebTransport) or \ transport.state != self.personality.RouterTransport.STATE_STARTED: emsg = "No transport with ID '{}' or transport is not a Web transport".format(transport_id) self.log.debug(emsg) raise ApplicationError('crossbar.error.not_running', emsg) if path not in transport.root: emsg = "Web transport {}: no service running on path '{}'".format(transport_id, path) self.log.debug(emsg) raise ApplicationError('crossbar.error.not_running', emsg) return transport.marshal()
def get_web_transport_services(self, transport_id, details=None): self.log.debug('{func}(transport_id={transport_id})', func=hltype(self.get_web_transport_services), transport_id=hlid(transport_id)) transport = self.transports.get(transport_id, None) if not transport or \ not isinstance(transport, self.personality.RouterWebTransport) or \ transport.state != self.personality.RouterTransport.STATE_STARTED: emsg = "No transport with ID '{}' or transport is not a Web transport".format(transport_id) self.log.debug(emsg) raise ApplicationError('crossbar.error.not_running', emsg) return sorted(transport._config.get('paths', []))
def __init__(self, worker, transport_id, config): """ :param worker: The (router) worker session the transport is created from. :type worker: crossbar.worker.router.RouterController :param transport_id: The transport ID within the router. :type transport_id: str :param config: The transport's configuration. :type config: dict """ self._worker = worker self._transport_id = transport_id try: self._worker.personality.check_router_transport( self._worker.personality, config) except Exception as e: emsg = "Invalid router transport configuration: {}".format(e) self.log.error(emsg) raise ApplicationError(u"crossbar.error.invalid_configuration", emsg) else: self.log.debug( "Router transport parsed successfully (transport_id={transport_id}, transport_type={transport_type})", transport_id=transport_id, transport_type=config['type']) self._config = config self._type = config['type'] self._cbdir = self._worker.config.extra.cbdir self._templates = self._worker.templates() self._created_at = datetime.utcnow() self._listening_since = None self._state = RouterTransport.STATE_CREATED self._transport_factory = None self._root_webservice = None # twisted.internet.interfaces.IListeningPort self._port = None
def start_web_transport_service(self, transport_id, path, config, details=None): """ Start a service on a Web transport. :param transport_id: The ID of the transport to start the Web transport service on. :type transport_id: str :param path: The path (absolute URL, eg "/myservice1") on which to start the service. :type path: str :param config: The Web service configuration. :type config: dict :param details: Call details. :type details: :class:`autobahn.wamp.types.CallDetails` """ if not isinstance(config, dict) or 'type' not in config: raise ApplicationError( 'crossbar.invalid_argument', 'config parameter must be dict with type attribute') self.log.info( 'Starting "{service_type}" Web service on path "{path}" of transport "{transport_id}" {func}', service_type=hlval(config.get('type', 'unknown')), path=hlval(path), transport_id=hlid(transport_id), func=hltype(self.start_web_transport_service)) transport = self.transports.get(transport_id, None) if not transport: emsg = 'Cannot start service on transport: no transport with ID "{}"'.format( transport_id) self.log.error(emsg) raise ApplicationError('crossbar.error.not_running', emsg) if not isinstance(transport, self.personality.RouterWebTransport): emsg = 'Cannot start service on transport: transport is not a Web transport (transport_type={})'.format( hltype(transport.__class__)) self.log.error(emsg) raise ApplicationError('crossbar.error.not_running', emsg) if transport.state != self.personality.RouterTransport.STATE_STARTED: emsg = 'Cannot start service on Web transport service: transport {} is not running (transport_state={})'.format( transport_id, self.personality.RouterWebTransport.STATES.get( transport.state, None)) self.log.error(emsg) raise ApplicationError('crossbar.error.not_running', emsg) if path in transport.root: emsg = 'Cannot start service on Web transport "{}": a service is already running on path "{}"'.format( transport_id, path) self.log.error(emsg) raise ApplicationError('crossbar.error.already_running', emsg) caller = details.caller if details else None self.publish(self._uri_prefix + '.on_web_transport_service_starting', transport_id, path, options=PublishOptions(exclude=caller)) # now actually add the web service .. # note: currently this is NOT async, but direct/sync. webservice_factory = self.personality.WEB_SERVICE_FACTORIES[ config['type']] webservice = yield maybeDeferred(webservice_factory.create, transport, path, config) transport.root[path] = webservice on_web_transport_service_started = { 'transport_id': transport_id, 'path': path, 'config': config } caller = details.caller if details else None self.publish(self._uri_prefix + '.on_web_transport_service_started', transport_id, path, on_web_transport_service_started, options=PublishOptions(exclude=caller)) returnValue(on_web_transport_service_started)