Beispiel #1
0
class WebServer:
    def __init__(self, loop):
        self.host = config.get('webserver.host')
        self.port = config.get('webserver.port')
        self.loop = loop
        self.app = None
        self.handler = None
        self.server = None

    def __enter__(self):
        self.app = Application(loop=self.loop)
        for api in api_registry:
            self.app.router.add_route(api.method, API_ROUTE + api.path,
                                      api.handler)
        setup_swagger(self.app, swagger_url=API_ROUTE, title='Skywall web API')
        if os.path.isdir('build'):
            self.app.router.add_static(BUILD_ROUTE, 'build')
        self.app.router.add_get('/{tail:.*}', get_frontend)

        self.handler = self.app.make_handler()
        self.loop.run_until_complete(self.app.startup())
        self.server = self.loop.run_until_complete(
            self.loop.create_server(self.handler, self.host, self.port))

        print('Web server listening on http://{}:{}'.format(
            self.host, self.port),
              flush=True)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.server.close()
        self.loop.run_until_complete(self.server.wait_closed())
        self.loop.run_until_complete(self.app.shutdown())
        self.loop.run_until_complete(self.handler.shutdown(60))
        self.loop.run_until_complete(self.app.cleanup())
Beispiel #2
0
def gen_rpc_context(loop,
                    host,
                    port,
                    rpc,
                    rpc_route,
                    routes=(),
                    RpcContext=RpcContext):
    # make app
    app = Application(loop=loop)

    app.router.add_route(*rpc_route)

    for route in routes:
        app.router.add_route(*route)

    # make handler
    handler = app.make_handler()

    server = loop.run_until_complete(loop.create_server(handler, host, port))

    # create RpcContext
    rpc_context = RpcContext(app, rpc, host, port, rpc_route[1])

    yield rpc_context

    # teardown clients
    loop.run_until_complete(rpc_context.finish_connections())

    # teardown server
    server.close()
    loop.run_until_complete(server.wait_closed())
    loop.run_until_complete(app.shutdown())
    loop.run_until_complete(handler.finish_connections(1))
    loop.run_until_complete(app.cleanup())
Beispiel #3
0
class WebsocketServer:
    def __init__(self, loop):
        self.host = config.get('server.host')
        self.port = config.get('server.port')
        self.loop = loop
        self.app = None
        self.handler = None
        self.server = None
        self.connections = []

    def __enter__(self):
        before_server_start.emit(server=self)
        self.app = Application(loop=self.loop)
        self.app.router.add_get('/', self._connect)
        self.app.on_shutdown.append(self._on_shutdown)

        self.handler = self.app.make_handler()
        self.loop.run_until_complete(self.app.startup())
        self.server = self.loop.run_until_complete(
            self.loop.create_server(self.handler, self.host, self.port))

        print('Websocket server listening on http://{}:{}'.format(
            self.host, self.port),
              flush=True)
        after_server_start.emit(server=self)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        before_server_stop.emit(server=self)
        self.server.close()
        self.loop.run_until_complete(self.server.wait_closed())
        self.loop.run_until_complete(self.app.shutdown())
        self.loop.run_until_complete(self.handler.shutdown(60))
        self.loop.run_until_complete(self.app.cleanup())
        after_server_stop.emit(server=self)

    async def _connect(self, request):
        connection = WebsocketConnection(self, request)

        # If a client connects again without closing his previous connection, close it manually.
        # Each client may have only one opened connection at any time.
        old_connection = self.get_connection(connection.client_id)
        if old_connection:
            await old_connection.close()

        self.connections.append(connection)
        try:
            await connection.connect()
        finally:
            self.connections.remove(connection)
        return connection.socket

    async def _on_shutdown(self, app):
        for connection in self.connections:
            await connection.close()

    def get_connection(self, client_id):
        for connection in self.connections:
            if connection.client_id == client_id:
                return connection
        return None
Beispiel #4
0
class ControlSocket(object):
    """Create a asynchronous HTTP server ready to receive commands."""

    # TODO rivedere i test di questa classe

    def __init__(self, timetable, heating, cooling, thermometer, host, port,
                 lock, loop):
        baselogger.debug('initializing control socket')

        if not isinstance(lock, asyncio.Condition):
            raise TypeError(
                'the lock in ControlSocket must be an asyncio.Condition object'
            )

        self.app = Application(middlewares=[exceptions_middleware], loop=loop)
        self.host = host
        self.port = port

        self.app['lock'] = lock
        self.app['monitors'] = asyncio.Queue(loop=loop)

        self.app['timetable'] = timetable
        self.app['heating'] = heating
        self.app['cooling'] = cooling
        self.app['thermometer'] = thermometer

        self.app.router.add_get('/{action}', GET_handler)
        self.app.router.add_post('/{action}', POST_handler)

        baselogger.debug('control socket initialized')

    def start(self):
        """Start the internal HTTP server."""
        baselogger.debug('starting control socket')
        loop = self.app.loop
        loop.run_until_complete(self.app.startup())
        self.handler = self.app.make_handler()
        self.srv = loop.run_until_complete(
            loop.create_server(self.handler, self.host, self.port))
        baselogger.info('control socket listening on {}:{}', self.host,
                        self.port)

    def stop(self):
        """Stop the internal HTTP server."""
        baselogger.debug('stopping control socket')
        self.srv.close()

        loop = self.app.loop
        loop.run_until_complete(self.srv.wait_closed())
        loop.run_until_complete(self.app.shutdown())
        loop.run_until_complete(self.handler.shutdown(6))
        loop.run_until_complete(self.app.cleanup())

        baselogger.info('control socket halted')

    async def update_monitors(self, status):
        """Send new status to every connected monitor.
        
        The new status must be a subclass of `thermod.common.ThermodStatus`
        to be fully compliant.
        """

        if not isinstance(status, ThermodStatus):
            raise TypeError(
                'new status for monitors must be a ThermodStatus object')

        baselogger.debug('updating connected monitors')

        if self.app['monitors'].empty():
            baselogger.debug('no monitors to be updated, the queue is empty')
        else:
            baselogger.debug('there are {} monitor(s) in the queue'.format(
                self.app['monitors'].qsize()))

        count = 0
        while not self.app['monitors'].empty():
            try:
                future = await self.app['monitors'].get()
                if not future.cancelled():
                    future.set_result(status)
                    baselogger.debug('monitor {} updated'.format(count))
                else:
                    baselogger.debug('monitor {} disconnected'.format(count))

            except asyncio.InvalidStateError:
                baselogger.debug(
                    'cannot update monitor {} because the client '
                    'has probably closed the connection'.format(count))

            count += 1