예제 #1
0
 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")
예제 #2
0
    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")
예제 #3
0
    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)
예제 #4
0
    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)
예제 #5
0
    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)
예제 #6
0
    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)
예제 #7
0
    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")
예제 #8
0
 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")
예제 #9
0
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")