Beispiel #1
0
class MyBot(AutoShardedBot):
    def __init__(self, *args, **kwargs):
        self.logger = FakeLogger()
        self.config: dict = {}
        self.reload_config()
        activity = discord.Game(self.config["bot"]["playing"])
        super().__init__(*args,
                         command_prefix=get_prefix,
                         activity=activity,
                         case_insensitive=self.config["bot"]
                         ["commands_are_case_insensitive"],
                         **kwargs)
        self.commands_used = collections.Counter()
        self.uptime = datetime.datetime.utcnow()
        self.shards_ready = set()
        self._worldometers_api = covid19api.Covid19StatsWorldometers()
        self._vaccine_api = covid19api.VaccineStats()
        self._jhucsse_api = covid19api.Covid19JHUCSSEStats()
        self.news_api = news.NewsAPI(self.config["auth"]["news_api"]["token"])
        self._owid_api = covid19api.OWIDData()
        self.custom_updater_helper: Optional[CustomUpdater] = None
        self._client_session: Optional[aiohttp.ClientSession] = None
        self.basic_process_pool = concurrent.futures.ProcessPoolExecutor(2)
        self.premium_process_pool = concurrent.futures.ProcessPoolExecutor(4)
        self.statcord: Optional[statcord.Client] = None
        self.maps_api: Optional[MapGetter] = None
        self.support_server_invite = "https://discord.gg/myJh5hkjpS"
        self.autoupdater_dump: asyncio.Queue = asyncio.Queue(maxsize=1)
        self.blackfire: bool = blackfire
        self.sync_queue: Optional[Queue] = None
        self.task_processors: Optional[List[Process]] = None
        asyncio.ensure_future(self.async_setup())

    @property
    def client_session(self):
        if self._client_session:
            return self._client_session
        else:
            raise _runtime_error

    @property
    def worldometers_api(self):
        if self._worldometers_api.data_is_valid:
            return self._worldometers_api
        else:
            raise _runtime_error

    @property
    def vaccine_api(self):
        if self._vaccine_api.data_is_valid:
            return self._vaccine_api
        else:
            raise _runtime_error

    @property
    def jhucsse_api(self):
        if self._jhucsse_api.data_is_valid:
            return self._jhucsse_api
        else:
            raise _runtime_error

    @property
    def owid_api(self):
        if self._owid_api.data_is_valid:
            return self._owid_api
        else:
            raise _runtime_error

    def reload_config(self):
        self.config = config.load_config()

    async def async_setup(self):
        """
        This funtcion is run once, and is used to setup the bot async features, like the ClientSession from aiohttp.
        """
        if self._client_session is None:
            self._client_session = aiohttp.ClientSession(
            )  # There is no need to call __aenter__, since that does
            # nothing in this case
        try:
            await self._worldometers_api.update_covid_19_virus_stats()
            await self._vaccine_api.update_covid_19_vaccine_stats()
            await self._jhucsse_api.update_covid_19_virus_stats()
            await self._owid_api.update_covid_19_owid_data()
        except RuntimeError as e:
            self.logger.exception(
                "Fatal RuntimeError while running initial update!", exc_info=e)
        except Exception as e:
            self.logger.exception(
                "Fatal general error while running initial update!",
                exc_info=e)
        try:
            if not self.maps_api:
                self.maps_api = MapGetter("/home/pi/covid_bot_beta/maps")
                await wrap_in_async(self.maps_api.initalize_firefox,
                                    thread_pool=True)
        except Exception as e:
            self.logger.exception("Fatal error while initializing Firefox!",
                                  exc_info=e)
        try:
            self.custom_updater_helper = CustomUpdater(self)
            await self.custom_updater_helper.setup()
        except Exception as e:
            self.logger.exception(
                "Fatal error while initializing the custom updater!",
                exc_info=e)

    async def on_message(self, message: discord.Message):
        if not self.is_ready():
            return  # Ignoring messages when not ready

        if message.author.bot:
            return  # ignore messages from other bots

        ctx: MyContext = await self.get_context(message, cls=MyContext)
        if self.user.mentioned_in(message) and ctx.prefix is None and str(
                self.user.id) in message.content:
            _ = await ctx.get_translate_function()
            await ctx.send(
                _("Hi there! I'm a bot for giving live stats on the COVID-19 pandemic. My default prefix is "
                  "`c!`. This can be changed with `c!settings prefix <new prefix>`, replacing <new prefix> "
                  "with the prefix you want. For a list of my commands, run `c!help`."
                  ))
        elif ctx.valid:
            try:
                async with ctx.typing():
                    await self.invoke(ctx)
            except discord.Forbidden:
                await self.invoke(ctx)

    async def on_command(self, ctx: MyContext):
        if self.blackfire:
            probe.add_marker(f"Command {ctx.command} {ctx.invoked_subcommand}")
        self.commands_used[ctx.command.name] += 1
        self.statcord.command_run(ctx)
        ctx.logger.info(f"{ctx.message.clean_content}")

    async def on_shard_ready(self, shard_id):
        self.shards_ready.add(shard_id)

    async def on_disconnect(self):
        self.shards_ready = set()

    async def on_ready(self):
        messages = [
            "-----------", f"The bot is ready.",
            f"Logged in as {self.user.name} ({self.user.id})."
        ]
        total_members = len(self.users)
        messages.append(
            f"I see {len(self.guilds)} guilds, and {total_members} members.")
        messages.append(
            f"To invite your bot to your server, use the following link: "
            f"https://discord.com/api/oauth2/authorize?client_id={self.user.id}&scope=bot&permissions=0"
        )
        cogs_count = len(self.cogs)
        messages.append(f"{cogs_count} cogs are loaded")
        messages.append("-----------")
        for message in messages:
            self.logger.info(message)

        for message in messages:
            print(message)
Beispiel #2
0
class MyBot(AutoShardedBot):
    def __init__(self, *args, **kwargs):
        self.logger = FakeLogger()
        self.config: dict = {}
        self.reload_config()
        #activity = discord.Game(self.config["bot"]["playing"])
        self.current_event: Events = Events.CALM
        activity = discord.Game(self.current_event.value[0])
        super().__init__(*args,
                         command_prefix=get_prefix,
                         activity=activity,
                         case_insensitive=self.config["bot"]
                         ["commands_are_case_insensitive"],
                         **kwargs)
        self.commands_used = collections.Counter()
        self.top_users = collections.Counter()
        self.uptime = datetime.datetime.utcnow()
        self.shards_ready = set()
        self._client_session: Optional[aiohttp.ClientSession] = None
        self.ducks_spawned: collections.defaultdict[
            discord.TextChannel,
            collections.deque['Duck']] = collections.defaultdict(
                collections.deque)
        self.enabled_channels: typing.Dict[discord.TextChannel, int] = {}
        self.concurrency = MaxConcurrency(number=1,
                                          per=BucketType.channel,
                                          wait=True)
        self.allow_ducks_spawning = True

        self._duckhunt_public_log = None

        asyncio.ensure_future(self.async_setup())

    @property
    def client_session(self):
        if self._client_session:
            return self._client_session
        else:
            raise RuntimeError(
                "The bot haven't been setup yet. Ensure you call bot.async_setup asap."
            )

    @property
    def available_guilds(self) -> typing.Iterable[Guild]:
        return filter(lambda g: not g.unavailable, self.guilds)

    def reload_config(self):
        self.config = config.load_config()

    async def async_setup(self):
        """
        This function is run once, and is used to setup the bot async features, like the ClientSession from aiohttp.
        """
        self._client_session = aiohttp.ClientSession(
        )  # There is no need to call __aenter__, since that does nothing in that case

    def get_logging_channel(self):
        if not self._duckhunt_public_log:
            config = self.config['duckhunt_public_log']
            self._duckhunt_public_log = self.get_guild(
                config['server_id']).get_channel(config['channel_id'])

        return self._duckhunt_public_log

    async def log_to_channel(self, *args, **kwargs):
        channel = self.get_logging_channel()
        message = await channel.send(*args, **kwargs)
        try:
            await message.publish()
            return True
        except discord.Forbidden:
            self.logger.warning(
                "Couldn't publish message to announcement channel, I don't have the required permissions"
            )
            return False
        except discord.HTTPException as e:
            self.logger.exception(
                f"Couldn't publish message to announcement channel: {e}. "
                f"Too many messages published recently ?")
            return False

    async def on_message(self, message):
        if not self.is_ready():
            return  # Ignoring messages when not ready

        if message.author.bot:
            return  # ignore messages from other bots

        ctx = await self.get_context(message, cls=MyContext)
        if ctx.prefix is not None:
            db_user = await get_from_db(ctx.author)

            access = db_user.get_access_level()

            if access != AccessLevel.BANNED:
                await self.concurrency.acquire(message)
                await self.invoke(ctx)
                await self.concurrency.release(message)

    async def on_command(self, ctx: MyContext):
        db_user = await get_from_db(ctx.author, as_user=True)
        if db_user.first_use:
            _ = await ctx.get_translate_function(user_language=True)

            ctx.logger.info(
                f"It's the first time that {ctx.author.name}#{ctx.author.discriminator} is intreracting with us. Sending welcome DM."
            )

            try:
                await ctx.author.send(
                    _(
                        "Hello! The following message (written by the owner of DuckHunt) will give you a brief introduction to the bot, "
                        "and also provide you with links to the DuckHunt wiki.\n"
                        "First of all, thank you for using my bot! If you have any unanswered questions after reading this message and the wiki, "
                        "you are more than welcome to ask for help in the support channels at <{support_server_link}>.\n\n"
                        "When a duck spawns you shoot at it by using the `dh!bang` command.\n"
                        "However, if the duck says **COIN** it's a **baby duck** and you should hug it with `dh!hug`.\n"
                        "You can reload your ammunition with `dh!reload` and buy new magazines with `dh!shop magazine` or `dh!shop 2`.\n"
                        "If you want to learn more about the game, use the wiki! <{wiki_link}>",
                        support_server_link=_("https://discord.gg/G4skWae"),
                        wiki_link=
                        _("https://duckhunt.me/docs/players-guide/players-quickstart"
                          ),
                    ))
            except discord.Forbidden:
                ctx.logger.debug(f"Couldn't send the welcome DM, forbidden.")

            db_user.first_use = False
            await db_user.save()

        self.commands_used[ctx.command.qualified_name] += 1
        self.top_users[ctx.author.id] += 1
        ctx.logger.info(f"{ctx.message.clean_content}")

    async def on_shard_ready(self, shard_id):
        self.shards_ready.add(shard_id)

    async def on_disconnect(self):
        self.shards_ready = set()

    async def on_ready(self):
        messages = [
            "-----------", f"The bot is ready.",
            f"Logged in as {self.user.name} ({self.user.id})."
        ]
        total_members = len(self.users)
        messages.append(
            f"I see {len(self.guilds)} guilds, and {total_members} members.")
        messages.append(
            f"To invite your bot to your server, use the following link: https://discord.com/oauth2/authorize?client_id=187636051135823872&scope=bot&permissions=741735489"
        )
        cogs_count = len(self.cogs)
        messages.append(f"{cogs_count} cogs are loaded")
        messages.append("-----------")
        for message in messages:
            self.logger.info(message)

        for message in messages:
            print(message)