예제 #1
0
    def process_publish(self, project, params, info=None):
        """
        Publish message into appropriate channel.
        """
        message, error = yield self.prepare_message(project, params, info)
        if error:
            raise Return((False, self.INTERNAL_SERVER_ERROR))

        if not message:
            # message was discarded
            raise Return((False, None))

        # publish prepared message
        result, error = yield self.publish_message(project, message)

        if error:
            raise Return((False, error))

        for callback in self.post_publish_callbacks:
            try:
                yield callback(project["name"], message)
            except Exception as err:
                logger.exception(err)

        raise Return((True, None))
예제 #2
0
파일: core.py 프로젝트: byouloh/centrifuge
    def process_publish(self, project, params, client=None):
        """
        Publish message into appropriate channel.
        """
        message, error = yield self.prepare_message(
            project, params, client
        )
        if error:
            raise Return((False, self.INTERNAL_SERVER_ERROR))

        if not message:
            # message was discarded
            raise Return((False, None))

        # publish prepared message
        result, error = yield self.publish_message(
            project, message
        )
        if error:
            raise Return((False, error))

        for callback in self.post_publish_callbacks:
            try:
                yield callback(message)
            except Exception as err:
                logger.exception(err)

        raise Return((True, None))
예제 #3
0
    def prepare_message(self, project, params, info):
        """
        Prepare message before actual publishing.
        """
        channel = params.get('channel')
        if not channel:
            raise Return((None, None))

        data = params.get('data', None)

        message = {
            'uid': uuid.uuid4().hex,
            'timestamp': int(time.time()),
            'info': info,
            'channel': channel,
            'data': data
        }

        for callback in self.pre_publish_callbacks:
            try:
                message = yield callback(project["name"], message)
            except Exception as err:
                logger.exception(err)
            else:
                if message is None:
                    raise Return((None, None))

        raise Return((message, None))
예제 #4
0
    def prepare_message(self, project, params, client):
        """
        Prepare message before actual publishing.
        """
        data = params.get('data', None)

        message = {
            'project_id': project['_id'],
            'uid': uuid.uuid4().hex,
            'timestamp': int(time.time()),
            'client': client,
            'channel': params.get('channel'),
            'data': data
        }

        for callback in self.pre_publish_callbacks:
            try:
                message = yield callback(message)
            except Exception as err:
                logger.exception(err)
            else:
                if message is None:
                    raise Return((None, None))

        raise Return((message, None))
예제 #5
0
파일: core.py 프로젝트: byouloh/centrifuge
    def prepare_message(self, project, params, client):
        """
        Prepare message before actual publishing.
        """
        data = params.get('data', None)

        message = {
            'project_id': project['_id'],
            'uid': uuid.uuid4().hex,
            'timestamp': int(time.time()),
            'client': client,
            'channel': params.get('channel'),
            'data': data
        }

        for callback in self.pre_publish_callbacks:
            try:
                message = yield callback(message)
            except Exception as err:
                logger.exception(err)
            else:
                if message is None:
                    raise Return((None, None))

        raise Return((message, None))
예제 #6
0
    def prepare_message(self, project, params, info):
        """
        Prepare message before actual publishing.
        """
        channel = params.get('channel')
        if not channel:
            raise Return((None, None))

        data = params.get('data', None)

        message = {
            'uid': uuid.uuid4().hex,
            'timestamp': int(time.time()),
            'info': info,
            'channel': channel,
            'data': data
        }

        for callback in self.pre_publish_callbacks:
            try:
                message = yield callback(project["name"], message)
            except Exception as err:
                logger.exception(err)
            else:
                if message is None:
                    raise Return((None, None))

        raise Return((message, None))
예제 #7
0
파일: core.py 프로젝트: nigma/centrifuge
    def process_publish(self, project, params, allowed_namespaces=None, client=None):
        """
        Publish message into appropriate channel.
        """
        if allowed_namespaces is None:
            project_namespaces, error = yield self.structure.get_project_namespaces(project)
            if error:
                raise Return((None, error))

            allowed_namespaces = dict((x["name"], x) for x in project_namespaces)

        message, error = yield self.prepare_message(project, allowed_namespaces, params, client)
        if error:
            raise Return((None, error))

        if not message:
            # message was discarded
            raise Return((True, None))

        # publish prepared message
        result, error = yield self.publish_message(message, allowed_namespaces)
        if error:
            raise Return((None, error))

        for callback in self.post_publish_callbacks:
            try:
                yield callback(message)
            except Exception as err:
                logger.exception(err)

        raise Return((True, None))
예제 #8
0
    def send(self, response):
        """
        Send message directly to client.
        """
        if not self.sock:
            raise Return((False, None))

        try:
            self.sock.send(response)
        except Exception as err:
            logger.exception(err)
            yield self.close_sock(pause=False)
            raise Return((False, None))

        raise Return((True, None))
예제 #9
0
    def on_connection_ready(self, ready_callback):
        project = 'CREATE TABLE IF NOT EXISTS projects (id SERIAL, _id varchar(32) UNIQUE, ' \
                  'secret_key varchar(32), options text)'

        namespace = 'CREATE TABLE IF NOT EXISTS namespaces (id SERIAL, ' \
                    '_id varchar(32) UNIQUE, project_id varchar(32), ' \
                    'name varchar(100) NOT NULL, options text, ' \
                    'constraint namespaces_unique unique(project_id, name))'

        try:
            yield momoko.Op(self._conn.execute, project, ())
            yield momoko.Op(self._conn.execute, namespace, ())
        except Exception as err:
            logger.exception(err)
        ready_callback()
예제 #10
0
    def send(self, response):
        """
        Send message directly to client.
        """
        if not self.sock:
            raise Return((False, None))

        try:
            self.sock.send(response)
        except Exception as err:
            logger.exception(err)
            yield self.close_sock(pause=False)
            raise Return((False, None))

        raise Return((True, None))
예제 #11
0
파일: core.py 프로젝트: nigma/centrifuge
    def prepare_message(self, project, allowed_namespaces, params, client):
        """
        Prepare message before actual publishing.
        """
        namespace_name = params.get("namespace")
        namespace, error = yield self.structure.get_namespace_by_name(project, namespace_name)
        if error:
            raise Return((None, error))
        if not namespace:
            raise Return((None, self.NAMESPACE_NOT_FOUND))
        namespace_name = namespace["name"]

        namespace = allowed_namespaces.get(namespace_name, None)
        if not namespace:
            raise Return((None, "namespace not found in allowed namespaces"))

        data = params.get("data", None)

        message = {
            "project_id": project["_id"],
            "namespace": namespace["name"],
            "uid": uuid.uuid4().hex,
            "timestamp": int(time.time()),
            "client": client,
            "channel": params.get("channel"),
            "data": data,
        }

        for callback in self.pre_publish_callbacks:
            try:
                message = yield callback(message)
            except Exception as err:
                logger.exception(err)
            else:
                if message is None:
                    raise Return((None, None))

        raise Return((message, None))
예제 #12
0
    def authorize(self, auth_address, project, channel):
        """
        Send POST request to web application to ask it if current client
        has a permission to subscribe on channel.
        """
        project_id = self.project_id

        http_client = AsyncHTTPClient()
        request = HTTPRequest(
            auth_address,
            method="POST",
            body=urlencode({
                'user': self.user,
                'channel': channel
            }),
            request_timeout=1
        )

        max_auth_attempts = project.get('max_auth_attempts')
        back_off_interval = project.get('back_off_interval')
        back_off_max_timeout = project.get('back_off_max_timeout')

        attempts = 0

        while attempts < max_auth_attempts:

            # get current timeout for project
            current_attempts = self.application.back_off.setdefault(project_id, 0)

            factor = random.randint(0, 2**current_attempts-1)
            timeout = factor*back_off_interval

            if timeout > back_off_max_timeout:
                timeout = back_off_max_timeout

            # wait before next authorization request attempt
            yield sleep(float(timeout)/1000)

            try:
                response = yield http_client.fetch(request)
            except HTTPError as err:
                if err.code == 403:
                    # access denied for this client
                    raise Return((False, None))
                else:
                    # let it fail and try again after some timeout
                    logger.info("{0} status code when fetching auth address {1}".format(
                        err.code, auth_address
                    ))
            except Exception as err:
                logger.error("error fetching auth address {0}".format(auth_address))
                logger.exception(err)
                raise Return((False, None))
            else:
                # reset back-off attempts
                self.application.back_off[project_id] = 0

                if response.code == 200:
                    # auth successful
                    self.update_channel_user_info(response.body, channel)
                    raise Return((True, None))

                else:
                    # access denied for this client
                    raise Return((False, None))
            attempts += 1
            self.application.back_off[project_id] += 1

        raise Return((False, None))