def run_server(config): setup_app(config) setup_logging(config) # Initialize huey task queue global task_queue db_location = os.path.join(config.config_dir(), 'queue.db') task_queue = SqliteHuey(location=db_location) consumer = Consumer(task_queue) ip_address = get_ip_address() if (app.config['standalone'] and ip_address and config['driver'].get() in ['chdkcamera', 'a2200']): # Display the address of the web interface on the camera displays try: for cam in get_devices(config): cam.show_textbox( "\n You can now access the web interface at:" "\n\n\n http://{0}:5000".format(ip_address)) except: logger.warn("No devices could be found at startup.") # Start task consumer consumer.start() try: import waitress # NOTE: We spin up this obscene number of threads since we have # some long-polling going on, which will always block # one worker thread. waitress.serve(app, port=5000, threads=16) finally: consumer.shutdown() if app.config['DEBUG']: logger.info("Waiting for remaining connections to close...")
def run_server(config): listening_port = config['web']['port'].get(int) ws_server = WebSocketServer(port=listening_port+1) setup_app(config) setup_logging(config) setup_task_queue(config) setup_signals(ws_server) consumer = Consumer(task_queue) ip_address = get_ip_address() if (app.config['standalone'] and ip_address and config['driver'].get() == 'chdkcamera'): # Display the address of the web interface on the camera displays try: for cam in plugin.get_devices(config): cam.show_textbox( "\n You can now access the web interface at:" "\n\n\n http://{0}:{1}" .format(ip_address, listening_port)) except plugin.DeviceException: logger.warn("No devices could be found at startup.") # Start task consumer consumer.start() # Start websocket server ws_server.start() if app.config['mode'] in ('processor', 'full'): discovery_listener = DiscoveryListener(listening_port) discovery_listener.start() try: import waitress waitress.serve(app, port=listening_port) finally: consumer.shutdown() ws_server.stop() if app.config['mode'] in ('processor', 'full'): discovery_listener.stop()
def run_server(config): listening_port = config['web']['port'].get(int) ws_server = WebSocketServer(port=listening_port + 1) setup_app(config) setup_logging(config) setup_task_queue(config) setup_signals(ws_server) consumer = Consumer(task_queue) ip_address = get_ip_address() if (app.config['standalone'] and ip_address and config['driver'].get() == 'chdkcamera'): # Display the address of the web interface on the camera displays try: for cam in plugin.get_devices(config): cam.show_textbox( "\n You can now access the web interface at:" "\n\n\n http://{0}:{1}".format( ip_address, listening_port)) except plugin.DeviceException: logger.warn("No devices could be found at startup.") # Start task consumer consumer.start() # Start websocket server ws_server.start() if app.config['mode'] in ('processor', 'full'): discovery_listener = DiscoveryListener(listening_port) discovery_listener.start() try: import waitress waitress.serve(app, port=listening_port) finally: consumer.shutdown() ws_server.stop() if app.config['mode'] in ('processor', 'full'): discovery_listener.stop()
def run_server(config): ws_server = WebSocketServer(port=5001) setup_app(config) setup_logging(config) setup_signals(ws_server) # Initialize huey task queue global task_queue db_location = config.cfg_path.parent / 'queue.db' task_queue = SqliteHuey(location=unicode(db_location)) consumer = Consumer(task_queue) ip_address = get_ip_address() if (app.config['standalone'] and ip_address and config['driver'].get() == 'chdkcamera'): # Display the address of the web interface on the camera displays try: for cam in plugin.get_devices(config): cam.show_textbox( "\n You can now access the web interface at:" "\n\n\n http://{0}:5000".format(ip_address)) except plugin.DeviceException: logger.warn("No devices could be found at startup.") # Start task consumer consumer.start() # Start websocket server ws_server.start() try: import waitress # NOTE: We spin up this obscene number of threads since we have # some long-polling going on, which will always block # one worker thread. waitress.serve(app, port=5000, threads=16) finally: consumer.shutdown() ws_server.stop()
class WebApplication(object): """ Manages initialization, configuration and launch of the web app. :attr config: Web plugin configuration :type config: :py:class:`confit.ConfigView` :attr global_config: Global application configuration :type global_config: :py:class:`spreads.config.Configuration` :attr consumer: Background task consumer :type consumer: :py:class:`huey.consumer.Consumer` :attr application: Tornado web application :type application: :py:class:`tornado.web.Application` """ def __init__(self, config): self.global_config = config self.config = config['web'] mode = self.config['mode'].get() logger.debug("Starting scanning station server in \"{0}\" mode" .format(mode)) # Directory that workflows should be stored in project_dir = os.path.expanduser(self.config['project_dir'].get()) if not os.path.exists(project_dir): os.mkdir(project_dir) self._debug = self.config['debug'].get(bool) # Expose some configuration to the WSGI app app.config['debug'] = self._debug app.config['mode'] = mode app.config['base_path'] = project_dir app.config['default_config'] = config app.config['standalone'] = self.config['standalone_device'].get() app.config['postprocessing_server'] = ( self.config['postprocessing_server'].get() or None) if not self._debug: app.error_handler_spec[None][500] = ( endpoints.handle_general_exception) def setup_task_queue(self): """ Configure task queue and consumer. """ # Initialize huey task queue global task_queue db_location = self.global_config.cfg_path.parent / 'queue.db' task_queue = SqliteHuey(location=unicode(db_location)) self.consumer = Consumer(task_queue) def setup_logging(self): """ Configure loggers. """ # Add in-memory log handler memoryhandler = logging.handlers.BufferingHandler(1024*10) memoryhandler.setLevel(logging.DEBUG) logger.root.addHandler(memoryhandler) # Silence some rather annoying loggers logging.getLogger('huey.consumer').setLevel(logging.INFO) logging.getLogger('huey.consumer.ConsumerThread').setLevel( logging.INFO) logging.getLogger('bagit').setLevel(logging.ERROR) logging.getLogger('isbnlib.dev.webservice').setLevel(logging.ERROR) logging.getLogger('tornado.access').setLevel(logging.ERROR) def setup_signals(self): """ Connect signal handlers. """ def get_signal_callback_http(signal): """ Create a signal callback that adds a signal as a :py:class:`util.Event` to the buffer in :py:mod:`handlers`. """ def signal_callback(sender, **kwargs): event = util.Event(signal, sender, kwargs) handlers.event_buffer.new_events([event]) return signal_callback def get_signal_callback_websockets(signal): """ Create a signal callback that sends out a signals as a :py:class:`util.Event` via the :py:class:`tornado.web.WebSocketHandler` in :py:mod:`handlers`. """ def signal_callback(sender, **kwargs): handlers.WebSocketHandler.send_event( util.Event(signal, sender, kwargs)) return signal_callback # Register event handlers import tasks signals_ = chain(*(x.signals.values() for x in (spreads.workflow, util.EventHandler, tasks, handlers))) for signal in signals_: signal.connect(get_signal_callback_http(signal), weak=False) signal.connect(get_signal_callback_websockets(signal), weak=False) def setup_tornado(self): """ Configure Tornado web application. """ if self._debug: # Exposes Werkzeug's interactive debugger for WSGI endpoints. logger.info("Starting server in debugging mode") from werkzeug.debug import DebuggedApplication container = WSGIContainer(DebuggedApplication(app, evalex=True)) else: container = WSGIContainer(app) self.application = Application([ (r"/ws", handlers.WebSocketHandler), (r"/api/workflow/([0-9a-z-]+)/download/(.*)\.zip", handlers.ZipDownloadHandler, dict(base_path=app.config['base_path'])), (r"/api/workflow/([0-9a-z-]+)/download/(.*).\.tar", handlers.TarDownloadHandler, dict(base_path=app.config['base_path'])), (r"/api/workflow/upload", handlers.StreamingUploadHandler, dict(base_path=app.config['base_path'])), (r"/api/poll", handlers.EventLongPollingHandler), # Fall back to WSGI endpoints (r".*", FallbackHandler, dict(fallback=container)) ], debug=self._debug) def display_ip(self): """ Display external IP address on device displays. """ # Display the address of the web interface on the camera displays try: for cam in plugin.get_devices(self.global_config): cam.show_textbox( "\n You can now access the web interface at:" "\n\n\n http://{0}:{1}" .format(self._ip_address, self._listening_port)) self._display_callback.stop() except plugin.DeviceException: # Try again next time... return def run_server(self): """ Run the web application. """ self.setup_logging() self.setup_task_queue() self.setup_signals() self.setup_tornado() self._listening_port = self.config['port'].get(int) self._ip_address = get_ip_address() try: device_driver = plugin.get_driver(self.global_config['driver'] .get()) should_display_ip = (app.config['standalone'] and self._ip_address and plugin.DeviceFeatures.CAN_DISPLAY_TEXT in device_driver.features) except ConfigError: if self.config['mode'] not in ('scanner', 'full'): should_display_ip = False raise ConfigError( "You need to specify a value for `driver`.\n" "Either run `spread [gui]configure` or edit the configuration " "file.") if should_display_ip: # Every 30 seconds, see if there are devices attached and display # IP address and port on them, then disable the callback self._display_callback = PeriodicCallback( self.display_ip, 30*10**3) # Run once immediately self.display_ip() # Start task consumer self.consumer.start() # Start discovery listener if app.config['mode'] in ('processor', 'full'): discovery_listener = DiscoveryListener(self._listening_port) discovery_listener.start() # Spin up WSGI server self.application.listen(self._listening_port) try: IOLoop.instance().start() finally: # Shut everything down that is still running in the background self.consumer.shutdown() if app.config['mode'] in ('processor', 'full'): discovery_listener.stop()