Esempio n. 1
0
def create_application_handlers(sockjs_settings):

    handlers = [
        tornado.web.url(r'/api/([^/]+)/?$', ApiHandler, name="api"),
        tornado.web.url(r'/info/$', InfoHandler, name="info"),
        tornado.web.url(r'/action/$', ActionHandler, name="action"),
        tornado.web.url(r'/auth/$', AuthHandler, name="auth"),
        (r'/socket', AdminWebSocketHandler),
    ]

    if options.web:
        logger.info("serving web application from {0}".format(os.path.abspath(options.web)))
        handlers.append(
            (
                r'/(.*)',
                tornado.web.StaticFileHandler,
                {"path": options.web, "default_filename": "index.html"}
            )
        )

    # create SockJS route for client connections
    client_sock_router = SockJSRouter(
        SockjsConnection, '/connection', user_settings=sockjs_settings
    )
    handlers = client_sock_router.urls + handlers

    return handlers
Esempio n. 2
0
    def init_structure(self):
        """
        Initialize structure manager using settings provided
        in configuration file.
        """
        custom_settings = self.settings["config"]
        structure_settings = custom_settings.get("structure", {})

        # detect and apply database storage module
        storage_backend = structure_settings.get("storage", "centrifuge.structure.sqlite.Storage")
        storage_backend_class = utils.namedAny(storage_backend)
        logger.info("Storage module: {0}".format(storage_backend))

        self.structure = Structure(self)
        storage = storage_backend_class(self.structure, structure_settings.get("settings", {}))
        self.structure.set_storage(storage)

        def run_periodic_structure_update():
            # update structure periodically from database. This is necessary to be sure
            # that application has actual and correct structure information. Structure
            # updates also triggered in real-time by message passing through control channel,
            # but in rare cases those update messages can be lost because of some kind of
            # network errors
            logger.info("Structure storage connected")
            self.structure.update()
            periodic_structure_update = tornado.ioloop.PeriodicCallback(
                self.structure.update, structure_settings.get("update_interval", 30) * 1000
            )
            periodic_structure_update.start()

        tornado.ioloop.IOLoop.instance().add_callback(partial(storage.connect, run_periodic_structure_update))
Esempio n. 3
0
def create_application_handlers(sockjs_settings):

    handlers = [
        tornado.web.url(r'/api/([^/]+)/?$', ApiHandler, name="api"),
        tornado.web.url(r'/info/$', InfoHandler, name="info"),
        tornado.web.url(r'/action/$', ActionHandler, name="action"),
        tornado.web.url(r'/auth/$', AuthHandler, name="auth"),
        (r'/socket', AdminWebSocketHandler),
    ]

    if options.web:
        logger.info("serving web application from {0}".format(
            os.path.abspath(options.web)))
        handlers.append((r'/(.*)', tornado.web.StaticFileHandler, {
            "path": options.web,
            "default_filename": "index.html"
        }))

    # create SockJS route for client connections
    client_sock_router = SockJSRouter(SockjsConnection,
                                      '/connection',
                                      user_settings=sockjs_settings)
    handlers = client_sock_router.urls + handlers

    return handlers
Esempio n. 4
0
def init_storage(structure, settings, ready_callback):
    conn = sqlite3.connect(settings.get('path', 'centrifuge.db'))
    # noinspection PyPropertyAccess
    conn.row_factory = dict_factory
    cursor = conn.cursor()

    project = 'CREATE TABLE IF NOT EXISTS projects (id INTEGER PRIMARY KEY AUTOINCREMENT, ' \
              '_id varchar(24) UNIQUE, name varchar(100) NOT NULL UNIQUE, display_name ' \
              'varchar(100) NOT NULL, auth_address varchar(255), ' \
              'max_auth_attempts integer, back_off_interval integer, ' \
              'back_off_max_timeout integer, secret_key varchar(32), ' \
              'default_namespace varchar(32))'

    namespace = 'CREATE TABLE IF NOT EXISTS namespaces (id INTEGER PRIMARY KEY AUTOINCREMENT, ' \
                '_id varchar(24) UNIQUE, project_id varchar(24), ' \
                'name varchar(100) NOT NULL, ' \
                'publish bool, is_watching bool, presence bool, history bool, ' \
                'history_size integer, is_private bool, auth_address varchar(255), join_leave bool, ' \
                'UNIQUE (project_id, name) ON CONFLICT ABORT)'

    cursor.execute(project, ())
    conn.commit()
    cursor.execute(namespace, ())
    conn.commit()

    structure.set_db(cursor)
    ready_callback()
    logger.info("Database ready")
Esempio n. 5
0
 def check_connection(self):
     conn_statuses = [self.subscriber.is_connected(), self.publisher.is_connected(), self.worker.is_connected()]
     connection_dropped = not all(conn_statuses)
     if connection_dropped or self._need_reconnect:
         logger.info("reconnecting to Redis")
         self._need_reconnect = False
         self.connect()
Esempio n. 6
0
def init_storage(structure, settings, ready_callback):
    conn = sqlite3.connect(settings.get('path', 'centrifuge.db'))
    # noinspection PyPropertyAccess
    conn.row_factory = dict_factory
    cursor = conn.cursor()

    project = 'CREATE TABLE IF NOT EXISTS projects (id INTEGER PRIMARY KEY AUTOINCREMENT, ' \
              '_id varchar(24) UNIQUE, name varchar(100) NOT NULL UNIQUE, display_name ' \
              'varchar(100) NOT NULL, auth_address varchar(255), ' \
              'max_auth_attempts integer, back_off_interval integer, ' \
              'back_off_max_timeout integer, secret_key varchar(32), ' \
              'default_namespace varchar(32))'

    namespace = 'CREATE TABLE IF NOT EXISTS namespaces (id INTEGER PRIMARY KEY AUTOINCREMENT, ' \
                '_id varchar(24) UNIQUE, project_id varchar(24), ' \
                'name varchar(100) NOT NULL, ' \
                'publish bool, is_watching bool, presence bool, history bool, ' \
                'history_size integer, is_private bool, auth_address varchar(255), join_leave bool, ' \
                'UNIQUE (project_id, name) ON CONFLICT ABORT)'

    cursor.execute(project, ())
    conn.commit()
    cursor.execute(namespace, ())
    conn.commit()

    structure.set_db(cursor)
    ready_callback()
    logger.info("Database ready")
Esempio n. 7
0
 def check_connection(self):
     connection_dropped = not self.subscriber.is_connected(
     ) or not self.publisher.is_connected()
     if connection_dropped or self._need_reconnect:
         logger.info('reconnecting to Redis')
         self._need_reconnect = False
         self.connect()
Esempio n. 8
0
    def init_structure(self):
        """
        Initialize structure manager using settings provided
        in configuration file.
        """
        custom_settings = self.settings['config']
        structure_settings = custom_settings.get('structure', {})

        # detect and apply database storage module
        storage_module = structure_settings.get(
            'storage', 'centrifuge.structure.sqlite'
        )
        storage = utils.import_module(storage_module)

        structure = Structure(self)
        structure.set_storage(storage)
        self.structure = structure

        def run_periodic_structure_update():
            structure.update()
            periodic_structure_update = tornado.ioloop.PeriodicCallback(
                structure.update, structure_settings.get('update_interval', 30)*1000
            )
            periodic_structure_update.start()

        tornado.ioloop.IOLoop.instance().add_callback(
            partial(
                storage.init_storage,
                structure,
                structure_settings.get('settings', {}),
                run_periodic_structure_update
            )
        )

        logger.info("Storage module: {0}".format(storage_module))
Esempio n. 9
0
 def initialize(self):
     self.connect()
     logger.info("Redis engine at {0}:{1} (db {2})".format(self.host, self.port, self.db))
     if self.options.redis_api:
         logger.info(
             "Redis API endpoint enabled via RPUSH to {0} key".format(self.api_key)
         )
Esempio n. 10
0
    def init_structure(self):
        """
        Initialize structure manager using settings provided
        in configuration file.
        """
        custom_settings = self.settings['config']
        structure_settings = custom_settings.get('structure', {})

        # detect and apply database storage module
        storage_module = structure_settings.get(
            'storage', 'centrifuge.structure.sqlite'
        )
        storage = utils.import_module(storage_module)

        structure = Structure(self)
        structure.set_storage(storage)
        self.structure = structure

        def run_periodic_structure_update():
            structure.update()
            periodic_structure_update = tornado.ioloop.PeriodicCallback(
                structure.update, structure_settings.get('update_interval', 30)*1000
            )
            periodic_structure_update.start()

        tornado.ioloop.IOLoop.instance().add_callback(
            partial(
                storage.init_storage,
                structure,
                structure_settings.get('settings', {}),
                run_periodic_structure_update
            )
        )

        logger.info("Storage module: {0}".format(storage_module))
Esempio n. 11
0
def main():
    ioloop_instance = tornado.ioloop.IOLoop.instance()
    create_centrifuge_application()
    try:
        ioloop_instance.start()
    except KeyboardInterrupt:
        logger.info('interrupted')
Esempio n. 12
0
def main():
    ioloop_instance = tornado.ioloop.IOLoop.instance()
    create_centrifuge_application()
    try:
        ioloop_instance.start()
    except KeyboardInterrupt:
        logger.info('interrupted')
Esempio n. 13
0
 def initialize(self):
     options = self.application.settings['options']
     self.host = options.redis_host
     self.port = options.redis_port
     self.db = options.redis_db
     self.connection_check = PeriodicCallback(self.check_connection, 1000)
     self.connect()
     logger.info("Redis PUB/SUB at {0}:{1} (db {2})".format(self.host, self.port, self.db))
Esempio n. 14
0
 def initialize(self):
     options = self.application.settings['options']
     self.host = options.redis_host
     self.port = options.redis_port
     self.db = options.redis_db
     self.connection_check = PeriodicCallback(self.check_connection, 1000)
     self.connect()
     logger.info("Redis PUB/SUB at {0}:{1} (db {2})".format(
         self.host, self.port, self.db))
Esempio n. 15
0
 def initialize(self):
     settings = self.config.get('settings', {})
     self.host = settings.get("host", "localhost")
     self.port = settings.get("port", 6379)
     self.db = settings.get("db", 0)
     self.client = toredis.Client(io_loop=self.io_loop)
     self.client.state = self
     self.connection_check = PeriodicCallback(self.check_connection, 1000)
     self.connect()
     logger.info("Redis State initialized")
Esempio n. 16
0
def ensure_indexes(db, drop=False):
    if drop:
        logger.info('dropping indexes...')
        db.project.drop_indexes()
        db.namespace.drop_indexes()

    db.project.ensure_index([('name', 1)], unique=True)
    db.namespace.ensure_index([('name', 1), ('project', 1)], unique=True)

    logger.info('Database ready')
Esempio n. 17
0
 def initialize(self):
     settings = self.config.get('settings', {})
     self.host = settings.get("host", "localhost")
     self.port = settings.get("port", 6379)
     self.db = settings.get("db", 0)
     self.client = toredis.Client(io_loop=self.io_loop)
     self.client.state = self
     self.connection_check = PeriodicCallback(self.check_connection, 1000)
     self.connect()
     logger.info("Redis State initialized")
Esempio n. 18
0
def ensure_indexes(db, drop=False):
    if drop:
        logger.info('dropping indexes...')
        db.project.drop_indexes()
        db.namespace.drop_indexes()

    db.project.ensure_index([('name', 1)], unique=True)
    db.namespace.ensure_index([('name', 1), ('project', 1)], unique=True)

    logger.info('Database ready')
Esempio n. 19
0
 def check_connection(self):
     conn_statuses = [
         self.subscriber.is_connected(),
         self.publisher.is_connected(),
         self.worker.is_connected()
     ]
     connection_dropped = not all(conn_statuses)
     if connection_dropped or self._need_reconnect:
         logger.info('reconnecting to Redis')
         self._need_reconnect = False
         self.connect()
Esempio n. 20
0
def main():

    try:
        custom_settings = json.load(open(options.config, 'r'))
    except IOError:
        logger.warning("Application started without configuration file.\n"
                       "This is normal only during development")
        custom_settings = {}

    ioloop_instance = tornado.ioloop.IOLoop.instance()

    settings = dict(
        cookie_secret=custom_settings.get("cookie_secret", "bad secret"),
        login_url="/auth",
        template_path=os.path.join(os.path.dirname(__file__),
                                   os.path.join("web/frontend", "templates")),
        static_path=os.path.join(os.path.dirname(__file__),
                                 os.path.join("web/frontend", "static")),
        xsrf_cookies=True,
        autoescape="xhtml_escape",
        debug=options.debug,
        options=options,
        config=custom_settings)

    handlers = create_application_handlers()

    try:
        app = Application(handlers=handlers, **settings)
        server = tornado.httpserver.HTTPServer(app)
        server.listen(options.port)
    except Exception as e:
        return stop_running(str(e))

    # create references to application from SockJS handlers
    AdminSocketHandler.application = app
    Client.application = app

    app.initialize()

    # summarize run configuration writing it into logger
    logger.info("Tornado port: {0}".format(options.port))

    # finally, let's go
    try:
        ioloop_instance.start()
    except KeyboardInterrupt:
        logger.info('interrupted')
    finally:
        # clean
        if hasattr(app, 'pub_stream'):
            app.pub_stream.close()
        if hasattr(app, 'sub_stream'):
            app.sub_stream.stop_on_recv()
            app.sub_stream.close()
Esempio n. 21
0
 def run_periodic_structure_update():
     # update structure periodically from database. This is necessary to be sure
     # that application has actual and correct structure information. Structure
     # updates also triggered in real-time by message passing through control channel,
     # but in rare cases those update messages can be lost because of some kind of
     # network errors
     logger.info("Structure storage connected")
     self.structure.update()
     periodic_structure_update = tornado.ioloop.PeriodicCallback(
         self.structure.update, structure_settings.get("update_interval", 30) * 1000
     )
     periodic_structure_update.start()
Esempio n. 22
0
    def check_connection(self):
        conn_statuses = [
            self.subscriber.is_connected(),
            self.publisher.is_connected(),
            self.worker.is_connected()
        ]
        if self.options.redis_api:
            conn_statuses.append(self.listener.is_connected())

        connection_dropped = not all(conn_statuses)
        if connection_dropped or self._need_reconnect:
            logger.info('reconnecting to Redis')
            self._need_reconnect = False
            self.connect()
Esempio n. 23
0
    def message_received(self, message):
        """
        Called when message from client received.
        """
        multi_response = MultiResponse()
        try:
            data = json_decode(message)
        except ValueError:
            logger.error('malformed JSON data')
            yield self.close_sock()
            raise Return((True, None))

        if isinstance(data, dict):
            # single object request
            response, err = yield self.process_obj(data)
            multi_response.add(response)
            if err:
                # error occurred, connection must be closed
                logger.error(err)
                yield self.sock.send(multi_response.as_message())
                yield self.close_sock()
                raise Return((True, None))

        elif isinstance(data, list):
            # multiple object request
            if len(data) > self.application.CLIENT_API_MESSAGE_LIMIT:
                logger.info("client API message limit exceeded")
                yield self.close_sock()
                raise Return((True, None))

            for obj in data:
                response, err = yield self.process_obj(obj)
                multi_response.add(response)
                if err:
                    # close connection in case of any error
                    logger.error(err)
                    yield self.sock.send(multi_response.as_message())
                    yield self.send_disconnect_message()
                    yield self.close_sock()
                    raise Return((True, None))

        else:
            logger.error('data not list and not dictionary')
            yield self.close_sock()
            raise Return((True, None))

        yield self.send(multi_response.as_message())

        raise Return((True, None))
Esempio n. 24
0
    def message_received(self, message):
        """
        Called when message from client received.
        """
        multi_response = MultiResponse()
        try:
            data = json_decode(message)
        except ValueError:
            logger.error('malformed JSON data')
            yield self.close_sock()
            raise Return((True, None))

        if isinstance(data, dict):
            # single object request
            response, err = yield self.process_obj(data)
            multi_response.add(response)
            if err:
                # error occurred, connection must be closed
                logger.error(err)
                yield self.sock.send(multi_response.as_message())
                yield self.close_sock()
                raise Return((True, None))

        elif isinstance(data, list):
            # multiple object request
            if len(data) > self.application.CLIENT_API_MESSAGE_LIMIT:
                logger.info("client API message limit exceeded")
                yield self.close_sock()
                raise Return((True, None))

            for obj in data:
                response, err = yield self.process_obj(obj)
                multi_response.add(response)
                if err:
                    # close connection in case of any error
                    logger.error(err)
                    yield self.sock.send(multi_response.as_message())
                    yield self.send_disconnect_message()
                    yield self.close_sock()
                    raise Return((True, None))

        else:
            logger.error('data not list and not dictionary')
            yield self.close_sock()
            raise Return((True, None))

        yield self.send(multi_response.as_message())

        raise Return((True, None))
Esempio n. 25
0
 def init_state(self):
     """
     Initialize state manager (for presence/history data).
     """
     config = self.settings['config']
     state_config = config.get("state", {})
     if not state_config:
         # use base fake state
         logger.info("No State configured")
         self.state = State(self, fake=True)
     else:
         state_storage = state_config.get('storage', 'centrifuge.state.base.State')
         state_storage_class = utils.namedAny(state_storage)
         self.state = state_storage_class(self)
         tornado.ioloop.IOLoop.instance().add_callback(self.state.initialize)
Esempio n. 26
0
 def init_state(self):
     """
     Initialize state manager (for presence/history data).
     """
     config = self.settings['config']
     state_config = config.get("state", {})
     if not state_config:
         # use base fake state
         logger.info("No State configured")
         self.state = State(self, fake=True)
     else:
         state_storage = state_config.get('storage', 'centrifuge.state.base.State')
         state_storage_class = utils.namedAny(state_storage)
         self.state = state_storage_class(self)
         tornado.ioloop.IOLoop.instance().add_callback(self.state.initialize)
Esempio n. 27
0
    def flush_metrics(self):

        if not self.collector:
            return

        for key, value in six.iteritems(self.get_node_gauges()):
            self.collector.gauge(key, value)

        metrics = self.collector.get()

        if self.log_metrics:
            logger.info(metrics)

        if self.graphite_metrics:
            self.exporter.export(metrics)
Esempio n. 28
0
    def flush_metrics(self):

        if not self.collector:
            return

        for key, value in six.iteritems(self.get_node_gauges()):
            self.collector.gauge(key, value)

        metrics = self.collector.get()

        if self.log_metrics:
            logger.info(metrics)

        if self.graphite_metrics:
            self.exporter.export(metrics)
Esempio n. 29
0
 def run_periodic_structure_update():
     # update structure periodically from database. This is necessary to be sure
     # that application has actual and correct structure information. Structure
     # updates also triggered in real-time by message passing through control channel,
     # but in rare cases those update messages can be lost because of some kind of
     # network errors
     logger.info("Structure initialized")
     self.structure.update()
     structure_update_interval = custom_settings.get(
         'structure_update_interval', 60)
     logger.info(
         "Periodic structure update interval: {0} seconds".format(
             structure_update_interval))
     periodic_structure_update = tornado.ioloop.PeriodicCallback(
         self.structure.update, structure_update_interval * 1000)
     periodic_structure_update.start()
Esempio n. 30
0
 def __init__(self, sock, info):
     self.sock = sock
     self.info = info
     self.uid = uuid.uuid4().hex
     self.is_authenticated = False
     self.user = None
     self.timestamp = None
     self.channel_info = {}
     self.default_info = {}
     self.project_id = None
     self.channels = None
     self.presence_ping_task = None
     self.expire_timeout = None
     logger.info("client created via {0} (uid: {1}, ip: {2})".format(
         self.sock.session.transport_name, self.uid, getattr(self.info, 'ip', '-')
     ))
Esempio n. 31
0
 def __init__(self, sock, info):
     self.sock = sock
     self.info = info
     self.uid = uuid.uuid4().hex
     self.is_authenticated = False
     self.user = None
     self.timestamp = None
     self.channel_info = {}
     self.default_info = {}
     self.project_name = None
     self.channels = None
     self.presence_ping_task = None
     self.expire_timeout = None
     logger.info("client created via {0} (uid: {1}, ip: {2})".format(
         self.sock.session.transport_name, self.uid, getattr(self.info, 'ip', '-')
     ))
Esempio n. 32
0
 def run_periodic_structure_update():
     # update structure periodically from database. This is necessary to be sure
     # that application has actual and correct structure information. Structure
     # updates also triggered in real-time by message passing through control channel,
     # but in rare cases those update messages can be lost because of some kind of
     # network errors
     logger.info("Structure initialized")
     self.structure.update()
     structure_update_interval = config.get('structure_update_interval', 60)
     logger.info(
         "Periodic structure update interval: {0} seconds".format(
             structure_update_interval
         )
     )
     periodic_structure_update = tornado.ioloop.PeriodicCallback(
         self.structure.update, structure_update_interval*1000
     )
     periodic_structure_update.start()
Esempio n. 33
0
def on_connection_ready(structure, ready_callback):

    db = structure.db

    project = 'CREATE TABLE IF NOT EXISTS projects (id SERIAL, _id varchar(24) UNIQUE, ' \
              'name varchar(100) NOT NULL UNIQUE, display_name ' \
              'varchar(100) NOT NULL, auth_address varchar(255), ' \
              'max_auth_attempts integer, back_off_interval integer, ' \
              'back_off_max_timeout integer, secret_key varchar(32), ' \
              'default_namespace varchar(32))'

    namespace = 'CREATE TABLE IF NOT EXISTS namespaces (id SERIAL, ' \
                '_id varchar(24) UNIQUE, project_id varchar(24), ' \
                'name varchar(100) NOT NULL, publish bool, ' \
                'is_watching bool, presence bool, history bool, history_size integer, ' \
                'is_private bool, auth_address varchar(255), join_leave bool, ' \
                'constraint namespaces_unique unique(project_id, name))'

    yield momoko.Op(db.execute, project, ())
    yield momoko.Op(db.execute, namespace, ())
    ready_callback()
    logger.info("Database ready")
Esempio n. 34
0
def on_connection_ready(structure, ready_callback):

    db = structure.db

    project = 'CREATE TABLE IF NOT EXISTS projects (id SERIAL, _id varchar(24) UNIQUE, ' \
              'name varchar(100) NOT NULL UNIQUE, display_name ' \
              'varchar(100) NOT NULL, auth_address varchar(255), ' \
              'max_auth_attempts integer, back_off_interval integer, ' \
              'back_off_max_timeout integer, secret_key varchar(32), ' \
              'default_namespace varchar(32))'

    namespace = 'CREATE TABLE IF NOT EXISTS namespaces (id SERIAL, ' \
                '_id varchar(24) UNIQUE, project_id varchar(24), ' \
                'name varchar(100) NOT NULL, publish bool, ' \
                'is_watching bool, presence bool, history bool, history_size integer, ' \
                'is_private bool, auth_address varchar(255), join_leave bool, ' \
                'constraint namespaces_unique unique(project_id, name))'

    yield momoko.Op(db.execute, project, ())
    yield momoko.Op(db.execute, namespace, ())
    ready_callback()
    logger.info("Database ready")
Esempio n. 35
0
 def unsubscribe(self):
     if not hasattr(self, 'uid'):
         return
     self.application.remove_admin_connection(self.uid)
     logger.info('admin disconnected')
Esempio n. 36
0
 def subscribe(self):
     self.uid = uuid.uuid4().hex
     self.application.add_admin_connection(self.uid, self)
     logger.info('admin connected')
Esempio n. 37
0
 def initialize(self):
     logger.info("Base PUB/SUB")
Esempio n. 38
0
    def initialize(self):

        self.zmq_context = zmq.Context()
        options = self.application.settings['options']

        self.zmq_pub_sub_proxy = options.zmq_pub_sub_proxy

        # create PUB socket to publish instance events into it
        publish_socket = self.zmq_context.socket(zmq.PUB)

        # do not try to send messages after closing
        publish_socket.setsockopt(zmq.LINGER, 0)

        if self.zmq_pub_sub_proxy:
            # application started with XPUB/XSUB proxy
            self.zmq_xsub = options.zmq_xsub
            publish_socket.connect(self.zmq_xsub)
        else:

            # application started without XPUB/XSUB proxy
            if options.zmq_pub_port_shift:
                # calculate zmq pub port number
                zmq_pub_port = options.port - options.zmq_pub_port_shift
            else:
                zmq_pub_port = options.zmq_pub_port

            self.zmq_pub_port = zmq_pub_port

            publish_socket.bind(
                "tcp://%s:%s" %
                (options.zmq_pub_listen, str(self.zmq_pub_port)))

        # wrap pub socket into ZeroMQ stream
        self.pub_stream = ZMQStream(publish_socket)

        # create SUB socket listening to all events from all app instances
        subscribe_socket = self.zmq_context.socket(zmq.SUB)

        if self.zmq_pub_sub_proxy:
            # application started with XPUB/XSUB proxy
            self.zmq_xpub = options.zmq_xpub
            subscribe_socket.connect(self.zmq_xpub)
        else:
            # application started without XPUB/XSUB proxy
            self.zmq_sub_address = options.zmq_sub_address
            for address in self.zmq_sub_address:
                subscribe_socket.connect(address)

        subscribe_socket.setsockopt_string(zmq.SUBSCRIBE,
                                           six.u(CONTROL_CHANNEL))

        subscribe_socket.setsockopt_string(zmq.SUBSCRIBE, six.u(ADMIN_CHANNEL))

        def listen_socket():
            # wrap sub socket into ZeroMQ stream and set its on_recv callback
            self.sub_stream = ZMQStream(subscribe_socket)
            self.sub_stream.on_recv(self.dispatch_published_message)

        tornado.ioloop.IOLoop.instance().add_callback(listen_socket)

        if self.zmq_pub_sub_proxy:
            logger.info("ZeroMQ XPUB: {0}, XSUB: {1}".format(
                self.zmq_xpub, self.zmq_xsub))
        else:
            logger.info("ZeroMQ PUB - {0}; subscribed to {1}".format(
                self.zmq_pub_port, self.zmq_sub_address))
Esempio n. 39
0
 def initialize(self):
     self.connect()
     logger.info("Redis engine at {0}:{1} (db {2})".format(
         self.host, self.port, self.db))
Esempio n. 40
0
def create_centrifuge_application():

    try:
        custom_settings = json.load(open(options.config, 'r'))
    except IOError:
        logger.warning("No configuration file found. "
                       "In production make sure security settings provided")
        custom_settings = {}

    # override security related options using environment variable
    # value if exists
    for option_name in ["password", "cookie_secret", "api_secret"]:
        environment_var_name = "CENTRIFUGE_{0}".format(option_name.upper())
        environment_value = os.environ.get(environment_var_name)
        if environment_value:
            logger.debug(
                "using {0} environment variable for {1} option value".format(
                    environment_var_name, option_name))
            custom_settings[option_name] = environment_value

    if os.environ.get("CENTRIFUGE_INSECURE") == "1":
        custom_settings["insecure"] = True

    settings = dict(
        cookie_secret=custom_settings.get("cookie_secret", "bad secret"),
        login_url="/auth",
        template_path=os.path.join(os.path.dirname(__file__),
                                   os.path.join("web/frontend", "templates")),
        static_path=os.path.join(os.path.dirname(__file__),
                                 os.path.join("web/frontend", "static")),
        xsrf_cookies=True,
        autoescape="xhtml_escape",
        debug=options.debug,
        options=options,
        config=custom_settings)

    sockjs_settings = custom_settings.get("sockjs_settings", {})
    if not sockjs_settings or not sockjs_settings.get("sockjs_url"):
        # SockJS CDN will be retired
        # see https://github.com/sockjs/sockjs-client/issues/198
        # if no explicit SockJS url provided in configuration file
        # then we use jsdelivr CDN instead of default cdn.sockjs.org
        # this can be fixed directly in SockJS-Tornado soon
        sockjs_settings[
            "sockjs_url"] = "https://cdn.jsdelivr.net/sockjs/0.3/sockjs.min.js"

    handlers = create_application_handlers(sockjs_settings)

    # custom settings to configure the tornado HTTPServer
    tornado_settings = custom_settings.get("tornado_settings", {})
    logger.debug("tornado_settings: %s", tornado_settings)
    if 'io_loop' in tornado_settings:
        stop_running(
            "The io_loop in tornado_settings is not supported for now.")

    try:
        app = Application(handlers=handlers, **settings)
        server = tornado.httpserver.HTTPServer(app, **tornado_settings)
        server.listen(options.port, address=options.address)
    except Exception as e:
        return stop_running(str(e))

    logger.info("Engine class: {0}".format(engine_class_path))
    app.engine = engine_class(app)

    logger.info("Storage class: {0}".format(storage_class_path))
    app.storage = storage_class(options)

    # create reference to application from SockJS handlers
    AdminSocketHandler.application = app

    # create reference to application from Client
    Client.application = app

    app.initialize()

    logger.info("Tornado port: {0}, address: {1}".format(
        options.port, options.address))
    return app
Esempio n. 41
0
 def close(self):
     yield self.clean()
     logger.info('client destroyed (uid: %s)' % self.uid)
     raise Return((True, None))
Esempio n. 42
0
 def initialize(self):
     self.history_expire_task.start()
     logger.info("Memory engine initialized")
Esempio n. 43
0
 def initialize(self):
     self.history_expire_task.start()
     logger.info("Memory engine initialized")
Esempio n. 44
0
 def on_close(self):
     self.unsubscribe()
     logger.info("admin disconnected")
Esempio n. 45
0
 def open(self):
     logger.info('admin connected')
Esempio n. 46
0
 def initialize(self):
     logger.info("Base State initialized")
Esempio n. 47
0
 def initialize(self):
     logger.info("Base PUB/SUB")
Esempio n. 48
0
 def check_connection(self):
     if not self.client.is_connected():
         logger.info('reconnecting to Redis')
         self.connect()
Esempio n. 49
0
 def unsubscribe(self):
     if not hasattr(self, 'uid'):
         return
     self.application.remove_admin_connection(self.uid)
     logger.info('admin disconnected')
Esempio n. 50
0
 def check_connection(self):
     if not self.client.is_connected():
         logger.info('reconnecting to Redis')
         self.connect()
Esempio n. 51
0
 def subscribe(self):
     self.uid = uuid.uuid4().hex
     self.application.add_admin_connection(self.uid, self)
     logger.info('admin connected')
Esempio n. 52
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))
Esempio n. 53
0
def create_centrifuge_application():

    try:
        custom_settings = json.load(open(options.config, 'r'))
    except IOError:
        return stop_running("No configuration file found.")

    # override security related options using environment variable
    # value if exists
    for option_name in ["password", "cookie_secret", "api_secret"]:
        environment_var_name = "CENTRIFUGE_{0}".format(option_name.upper())
        environment_value = os.environ.get(environment_var_name)
        if environment_value:
            logger.debug("using {0} environment variable for {1} option value".format(
                environment_var_name, option_name
            ))
            custom_settings[option_name] = environment_value

    if os.environ.get("CENTRIFUGE_INSECURE") == "1":
        custom_settings["insecure"] = True

    settings = dict(
        cookie_secret=custom_settings.get("cookie_secret", "bad secret"),
        template_path=os.path.join(
            os.path.dirname(__file__),
            os.path.join("web/frontend", "templates")
        ),
        static_path=os.path.join(
            os.path.dirname(__file__),
            os.path.join("web/frontend", "static")
        ),
        xsrf_cookies=False,
        autoescape="xhtml_escape",
        debug=options.debug,
        options=options,
        config=custom_settings
    )

    sockjs_settings = custom_settings.get("sockjs_settings", {})
    if not sockjs_settings or not sockjs_settings.get("sockjs_url"):
        # SockJS CDN will be retired
        # see https://github.com/sockjs/sockjs-client/issues/198
        # if no explicit SockJS url provided in configuration file
        # then we use jsdelivr CDN instead of default cdn.sockjs.org
        # this can be fixed directly in SockJS-Tornado soon
        sockjs_settings["sockjs_url"] = "https://cdn.jsdelivr.net/sockjs/1.0/sockjs.min.js"

    handlers = create_application_handlers(sockjs_settings)

    # custom settings to configure the tornado HTTPServer
    tornado_settings = custom_settings.get("tornado_settings", {})
    logger.debug("tornado_settings: %s", tornado_settings)
    if 'io_loop' in tornado_settings:
        stop_running(
            "The io_loop in tornado_settings is not supported for now."
            )

    try:
        app = Application(handlers=handlers, **settings)
        server = tornado.httpserver.HTTPServer(app, **tornado_settings)
        server.listen(options.port, address=options.address)
    except Exception as e:
        return stop_running(str(e))

    logger.info("Engine class: {0}".format(engine_class_path))
    app.engine = engine_class(app)

    # create reference to application from Client
    Client.application = app

    app.initialize()

    logger.info("Tornado port: {0}, address: {1}".format(options.port, options.address))
    return app
Esempio n. 54
0
def main():

    try:
        custom_settings = json.load(open(options.config, 'r'))
    except IOError:
        logger.warning(
            "Application started without configuration file.\n"
            "This is normal only during development"
        )
        custom_settings = {}

    ioloop_instance = tornado.ioloop.IOLoop.instance()

    settings = dict(
        cookie_secret=custom_settings.get("cookie_secret", "bad secret"),
        login_url="/auth",
        template_path=os.path.join(
            os.path.dirname(__file__),
            os.path.join("web/frontend", "templates")
        ),
        static_path=os.path.join(
            os.path.dirname(__file__),
            os.path.join("web/frontend", "static")
        ),
        xsrf_cookies=True,
        autoescape="xhtml_escape",
        debug=options.debug,
        options=options,
        config=custom_settings
    )

    handlers = create_application_handlers()

    try:
        app = Application(handlers=handlers, **settings)
        server = tornado.httpserver.HTTPServer(app)
        server.listen(options.port)
    except Exception as e:
        return stop_running(str(e))

    # create references to application from SockJS handlers
    AdminSocketHandler.application = app
    Client.application = app

    app.initialize()

    # summarize run configuration writing it into logger
    logger.info("Tornado port: {0}".format(options.port))

    # finally, let's go
    try:
        ioloop_instance.start()
    except KeyboardInterrupt:
        logger.info('interrupted')
    finally:
        # clean
        if hasattr(app, 'pub_stream'):
            app.pub_stream.close()
        if hasattr(app, 'sub_stream'):
            app.sub_stream.stop_on_recv()
            app.sub_stream.close()
Esempio n. 55
0
def main():

    try:
        custom_settings = json.load(open(options.config, 'r'))
    except IOError:
        logger.warning("Application started without configuration file.\n"
                       "This is normal only during development")
        custom_settings = {}

    ioloop_instance = tornado.ioloop.IOLoop.instance()

    settings = dict(
        cookie_secret=custom_settings.get("cookie_secret", "bad secret"),
        login_url="/auth",
        template_path=os.path.join(os.path.dirname(__file__),
                                   os.path.join("web/frontend", "templates")),
        static_path=os.path.join(os.path.dirname(__file__),
                                 os.path.join("web/frontend", "static")),
        xsrf_cookies=True,
        autoescape="xhtml_escape",
        debug=options.debug,
        options=options,
        config=custom_settings)

    sockjs_settings = custom_settings.get("sockjs_settings", {})

    handlers = create_application_handlers(sockjs_settings)

    try:
        app = Application(handlers=handlers, **settings)
        server = tornado.httpserver.HTTPServer(app)
        server.listen(options.port)
    except Exception as e:
        return stop_running(str(e))

    logger.info("Engine class: {0}".format(engine_class_path))
    app.engine = engine_class(app)

    logger.info("Storage class: {0}".format(storage_class_path))
    app.storage = storage_class(options)

    # create references to application from SockJS handlers
    AdminSocketHandler.application = app
    Client.application = app

    app.initialize()

    max_channel_length = custom_settings.get('max_channel_length')
    if max_channel_length:
        app.MAX_CHANNEL_LENGTH = max_channel_length

    admin_api_message_limit = custom_settings.get('admin_api_message_limit')
    if admin_api_message_limit:
        app.ADMIN_API_MESSAGE_LIMIT = admin_api_message_limit

    client_api_message_limit = custom_settings.get('client_api_message_limit')
    if client_api_message_limit:
        app.CLIENT_API_MESSAGE_LIMIT = client_api_message_limit

    owner_api_project_id = custom_settings.get('owner_api_project_id')
    if owner_api_project_id:
        app.OWNER_API_PROJECT_ID = owner_api_project_id

    owner_api_project_param = custom_settings.get('owner_api_project_param')
    if owner_api_project_param:
        app.OWNER_API_PROJECT_PARAM = owner_api_project_param

    connection_expire_check = custom_settings.get('connection_expire_check',
                                                  True)
    if connection_expire_check:
        app.CONNECTION_EXPIRE_CHECK = connection_expire_check

    connection_expire_collect_interval = custom_settings.get(
        'connection_expire_collect_interval')
    if connection_expire_collect_interval:
        app.CONNECTION_EXPIRE_COLLECT_INTERVAL = connection_expire_collect_interval

    connection_expire_check_interval = custom_settings.get(
        'connection_expire_check_interval')
    if connection_expire_check_interval:
        app.CONNECTION_EXPIRE_CHECK_INTERVAL = connection_expire_check_interval

    logger.info("Tornado port: {0}".format(options.port))

    # finally, let's go
    try:
        ioloop_instance.start()
    except KeyboardInterrupt:
        logger.info('interrupted')
    finally:
        # cleaning
        if hasattr(app.engine, 'clean'):
            app.engine.clean()