Exemple #1
0
 def setUp(self):
     super(StateTest, self).setUp()
     self.project_id = 'test'
     self.namespace = 'test'
     self.channel = 'test'
     self.uid_1 = 'test-1'
     self.uid_2 = 'test-2'
     self.user_id = 'test'
     self.user_id_extra = 'test_extra'
     self.user_info = 'test user info'
     self.message_1 = json.dumps('test message 1')
     self.message_2 = json.dumps('test message 2')
     self.message_3 = json.dumps('test message 3')
     self.state = State(io_loop=self.io_loop,
                        history_size=2,
                        presence_timeout=1)
     self.state.connect()
Exemple #2
0
 def setUp(self):
     super(StateTest, self).setUp()
     self.project_id = 'test'
     self.namespace = 'test'
     self.channel = 'test'
     self.uid_1 = 'test-1'
     self.uid_2 = 'test-2'
     self.user_id = 'test'
     self.user_id_extra = 'test_extra'
     self.user_info = 'test user info'
     self.message_1 = json.dumps('test message 1')
     self.message_2 = json.dumps('test message 2')
     self.message_3 = json.dumps('test message 3')
     self.state = State(io_loop=self.io_loop, history_size=2, presence_timeout=1)
     self.state.connect()
Exemple #3
0
def main():

    tornado.options.parse_command_line()

    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 and if you\n"
            "want to use MongoDB as data storage.\n"
        )
        custom_settings = {}

    database_settings = custom_settings.get('storage', {})

    # detect and apply database storage module
    storage_module = database_settings.get(
        'module', 'centrifuge.storage.mongodb'
    )
    storage = utils.import_module(storage_module)

    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=custom_settings
    )

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

    # create unique uid for this application
    app.uid = uuid.uuid4().hex

    state = State(app)

    centrifuge.handlers.state = state
    centrifuge.web.handlers.state = state
    centrifuge.rpc.state = state

    state.set_storage(storage)

    def run_periodic_state_update():
        state.update()
        periodic_state_update = tornado.ioloop.PeriodicCallback(
            state.update, custom_settings.get('state_update_interval', 30000)
        )
        periodic_state_update.start()

    ioloop_instance.add_callback(
        functools.partial(
            storage.init_db,
            state,
            database_settings.get('settings', {}),
            run_periodic_state_update
        )
    )

    app.zmq_pub_sub_proxy = options.zmq_pub_sub_proxy

    context = zmq.Context()

    # create PUB socket to publish instance events into it
    publish_socket = context.socket(zmq.PUB)
    # do not try to send messages after closing
    publish_socket.setsockopt(zmq.LINGER, 0)

    if app.zmq_pub_sub_proxy:
        # application started with XPUB/XSUB proxy
        app.zmq_xsub = options.zmq_xsub
        publish_socket.connect(app.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

        app.zmq_pub_port = zmq_pub_port

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

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

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

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

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

    def listen_control_channel():
        # wrap sub socket into ZeroMQ stream and set its on_recv callback
        app.sub_stream = ZMQStream(subscribe_socket)
        handle = functools.partial(handle_control_message, app)
        app.sub_stream.on_recv(handle)

    ioloop_instance.add_callback(listen_control_channel)

    app.event_callbacks = []
    callbacks = custom_settings.get('event_callbacks', [])

    for callback in callbacks:
        event_callback = utils.namedAny(callback)
        app.event_callbacks.append(event_callback)

    if not hasattr(app, 'admin_connections'):
        # initialize dict to keep admin connections
        app.admin_connections = {}

    if not hasattr(app, 'connections'):
        # initialize dict to keep client's connections
        app.connections = {}

    if not hasattr(app, 'back_off'):
        # initialize dict to keep back-off information for projects
        app.back_off = {}

    logger.info("Application started")
    logger.info("Tornado port: {0}".format(options.port))
    if app.zmq_pub_sub_proxy:
        logger.info(
            "ZeroMQ XPUB: {0}, XSUB: {1}".format(
                app.zmq_xpub, app.zmq_xsub,
            )
        )
    else:
        logger.info(
            "ZeroMQ PUB - {0}; subscribed to {1}".format(
                app.zmq_pub_port, app.zmq_sub_address
            )
        )
    logger.info("Storage module: {0}".format(storage_module))

    # 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.on_recv(None)
            app.sub_stream.close()
Exemple #4
0
class StateTest(AsyncTestCase):
    """ Test the client """
    def setUp(self):
        super(StateTest, self).setUp()
        self.project_id = 'test'
        self.namespace = 'test'
        self.channel = 'test'
        self.uid_1 = 'test-1'
        self.uid_2 = 'test-2'
        self.user_id = 'test'
        self.user_id_extra = 'test_extra'
        self.user_info = 'test user info'
        self.message_1 = json.dumps('test message 1')
        self.message_2 = json.dumps('test message 2')
        self.message_3 = json.dumps('test message 3')
        self.state = State(io_loop=self.io_loop,
                           history_size=2,
                           presence_timeout=1)
        self.state.connect()

    @gen_test
    def test_presence(self):
        result = yield Task(self.state.client.flushdb)
        self.assertEqual(result, "OK")

        result, error = yield self.state.get_presence(self.project_id,
                                                      self.namespace,
                                                      self.channel)
        self.assertEqual(result, {})

        result, error = yield self.state.add_presence(self.project_id,
                                                      self.namespace,
                                                      self.channel, self.uid_1,
                                                      self.user_info)
        self.assertEqual(result, True)

        result, error = yield self.state.get_presence(self.project_id,
                                                      self.namespace,
                                                      self.channel)
        self.assertTrue(self.uid_1 in result)

        result, error = yield self.state.add_presence(self.project_id,
                                                      self.namespace,
                                                      self.channel, self.uid_1,
                                                      self.user_info)
        self.assertEqual(result, True)

        result, error = yield self.state.get_presence(self.project_id,
                                                      self.namespace,
                                                      self.channel)
        self.assertTrue(self.uid_1 in result)
        self.assertEqual(len(result), 1)

        result, error = yield self.state.add_presence(self.project_id,
                                                      self.namespace,
                                                      self.channel, self.uid_2,
                                                      self.user_info)
        self.assertEqual(result, True)

        result, error = yield self.state.get_presence(self.project_id,
                                                      self.namespace,
                                                      self.channel)
        self.assertTrue(self.uid_1 in result)
        self.assertTrue(self.uid_2 in result)
        self.assertEqual(len(result), 2)

        result, error = yield self.state.remove_presence(
            self.project_id, self.namespace, self.channel, self.uid_2)
        self.assertEqual(result, True)

        result, error = yield self.state.get_presence(self.project_id,
                                                      self.namespace,
                                                      self.channel)
        self.assertTrue(self.uid_1 in result)
        self.assertTrue(self.uid_2 not in result)
        self.assertEqual(len(result), 1)

        time.sleep(2)
        result, error = yield self.state.get_presence(self.project_id,
                                                      self.namespace,
                                                      self.channel)
        self.assertEqual(result, {})

    @gen_test
    def test_history(self):
        result = yield Task(self.state.client.flushdb)
        self.assertEqual(result, "OK")

        result, error = yield self.state.add_history_message(
            self.project_id, self.namespace, self.channel, self.message_1)
        self.assertEqual(error, None)
        self.assertEqual(result, True)

        result, error = yield self.state.get_history(self.project_id,
                                                     self.namespace,
                                                     self.channel)
        self.assertEqual(error, None)
        self.assertEqual(len(result), 1)

        result, error = yield self.state.add_history_message(
            self.project_id, self.namespace, self.channel, self.message_2)
        self.assertEqual(error, None)
        self.assertEqual(result, True)

        result, error = yield self.state.get_history(self.project_id,
                                                     self.namespace,
                                                     self.channel)
        self.assertEqual(error, None)
        self.assertEqual(len(result), 2)

        result, error = yield self.state.add_history_message(
            self.project_id, self.namespace, self.channel, self.message_3)
        self.assertEqual(error, None)
        self.assertEqual(result, True)

        result, error = yield self.state.get_history(self.project_id,
                                                     self.namespace,
                                                     self.channel)
        self.assertEqual(error, None)
        self.assertEqual(len(result), 2)
Exemple #5
0
class StateTest(AsyncTestCase):
    """ Test the client """

    def setUp(self):
        super(StateTest, self).setUp()
        self.project_id = 'test'
        self.namespace = 'test'
        self.channel = 'test'
        self.uid_1 = 'test-1'
        self.uid_2 = 'test-2'
        self.user_id = 'test'
        self.user_id_extra = 'test_extra'
        self.user_info = 'test user info'
        self.message_1 = json.dumps('test message 1')
        self.message_2 = json.dumps('test message 2')
        self.message_3 = json.dumps('test message 3')
        self.state = State(io_loop=self.io_loop, history_size=2, presence_timeout=1)
        self.state.connect()

    @gen_test
    def test_presence(self):
        result = yield Task(self.state.client.flushdb)
        self.assertEqual(result, "OK")

        result, error = yield self.state.get_presence(
            self.project_id, self.namespace, self.channel
        )
        self.assertEqual(result, {})

        result, error = yield self.state.add_presence(
            self.project_id, self.namespace, self.channel,
            self.uid_1, self.user_info
        )
        self.assertEqual(result, True)

        result, error = yield self.state.get_presence(
            self.project_id, self.namespace, self.channel
        )
        self.assertTrue(self.uid_1 in result)

        result, error = yield self.state.add_presence(
            self.project_id, self.namespace, self.channel,
            self.uid_1, self.user_info
        )
        self.assertEqual(result, True)

        result, error = yield self.state.get_presence(
            self.project_id, self.namespace, self.channel
        )
        self.assertTrue(self.uid_1 in result)
        self.assertEqual(len(result), 1)

        result, error = yield self.state.add_presence(
            self.project_id, self.namespace, self.channel,
            self.uid_2, self.user_info
        )
        self.assertEqual(result, True)

        result, error = yield self.state.get_presence(
            self.project_id, self.namespace, self.channel
        )
        self.assertTrue(self.uid_1 in result)
        self.assertTrue(self.uid_2 in result)
        self.assertEqual(len(result), 2)

        result, error = yield self.state.remove_presence(
            self.project_id, self.namespace, self.channel, self.uid_2
        )
        self.assertEqual(result, True)

        result, error = yield self.state.get_presence(
            self.project_id, self.namespace, self.channel
        )
        self.assertTrue(self.uid_1 in result)
        self.assertTrue(self.uid_2 not in result)
        self.assertEqual(len(result), 1)

        time.sleep(2)
        result, error = yield self.state.get_presence(
            self.project_id, self.namespace, self.channel
        )
        self.assertEqual(result, {})

    @gen_test
    def test_history(self):
        result = yield Task(self.state.client.flushdb)
        self.assertEqual(result, "OK")

        result, error = yield self.state.add_history_message(
            self.project_id, self.namespace, self.channel, self.message_1
        )
        self.assertEqual(error, None)
        self.assertEqual(result, True)

        result, error = yield self.state.get_history(
            self.project_id, self.namespace, self.channel
        )
        self.assertEqual(error, None)
        self.assertEqual(len(result), 1)

        result, error = yield self.state.add_history_message(
            self.project_id, self.namespace, self.channel, self.message_2
        )
        self.assertEqual(error, None)
        self.assertEqual(result, True)

        result, error = yield self.state.get_history(
            self.project_id, self.namespace, self.channel
        )
        self.assertEqual(error, None)
        self.assertEqual(len(result), 2)

        result, error = yield self.state.add_history_message(
            self.project_id, self.namespace, self.channel, self.message_3
        )
        self.assertEqual(error, None)
        self.assertEqual(result, True)

        result, error = yield self.state.get_history(
            self.project_id, self.namespace, self.channel
        )
        self.assertEqual(error, None)
        self.assertEqual(len(result), 2)
Exemple #6
0
def main():

    tornado.options.parse_command_line()

    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 and if you\n"
            "want to use MongoDB as data storage.\n"
        )
        custom_settings = {}

    database_settings = custom_settings.get("storage", {})

    # detect and apply database storage module
    storage_module = database_settings.get("module", "centrifuge.storage.mongodb")
    storage = utils.import_module(storage_module)

    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=custom_settings,
    )

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

    # create unique uid for this application
    app.uid = uuid.uuid4().hex

    state = State(app)

    centrifuge.handlers.state = state
    centrifuge.web.handlers.state = state
    centrifuge.rpc.state = state

    state.set_storage(storage)

    def run_periodic_state_update():
        state.update()
        periodic_state_update = tornado.ioloop.PeriodicCallback(
            state.update, custom_settings.get("state_update_interval", 30000)
        )
        periodic_state_update.start()

    ioloop_instance.add_callback(
        functools.partial(storage.init_db, state, database_settings.get("settings", {}), run_periodic_state_update)
    )

    app.zmq_pub_sub_proxy = options.zmq_pub_sub_proxy

    context = zmq.Context()

    # create PUB socket to publish instance events into it
    publish_socket = context.socket(zmq.PUB)
    # do not try to send messages after closing
    publish_socket.setsockopt(zmq.LINGER, 0)

    if app.zmq_pub_sub_proxy:
        # application started with XPUB/XSUB proxy
        app.zmq_xsub = options.zmq_xsub
        publish_socket.connect(app.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

        app.zmq_pub_port = zmq_pub_port

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

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

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

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

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

    def listen_control_channel():
        # wrap sub socket into ZeroMQ stream and set its on_recv callback
        app.sub_stream = ZMQStream(subscribe_socket)
        handle = functools.partial(handle_control_message, app)
        app.sub_stream.on_recv(handle)

    ioloop_instance.add_callback(listen_control_channel)

    app.event_callbacks = []
    callbacks = custom_settings.get("event_callbacks", [])

    for callback in callbacks:
        event_callback = utils.namedAny(callback)
        app.event_callbacks.append(event_callback)

    if not hasattr(app, "admin_connections"):
        # initialize dict to keep admin connections
        app.admin_connections = {}

    if not hasattr(app, "connections"):
        # initialize dict to keep client's connections
        app.connections = {}

    if not hasattr(app, "back_off"):
        # initialize dict to keep back-off information for projects
        app.back_off = {}

    logger.info("Application started")
    logger.info("Tornado port: {0}".format(options.port))
    if app.zmq_pub_sub_proxy:
        logger.info("ZeroMQ XPUB: {0}, XSUB: {1}".format(app.zmq_xpub, app.zmq_xsub))
    else:
        logger.info("ZeroMQ PUB - {0}; subscribed to {1}".format(app.zmq_pub_port, app.zmq_sub_address))
    logger.info("Storage module: {0}".format(storage_module))

    # 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.on_recv(None)
            app.sub_stream.close()