Exemplo n.º 1
0
    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)
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
    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
Exemplo n.º 4
0
    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)
Exemplo n.º 5
0
    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()
Exemplo n.º 6
0
    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', []))
Exemplo n.º 7
0
    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
Exemplo n.º 8
0
    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)