Enhance automatic leaderboard sync process in Leaderboard cog by refining user credit aggregation and error handling. Implement detailed logging for successes and failures during sync, and ensure opted-out users are included in the sync process. Improve API verification after sync to confirm data integrity. Update user credit retrieval to streamline balance fetching across servers.
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run
This commit is contained in:
parent
9b8d4be301
commit
7eddd891bc
1 changed files with 69 additions and 40 deletions
|
@ -122,8 +122,8 @@ class Leaderboard(commands.Cog):
|
|||
await self.bot.wait_until_ready()
|
||||
while True:
|
||||
try:
|
||||
await self._perform_full_sync()
|
||||
log.info("Completed automatic leaderboard sync")
|
||||
success_count, fail_count = await self._perform_full_sync()
|
||||
log.info(f"Completed automatic leaderboard sync: {success_count} successes, {fail_count} failures")
|
||||
await asyncio.sleep(21600) # 6 hours in seconds
|
||||
except asyncio.CancelledError:
|
||||
break
|
||||
|
@ -137,27 +137,69 @@ class Leaderboard(commands.Cog):
|
|||
success_count = 0
|
||||
fail_count = 0
|
||||
processed_users = set()
|
||||
users_to_sync = []
|
||||
|
||||
# First, collect all users and their credits
|
||||
for guild in self.bot.guilds:
|
||||
for member in guild.members:
|
||||
if member.bot or member.id in processed_users:
|
||||
continue
|
||||
|
||||
try:
|
||||
# Get total credits across all guilds
|
||||
credits = await self.get_user_credits(member)
|
||||
opted_out = await self.config.user(member).opted_out()
|
||||
|
||||
# Update API
|
||||
if await self._try_api_update(str(member.id), str(member), credits):
|
||||
success_count += 1
|
||||
else:
|
||||
fail_count += 1
|
||||
|
||||
# Only include users with sufficient credits or who are opted out
|
||||
# (we need to sync opted-out status even for users below threshold)
|
||||
if credits >= 10000 or opted_out:
|
||||
users_to_sync.append({
|
||||
"member": member,
|
||||
"credits": credits,
|
||||
"opted_out": opted_out
|
||||
})
|
||||
processed_users.add(member.id)
|
||||
except Exception as e:
|
||||
log.error(f"Error syncing user {member} ({member.id}): {e}")
|
||||
log.error(f"Error processing user {member} ({member.id}): {e}")
|
||||
fail_count += 1
|
||||
|
||||
# Debug logging
|
||||
log.info(f"Found {len(users_to_sync)} users to sync")
|
||||
|
||||
# Now perform the sync
|
||||
for user_data in users_to_sync:
|
||||
member = user_data["member"]
|
||||
try:
|
||||
if await self._try_api_update(
|
||||
str(member.id),
|
||||
str(member),
|
||||
user_data["credits"]
|
||||
):
|
||||
success_count += 1
|
||||
log.debug(f"Successfully synced {member} ({member.id})")
|
||||
else:
|
||||
fail_count += 1
|
||||
log.error(f"Failed to sync {member} ({member.id})")
|
||||
except Exception as e:
|
||||
log.error(f"Error syncing user {member} ({member.id}): {e}")
|
||||
fail_count += 1
|
||||
|
||||
# Verify the sync by checking the API
|
||||
try:
|
||||
async with self.session.get(
|
||||
f"{self.api_base_url}/leaderboard",
|
||||
headers={"Authorization": self.admin_secret["admin_secret"]}
|
||||
) as resp:
|
||||
if resp.status == 200:
|
||||
data = await resp.json()
|
||||
if "leaderboard" in data:
|
||||
log.info(f"API verification: {len(data['leaderboard'])} users in leaderboard after sync")
|
||||
else:
|
||||
log.error("API verification failed: Invalid response format")
|
||||
else:
|
||||
log.error(f"API verification failed: Status {resp.status}")
|
||||
except Exception as e:
|
||||
log.error(f"API verification failed: {e}")
|
||||
|
||||
return success_count, fail_count
|
||||
|
||||
async def cog_load(self):
|
||||
|
@ -166,38 +208,18 @@ class Leaderboard(commands.Cog):
|
|||
|
||||
async def get_user_credits(self, user: discord.Member) -> int:
|
||||
"""Get a user's total credits from all servers."""
|
||||
total_credits = 0
|
||||
|
||||
try:
|
||||
# Get credits from the user's current server
|
||||
try:
|
||||
total_credits = await bank.get_balance(user)
|
||||
except Exception as e:
|
||||
log.error(f"Error getting balance for {user} in current guild: {e}")
|
||||
|
||||
# Then add credits from all other servers
|
||||
for guild in self.bot.guilds:
|
||||
if guild.id != user.guild.id: # Skip current guild
|
||||
try:
|
||||
member = guild.get_member(user.id)
|
||||
if member: # If user is in this guild
|
||||
guild_credits = await bank.get_balance(member)
|
||||
total_credits += guild_credits
|
||||
except Exception as e:
|
||||
log.error(f"Error getting bank balance for {user} in {guild}: {e}")
|
||||
continue
|
||||
|
||||
# Use Red's bank API to get the user's balance
|
||||
# This automatically handles the global bank if enabled
|
||||
return await bank.get_balance(user)
|
||||
except Exception as e:
|
||||
log.error(f"Error getting total credits for {user}: {e}")
|
||||
|
||||
return total_credits
|
||||
log.error(f"Error getting credits for {user}: {e}")
|
||||
return 0
|
||||
|
||||
async def get_all_balances(self) -> List[dict]:
|
||||
"""Get all users' credit balances across all servers."""
|
||||
all_users = {}
|
||||
min_credits = 10000 # Minimum credits to show on leaderboard - matches API's MIN_CREDITS
|
||||
|
||||
# First get all unique members across all guilds
|
||||
processed_users = set()
|
||||
|
||||
# Process each guild
|
||||
|
@ -215,13 +237,16 @@ class Leaderboard(commands.Cog):
|
|||
continue
|
||||
|
||||
try:
|
||||
total_credits = await self.get_user_credits(member)
|
||||
credits = await self.get_user_credits(member)
|
||||
|
||||
if total_credits >= min_credits:
|
||||
# Debug logging for credit calculation
|
||||
log.debug(f"Calculated credits for {member} ({member.id}): {credits}")
|
||||
|
||||
if credits >= min_credits:
|
||||
all_users[member.id] = {
|
||||
"userId": str(member.id),
|
||||
"username": str(member),
|
||||
"points": total_credits
|
||||
"points": credits
|
||||
}
|
||||
|
||||
processed_users.add(member.id)
|
||||
|
@ -255,6 +280,9 @@ class Leaderboard(commands.Cog):
|
|||
# Get opt-out status
|
||||
opted_out = await self.config.user_from_id(int(user_id)).opted_out()
|
||||
|
||||
# Debug logging before update
|
||||
log.debug(f"Sending API update for {username} ({user_id}): {credits} credits, opted_out: {opted_out}")
|
||||
|
||||
async with self.session.post(
|
||||
f"{self.api_base_url}/leaderboard",
|
||||
headers={
|
||||
|
@ -409,7 +437,7 @@ class Leaderboard(commands.Cog):
|
|||
credits = await self.get_user_credits(member)
|
||||
|
||||
# Debug logging
|
||||
log.info(f"Credits check for {member}: {credits} credits")
|
||||
log.info(f"Credits check for {member} ({member.id}): {credits} credits")
|
||||
|
||||
# Get user's rank
|
||||
leaderboard_data = await self.get_all_balances()
|
||||
|
@ -455,7 +483,8 @@ class Leaderboard(commands.Cog):
|
|||
title="🔄 Global Leaderboard Resync Complete",
|
||||
description=(
|
||||
f"Successfully updated: **{success_count}** users\n"
|
||||
f"Failed to update: **{fail_count}** users"
|
||||
f"Failed to update: **{fail_count}** users\n\n"
|
||||
"Note: Updates may take a few moments to appear on the website."
|
||||
),
|
||||
color=await ctx.embed_color(),
|
||||
timestamp=datetime.now(timezone.utc)
|
||||
|
|
Loading…
Add table
Reference in a new issue