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
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
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)
# 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