Esempio n. 1
0
    def __init__(self, user_directory, check_dir=True):
        self.host = "127.0.0.1"
        self.port = 9000
        self.forwarding_port = None
        self.hostname = "localhost"
        if check_dir:
            self.user_directory = self.check_directory(user_directory)
        else:
            self.user_directory = user_directory

        self.cp_config = {}
        self.dispatcher = AboardDispatcher()
        self.loader = AutoLoader(self)
        self.bundles = {}
        self.configurations = {}
        self.plugin_manager = PluginManager(self)
        self.services = manager
        self.services.register_defaults()
        self.source_directory = ""
        self.templating_system = Jinja2(self)
        self.templating_system.setup()

        Controller.server = self
        Formatter.server = self
Esempio n. 2
0
class Server:

    """Wrapper of a cherrypy server."""

    def __init__(self, user_directory, check_dir=True):
        self.host = "127.0.0.1"
        self.port = 9000
        self.forwarding_port = None
        self.hostname = "localhost"
        if check_dir:
            self.user_directory = self.check_directory(user_directory)
        else:
            self.user_directory = user_directory

        self.cp_config = {}
        self.dispatcher = AboardDispatcher()
        self.loader = AutoLoader(self)
        self.bundles = {}
        self.configurations = {}
        self.plugin_manager = PluginManager(self)
        self.services = manager
        self.services.register_defaults()
        self.source_directory = ""
        self.templating_system = Jinja2(self)
        self.templating_system.setup()

        Controller.server = self
        Formatter.server = self

    @property
    def models(self):
        """Return all the models."""
        models = []
        for bundle in self.bundles.values():
            models.extend(list(bundle.models.values()))

        return models

    def check_directory(self, directory):
        """Check whether the directory is correct.

        A directory is not correct if:
            It doesn't exist (surprising, hu?)
            It doesn't contain the right repositories and files

        """
        directories = (
            "bundles",
            "config",
            "layout",
        )

        if not os.path.exists(directory):
            raise ValueError("the directory {} doesn't exist".format(
                    directory))

        existing_dirs = [name for name in os.listdir(directory) if \
                os.path.isdir(directory + os.sep + name)]
        for required_dir in directories:
            if required_dir not in existing_dirs:
                raise RuntimeError("the {} directory doesn't exist in " \
                        "{}".format(repr(required_dir), directory))

        abs_directory = os.path.abspath(directory)
        sys.path.append(abs_directory)
        return abs_directory

    def load_configurations(self):
        """This method reads the configuration files found in /config."""
        path = os.path.join(self.user_directory, "config")
        configurations = {
            "data_connector": DataConnectorConfiguration,
            "formats": FormatsConfiguration,
            "server": ServerConfiguration,
        }

        for filename, configuration in configurations.items():
            config_path = os.path.join(path, filename + ".yml")
            configuration = configuration.read_YAML(config_path)
            self.configurations[filename] = configuration

    def prepare(self):
        """Prepare the server."""
        # Update the server's host and port
        if "server" in self.configurations:
            server = self.configurations["server"]
            if "host" in server:
                self.host = server["host"]
            if "port" in server:
                self.port = server["port"]
            if "hostname" in server:
                self.hostname = server["hostname"]
            if "forwarding_port" in server:
                self.forwarding_port = server["forwarding_port"]

        # DataConnector configuration
        dc_conf = self.configurations["data_connector"].datas
        dc_name = dc_conf["dc_name"]
        dc_spec = dict(dc_conf)
        del dc_spec["dc_name"]
        try:
            dc = connectors[dc_name]
        except KeyError:
            print("Unknown data connector {}".format(dc_name))
            return

        dc = dc()
        config_path = os.path.join(self.user_directory, "config",
                "data_connector.yml")
        dc.setup(config_path)
        Model.data_connector = dc
        self.services.services["data_connector"].data_connector = dc

        if "formats" not in self.configurations:
            return
        cfg_formats = self.configurations["formats"]

        # Setup the default_format
        default = cfg_formats["default_format"].lower()
        if default not in formats:
            raise ValueError("unknown format {}".format(default))

        allowed_formats = []
        for format in cfg_formats.get("allowed_formats", []):
            format = format.lower()
            if format not in formats:
                raise ValueError("unknown format {}".format(format))

            allowed_formats.append(format)

        self.data_connector = dc
        self.default_format = default
        self.allowed_formats = allowed_formats
        self.loader.add_default_rules()

    def load_bundles(self):
        """Load the user's bundles."""
        path = os.path.join(self.user_directory, "bundles")
        for name in os.listdir(path):
            if not name.startswith("__") and os.path.isdir(path + "/" + name):
                bundle = Bundle(self, name)
                self.bundles[name] = bundle
        for bundle in self.bundles.values():
            bundle.setup(self, self.loader)

        for model in self.models:
            type(model).extend(model)
        for model in self.models:
            self.data_connector.repository_manager.add_model(model)

    def run(self):
        """Run the server."""
        cherrypy.engine.autoreload.unsubscribe()
        if hasattr(cherrypy.engine, 'signal_handler'):
            cherrypy.engine.signal_handler.subscribe()
        if hasattr(cherrypy.engine, "console_control_handler"):
            cherrypy.engine.console_control_handler.subscribe()
        #cherrypy.engine.reloader = Reloader(cherrypy.engine)
        #cherrypy.engine.reloader.loader = self.loader
        #cherrypy.engine.reloader.server = self
        #cherrypy.engine.reloader.subscribe()
        cherrypy.config.update({
                'server.socket_host': self.host,
                'server.socket_port': self.port,
                'tools.staticdir.root': self.user_directory,
        })
        cherrypy.config["tools.encode.on"] = True
        cherrypy.config["tools.decode.on"] = True
        config = self.cp_config
        config.update({
            '/static': {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': 'static',
                'tools.staticdir.content_types': {
                        'ogg': 'application/ogg',
                },
            },
        })

        # Some plugins add configuration
        self.plugin_manager.call("extend_server_configuration", cherrypy.engine, config)
        cherrypy.tree.mount(root=self.dispatcher, config=config)
        self.write_PID()
        cherrypy.engine.start()
        cherrypy.engine.block()
        self.del_PID()

    def get_model(self, name):
        """Try and retrieve a Model class."""
        bundle_name, model_name = name.split(".")
        bundle = self.bundles[bundle_name]
        model = bundle.models[name]
        return model

    def get_repository(self, model_name):
        """Return the repository bound to the specified model.

        The full name ('bundle.Model') should be specified.

        """
        model = self.get_model(model_name)
        return model._repository

    def write_PID(self):
        """Write the PID (os.pid) in the user's directory configuration."""
        path = os.path.join(self.user_directory, "tmp")
        if not os.path.exists(path):
            os.makedirs(path)

        pid = os.getpid()
        pid_path = os.path.join(path, "pid")
        with open(pid_path, "w") as pid_file:
            pid_file.write(str(pid))

    def del_PID(self):
        """Delete the file containing the server's PID."""
        path = os.path.join(self.user_directory, "tmp")
        if os.path.exists(path):
            pid_path = os.path.join(path, "pid")
            os.remove(pid_path)

    def get_cookie(self, name, value=None):
        """Get the cookie and return its value or 'value' if not found."""
        try:
            return cherrypy.request.cookie[name].value
        except KeyError:
            return value

    def set_cookie(self, name, value, max_age, path="/", version=1):
        """Set a cookie."""
        cookie = cherrypy.response.cookie
        cookie[name] = value
        cookie[name]['path'] = path
        cookie[name]['max-age'] = max_age
        cookie[name]['version'] = 1

    def authenticated(self):
        """Return whether the current request is authenticated or not."""
        client_token = self.get_cookie("PA-client-token")
        if not client_token:
            print("no cookie")
            return False

        headers = cherrypy.request.headers
        if "Remote-Addr" not in headers:
            print("no IP")
            return False

        to_hash = "Python-Aboard " + headers.get("Remote-Addr", "none")
        to_hash += " " + headers.get("User-Agent", "unknown")
        to_hash = to_hash.encode()
        token = hashlib.sha256(to_hash).digest()
        return client == client_token