-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
143 lines (128 loc) · 5.25 KB
/
Copy pathmain.py
File metadata and controls
143 lines (128 loc) · 5.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import discord
from discord.ext import commands, tasks
import logging
import os
import aiohttp
import traceback
import asyncio
from datetime import datetime, timedelta
from core.config import Config
from core import database as db
from services import backup
from tasks.activity_monitor import ActivityMonitor
from web.http_keepalive import start_http_server
# Set up logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('pavia_bot.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
class PaviaBot(commands.Bot):
def __init__(self):
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
# Legge il proxy dalle variabili d'ambiente (se presente)
proxy_url = os.getenv("PROXY_URL")
super().__init__(
command_prefix="!",
intents=intents,
proxy=proxy_url # <-- Aggiunto
)
self.http_session = None
self.activity_monitor = None # Verrà inizializzato dopo la creazione del bot
self.command_semaphore = asyncio.Semaphore(3)
async def setup_hook(self):
await db.init_db()
self.http_session = aiohttp.ClientSession()
self.activity_monitor = ActivityMonitor(self) # Inizializza qui
for filename in os.listdir("cogs"):
if filename.endswith(".py") and not filename.startswith("__"):
cog_name = filename[:-3]
try:
await self.load_extension(f"cogs.{cog_name}")
logger.info(f"Loaded cog: {cog_name}")
except Exception as e:
logger.error(f"Failed to load cog {cog_name}: {e}")
await self.tree.sync()
logger.info("All cogs loaded and synced.")
commands_list = [cmd.name for cmd in self.tree.get_commands()]
logger.info(f"Registered commands: {commands_list}")
self.tree.on_error = self.on_app_command_error
async def on_app_command_error(self, interaction: discord.Interaction, error: discord.app_commands.AppCommandError):
logger.error(f"Unhandled app command error in {interaction.command}: {error}\n{traceback.format_exc()}")
if isinstance(error, discord.HTTPException) and error.status == 429:
embed = discord.Embed(
title="⏳ Troppe richieste",
description="Il bot ha raggiunto il limite di richieste a Discord. Attendi qualche secondo e riprova.",
color=0xff9900
)
else:
embed = discord.Embed(
title="❌ Unexpected Error",
description="An unexpected error occurred. The developers have been notified.",
color=0xED4245
)
try:
if not interaction.response.is_done():
await interaction.response.send_message(embed=embed, ephemeral=True)
else:
await interaction.followup.send(embed=embed, ephemeral=True)
except:
pass
@tasks.loop(hours=24)
async def daily_backup(self):
await self.wait_until_ready()
await backup.create_backup("auto", "daily_scheduled")
logger.info("Daily backup created.")
@daily_backup.before_loop
async def before_daily_backup(self):
await self.wait_until_ready()
now = datetime.now()
target = now.replace(hour=2, minute=0, second=0, microsecond=0)
if now > target:
target += timedelta(days=1)
await asyncio.sleep((target - now).total_seconds())
async def close(self):
if self.http_session and not self.http_session.closed:
await self.http_session.close()
await db.close_pool()
await super().close()
async def run_bot():
"""Avvia il bot con retry in caso di rate limiting."""
max_retries = 5
retry_delay = 5 # secondi iniziali
for attempt in range(max_retries):
bot = PaviaBot()
try:
await bot.start(Config.DISCORD_TOKEN)
# Se arriva qui, il bot è partito e rimarrà in esecuzione
await bot.wait_until_ready()
logger.info(f"Logged in as {bot.user}")
bot.daily_backup.start()
bot.activity_monitor.daily_check.start()
print(f"✅ Bot online as {bot.user}")
# Mantieni il bot in esecuzione
await asyncio.Future() # Attende indefinitamente
except discord.HTTPException as e:
if e.status == 429 and attempt < max_retries - 1:
logger.warning(f"Rate limited (429) during login. Retrying in {retry_delay} seconds... (attempt {attempt+1}/{max_retries})")
await bot.close() # Chiudi il bot corrente
await asyncio.sleep(retry_delay)
retry_delay *= 2 # backoff esponenziale
else:
logger.error(f"Fatal HTTP error during login: {e}")
raise
except Exception as e:
logger.error(f"Unexpected error during bot.run: {e}")
await bot.close()
raise
finally:
await bot.close()
if __name__ == "__main__":
start_http_server()
asyncio.run(run_bot())