Пример #1
0
 async def my_exec(self, ctx: commands.Context, *args, **kwargs) -> bool:
     tasks: List[asyncio.Task] = [
         asyncio.create_task(
             ctx.bot.wait_for("message",
                              check=MessagePredicate.cancelled(ctx))),
         asyncio.create_task(self._my_exec(ctx, *args, **kwargs)),
     ]
     async with ctx.typing():
         done, pending = await asyncio.wait(
             tasks, return_when=asyncio.FIRST_COMPLETED)
     for task in pending:
         task.cancel()
     result = done.pop().result()
     if isinstance(result, bool):
         return result
     # wait_for finished
     # do nothing
     return False
Пример #2
0
 async def my_exec(self, ctx: commands.Context, *args, **kwargs) -> None:
     tasks = [
         ctx.bot.wait_for("message", check=MessagePredicate.cancelled(ctx)),
         self._my_exec(ctx, *args, **kwargs),
     ]
     async with ctx.typing():
         done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
     for task in pending:
         task.cancel()
     for task in done:
         result = task.result()
         if not result:
             # _my_exec finished
             return
         # wait_for finished
         assert isinstance(result, discord.Message)
         if not ctx.channel.permissions_for(
             ctx.me
         ).add_reactions or not await ctx.react_quietly("\N{CROSS MARK}"):
             await ctx.send("Cancelled.")
Пример #3
0
    async def logsfrom(
        self,
        ctx,
        after: Optional[discord.PartialMessage] = None,
        before: Optional[discord.PartialMessage] = None,
        *,
        channel: discord.TextChannel = None,
    ):
        """
        Logs the specified channel into a file, then uploads the file.

        The channel will default to the current channel if none is specified.
        The limit may be the number of messages to log or the ID of the message to start after, exclusive.
        All timestamps are in UTC.
        """
        if channel:
            ctxc = copy(ctx)
            ctxc.channel = channel
        else:
            channel = ctx.channel
            ctxc = ctx
        if not channel.permissions_for(ctx.me).read_message_history:
            raise commands.BotMissingPermissions(["read_message_history"])
        if not await check_permissions(ctxc, {"read_message_history": True}):
            raise commands.MissingPermissions(["read_message_history"])
        after, before = getattr(after, "id",
                                after), getattr(before, "id", before)
        cancel_task = asyncio.ensure_future(
            ctx.bot.wait_for("message", check=MessagePredicate.cancelled(ctx)))
        async with ctx.typing():
            kwargs = {"oldest_first": False}
            if not after and not before:
                kwargs["limit"] = 100
            elif not before:
                kwargs.update(after=discord.Object(id=after), limit=after)
            elif not after:
                raise RuntimeError("This should never happen.")
            else:
                before = min((ctx.message.id, before))
                # TODO: wtf should this shit even *mean*
                if after >= before:
                    kwargs.update(after=discord.Object(id=after),
                                  limit=before,
                                  oldest_first=True)
                else:
                    kwargs.update(
                        after=discord.Object(id=after),
                        before=discord.Object(id=before),
                        limit=min((before, after)),
                    )
            print(kwargs)
            stream = io.BytesIO()
            last_h = MHeaders(None, None, None)
            message_task = asyncio.ensure_future(history(channel, **kwargs))
            done, _ = await asyncio.wait((cancel_task, message_task),
                                         return_when=asyncio.FIRST_COMPLETED)
            if cancel_task in done:
                message_task.cancel()
                return await ctx.send(_T("Okay, I've cancelled my logging."))
            messages = message_task.result()
            processed = 0
            pop = messages.popleft if kwargs["oldest_first"] else messages.pop
            while messages:
                await asyncio.sleep(0)
                if cancel_task.done():
                    return await ctx.send(
                        _T("Okay, I've cancelled my logging."))
                message = pop()
                now_h = MHeaders(message.author, message.created_at,
                                 message.edited_at)
                headers = now_h.to_str(last_h)
                last_h = now_h
                if headers:
                    stream.write(headers.encode("utf-8"))
                stream.write(message.clean_content.encode("utf-8"))
                if message.attachments:
                    stream.write(b"\n")
                    stream.write("; ".join(
                        f"[{a.filename}]({a.url})"
                        for a in message.attachments).encode("utf-8"))
                stream.write(b"\n")
                processed += 1
            cancel_task.cancel()
            stream.seek(0)
            return await ctx.send(
                content=_T("{} message{s} logged.").format(
                    processed, s=("" if processed == 1 else "s")),
                file=discord.File(stream, filename=f"{channel.name}.md"),
                delete_after=300,
            )