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)
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)