Exemple #1
0
 async def start(self):
     runner = AppRunner(self.buildApp(Application()))
     await runner.setup()
     site = TCPSite(runner, "0.0.0.0", int(self.config.get(Setting.PORT)))
     await site.start()
     self.logger.info("Backup Auth Server Started")
Exemple #2
0
async def obtain_access_token(studip_session: StudIPSession,
                              oauth1_client: OAuth1Client = None,
                              http_session: aiohttp.ClientSession = None,
                              port=OAUTH_CALLBACK_PORT,
                              open_browser=True):
    if not http_session:
        http_session = studip_session.http.http_session
    if not oauth1_client:
        if isinstance(http_session._default_auth, OAuth1Client):
            oauth1_client = http_session._default_auth
        else:
            oauth1_client = OAuth1Client(
                *get_tokens(studip_session.studip_base))
            http_session._default_auth = oauth1_client

    try:
        await studip_session.check_login()
        return oauth1_client
    except (HTTPException, aiohttp.ClientResponseError) as e:
        if e.status != HTTPUnauthorized.status_code \
                and getattr(e, "message", "") != "Can't verify request, missing oauth_consumer_key or oauth_token":
            raise
        log.info("OAuth Session invalid, starting log-in flow")

    app = Application()
    app.add_routes(routes)

    app["http_session"] = http_session
    app["studip_session"] = studip_session
    app["oauth1_client"] = oauth1_client
    app["finished_client_future"] = asyncio.get_event_loop().create_future()
    app["check_running_future"] = asyncio.get_event_loop().create_future()

    runner = AppRunner(app)
    try:
        await runner.setup()
        site = TCPSite(runner, host="127.0.0.1", port=port)
        await site.start()

        nonce = generate_nonce()
        log.debug("nonce         %s", nonce)
        async with http_session.get(
                url_for("check_running", app=app,
                        site=site).with_query(nonce=nonce)) as resp:
            resp.raise_for_status()
            assert await resp.text() == "running"
            assert await asyncio.wait_for(app["check_running_future"],
                                          0) == nonce
        log.debug("server check passed")

        start_addr = str(url_for("start_oauth", app=app, site=site))
        log.info("Go to the following address to log in via OAuth1: %s",
                 start_addr)
        if open_browser is True:
            import webbrowser
            open_browser = webbrowser.open
        if callable(open_browser):
            await asyncio.get_event_loop().run_in_executor(
                None, lambda: open_browser(start_addr)),
        return await app["finished_client_future"]
    finally:
        await runner.cleanup()
Exemple #3
0
def run_website(args: argparse.Namespace) -> None:
    """
    Starts the website, connects the database, logs in the specified bots, runs the async loop forever.

    Parameters
    -----------
    args: :class:`argparse.Namespace`
        The arguments namespace that wants to be run.
    """

    # Load our imports here so we don't need to require them all the time
    from aiohttp.web import Application, AppRunner, TCPSite
    from aiohttp_jinja2 import setup as jinja_setup
    from aiohttp_session import setup as session_setup, SimpleCookieStorage
    from aiohttp_session.cookie_storage import EncryptedCookieStorage as ECS
    from jinja2 import FileSystemLoader
    import re
    import html
    from datetime import datetime as dt
    import markdown

    os.chdir(args.website_directory)
    set_event_loop()

    # Read config
    with open(args.config_file) as a:
        config = toml.load(a)

    # Create website object - don't start based on argv
    app = Application(loop=asyncio.get_event_loop(), debug=args.debug)
    app['static_root_url'] = '/static'
    for route in config['routes']:
        module = importlib.import_module(f"website.{route}", "temp")
        app.router.add_routes(module.routes)
    app.router.add_static('/static', os.getcwd() + '/website/static', append_version=True)

    # Add middlewares
    if args.debug:
        session_setup(app, SimpleCookieStorage(max_age=1_000_000))
    else:
        session_setup(app, ECS(os.urandom(32), max_age=1_000_000))
    jinja_env = jinja_setup(app, loader=FileSystemLoader(os.getcwd() + '/website/templates'))

    # Add our jinja env filters
    def regex_replace(string, find, replace):
        return re.sub(find, replace, string, re.IGNORECASE | re.MULTILINE)

    def escape_text(string):
        return html.escape(string)

    def timestamp(string):
        return dt.fromtimestamp(float(string))

    def int_to_hex(string):
        return format(hex(int(string))[2:], "0>6")

    def to_markdown(string):
        return markdown.markdown(string, extensions=['extra'])

    def display_mentions(string, users):
        def get_display_name(group):
            user = users.get(group.group('userid'))
            if not user:
                return 'unknown-user'
            return user.get('display_name') or user.get('username')
        return re.sub(
            '(?:<|(?:&lt;))@!?(?P<userid>\\d{16,23})(?:>|(?:&gt;))',
            lambda g: f'<span class="chatlog__mention">@{get_display_name(g)}</span>',
            string,
            re.IGNORECASE | re.MULTILINE,
        )

    def display_emojis(string):
        def get_html(group):
            return (
                f'<img class="discord_emoji" src="https://cdn.discordapp.com/emojis/{group.group("id")}'
                f'.{"gif" if group.group("animated") else "png"}" alt="Discord custom emoji: '
                f'{group.group("name")}" style="height: 1em; width: auto;">'
            )
        return re.sub(
            r"(?P<emoji>(?:<|&lt;)(?P<animated>a)?:(?P<name>\w+):(?P<id>\d+)(?:>|&gt;))",
            get_html,
            string,
            re.IGNORECASE | re.MULTILINE,
        )

    jinja_env.filters['regex_replace'] = regex_replace
    jinja_env.filters['escape_text'] = escape_text
    jinja_env.filters['timestamp'] = timestamp
    jinja_env.filters['int_to_hex'] = int_to_hex
    jinja_env.filters['markdown'] = to_markdown
    jinja_env.filters['display_mentions'] = display_mentions
    jinja_env.filters['display_emojis'] = display_emojis

    # Add our connections and their loggers
    app['database'] = DatabaseWrapper
    app['redis'] = RedisConnection
    app['logger'] = logger.getChild("route")
    app['stats'] = StatsdConnection

    # Add our config
    app['config'] = config

    loop = app.loop

    # Connect the database pool
    if app['config'].get('database', {}).get('enabled', False):
        db_connect_task = start_database_pool(app['config'])
        loop.run_until_complete(db_connect_task)

    # Connect the redis pool
    if app['config'].get('redis', {}).get('enabled', False):
        re_connect = start_redis_pool(app['config'])
        loop.run_until_complete(re_connect)

    # Add our bots
    app['bots'] = {}
    for index, (bot_name, bot_config_location) in enumerate(config.get('discord_bot_configs', dict()).items()):
        bot = Bot(f"./config/{bot_config_location}")
        app['bots'][bot_name] = bot
        if index == 0:
            set_default_log_levels(args)
        try:
            loop.run_until_complete(bot.login())
            bot.load_all_extensions()
        except Exception:
            logger.error(f"Failed to start bot {bot_name}", exc_info=True)
            exit(1)

    # Start the HTTP server
    logger.info("Creating webserver...")
    application = AppRunner(app)
    loop.run_until_complete(application.setup())
    webserver = TCPSite(application, host=args.host, port=args.port)

    # Start the webserver
    loop.run_until_complete(webserver.start())
    logger.info(f"Server started - http://{args.host}:{args.port}/")

    # This is the forever loop
    try:
        logger.info("Running webserver")
        loop.run_forever()
    except KeyboardInterrupt:
        pass

    # We're now done running the bot, time to clean up and close
    loop.run_until_complete(application.cleanup())
    if config.get('database', {}).get('enabled', False):
        logger.info("Closing database pool")
        try:
            if DatabaseWrapper.pool:
                loop.run_until_complete(asyncio.wait_for(DatabaseWrapper.pool.close(), timeout=30.0))
        except asyncio.TimeoutError:
            logger.error("Couldn't gracefully close the database connection pool within 30 seconds")
    if config.get('redis', {}).get('enabled', False):
        logger.info("Closing redis pool")
        RedisConnection.pool.close()

    logger.info("Closing asyncio loop")
    loop.stop()
    loop.close()
Exemple #4
0
 def _new_transport_tcp(self) -> BaseSite:
     return TCPSite(
         self._runner,
         self.app.conf.web_bind,
         self.app.conf.web_port,
     )
Exemple #5
0
 async def run_web_app(cls,app,host,port):
     runner = AppRunner(app)
     await runner.setup()
     site = TCPSite(runner, host,port)
     await site.start()
Exemple #6
0
def run_interactions(args: argparse.Namespace) -> None:
    """
    Starts the bot, connects the database, runs the async loop forever.

    Parameters
    -----------
    args: :class:`argparse.Namespace`
        The arguments namespace that wants to be run.
    """

    from aiohttp.web import Application, AppRunner, TCPSite
    os.chdir(args.bot_directory)
    set_event_loop()

    # And run file
    bot = Bot(config_file=args.config_file, intents=discord.Intents.none())
    loop = bot.loop
    EventLoopCallbackHandler.bot = bot

    # Set up loggers
    bot.logger = logger.getChild("bot")
    set_default_log_levels(args)

    # Connect the database pool
    if bot.config.get('database', {}).get('enabled', False):
        db_connect_task = start_database_pool(bot.config)
        loop.run_until_complete(db_connect_task)

    # Connect the redis pool
    if bot.config.get('redis', {}).get('enabled', False):
        re_connect = start_redis_pool(bot.config)
        loop.run_until_complete(re_connect)

    # Load the bot's extensions
    logger.info('Loading extensions... ')
    bot.load_all_extensions()

    # Run the bot
    logger.info("Logging in bot")
    loop.run_until_complete(bot.login())
    websocket_task = None
    if args.connect:
        logger.info("Connecting bot to gateway")
        websocket_task = loop.create_task(bot.connect())

    # Create the webserver
    app = Application(loop=asyncio.get_event_loop(), debug=args.debug)
    app.router.add_routes(commands.get_interaction_route_table(bot, bot.config.get("pubkey", ""), path=args.path))

    # Start the HTTP server
    logger.info("Creating webserver...")
    application = AppRunner(app)
    loop.run_until_complete(application.setup())
    webserver = TCPSite(application, host=args.host, port=args.port)

    # Start the webserver
    loop.run_until_complete(webserver.start())
    logger.info(f"Server started - http://{args.host}:{args.port}/")

    # This is the forever loop
    try:
        logger.info("Running webserver")
        loop.run_forever()
    except KeyboardInterrupt:
        pass

    # We're now done running the webserver, time to clean up and close
    if websocket_task:
        websocket_task.cancel()
    if bot.config.get('database', {}).get('enabled', False):
        logger.info("Closing database pool")
        try:
            if DatabaseWrapper.pool:
                loop.run_until_complete(asyncio.wait_for(DatabaseWrapper.pool.close(), timeout=30.0))
        except asyncio.TimeoutError:
            logger.error("Couldn't gracefully close the database connection pool within 30 seconds")
    if bot.config.get('redis', {}).get('enabled', False):
        logger.info("Closing redis pool")
        RedisConnection.pool.close()

    logger.info("Closing asyncio loop")
    loop.stop()
    loop.close()
Exemple #7
0
            utils.DatabaseConnection.create_pool(app['config']['database']))

    # Connect the redis pool
    if app['config'].get('redis', {}).get('enabled', True):
        logger.info("Creating redis pool")
        loop.run_until_complete(
            utils.RedisConnection.create_pool(app['config']['redis']))

    # Start the server unless I said otherwise
    webserver = None

    # HTTP server
    logger.info("Creating webserver...")
    application = AppRunner(app)
    loop.run_until_complete(application.setup())
    webserver = TCPSite(application, host=args.host, port=args.port)

    # Start server
    loop.run_until_complete(webserver.start())
    logger.info(f"Server started - http://{args.host}:{args.port}/")

    # This is the forever loop
    try:
        logger.info("Running webserver")
        loop.run_forever()
    except KeyboardInterrupt:
        pass

    # Clean up our shit
    logger.info("Closing webserver")
    loop.run_until_complete(application.cleanup())
Exemple #8
0
    loop = app.loop

    logger.info("Creating database pool")
    loop.run_until_complete(
        DatabaseConnection.create_pool(app['config']['database']))

    # Start the server unless I said otherwise
    webserver = None
    ssl_webserver = None

    # HTTP server
    logger.info("Creating webserver...")
    application = AppRunner(app)
    loop.run_until_complete(application.setup())
    webserver = TCPSite(application, host=args.host, port=args.port)

    # SSL server
    try:
        if not args.nossl:
            ssl_context = SSLContext()
            ssl_context.load_cert_chain(**app['config']['ssl_context'])
            ssl_webserver = TCPSite(application,
                                    host=args.host,
                                    port=args.sslport,
                                    ssl_context=ssl_context)
    except Exception as e:
        ssl_webserver = None
        logger.exception("Could not make SSL webserver")

    # Start servers
Exemple #9
0
async def run_app(host: str, port: int) -> None:
    runner = AppRunner(app)
    await runner.setup()
    site = TCPSite(runner, host, port)
    await site.start()
Exemple #10
0
async def test_cuncurrent_transactions(event_loop, unused_tcp_port):
    """
    This test tests aiohttp_json_rpc.django.patch_db_connections.

    The test sets up a JsonRpc and starts two concurrent clients.
    Both clients try to open a Django transaction.
    The test is successful if only the first client is able to commit its
    database changes.

    Note:
        The transactions are slowed down artificial and Client #2 sleeps 200ms
        on start using asyncio.sleep to make the test log more readable and
        ensure the transactions are concurrent.

    Note:
        The test starts an watchdog to make sure the test does not hang if the
        rpc communication is broken or hanging.
    """

    from django_project.models import Item
    from aiohttp_json_rpc.django import patch_db_connections

    def create_client(client_id, *args, **kwargs):
        url = 'http://localhost:{}'.format(unused_tcp_port)
        future = asyncio.ensure_future(client(client_id, url, *args, **kwargs))
        future.client_id = client_id

        return future

    patch_db_connections()

    # just to be sure
    assert Item.objects.count() == 0

    # setup rpc
    app = Application()
    rpc = JsonRpc()

    rpc.add_methods(
        ('', add),
    )

    app.router.add_route('*', '/', rpc.handle_request)

    runner = AppRunner(app)
    await runner.setup()
    site = TCPSite(runner, 'localhost', unused_tcp_port)
    await site.start()

    # setup clients and watchdog
    tasks = [
        create_client(1, list(range(0, 10))),
        create_client(2, list(range(2, 5)), sleep=0.2),
    ]

    tasks = [
        *tasks,
        asyncio.ensure_future(watchdog(tasks)),
    ]

    # run
    await asyncio.gather(*tasks)

    # checks
    assert Item.objects.filter(client_id=1).count() == 10
    assert not Item.objects.filter(client_id=2).exists()

    assert tasks[0].result() == 0  # client #1
    assert tasks[1].result() == 1  # client #2
    assert tasks[2].result() == 0  # watchdog
Exemple #11
0
if __name__ == '__main__':
    '''
    Starts the bot (and webserver if specified) and runs forever
    '''

    loop = bot.loop

    print("Starting bot...")
    bot.loop.create_task(bot.start_all())

    if not args.noserver:
        print("Starting server...")
        web_runner = AppRunner(app)
        loop.run_until_complete(web_runner.setup())
        site = TCPSite(web_runner, args.host, args.port)
        loop.run_until_complete(site.start())
        print(f"Server started: http://{args.host}:{args.port}/")

        # Store stuff in the bot for later
        bot.web_runner = web_runner

    # This is the forever loop
    try:
        loop.run_forever()
    except (Exception, KeyboardInterrupt):
        pass
    finally:
        # Logout the bot
        loop.run_until_complete(bot.logout())