async def on_command_completion(self, context): usr = context.message.author chn = context.channel gld = context.guild asmbot.log( "{} ({}) executed command {} in guild {} ({}) on shard {}, channel {} ({})" .format(usr, usr.id, context.command.qualified_name, gld.name, gld.id, self.shard_id, chn.name, chn.id), tag="ASM CMD")
def run(self, **kwargs): loop = self.loop # core bot config asmbot_shard = kwargs.get("shard_id", 0) asmbot_totalshards = kwargs.get("shard_count", 1) asmbot_token = kwargs.get("token", None) asmbot_script = kwargs.get("script", None) asmbot_blacklist = kwargs.get("guild_blacklist", []) asmbot_exempt_list = kwargs.get("guild_exempt_list", []) # init pam asmbot.log("Initializing ASM", tag="ASM") asmbot_config = { "shard_id": asmbot_shard, "shard_count": asmbot_totalshards } asmbot_bot = asmbot.AsmBot(asmbot_blacklist, asmbot_exempt_list, **asmbot_config) asmbot_bot.remove_command("help") asmbot_cmd = asmbot.AsmBotCommands(asmbot_bot) asmbot_cmd.script = asmbot_script asmbot_bot.add_cog(asmbot_cmd) try: asmbot.log("Shard {} logging in".format(asmbot_bot.shard_id), tag="SHARDMGR") loop.run_until_complete(asmbot_bot.login(asmbot_token)) asmbot.log("Shard {} connecting".format(asmbot_bot.shard_id), tag="SHARDMGR") loop.run_until_complete(asmbot_bot.connect()) except KeyboardInterrupt: pass finally: asmbot.log("Shard {} dying".format(asmbot_bot.shard_id), tag="SHARDMGR") loop.run_until_complete(asmbot_bot.logout()) for task in asyncio.Task.all_tasks(loop): task.cancel() try: loop.run_until_complete(task) except: pass loop.close() asmbot.log("Shard {} died".format(asmbot_bot.shard_id), tag="SHARDMGR")
def _restart_gamewatch(self, fut): self.tasks.remove(fut) fut.cancel() if not self.is_closed() and not self.gamewatch_running: asmbot.log("Gamewatch for shard {} crashed, restarting".format( self.shard_id), tag="ASM GAME") task = self.loop.create_task(self.game_watch()) task.add_done_callback(self._restart_gamewatch) self.tasks.append(task)
async def on_ready(self): self.processed_guilds = [] asmbot.log("Logged in as {} on shard {} as PID {:05}".format( self.user.name, self.shard_id, os.getpid()), tag="ASM CORE") for gld in self.guilds: await self.on_guild_available(gld) task = self.loop.create_task(self.game_watch()) task.add_done_callback(self._restart_gamewatch) self.tasks.append(task)
async def on_guild_available(self, guild): if guild.id in self.processed_guilds: return asmbot.log("Guild available: {}".format(guild.name), tag="ASM CORE") # check blacklist if guild.id in self.guild_exempt_list: asmbot.log("Ignoring exempt guild {} ({})".format( guild.name, guild.id), tag="ASM CORE") self.processed_guilds.append(guild.id) return if guild.id in self.guild_blacklist: asmbot.log("Leaving blacklisted guild {} ({})".format( guild.name, guild.id), tag="ASM CORE") await guild.leave() mra = [0, 0] for xm in guild.members: mra[0] += 1 if xm.bot: mra[1] += 1 if mra[0] - mra[1] > 0: mr = mra[1] / (mra[0] - mra[1]) if mra[0] > 25 and mr >= 0.4: asmbot.log( "Guild {} ({}) has too high bot-to-human ratio ({:.0f}% at {:n} members)" .format(guild.name, guild.id, mr * 100, mra[0]), tag="ASM CORE") await guild.leave() elif mra[0] > 0: asmbot.log( "Guild {} ({}) appears to have no human members ({:n} total)". format(guild.name, guild.id, mra[0]), tag="ASM CORE") await guild.leave() self.processed_guilds.append(guild.id)
async def on_command_error(self, context, exception): extype = type(exception) value = exception tback = exception.__traceback__ exinfo = (extype, value, tback) exfmts = [ s.replace("\\n", "") for s in traceback.format_exception(*exinfo) ] exfmt = [""] for exf in exfmts: ci = len(exfmt) - 1 if len(exfmt[ci]) + len(exf) + 1 > 1024: exfmt.append(exf) else: exfmt[ci] = exfmt[ci] + "\n" + exf if context.command is None: return cmd = context.command.qualified_name iex = exception.original if isinstance( exception, commands.CommandInvokeError) else None if iex and isinstance(iex, asmbot.AssemblerException): embed = self._embed(context, "Error assembling code", "An error occured when assembling code", "error") embed.add_field(name="Details", value=f"```\n{iex.clang_data}\n```", inline=False) else: embed = self._embed( context, "Error executing command", "An error occured when executing command `{}`".format(cmd), "error") asmbot.log(*exfmts, tag="CMD ERR") await context.message.channel.send(embed=embed)
async def game_watch(self): if self.gamewatch_running: return self.gamewatch_running = True try: lop = datetime.datetime(2015, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc) asmbot.log("Gamewatch for shard {} initialized".format( self.shard_id), tag="ASM GAME") while not self.is_closed(): cop = datetime.datetime.now(datetime.timezone.utc) tdelta = cop - lop if tdelta.seconds >= 900: lop = cop await self.change_presence(activity=discord.Game( name="LLVM")) await asyncio.sleep(0.1) except CancelledError as e: pass except Exception as e: asmbot.logex(e, tag="ASM GAME") finally: self.gamewatch_running = False asmbot.log("Gamewatch for shard {} closed".format(self.shard_id), tag="ASM GAME")
async def on_error(self, event, *args, **kwargs): exinfo = sys.exc_info() exfmts = [ s.replace("\\n", "") for s in traceback.format_exception(*exinfo) ] asmbot.log(*exfmts, tag="ASM ERR")
def main(): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) asmbot.log("ASM version {} booting".format(asmbot.__version__), tag="ASM LDR") asmbot.log("Loading config", tag="ASM LDR") configName = f"/run/secrets/{env['DOCKER_SECRET']}" if getenv("DOCKER_SECRET") else "config.json" asmbot.log("Config will be loaded from {}".format(configName), tag="ASM LDR") with open(configName, "r") as f: cts = f.read() tkd = json.loads(cts) asmbot.log("Launching ASM", tag="ASM LDR") mp.set_start_method("spawn") executor = ThreadPoolExecutor(max_workers=int(tkd["shard_count"])) processes = [] for i in range(0, int(tkd["shard_count"])): args = { "token": tkd["token"], "shard_id": i, "shard_count": int(tkd["shard_count"]), "script": tkd["script"], "guild_blacklist": tkd["guild_blacklist"], "guild_exempt_list": tkd["guild_exempt_list"] } loop.create_task(launch_process(executor, asmbotlauncher.initialize_asmbot, **args)) if i != int(tkd["shard_count"]) - 1: loop.run_until_complete(asyncio.sleep(10)) asmbot.log("Running", tag="ASM LDR") try: loop.run_until_complete(asyncio.gather(*asyncio.Task.all_tasks(loop))) except KeyboardInterrupt: pass finally: asmbot.log("Shutting down", tag="ASM LDR") for process in processes: process.join() asmbot.log("Shutdown finalized", tag="ASM LDR")