async def prepare(cls, db_cursor: aiomysql.DictCursor) -> 'Clans': """Fetch data from sql & return; preparing to run the server.""" log('Fetching clans from sql.', Ansi.LCYAN) await db_cursor.execute('SELECT * FROM clans') obj = cls([Clan(**row) async for row in db_cursor]) for clan in obj: await clan.members_from_sql(db_cursor) return obj
async def prepare(cls) -> None: """Fetch data from sql & return; preparing to run the server.""" log('Fetching clans from sql', Ansi.LCYAN) res = await glob.db.fetchall('SELECT * FROM clans') obj = cls([Clan(**row) for row in res]) for clan in obj: await clan.members_from_sql() return obj
async def connect( ) -> None: # ran before server startup, used to do things like connecting to mysql :D info(f"Asahi v{glob.version} starting") glob.web = ClientSession() # aiohttp session for external web requests from lists.players import PlayerList glob.players = PlayerList() # init player list try: glob.db = await fatFawkSQL.connect(**glob.config.sql ) # connect to db using config :p debug("Asahi connected to MySQL") except Exception: error(f"Asahi failed to connect to MySQL\n\n{traceback.format_exc()}") raise SystemExit(1) try: glob.redis = await aioredis.create_redis_pool( f"redis://{glob.config.redis['host']}", db=glob.config.redis["db"], password=glob.config.redis["password"] or None, ) debug("Asahi connected to Redis") except Exception: error(f"Asahi failed to connect to Redis\n\n{traceback.format_exc()}") raise SystemExit(1) from objects.player import Player botinfo = await glob.db.fetchrow( "SELECT name, pw, country, name FROM users WHERE id = 1", ) if not botinfo: error( "Bot account not found. " "Please insert the bot account with user ID 1 and start Asahi again" ) raise SystemExit(1) glob.bot = Player( id=1, name=botinfo["name"], offset=1, country_iso=botinfo["country"], country=country_codes[botinfo["country"].upper()], ) await glob.bot.set_stats() glob.players.append(glob.bot) debug(f"Added bot {glob.bot.name} to player list") async for ach_row in glob.db.iter("SELECT * FROM achievements"): ach_row["cond"] = eval(f'lambda s: {ach_row["cond"]}') ach_row["desc"] = ach_row.pop("descr") glob.achievements.append(Achievement(**ach_row)) init_customs() # set custom achievements list for assets proxy # add all channels to cache from objects.channel import Channel async for chan_row in glob.db.iter("SELECT * FROM channels"): chan_row["desc"] = chan_row.pop("descr") channel = Channel(**chan_row) glob.channels[channel.name] = channel debug(f"Added channel {channel.name} to channel list") # add announce channel to cache announce = Channel( name="#announce", desc="#1 scores and public announcements will be posted here", auto=True, perm=True, ) glob.channels[announce.name] = announce debug("Added channel #announce to channel list") # add lobby channel to cache lobby = Channel(name="#lobby", desc="Multiplayer lobby", auto=False, perm=True) glob.channels[lobby.name] = lobby debug("Added channel #lobby to channel list") # add all clans to cache async for clan_row in glob.db.iter("SELECT * FROM clans"): clan = Clan(**clan_row) clan_chan = Channel( name="#clan", desc=f"Clan chat for clan {clan.name}", auto=False, perm=True, ) clan.chan = clan_chan # uwu glob.clans[clan.id] = clan clan.country = await glob.db.fetchval( "SELECT country FROM users WHERE id = %s", [clan.owner], ) async for member_row in glob.db.iter( "SELECT id FROM users WHERE clan = %s", [clan.id], ): clan.members.append(member_row["id"]) await glob.redis.zadd(f"asahi:clan_leaderboard", clan.score, clan.id) await glob.redis.zadd( f"asahi:clan_leaderboard:{clan.country}", clan.score, clan.id, ) r = await glob.redis.zrevrank(f"asahi:clan_leaderboard", clan.id) cr = await glob.redis.zrevrank( f"asahi:clan_leaderboard:{clan.country}", clan.id, ) clan.rank = r + 1 if r else 0 clan.country_rank = cr + 1 if cr else 0 debug(f"Added clan {clan.name} to clan list") await prepare_tasks() # make new db conn for donor/freeze tasks glob.app.add_task(expired_donor) glob.app.add_task(freeze_timers) info(f"Asahi v{glob.version} started")
if glob.clans.get(name=name): return 'That name has already been claimed by another clan.' if glob.clans.get(tag=tag): return 'That tag has already been claimed by another clan.' created_at = datetime.now() # add clan to sql (generates id) id = await glob.db.execute( 'INSERT INTO clans ' '(name, tag, created_at, owner) ' 'VALUES (%s, %s, %s, %s)', [name, tag, created_at, p.id]) # add clan to cache clan = Clan(id=id, name=name, tag=tag, created_at=created_at, owner=p.id) glob.clans.append(clan) # set owner's clan & clan rank (cache & sql) p.clan = clan p.clan_rank = ClanRank.Owner clan.owner = p.id clan.members.add(p.id) await glob.db.execute( 'UPDATE users ' 'SET clan_id = %s, ' 'clan_rank = 3 ' # ClanRank.Owner 'WHERE id = %s', [id, p.id])
async def setup_collections() -> None: """Setup & cache many global collections (mostly from sql).""" # create our bot & append it to the global player list. res = await glob.db.fetch('SELECT name FROM users WHERE id = 1') # global players list glob.players = PlayerList() glob.bot = Player( id=1, name=res['name'], priv=Privileges.Normal, last_recv_time=float(0x7fffffff) # never auto-dc ) glob.players.append(glob.bot) # global channels list glob.channels = ChannelList() async for res in glob.db.iterall('SELECT * FROM channels'): chan = Channel(name=res['name'], topic=res['topic'], read_priv=Privileges(res['read_priv']), write_priv=Privileges(res['write_priv']), auto_join=res['auto_join'] == 1) glob.channels.append(chan) # global matches list glob.matches = MatchList() # global clans list glob.clans = ClanList() async for res in glob.db.iterall('SELECT * FROM clans'): clan = Clan(**res) await clan.members_from_sql() glob.clans.append(clan) # global mappools list glob.pools = MapPoolList() async for res in glob.db.iterall('SELECT * FROM tourney_pools'): pool = MapPool(id=res['id'], name=res['name'], created_at=res['created_at'], created_by=await glob.players.get_ensure(id=res['created_by'])) await pool.maps_from_sql() glob.pools.append(pool) # global achievements (sorted by vn gamemodes) glob.achievements = {0: [], 1: [], 2: [], 3: []} async for res in glob.db.iterall( 'SELECT `id`, `file`, `name`, `desc`, `cond`, `mode` FROM achievements' ): # NOTE: achievement conditions are stored as # stringified python expressions in the database # to allow for easy custom achievements. condition = eval(f'lambda score: {res.pop("cond")}') achievement = Achievement(**res, cond=condition) # NOTE: achievements are grouped by modes internally. glob.achievements[res['mode']].append(achievement) """ XXX: Unfinished code for beatmap submission.
async def on_start() -> None: glob.http = aiohttp.ClientSession(json_serialize=orjson.dumps) # connect to mysql glob.db = cmyui.AsyncSQLPool() await glob.db.connect(glob.config.mysql) # run the sql updater updater = Updater(glob.version) await updater.run() await updater.log_startup() # create our bot & append it to the global player list. glob.bot = Player(id=1, name='Aika', priv=Privileges.Normal) glob.bot.last_recv_time = float(0x7fffffff) glob.players.append(glob.bot) # TODO: this section is getting a bit gross.. :P # should be moved and probably refactored pretty hard. # add all channels from db. async for c_res in glob.db.iterall('SELECT * FROM channels'): c_res['read_priv'] = Privileges(c_res.get('read_priv', 1)) c_res['write_priv'] = Privileges(c_res.get('write_priv', 2)) glob.channels.append(Channel(**c_res)) # add all mappools from db. async for p_res in glob.db.iterall('SELECT * FROM tourney_pools'): # overwrite basic types with some class types creator = await glob.players.get(id=p_res['created_by'], sql=True) p_res['created_by'] = creator # replace id with player object pool = MapPool(**p_res) await pool.maps_from_sql() glob.pools.append(pool) # add all clans from db. async for c_res in glob.db.iterall('SELECT * FROM clans'): # fetch all members from sql m_res = await glob.db.fetchall( 'SELECT id, clan_rank ' 'FROM users ' 'WHERE clan_id = %s', c_res['id'], _dict=False) members = set() for p_id, clan_rank in m_res: if clan_rank == 3: c_res['owner'] = p_id members.add(p_id) glob.clans.append(Clan(**c_res, members=members)) # add all achievements from db. async for a_res in glob.db.iterall('SELECT * FROM achievements'): condition = eval(f'lambda score: {a_res.pop("cond")}') achievement = Achievement(**a_res, cond=condition) glob.achievements[a_res['mode']].append(achievement) """ bmsubmit stuff # get the latest set & map id offsets for custom maps. maps_res = await glob.db.fetch( 'SELECT id, set_id FROM maps ' 'WHERE server = "gulag" ' 'ORDER BY id ASC LIMIT 1' ) if maps_res: glob.gulag_maps = maps_res """ # add new donation ranks & enqueue tasks to remove current ones. # TODO: this system can get quite a bit better; rather than just # removing, it should rather update with the new perks (potentially # a different tier, enqueued after their current perks). async def rm_donor(userid: int, delay: int): await asyncio.sleep(delay) p = await glob.players.get(id=userid, sql=True) await p.remove_privs(Privileges.Donator) log(f"{p}'s donation perks have expired.", Ansi.MAGENTA) query = ('SELECT id, donor_end FROM users ' 'WHERE donor_end > UNIX_TIMESTAMP()') async for donation in glob.db.iterall(query): # calculate the delta between now & the exp date. delta = donation['donor_end'] - time.time() if delta > (60 * 60 * 24 * 30): # ignore donations expiring in over a months time; # the server should restart relatively often anyways. continue asyncio.create_task(rm_donor(donation['id'], delta))
async def connect( ) -> None: # ran before server startup, used to do things like connecting to mysql :D log(f'==== Asahi v{glob.version} starting ====', Ansi.GREEN) glob.web = ClientSession() # aiohttp session for external web requests glob.players = PlayerList() # init player list try: glob.db = await fatFawkSQL.connect(**glob.config.sql ) # connect to db using config :p if glob.config.debug: log('==== Asahi connected to MySQL ====', Ansi.GREEN) except Exception as error: log(f'==== Asahi failed to connect to MySQL ====\n\n{error}', Ansi.LRED) try: glob.redis = await aioredis.create_redis_pool( f"redis://{glob.config.redis['host']}", db=glob.config.redis['db'], password=glob.config.redis['password'] or None) if glob.config.debug: log('==== Asahi connected to Redis ====', Ansi.GREEN) except Exception as error: log(f'==== Asahi failed to connect to Redis ====\n\n{error}', Ansi.LRED) if not AVA_PATH.exists(): AVA_PATH.mkdir(parents=True) log( 'Avatars folder has been created, please set a default avatar by placing a file named "default.png" into resources/avatars!', Ansi.LRED) for directory in (SS_PATH, R_PATH, RRX_PATH, RAP_PATH, MAPS_PATH, ACHIEVEMENTS_PATH): if not directory.exists(): directory.mkdir(parents=True) botinfo = await glob.db.fetchrow( 'SELECT name, pw, country, name FROM users WHERE id = 1') glob.bot = Player(id=1, name=botinfo['name'], offset=1, country_iso=botinfo['country'], country=country_codes[botinfo['country'].upper()]) glob.players.append(glob.bot) if glob.config.debug: log(f"==== Added bot {glob.bot.name} to player list ====", Ansi.GREEN) async for clan_row in glob.db.iter('SELECT * FROM achievements'): clan_row['cond'] = eval(f'lambda s: {clan_row["cond"]}') clan_row['desc'] = clan_row.pop('descr') # TODO: fix in sql glob.achievements.append(**clan_row) init_customs() # set custom achievements list for assets proxy # add all channels to cache async for clan_row in glob.db.iter('SELECT * FROM channels'): clan_row['desc'] = clan_row.pop('descr') # TODO: fix in sql channel = Channel(**clan_row) glob.channels[channel.name] = channel if glob.config.debug: log(f'==== Added channel {channel.name} to channel list ====', Ansi.GREEN) # add announce channel to cache announce = Channel( name='#announce', desc='#1 scores and public announcements will be posted here', auto=True, perm=True) glob.channels[announce.name] = announce if glob.config.debug: log('==== Added channel #announce to channel list ====', Ansi.GREEN) # add lobby channel to cache lobby = Channel(name='#lobby', desc='Multiplayer lobby', auto=False, perm=True) glob.channels[lobby.name] = lobby if glob.config.debug: log('==== Added channel #lobby to channel list ====', Ansi.GREEN) # add all clans to cache async for clan_row in glob.db.iter('SELECT * FROM clans'): clan = Clan(**clan_row) clan_chan = Channel(name='#clan', desc=f'Clan chat for clan {clan.name}', auto=False, perm=True) clan.chan = clan_chan # uwu glob.clans[clan.id] = clan async for member_row in glob.db.iter( 'SELECT id FROM users WHERE clan = %s', [clan.id]): clan.members.append(member_row['id']) if glob.config.debug: log(f'==== Added clan {clan.name} to clan list ====', Ansi.GREEN) await prepare_tasks() # make new db conn for donor/freeze tasks log(f'==== Asahi v{glob.version} started ====', Ansi.GREEN)