Ejemplo n.º 1
0
async def main() -> int:
    """Initialize, and start up the server."""
    glob.loop = asyncio.get_running_loop()

    async with (
        misc.context.acquire_http_session(glob.has_internet) as glob.http_session,
        misc.context.acquire_mysql_db_pool(glob.config.mysql) as glob.db,
        misc.context.acquire_redis_db_pool() as glob.redis,
    ):
        await misc.utils.check_for_dependency_updates()
        await misc.utils.run_sql_migrations()

        with (
            misc.context.acquire_geoloc_db_conn(GEOLOC_DB_FILE) as glob.geoloc_db,
            misc.context.acquire_datadog_client(glob.config.datadog) as glob.datadog,
        ):
            # TODO: refactor debugging so
            # this can be moved to `run_server`.
            glob.app = cmyui.Server(
                name=f"gulag v{glob.version}",
                gzip=4,
                debug=glob.config.debug,
            )

            # prepare our ram caches, populating from sql where necessary.
            # this includes channels, clans, mappools, bot info, etc.
            async with glob.db.pool.acquire() as conn:
                async with conn.cursor(aiomysql.DictCursor) as db_cursor:
                    await objects.collections.initialize_ram_caches(db_cursor)  # type: ignore

            # initialize housekeeping tasks to automatically manage
            # and ensure memory on ram & disk are kept up to date.
            await bg_loops.initialize_housekeeping_tasks()

            # handle signals so we can ensure a graceful shutdown
            sig_handler = misc.utils.shutdown_signal_handler
            for signum in (signal.SIGINT, signal.SIGTERM, signal.SIGHUP):
                glob.loop.add_signal_handler(signum, sig_handler, signum)

            # TODO: restart signal handler with SIGUSR1

            # run the server, handling connections
            # until a termination signal is received.
            await run_server()

            # we want to attempt to gracefully finish any ongoing connections
            # and shut down any of the housekeeping tasks running in the background.

            if glob.ongoing_conns:
                await misc.utils.await_ongoing_connections(timeout=5.0)

            await misc.utils.cancel_housekeeping_tasks()

    return 0
Ejemplo n.º 2
0
def create_server() -> cmyui.Server:
    """Create a server object, containing all domains & their endpoints."""
    server = cmyui.Server(name=f'gulag v{glob.version}',
                          gzip=4,
                          debug=glob.config.debug)

    # fetch the domains our server is able to handle
    # each may potentially hold many individual endpoints.
    from domains.cho import domain as cho_domain  # c[e4-6]?.ppy.sh
    from domains.osu import domain as osu_domain  # osu.ppy.sh
    from domains.ava import domain as ava_domain  # a.ppy.sh
    from domains.map import domain as map_domain  # b.ppy.sh
    server.add_domains({cho_domain, osu_domain, ava_domain, map_domain})

    # enqueue tasks to run once the server
    # begins, and stops serving connections.
    # these make sure we set everything up
    # and take it down nice and graceful.
    server.before_serving = before_serving
    server.after_serving = after_serving

    return server
Ejemplo n.º 3
0
def main() -> None:
    """Attempt to start up gulag."""
    # make sure we're running on an appropriate
    # platform with all required software.
    ensure_platform()

    # make sure all required services
    # are being run in the background.
    ensure_services()

    # warn the user if gulag is running on root.
    if os.geteuid() == 0:
        log(
            'It is not recommended to run gulag as root, '
            'especially in production..', Ansi.LYELLOW)

        if glob.config.advanced:
            log(
                'The risk is even greater with features '
                'such as config.advanced enabled.', Ansi.LRED)

    # check whether we are connected to the internet.
    glob.has_internet = utils.misc.check_connection(timeout=1.5)
    if not glob.has_internet:
        log('Running in offline mode, some features '
            'will not be available.', Ansi.LRED)

    # create /.data and its subdirectories.
    data_path = Path.cwd() / '.data'
    data_path.mkdir(exist_ok=True)

    for sub_dir in ('avatars', 'logs', 'osu', 'osr', 'ss'):
        subdir = data_path / sub_dir
        subdir.mkdir(exist_ok=True)

    achievements_path = data_path / 'assets/medals/client'
    if not achievements_path.exists():
        # create directory & download achievement images
        achievements_path.mkdir(parents=True)
        utils.misc.download_achievement_images(achievements_path)

    # make sure oppai-ng binary is built and ready.
    if not OPPAI_PATH.exists():
        log('No oppai-ng submodule found, attempting to clone.', Ansi.LMAGENTA)
        p = subprocess.Popen(args=['git', 'submodule', 'init'],
                             stdout=subprocess.DEVNULL,
                             stderr=subprocess.DEVNULL)
        if p.wait() == 1:
            sys.exit('Failed to initialize git submodules.')

        p = subprocess.Popen(args=['git', 'submodule', 'update'],
                             stdout=subprocess.DEVNULL,
                             stderr=subprocess.DEVNULL)
        if p.wait() == 1:
            sys.exit('Failed to update git submodules.')

    if not (OPPAI_PATH / 'oppai').exists():
        log('No oppai-ng binary found, attempting to build.', Ansi.LMAGENTA)
        p = subprocess.Popen(args=['./build'],
                             cwd='oppai-ng',
                             stdout=subprocess.DEVNULL,
                             stderr=subprocess.DEVNULL)
        if p.wait() == 1:
            sys.exit('Failed to build oppai-ng automatically.')

    # create a server object, which serves as a map of domains.
    app = glob.app = cmyui.Server(name=f'gulag v{glob.version}',
                                  gzip=4,
                                  debug=glob.config.debug)

    # add our endpoint's domains to the server;
    # each may potentially hold many individual endpoints.
    from domains.cho import domain as cho_domain  # c[e4-6]?.ppy.sh
    from domains.osu import domain as osu_domain  # osu.ppy.sh
    from domains.ava import domain as ava_domain  # a.ppy.sh
    from domains.map import domain as map_domain  # b.ppy.sh
    app.add_domains({cho_domain, osu_domain, ava_domain, map_domain})

    # enqueue tasks to run once the server
    # begins, and stops serving connections.
    # these make sure we set everything up
    # and take it down nice and graceful.
    app.before_serving = before_serving
    app.after_serving = after_serving

    # support for https://datadoghq.com
    if all(glob.config.datadog.values()):
        datadog.initialize(**glob.config.datadog)
        glob.datadog = datadog.ThreadStats()
        glob.datadog.start(flush_in_thread=True, flush_interval=15)

        # wipe any previous stats from the page.
        glob.datadog.gauge('gulag.online_players', 0)
    else:
        glob.datadog = None

    # start up the server; this starts an event loop internally,
    # using uvloop if it's installed. it uses SIGUSR1 for restarts.
    # NOTE: eventually the event loop creation will likely be
    # moved into the gulag codebase for increased flexibility.
    app.run(glob.config.server_addr, handle_restart=True)
Ejemplo n.º 4
0
        # create directory & download achievement pngs
        achievements_path.mkdir(parents=True)
        download_achievement_pngs(achievements_path)

    # make sure oppai-ng is built and ready.
    glob.oppai_built = (Path.cwd() / 'oppai-ng/oppai').exists()

    if not glob.oppai_built:
        log(
            'No oppai-ng compiled binary found. PP for all '
            'std & taiko scores will be set to 0; instructions '
            'can be found in the README file.', Ansi.LRED)

    # create a server object, which serves as a map of domains.
    app = glob.app = cmyui.Server(name=f'gulag v{glob.version}',
                                  gzip=4,
                                  debug=glob.config.debug)

    # add our endpoint's domains to the server;
    # each may potentially hold many individual endpoints.
    from domains.cho import domain as cho_domain  # c[e4-6]?.ppy.sh
    from domains.osu import domain as osu_domain  # osu.ppy.sh
    from domains.ava import domain as ava_domain  # a.ppy.sh
    app.add_domains({cho_domain, osu_domain, ava_domain})

    # enqueue tasks to run once the server
    # begins, and stops serving connections.
    # these make sure we set everything up
    # and take it down nice and graceful.
    app.before_serving = before_serving
    app.after_serving = after_serving