Beispiel #1
0
class FakeServerContext(object):
    def __init__(self, monkeypatch, fail_these, expected_basename):
        self._monkeypatch = monkeypatch
        self._fail_these = fail_these
        self._expected_basename = expected_basename
        self._url = None
        self._loop = None
        self._started = threading.Condition()
        self._thread = threading.Thread(target=self._run)

    def __exit__(self, type, value, traceback):
        if self._loop is not None:
            # we can ONLY use add_callback here, since the loop is
            # running in a different thread.
            self._loop.add_callback(self._stop)
        self._thread.join()

    def __enter__(self):
        self._started.acquire()
        self._thread.start()
        self._started.wait()
        self._started.release()
        _monkeypatch_client_config(self._monkeypatch, self._url)
        return self._url

    def _run(self):
        self._loop = IOLoop()
        self._server = FakeAnacondaServer(
            io_loop=self._loop,
            fail_these=self._fail_these,
            expected_basename=self._expected_basename)
        self._url = self._server.url

        def notify_started():
            self._started.acquire()
            self._started.notify()
            self._started.release()

        self._loop.add_callback(notify_started)
        self._loop.start()
        # done
        self._server.unlisten()

    def _stop(self):
        def really_stop():
            if self._loop is not None:
                self._loop.stop()
                self._loop = None

        # the delay allows pending next-tick things to go ahead
        # and happen, which may avoid some problems with trying to
        # output to stdout after pytest closes it
        if self._loop is not None:
            self._loop.call_later(delay=0.05, callback=really_stop)
Beispiel #2
0
class FakeServerContext(object):
    def __init__(self, monkeypatch, fail_these, expected_basename):
        self._monkeypatch = monkeypatch
        self._fail_these = fail_these
        self._expected_basename = expected_basename
        self._url = None
        self._loop = None
        self._started = threading.Condition()
        self._thread = threading.Thread(target=self._run)

    def __exit__(self, type, value, traceback):
        if self._loop is not None:
            # we can ONLY use add_callback here, since the loop is
            # running in a different thread.
            self._loop.add_callback(self._stop)
        self._thread.join()

    def __enter__(self):
        self._started.acquire()
        self._thread.start()
        self._started.wait()
        self._started.release()
        _monkeypatch_client_config(self._monkeypatch, self._url)
        return self._url

    def _run(self):
        self._loop = IOLoop()
        self._server = FakeAnacondaServer(io_loop=self._loop,
                                          fail_these=self._fail_these,
                                          expected_basename=self._expected_basename)
        self._url = self._server.url

        def notify_started():
            self._started.acquire()
            self._started.notify()
            self._started.release()

        self._loop.add_callback(notify_started)
        self._loop.start()
        # done
        self._server.unlisten()

    def _stop(self):
        def really_stop():
            if self._loop is not None:
                self._loop.stop()
                self._loop = None
        # the delay allows pending next-tick things to go ahead
        # and happen, which may avoid some problems with trying to
        # output to stdout after pytest closes it
        if self._loop is not None:
            self._loop.call_later(delay=0.05, callback=really_stop)
Beispiel #3
0
class LoopAndGroup(object):
    def __init__(self, quit_after=None):
        self.io_loop = IOLoop()
        self.group = _CallbackGroup(self.io_loop)

        if quit_after is not None:
            self.io_loop.call_later(quit_after / 1000.0, lambda: self.io_loop.stop())

    def __exit__(self, type, value, traceback):
        run(self.io_loop)
        self.io_loop.close()

    def __enter__(self):
        return self
class LoopAndGroup(object):
    def __init__(self, quit_after=None):
        self.io_loop = IOLoop()
        self.group = _CallbackGroup(self.io_loop)

        if quit_after is not None:
            self.io_loop.call_later(quit_after / 1000.0,
                                    lambda: self.io_loop.stop())

    def __exit__(self, type, value, traceback):
        run(self.io_loop)
        self.io_loop.close()

    def __enter__(self):
        return self
Beispiel #5
0
class LoadTest:
    def __init__(self, ws_url, concurrency, recycle, duration):
        self.ws_url = ws_url
        self.concurrency = concurrency
        self.recycle = recycle
        self.duration = duration
        self.loop = IOLoop()
        self.result = None

    def print_summary(self):
        print(f"Total of websockets opened: {self.result.websockets_opened}")
        print(f"Total of websockets closed: {self.result.websockets_closed}")

    async def websocket_connect(self):
        ws = await websocket_connect(self.ws_url)
        await gen.moment
        self.result.websockets_opened += 1
        self.loop.call_later(self.recycle, self.recycle_ws(ws))

    def recycle_ws(self, ws):
        async def handle():
            ws.close()
            self.result.websockets_closed += 1
            await self.websocket_connect()
        return handle

    def start(self):
        self.loop.make_current()
        self.result = Result()

        for _ in range(self.concurrency):
            self.loop.call_later(0, self.websocket_connect)

        self.loop.call_later(self.duration, self.stop)
        self.loop.start()

    def stop(self):
        self.print_summary()
        self.loop.stop()
class TornadoServer(AbstractServer):
    """ Flexx Server implemented in Tornado.
    """
    def __init__(self, host, port, new_loop):
        self._new_loop = new_loop
        super(TornadoServer, self).__init__(host, port)

    def _open(self, host, port):

        # Get a new ioloop or the current ioloop for this thread
        if self._new_loop:
            self._loop = IOLoop()
        else:
            self._loop = IOLoop.current(instance=is_main_thread())
            if self._loop is None:
                self._loop = IOLoop(make_current=True)

        # Create tornado application
        self._app = tornado.web.Application([
            (r"/(.*)/ws", WSHandler),
            (r"/(.*)", MainHandler),
        ])
        # Create tornado server, bound to our own ioloop
        self._server = tornado.httpserver.HTTPServer(self._app,
                                                     io_loop=self._loop)

        # Start server (find free port number if port not given)
        if port:
            # Turn port into int, use hashed port number if a string was given
            try:
                port = int(port)
            except ValueError:
                port = port_hash(port)
            self._server.listen(port, host)
        else:
            # Try N ports in a repeatable range (easier, browser history, etc.)
            prefered_port = port_hash('Flexx')
            for i in xrange(8):
                port = prefered_port + i
                try:
                    self._server.listen(port, host)
                    break
                except OSError:
                    pass  # address already in use
            else:
                # Ok, let Tornado figure out a port
                [sock] = netutil.bind_sockets(None,
                                              host,
                                              family=socket.AF_INET)
                self._server.add_sockets([sock])
                port = sock.getsockname()[1]

        # Notify address, so its easy to e.g. copy and paste in the browser
        self._serving = self._app._flexx_serving = host, port
        logger.info('Serving apps at http://%s:%i/' % (host, port))

    def _start(self):
        # Ensure that our loop is the current loop for this thread
        if self._new_loop:
            self._loop.make_current()
        elif IOLoop.current(instance=is_main_thread()) is not self._loop:
            raise RuntimeError(
                'Server must use ioloop that is current to this thread.')
        # Make use of the semi-standard defined by IPython to determine
        # if the ioloop is "hijacked" (e.g. in Pyzo). There is no public
        # way to determine if a loop is already running, but the
        # AbstractServer class keeps track of this.
        if not getattr(self._loop, '_in_event_loop', False):
            self._loop.start()

    def _stop(self):
        # todo: explicitly close all websocket connections
        logger.debug('Stopping Tornado server')
        self._loop.stop()

    def _close(self):
        self._server.stop()

    def call_later(self, delay, callback, *args, **kwargs):
        if delay <= 0:
            self._loop.add_callback(callback, *args, **kwargs)
        else:
            self._loop.call_later(delay, callback, *args, **kwargs)

    @property
    def app(self):
        """ The Tornado Application object being used."""
        return self._app

    @property
    def loop(self):
        """ The Tornado IOLoop object being used."""
        return self._loop

    @property
    def server(self):
        """ The Tornado HttpServer object being used."""
        return self._server
Beispiel #7
0
class TornadoServer(AbstractServer):
    """ Flexx Server implemented in Tornado.
    """
    def __init__(self, host, port, new_loop):
        self._new_loop = new_loop
        self._app = None
        self._server = None
        self._get_io_loop()
        super().__init__(host, port)

    def _get_io_loop(self):
        # Get a new ioloop or the current ioloop for this thread
        if self._new_loop:
            self._loop = IOLoop()
        else:
            self._loop = IOLoop.current(instance=is_main_thread())
            if self._loop is None:
                self._loop = IOLoop(make_current=True)

    def _open(self, host, port):
        # Note: does not get called if host is False. That way we can
        # run Flexx in e.g. JLab's application.

        # Create tornado application
        self._app = tornado.web.Application([
            (r"/flexx/ws/(.*)", WSHandler),
            (r"/flexx/(.*)", MainHandler),
            (r"/(.*)", AppHandler),
        ])
        # Create tornado server, bound to our own ioloop
        self._server = tornado.httpserver.HTTPServer(self._app,
                                                     io_loop=self._loop)

        # Start server (find free port number if port not given)
        if port:
            # Turn port into int, use hashed port number if a string was given
            try:
                port = int(port)
            except ValueError:
                port = port_hash(port)
            self._server.listen(port, host)
        else:
            # Try N ports in a repeatable range (easier, browser history, etc.)
            prefered_port = port_hash('Flexx')
            for i in range(8):
                port = prefered_port + i
                try:
                    self._server.listen(port, host)
                    break
                except OSError:
                    pass  # address already in use
            else:
                # Ok, let Tornado figure out a port
                [sock] = netutil.bind_sockets(None,
                                              host,
                                              family=socket.AF_INET)
                self._server.add_sockets([sock])
                port = sock.getsockname()[1]

        # Notify address, so its easy to e.g. copy and paste in the browser
        self._serving = self._app._flexx_serving = host, port
        logger.info('Serving apps at http://%s:%i/' % (host, port))

    def _start(self):
        # Ensure that our loop is the current loop for this thread
        if self._new_loop:
            self._loop.make_current()
        elif IOLoop.current(instance=is_main_thread()) is not self._loop:
            raise RuntimeError(
                'Server must use ioloop that is current to this thread.')
        # Make use of the semi-standard defined by IPython to determine
        # if the ioloop is "hijacked" (e.g. in Pyzo). There is no public
        # way to determine if a loop is already running, but the
        # AbstractServer class keeps track of this.
        if not getattr(self._loop, '_in_event_loop', False):
            self._loop.start()

    def _stop(self):
        # todo: explicitly close all websocket connections
        logger.debug('Stopping Tornado server')
        self._loop.stop()

    def _close(self):
        self._server.stop()

    def call_later(self, delay, callback, *args, **kwargs):
        # We use a wrapper func so that exceptions are processed via our
        # logging system. Also fixes that Tornado seems to close websockets
        # when an exception occurs (issue #164) though one could also
        # use ``with tornado.stack_context.NullContext()`` to make callbacks
        # be called more "independently".
        def wrapper():
            try:
                callback(*args, **kwargs)
            except Exception as err:
                err.skip_tb = 1
                logger.exception(err)

        if delay <= 0:
            self._loop.add_callback(wrapper)
        else:
            self._loop.call_later(delay, wrapper)

    @property
    def app(self):
        """ The Tornado Application object being used."""
        return self._app

    @property
    def loop(self):
        """ The Tornado IOLoop object being used."""
        return self._loop

    @property
    def server(self):
        """ The Tornado HttpServer object being used."""
        return self._server
Beispiel #8
0
class TornadoServer(AbstractServer):
    """ Flexx Server implemented in Tornado.
    """
    
    def __init__(self, host, port, new_loop):
        self._new_loop = new_loop
        super().__init__(host, port)
    
    def _open(self, host, port):
        
        # Get a new ioloop or the current ioloop for this thread
        if self._new_loop:
            self._loop = IOLoop()
        else:
            self._loop = IOLoop.current(instance=is_main_thread())
            if self._loop is None:
                self._loop = IOLoop(make_current=True)
        
        # Create tornado application
        self._app = tornado.web.Application([(r"/(.*)/ws", WSHandler), 
                                             (r"/(.*)", MainHandler), ])
        # Create tornado server, bound to our own ioloop
        self._server = tornado.httpserver.HTTPServer(self._app, io_loop=self._loop)
        
        # Start server (find free port number if port not given)
        if port:
            # Turn port into int, use hashed port number if a string was given
            try:
                port = int(port)
            except ValueError:
                port = port_hash(port)
            self._server.listen(port, host)
        else:
            # Try N ports in a repeatable range (easier, browser history, etc.)
            prefered_port = port_hash('Flexx')
            for i in range(8):
                port = prefered_port + i
                try:
                    self._server.listen(port, host)
                    break
                except OSError:
                    pass  # address already in use
            else:
                # Ok, let Tornado figure out a port
                [sock] = netutil.bind_sockets(None, host, family=socket.AF_INET)
                self._server.add_sockets([sock])
                port = sock.getsockname()[1]
        
        # Notify address, so its easy to e.g. copy and paste in the browser
        self._serving = self._app._flexx_serving = host, port
        logger.info('Serving apps at http://%s:%i/' % (host, port))
    
    def _start(self):
        # Ensure that our loop is the current loop for this thread
        if self._new_loop:
            self._loop.make_current()
        elif IOLoop.current(instance=is_main_thread()) is not self._loop:
            raise RuntimeError('Server must use ioloop that is current to this thread.')
        # Make use of the semi-standard defined by IPython to determine
        # if the ioloop is "hijacked" (e.g. in Pyzo). There is no public
        # way to determine if a loop is already running, but the
        # AbstractServer class keeps track of this.
        if not getattr(self._loop, '_in_event_loop', False):
            self._loop.start()
    
    def _stop(self):
        # todo: explicitly close all websocket connections
        logger.debug('Stopping Tornado server')
        self._loop.stop()
    
    def _close(self):
        self._server.stop()
    
    def call_later(self, delay, callback, *args, **kwargs):
        if delay <= 0:
            self._loop.add_callback(callback, *args, **kwargs)
        else:
            self._loop.call_later(delay, callback, *args, **kwargs)
    
    @property
    def app(self):
        """ The Tornado Application object being used."""
        return self._app
    
    @property
    def loop(self):
        """ The Tornado IOLoop object being used."""
        return self._loop
    
    @property
    def server(self):
        """ The Tornado HttpServer object being used."""
        return self._server
Beispiel #9
0
class TornadoServer(AbstractServer):
    """ Flexx Server implemented in Tornado.
    """

    def __init__(self, host, port, new_loop, **kwargs):
        self._new_loop = new_loop
        self._app = None
        self._server = None
        self._get_io_loop()
        super().__init__(host, port, **kwargs)

    def _get_io_loop(self):
        # Get a new ioloop or the current ioloop for this thread
        if self._new_loop:
            self._loop = IOLoop()
        else:
            self._loop = IOLoop.current(instance=is_main_thread())
            if self._loop is None:
                self._loop = IOLoop(make_current=True)

    def _open(self, host, port, **kwargs):
        # Note: does not get called if host is False. That way we can
        # run Flexx in e.g. JLab's application.

        # handle ssl, wether from configuration or given args
        if config.ssl_certfile:
            if 'ssl_options' not in kwargs:
                kwargs['ssl_options'] = {}
            if 'certfile' not in kwargs['ssl_options']:
                kwargs['ssl_options']['certfile'] = config.ssl_certfile

        if config.ssl_keyfile:
            if 'ssl_options' not in kwargs:
                kwargs['ssl_options'] = {}
            if 'keyfile' not in kwargs['ssl_options']:
                kwargs['ssl_options']['keyfile'] = config.ssl_keyfile

        if config.tornado_debug:
            app_kwargs = dict(debug=True)
        else:
            app_kwargs = dict()
        # Create tornado application
        self._app = Application([(r"/flexx/ws/(.*)", WSHandler),
                                 (r"/flexx/(.*)", MainHandler),
                                 (r"/(.*)", AppHandler), ], **app_kwargs)
        # Create tornado server, bound to our own ioloop
        self._server = HTTPServer(self._app, io_loop=self._loop, **kwargs)

        # Start server (find free port number if port not given)
        if port:
            # Turn port into int, use hashed port number if a string was given
            try:
                port = int(port)
            except ValueError:
                port = port_hash(port)
            self._server.listen(port, host)
        else:
            # Try N ports in a repeatable range (easier, browser history, etc.)
            prefered_port = port_hash('Flexx')
            for i in range(8):
                port = prefered_port + i
                try:
                    self._server.listen(port, host)
                    break
                except (OSError, IOError):
                    pass  # address already in use
            else:
                # Ok, let Tornado figure out a port
                [sock] = netutil.bind_sockets(None, host, family=socket.AF_INET)
                self._server.add_sockets([sock])
                port = sock.getsockname()[1]

        # Notify address, so its easy to e.g. copy and paste in the browser
        self._serving = self._app._flexx_serving = host, port
        proto = 'http'
        if 'ssl_options' in kwargs:
            proto = 'https'
        logger.info('Serving apps at %s://%s:%i/' % (proto, host, port))

    def _start(self):
        # Ensure that our loop is the current loop for this thread
        if self._new_loop:
            self._loop.make_current()
        elif IOLoop.current(instance=is_main_thread()) is not self._loop:
            raise RuntimeError('Server must use ioloop that is current to this thread.')
        # Make use of the semi-standard defined by IPython to determine
        # if the ioloop is "hijacked" (e.g. in Pyzo). There is no public
        # way to determine if a loop is already running, but the
        # AbstractServer class keeps track of this.
        if not getattr(self._loop, '_in_event_loop', False):
            self._loop.start()

    def _stop(self):
        # todo: explicitly close all websocket connections
        logger.debug('Stopping Tornado server')
        self._loop.stop()

    def _close(self):
        self._server.stop()

    def call_later(self, delay, callback, *args, **kwargs):
        # We use a wrapper func so that exceptions are processed via our
        # logging system. Also fixes that Tornado seems to close websockets
        # when an exception occurs (issue #164) though one could also
        # use ``with tornado.stack_context.NullContext()`` to make callbacks
        # be called more "independently".
        def wrapper():
            try:
                callback(*args, **kwargs)
            except Exception as err:
                err.skip_tb = 1
                logger.exception(err)

        if delay <= 0:
            self._loop.add_callback(wrapper)
        else:
            self._loop.call_later(delay, wrapper)

    @property
    def app(self):
        """ The Tornado Application object being used."""
        return self._app

    @property
    def loop(self):
        """ The Tornado IOLoop object being used."""
        return self._loop

    @property
    def server(self):
        """ The Tornado HttpServer object being used."""
        return self._server

    @property
    def protocol(self):
        """ Get a string representing served protocol."""
        if self._server.ssl_options is not None:
            return 'https'

        return 'http'