add logging and reconnection logic

This commit is contained in:
2025-02-22 02:52:02 -05:00
parent 818079775e
commit 0fb1a155b5

View File

@@ -1,31 +1,32 @@
import asyncio
from typing import Optional, Dict
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import logging
import discord
from discord.ext import commands
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional, Dict
from NoiseGatev2 import NoiseGate
import op25_controller
import pulse
# Initialize logging
logging.basicConfig(level=logging.INFO)
LOGGER = logging.getLogger(__name__)
# Define FastAPI app
app = FastAPI()
# Discord Bot Setup
intents = discord.Intents.default()
intents.voice_states = True
intents.guilds = True
# Models for API requests
class BotConfig(BaseModel):
token: str # Discord Bot Token
token: str
class VoiceChannelRequest(BaseModel):
guild_id: int
channel_id: int
# Discord Bot Manager
class DiscordBotManager:
def __init__(self):
self.bot: Optional[commands.Bot] = None
@@ -37,7 +38,7 @@ class DiscordBotManager:
async def start_bot(self, token: str):
async with self.lock:
if self.bot and self.bot.is_closed():
if self.bot and not self.bot.is_closed():
raise RuntimeError("Bot is already running.")
if self.bot_task and not self.bot_task.done():
raise RuntimeError("Bot is already running.")
@@ -47,17 +48,18 @@ class DiscordBotManager:
@self.bot.event
async def on_ready():
print(f'Logged in as {self.bot.user}')
LOGGER.info(f'Logged in as {self.bot.user}')
# Handle graceful shutdown when all voice connections are closed
@self.bot.event
async def on_voice_state_update(member, before, after):
# Check if all voice clients are disconnected
await asyncio.sleep(1) # Give time for the state to update
if not self.voice_clients:
await self.stop_bot()
# Check if the bot was disconnected
if member == self.bot.user and after.channel is None:
guild_id = before.channel.guild.id
LOGGER.info(f"Bot was disconnected from channel in guild {guild_id}. Attempting to reconnect...")
# Attempt to reconnect to the channel after a brief pause
await asyncio.sleep(2)
await self.join_voice_channel(guild_id, before.channel.id)
# Start the bot in the background
self.bot_task = self.loop.create_task(self.bot.start(token))
async def stop_bot(self):
@@ -69,7 +71,7 @@ class DiscordBotManager:
await self.bot_task
self.bot_task = None
self.voice_clients.clear()
print("Bot has been stopped.")
LOGGER.info("Bot has been stopped.")
async def join_voice_channel(self, guild_id: int, channel_id: int, ng_threshold: int = 50, device_id: int = 4):
if not self.bot:
@@ -86,15 +88,17 @@ class DiscordBotManager:
if guild_id in self.voice_clients:
raise RuntimeError("Already connected to this guild's voice channel.")
voice_client = await channel.connect()
streamHandler = NoiseGate(
try:
voice_client = await channel.connect(timeout=60.0, reconnect=True)
streamHandler = NoiseGate(
_input_device_index=device_id,
_voice_connection=voice_client,
_noise_gate_threshold=ng_threshold)
# Start the audio stream
streamHandler.run()
self.voice_clients[guild_id] = voice_client
print(f"Joined guild {guild_id} voice channel {channel_id}.")
streamHandler.run()
self.voice_clients[guild_id] = voice_client
LOGGER.info(f"Joined guild {guild_id} voice channel {channel_id}.")
except Exception as e:
LOGGER.error(f"Failed to connect to voice channel: {e}")
async def leave_voice_channel(self, guild_id: int):
if not self.bot:
@@ -106,9 +110,8 @@ class DiscordBotManager:
await voice_client.disconnect()
del self.voice_clients[guild_id]
print(f"Left guild {guild_id} voice channel.")
LOGGER.info(f"Left guild {guild_id} voice channel.")
# Initialize Discord Bot Manager
bot_manager = DiscordBotManager()
# API Endpoints
@@ -118,6 +121,7 @@ async def start_bot(config: BotConfig):
await bot_manager.start_bot(config.token)
return {"status": "Bot started successfully."}
except Exception as e:
LOGGER.error(f"Error starting bot: {e}")
raise HTTPException(status_code=400, detail=str(e))
@app.post("/stop_bot")
@@ -126,6 +130,7 @@ async def stop_bot():
await bot_manager.stop_bot()
return {"status": "Bot stopped successfully."}
except Exception as e:
LOGGER.error(f"Error stopping bot: {e}")
raise HTTPException(status_code=400, detail=str(e))
@app.post("/join_voice")
@@ -134,6 +139,7 @@ async def join_voice_channel(request: VoiceChannelRequest):
await bot_manager.join_voice_channel(request.guild_id, request.channel_id)
return {"status": f"Joined guild {request.guild_id} voice channel {request.channel_id}."}
except Exception as e:
LOGGER.error(f"Error joining voice channel: {e}")
raise HTTPException(status_code=400, detail=str(e))
@app.post("/leave_voice")
@@ -142,6 +148,7 @@ async def leave_voice_channel(request: VoiceChannelRequest):
await bot_manager.leave_voice_channel(request.guild_id)
return {"status": f"Left guild {request.guild_id} voice channel."}
except Exception as e:
LOGGER.error(f"Error leaving voice channel: {e}")
raise HTTPException(status_code=400, detail=str(e))
@app.get("/status")
@@ -152,6 +159,5 @@ async def get_status():
}
return status
app.include_router(op25_controller.router, prefix="/op25")
app.include_router(pulse.router, prefix="/pulse")