diff --git a/chat_listener.py b/chat_listener.py index 475a3b8..5b972e0 100644 --- a/chat_listener.py +++ b/chat_listener.py @@ -20,11 +20,12 @@ class TwitchBot(commands.Bot): super().__init__( token=access_token, + # Mandate: Explicitly disable the internal web server. web_server_adapter=adapter, - eventsub_url=None, # Explicitly disable EventSub + eventsub_url=None, prefix='!', # A prefix is required but won't be used for reading chat initial_channels=[channel_name], - # These are required by twitchio for authentication + # These are required by twitchio client_id=client_id, client_secret=client_secret, # The 'bot_id' is the Twitch ID of the user account the bot is running as @@ -36,7 +37,7 @@ class TwitchBot(commands.Bot): """Called once when the bot goes online.""" print(f"Listener ready for #{self.channel_name}") - async def event_message(self, message): + async def event_message(self, message): # Mandate: Type hint removed to prevent import errors. """Runs every time a message is sent in chat.""" # This is CRITICAL when overriding a listener in commands.Bot # to ensure the bot can still process commands if any are added. diff --git a/main.py b/main.py index aa40322..9d3cadd 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,5 @@ import os +import asyncio from fastapi import FastAPI, Request, Depends, HTTPException from starlette.middleware.sessions import SessionMiddleware from starlette.staticfiles import StaticFiles @@ -23,6 +24,20 @@ BASE_DIR = os.path.dirname(os.path.abspath(__file__)) STATIC_DIR = os.path.join(BASE_DIR, "static") TEMPLATES_DIR = os.path.join(BASE_DIR, "templates") +@asynccontextmanager +async def background_listener_startup(app: FastAPI): + """A non-blocking task to start listeners after the app has started.""" + print("Background task: Starting listeners for all users...") + db = SessionLocal() + users = db.query(models.User).all() + db.close() + for user in users: + # Use try/except to ensure one failing listener doesn't stop others + try: + await app.state.listener_manager.start_listener_for_user(user, app.state.websocket_manager) + except Exception as e: + print(f"ERROR: Failed to start listener for user {user.id} ({user.username}): {e}") + @asynccontextmanager async def lifespan(app: FastAPI): # This code runs on startup @@ -32,13 +47,8 @@ async def lifespan(app: FastAPI): models.Base.metadata.create_all(bind=engine) print("Application startup: Database tables created.") - # Start listeners for all existing users - db = SessionLocal() - users = db.query(models.User).all() - db.close() - for user in users: - await app.state.listener_manager.start_listener_for_user(user, app.state.websocket_manager) - + # Decouple listener startup from the main application startup + asyncio.create_task(background_listener_startup(app)) yield # This code runs on shutdown