예제 #1
0
    def __init__(self, token):
        self.token = token
        self.logger = logging.getLogger("pluralkit.bot")

        self.client = discord.Client()
        self.client.event(self.on_error)
        self.client.event(self.on_ready)
        self.client.event(self.on_message)
        self.client.event(self.on_socket_raw_receive)

        self.stats = NullStatCollector()

        self.channel_logger = channel_logger.ChannelLogger(self.client)
        self.proxy = proxy.Proxy(self.client, token, self.channel_logger,
                                 self.stats)
예제 #2
0
def run():
    pool = connect_to_database()

    async def create_tables():
        async with pool.acquire() as conn:
            await db.create_tables(conn)

    asyncio.get_event_loop().run_until_complete(create_tables())

    client = discord.Client()

    logger = channel_logger.ChannelLogger(client)

    @client.event
    async def on_ready():
        print("PluralKit started.")
        print("User: {}#{} (ID: {})".format(client.user.name, client.user.discriminator, client.user.id))
        print("{} servers".format(len(client.guilds)))
        print("{} shards".format(client.shard_count or 1))

        await client.change_presence(activity=discord.Game(name="pk;help"))

    @client.event
    async def on_message(message: discord.Message):
        # Ignore messages from bots
        if message.author.bot:
            return

        # Grab a database connection from the pool
        async with pool.acquire() as conn:
            # First pass: do command handling
            did_run_command = await commands.command_dispatch(client, message, conn)
            if did_run_command:
                return

            # Second pass: do proxy matching
            await proxy.try_proxy_message(conn, message, logger, client.user)

    @client.event
    async def on_raw_message_delete(payload: discord.RawMessageDeleteEvent):
        async with pool.acquire() as conn:
            await proxy.handle_deleted_message(conn, client, payload.message_id, None, logger)

    @client.event
    async def on_raw_bulk_message_delete(payload: discord.RawBulkMessageDeleteEvent):
        async with pool.acquire() as conn:
            for message_id in payload.message_ids:
                await proxy.handle_deleted_message(conn, client, message_id, None, logger)

    @client.event
    async def on_raw_reaction_add(payload: discord.RawReactionActionEvent):
        if payload.emoji.name == "\u274c":  # Red X
            async with pool.acquire() as conn:
                await proxy.try_delete_by_reaction(conn, client, payload.message_id, payload.user_id, logger)

    @client.event
    async def on_error(event_name, *args, **kwargs):
        log_channel_id = os.environ.get("LOG_CHANNEL")
        if not log_channel_id:
            return

        log_channel = client.get_channel(int(log_channel_id))

        # If this is a message event, we can attach additional information in an event
        # ie. username, channel, content, etc
        if args and isinstance(args[0], discord.Message):
            message: discord.Message = args[0]
            embed = embeds.exception_log(
                message.content,
                message.author.name,
                message.author.discriminator,
                message.author.id,
                message.guild.id if message.guild else None,
                message.channel.id
            )
        else:
            # If not, just post the string itself
            embed = None

        if sys.exc_info()[0].__name__ == "MissingPermissions":
            await message.channel.send(str(sys.exc_info()[1]))

        traceback_str = "```python\n{}```".format(traceback.format_exc())
        if len(traceback.format_exc()) >= (2000 - len("```python\n```")):
            traceback_str = "```python\n...{}```".format(traceback.format_exc()[- (2000 - len("```python\n...```")):])
        await log_channel.send(content=traceback_str, embed=embed)

        # Print it to stderr anyway, though
        logging.getLogger("pluralkit").exception("Exception while handling event {}".format(event_name))

    bot_token = os.environ["TOKEN"]
    if not bot_token:
        print("No token specified. Please pass a valid Discord bot token in the TOKEN environment variable.",
              file=sys.stderr)
        sys.exit(1)

    client.run(bot_token)
예제 #3
0
def run(token: str, db_uri: str, log_channel_id: int):
    pool = connect_to_database(db_uri)

    async def create_tables():
        async with pool.acquire() as conn:
            await db.create_tables(conn)

    asyncio.get_event_loop().run_until_complete(create_tables())

    client = discord.Client()
    logger = channel_logger.ChannelLogger(client)

    @client.event
    async def on_ready():
        print("PluralKit started.")
        print("User: {}#{} (ID: {})".format(client.user.name,
                                            client.user.discriminator,
                                            client.user.id))
        print("{} servers".format(len(client.guilds)))
        print("{} shards".format(client.shard_count or 1))

        await client.change_presence(activity=discord.Game(name="pk;help"))

    @client.event
    async def on_message(message: discord.Message):
        # Ignore messages from bots
        if message.author.bot:
            return

        # Grab a database connection from the pool
        async with pool.acquire() as conn:
            # First pass: do command handling
            did_run_command = await commands.command_dispatch(
                client, message, conn)
            if did_run_command:
                return

            # Second pass: do proxy matching
            await proxy.try_proxy_message(conn, message, logger, client.user)

    @client.event
    async def on_raw_message_delete(payload: discord.RawMessageDeleteEvent):
        async with pool.acquire() as conn:
            await proxy.handle_deleted_message(conn, client,
                                               payload.message_id, None,
                                               logger)

    @client.event
    async def on_raw_bulk_message_delete(
            payload: discord.RawBulkMessageDeleteEvent):
        async with pool.acquire() as conn:
            for message_id in payload.message_ids:
                await proxy.handle_deleted_message(conn, client, message_id,
                                                   None, logger)

    @client.event
    async def on_raw_reaction_add(payload: discord.RawReactionActionEvent):
        if payload.emoji.name == "\u274c":  # Red X
            async with pool.acquire() as conn:
                await proxy.try_delete_by_reaction(conn, client,
                                                   payload.message_id,
                                                   payload.user_id, logger)

    @client.event
    async def on_error(event_name, *args, **kwargs):
        # Print it to stderr
        logging.getLogger("pluralkit").exception(
            "Exception while handling event {}".format(event_name))

        # Then log it to the given log channel
        # TODO: replace this with Sentry or something
        if not log_channel_id:
            return
        log_channel = client.get_channel(log_channel_id)

        # If this is a message event, we can attach additional information in an event
        # ie. username, channel, content, etc
        if args and isinstance(args[0], discord.Message):
            message: discord.Message = args[0]
            embed = embeds.exception_log(
                message.content, message.author.name,
                message.author.discriminator, message.author.id,
                message.guild.id if message.guild else None,
                message.channel.id)
        else:
            # If not, just post the string itself
            embed = None

        traceback_str = "```python\n{}```".format(traceback.format_exc())
        if len(traceback.format_exc()) >= (2000 - len("```python\n```")):
            traceback_str = "```python\n...{}```".format(
                traceback.format_exc()[-(2000 - len("```python\n...```")):])
        await log_channel.send(content=traceback_str, embed=embed)

    client.run(token)