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
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))
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
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")
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()
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()
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))
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) )
def main(): ioloop_instance = tornado.ioloop.IOLoop.instance() create_centrifuge_application() try: ioloop_instance.start() except KeyboardInterrupt: logger.info('interrupted')
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))
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))
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")
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')
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()
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()
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()
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()
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))
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)
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)
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()
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', '-') ))
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', '-') ))
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()
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")
def unsubscribe(self): if not hasattr(self, 'uid'): return self.application.remove_admin_connection(self.uid) logger.info('admin disconnected')
def subscribe(self): self.uid = uuid.uuid4().hex self.application.add_admin_connection(self.uid, self) logger.info('admin connected')
def initialize(self): logger.info("Base PUB/SUB")
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))
def initialize(self): self.connect() logger.info("Redis engine at {0}:{1} (db {2})".format( self.host, self.port, self.db))
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
def close(self): yield self.clean() logger.info('client destroyed (uid: %s)' % self.uid) raise Return((True, None))
def initialize(self): self.history_expire_task.start() logger.info("Memory engine initialized")
def on_close(self): self.unsubscribe() logger.info("admin disconnected")
def open(self): logger.info('admin connected')
def initialize(self): logger.info("Base State initialized")
def check_connection(self): if not self.client.is_connected(): logger.info('reconnecting to Redis') self.connect()
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))
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
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()
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()