More error checks, better help, common sense channel edits, and rate limit checks

This commit is contained in:
bobloy 2020-07-27 12:19:09 -04:00
parent 27df384366
commit 9fdaf6ba07

View File

@ -5,13 +5,14 @@ from redbot.core import Config, checks, commands
from redbot.core.bot import Red from redbot.core.bot import Red
from redbot.core.commands import Cog from redbot.core.commands import Cog
# Cog: Any = getattr(commands, "Cog", object) # Cog: Any = getattr(commands, "Cog", object)
# listener = getattr(commands.Cog, "listener", None) # Trusty + Sinbad # listener = getattr(commands.Cog, "listener", None) # Trusty + Sinbad
# if listener is None: # if listener is None:
# def listener(name=None): # def listener(name=None):
# return lambda x: x # return lambda x: x
RATE_LIMIT_DELAY = 60 * 10 # If you're willing to risk rate limiting, you can decrease the delay
class InfoChannel(Cog): class InfoChannel(Cog):
""" """
@ -21,6 +22,7 @@ class InfoChannel(Cog):
""" """
def __init__(self, bot: Red): def __init__(self, bot: Red):
super().__init__()
self.bot = bot self.bot = bot
self.config = Config.get_conf( self.config = Config.get_conf(
self, identifier=731101021116710497110110101108, force_registration=True self, identifier=731101021116710497110110101108, force_registration=True
@ -37,6 +39,8 @@ class InfoChannel(Cog):
self.config.register_guild(**default_guild) self.config.register_guild(**default_guild)
self._critical_section_wooah_ = 0
@commands.command() @commands.command()
@checks.admin() @checks.admin()
async def infochannel(self, ctx: commands.Context): async def infochannel(self, ctx: commands.Context):
@ -46,9 +50,9 @@ class InfoChannel(Cog):
def check(m): def check(m):
return ( return (
m.content.upper() in ["Y", "YES", "N", "NO"] m.content.upper() in ["Y", "YES", "N", "NO"]
and m.channel == ctx.channel and m.channel == ctx.channel
and m.author == ctx.author and m.author == ctx.author
) )
guild: discord.Guild = ctx.guild guild: discord.Guild = ctx.guild
@ -72,9 +76,13 @@ class InfoChannel(Cog):
return return
if channel is None: if channel is None:
await self.make_infochannel(guild) try:
await self.make_infochannel(guild)
except discord.Forbidden:
await ctx.send("Failure: Missing permission to create voice channel")
return
else: else:
await self.delete_infochannel(guild, channel) await self.delete_all_infochannels(guild)
if not await ctx.tick(): if not await ctx.tick():
await ctx.send("Done!") await ctx.send("Done!")
@ -85,6 +93,8 @@ class InfoChannel(Cog):
""" """
Toggle different types of infochannels Toggle different types of infochannels
""" """
if not ctx.invoked_subcommand:
pass
@infochannelset.command(name="botcount") @infochannelset.command(name="botcount")
async def _infochannelset_botcount(self, ctx: commands.Context, enabled: bool = None): async def _infochannelset_botcount(self, ctx: commands.Context, enabled: bool = None):
@ -94,7 +104,10 @@ class InfoChannel(Cog):
guild = ctx.guild guild = ctx.guild
if enabled is None: if enabled is None:
enabled = not await self.config.guild(guild).bot_count() enabled = not await self.config.guild(guild).bot_count()
await self.config.guild(guild).bot_count.set(enabled) await self.config.guild(guild).bot_count.set(enabled)
await self.make_infochannel(ctx.guild)
if enabled: if enabled:
await ctx.send("InfoChannel for bot count has been enabled.") await ctx.send("InfoChannel for bot count has been enabled.")
else: else:
@ -108,7 +121,10 @@ class InfoChannel(Cog):
guild = ctx.guild guild = ctx.guild
if enabled is None: if enabled is None:
enabled = not await self.config.guild(guild).online_count() enabled = not await self.config.guild(guild).online_count()
await self.config.guild(guild).online_count.set(enabled) await self.config.guild(guild).online_count.set(enabled)
await self.make_infochannel(ctx.guild)
if enabled: if enabled:
await ctx.send("InfoChannel for online user count has been enabled.") await ctx.send("InfoChannel for online user count has been enabled.")
else: else:
@ -122,25 +138,49 @@ class InfoChannel(Cog):
guild.me: discord.PermissionOverwrite(manage_channels=True, connect=True), guild.me: discord.PermissionOverwrite(manage_channels=True, connect=True),
} }
# Remove the old info channel first
channel_id = await self.config.guild(guild).channel_id()
if channel_id is not None:
channel: discord.VoiceChannel = guild.get_channel(channel_id)
if channel:
await channel.delete(reason="InfoChannel delete")
# Then create the new one
channel = await guild.create_voice_channel( channel = await guild.create_voice_channel(
"Placeholder", reason="InfoChannel make", overwrites=overwrites "Total Humans:", reason="InfoChannel make", overwrites=overwrites
) )
await self.config.guild(guild).channel_id.set(channel.id) await self.config.guild(guild).channel_id.set(channel.id)
if botcount: if botcount:
# Remove the old bot channel first
botchannel_id = await self.config.guild(guild).botchannel_id()
if channel_id is not None:
botchannel: discord.VoiceChannel = guild.get_channel(botchannel_id)
if botchannel:
await botchannel.delete(reason="InfoChannel delete")
# Then create the new one
botchannel = await guild.create_voice_channel( botchannel = await guild.create_voice_channel(
"Placeholder", reason="InfoChannel botcount", overwrites=overwrites "Bots:", reason="InfoChannel botcount", overwrites=overwrites
) )
await self.config.guild(guild).botchannel_id.set(botchannel.id) await self.config.guild(guild).botchannel_id.set(botchannel.id)
if onlinecount: if onlinecount:
# Remove the old online channel first
onlinechannel_id = await self.config.guild(guild).onlinechannel_id()
if channel_id is not None:
onlinechannel: discord.VoiceChannel = guild.get_channel(onlinechannel_id)
if onlinechannel:
await onlinechannel.delete(reason="InfoChannel delete")
# Then create the new one
onlinechannel = await guild.create_voice_channel( onlinechannel = await guild.create_voice_channel(
"Placeholder", reason="InfoChannel onlinecount", overwrites=overwrites "Online:", reason="InfoChannel onlinecount", overwrites=overwrites
) )
await self.config.guild(guild).onlinechannel_id.set(onlinechannel.id) await self.config.guild(guild).onlinechannel_id.set(onlinechannel.id)
await self.update_infochannel(guild) await self.update_infochannel(guild)
async def delete_infochannel(self, guild: discord.Guild, channel: discord.VoiceChannel): async def delete_all_infochannels(self, guild: discord.Guild):
guild_data = await self.config.guild(guild).all() guild_data = await self.config.guild(guild).all()
botchannel_id = guild_data["botchannel_id"] botchannel_id = guild_data["botchannel_id"]
onlinechannel_id = guild_data["onlinechannel_id"] onlinechannel_id = guild_data["onlinechannel_id"]
@ -153,6 +193,7 @@ class InfoChannel(Cog):
await botchannel.delete(reason="InfoChannel delete") await botchannel.delete(reason="InfoChannel delete")
if onlinechannel_id is not None: if onlinechannel_id is not None:
await onlinechannel.delete(reason="InfoChannel delete") await onlinechannel.delete(reason="InfoChannel delete")
await self.config.guild(guild).clear() await self.config.guild(guild).clear()
async def update_infochannel(self, guild: discord.Guild): async def update_infochannel(self, guild: discord.Guild):
@ -164,23 +205,23 @@ class InfoChannel(Cog):
# bots = lambda x: x.bot # bots = lambda x: x.bot
# def bots(x): return x.bot # def bots(x): return x.bot
num = len([m for m in guild.members if m.bot]) bot_num = len([m for m in guild.members if m.bot])
bot_msg = f"Bots: {num}" # bot_msg = f"Bots: {num}"
# Gets count of online users # Gets count of online users
members = guild.member_count members = guild.member_count
offline = len(list(filter(lambda m: m.status is discord.Status.offline, guild.members))) offline = len(list(filter(lambda m: m.status is discord.Status.offline, guild.members)))
num = members - offline online_num = members - offline
online_msg = f"Online: {num}" # online_msg = f"Online: {num}"
# Gets count of actual users # Gets count of actual users
total = lambda x: not x.bot total = lambda x: not x.bot
num = len([m for m in guild.members if total(m)]) human_num = len([m for m in guild.members if total(m)])
human_msg = f"Total Humans: {num}" # human_msg = f"Total Humans: {num}"
channel_id = guild_data["channel_id"] channel_id = guild_data["channel_id"]
if channel_id is None: if channel_id is None:
return return False
botchannel_id = guild_data["botchannel_id"] botchannel_id = guild_data["botchannel_id"]
onlinechannel_id = guild_data["onlinechannel_id"] onlinechannel_id = guild_data["onlinechannel_id"]
@ -190,30 +231,51 @@ class InfoChannel(Cog):
onlinechannel: discord.VoiceChannel = guild.get_channel(onlinechannel_id) onlinechannel: discord.VoiceChannel = guild.get_channel(onlinechannel_id)
if guild_data["member_count"]: if guild_data["member_count"]:
name = "{} ".format(human_msg) name = f"{channel.name.split(':')[0]}: {human_num}"
await channel.edit(reason="InfoChannel update", name=name) await channel.edit(reason="InfoChannel update", name=name)
if botcount: if botcount:
name = "{} ".format(bot_msg) name = f"{botchannel.name.split(':')[0]}: {bot_num}"
await botchannel.edit(reason="InfoChannel update", name=name) await botchannel.edit(reason="InfoChannel update", name=name)
if onlinecount: if onlinecount:
name = "{} ".format(online_msg) name = f"{onlinechannel.name.split(':')[0]}: {online_num}"
await onlinechannel.edit(reason="InfoChannel update", name=name) await onlinechannel.edit(reason="InfoChannel update", name=name)
await asyncio.sleep(60) async def update_infochannel_with_cooldown(self, guild):
"""My attempt at preventing rate limits, lets see how it goes"""
if self._critical_section_wooah_:
if self._critical_section_wooah_ == 2:
print("Already pending, skipping")
return # Another one is already pending, don't queue more than one
print("Queuing another update")
self._critical_section_wooah_ = 2
while self._critical_section_wooah_:
await asyncio.sleep(RATE_LIMIT_DELAY // 4) # Max delay ends up as 1.25 * RATE_LIMIT_DELAY
print("Issuing queued update")
return await self.update_infochannel_with_cooldown(guild)
print("Entering critical")
self._critical_section_wooah_ = 1
await self.update_infochannel(guild)
await asyncio.sleep(RATE_LIMIT_DELAY)
self._critical_section_wooah_ = 0
print("Exiting critical")
@Cog.listener() @Cog.listener()
async def on_member_join(self, member: discord.Member): async def on_member_join(self, member: discord.Member):
await self.update_infochannel(member.guild) await self.update_infochannel_with_cooldown(member.guild)
@Cog.listener() @Cog.listener()
async def on_member_remove(self, member: discord.Member): async def on_member_remove(self, member: discord.Member):
await self.update_infochannel(member.guild) await self.update_infochannel_with_cooldown(member.guild)
@Cog.listener() @Cog.listener()
async def on_member_update(self, before: discord.Member, after: discord.Member): async def on_member_update(self, before: discord.Member, after: discord.Member):
onlinecount = await self.config.guild(after.guild).online_count() onlinecount = await self.config.guild(after.guild).online_count()
if onlinecount: if onlinecount:
if before.status != after.status: if before.status != after.status:
await self.update_infochannel(after.guild) await self.update_infochannel_with_cooldown(after.guild)