1919if TYPE_CHECKING :
2020 from collections .abc import Awaitable
2121
22+ from src import custom
23+
2224
2325def create_backend_app () -> FastAPI :
2426 """Create a FastAPI application for the backend server.
@@ -30,17 +32,15 @@ def create_backend_app() -> FastAPI:
3032 return FastAPI (title = "Botkit Backend" )
3133
3234
33- def create_backend_bot () -> discord .Bot :
34- """Create a minimal Discord bot for the backend server.
35-
36- The backend server needs a bot instance for certain operations,
37- but it doesn't need the full custom bot setup.
38-
39- Returns:
40- A basic Discord bot with default intents
35+ def create_backend_bot () -> "custom.Bot" :
36+ """Create a bot for backend-only mode.
4137
38+ Deprecated in favor of :func:`src.startup.bot.create_bot`, which applies cache
39+ and other bot configuration. Kept for backward compatibility.
4240 """
43- return discord .Bot (intents = discord .Intents .default ())
41+ from src .startup .bot import create_bot # noqa: PLC0415
42+
43+ return create_bot (config .bot )
4444
4545
4646def setup_backend_extensions (
@@ -80,55 +80,93 @@ async def run_startup_functions(
8080 await asyncio .gather (* startup_coros )
8181
8282
83- async def start_backend (app : FastAPI , bot : discord .Bot , token : str , backend_config : BackendConfig ) -> None :
83+ def _uvicorn_config (app : FastAPI , backend_config : BackendConfig ) -> uvicorn .Config :
84+ return uvicorn .Config (
85+ app = app ,
86+ host = backend_config .host ,
87+ port = backend_config .port ,
88+ access_log = backend_config .access_log ,
89+ server_header = backend_config .server_header ,
90+ log_config = None ,
91+ )
92+
93+
94+ async def serve_backend (app : FastAPI , backend_config : BackendConfig ) -> None :
95+ """Run the FastAPI app with Uvicorn (no Discord login)."""
96+ await uvicorn .Server (_uvicorn_config (app , backend_config )).serve ()
97+
98+
99+ async def run_backend_only (
100+ app : FastAPI ,
101+ bot : discord .Bot ,
102+ token : str ,
103+ backend_config : BackendConfig ,
104+ ) -> None :
105+ """Log in to Discord and serve the backend (backend-only mode)."""
106+ try :
107+ if not bot .user :
108+ await bot .login (token )
109+ await serve_backend (app , backend_config )
110+ except Exception as e : # noqa: BLE001
111+ logger .critical ("An error occurred while starting the backend server." )
112+ logger .debug ("" , exc_info = e )
113+
114+
115+ async def start_backend (
116+ app : FastAPI ,
117+ bot : discord .Bot ,
118+ token : str ,
119+ backend_config : BackendConfig ,
120+ * ,
121+ login : bool = True ,
122+ ) -> None :
84123 """Start the backend server with Uvicorn.
85124
86125 Args:
87126 app: The FastAPI application to serve
88- bot: The Discord bot instance (for login)
89- token: Discord bot token
127+ bot: The Discord bot instance
128+ token: Discord bot token (used when ``login`` is True)
90129 backend_config: Backend server settings
130+ login: When True, log in before serving (backend-only). When False, the caller
131+ is responsible for authentication (combined bot + backend mode).
91132
92133 """
93134 try :
94- await bot .login (token )
95- uvicorn_config = uvicorn .Config (
96- app = app ,
97- host = backend_config .host ,
98- port = backend_config .port ,
99- access_log = backend_config .access_log ,
100- server_header = backend_config .server_header ,
101- log_config = None ,
102- )
103-
104- await uvicorn .Server (uvicorn_config ).serve ()
135+ if login and not bot .user :
136+ await bot .login (token )
137+ await serve_backend (app , backend_config )
105138 except Exception as e : # noqa: BLE001
106139 logger .critical ("An error occurred while starting the backend server." )
107140 logger .debug ("" , exc_info = e )
108141
109142
110143async def setup_and_start_backend (
111144 back_functions : WebserverFunctionList ,
145+ bot : "custom.Bot | None" = None ,
112146) -> None :
113- """Create, configure, and start the backend server.
114-
115- This is a convenience function that combines backend app creation,
116- bot creation, extension setup, and server startup.
147+ """Configure and start the backend server.
117148
118149 Args:
119150 back_functions: List of (setup_webserver_function, config) tuples for extensions
151+ bot: Optional existing bot instance. When omitted, a new bot is created via
152+ :func:`src.startup.bot.create_bot`.
120153
121154 """
155+ from src .startup .bot import create_bot # noqa: PLC0415
156+
122157 app = create_backend_app ()
123- bot = create_backend_bot ()
158+ if bot is None :
159+ bot = create_bot (config .bot )
124160 setup_backend_extensions (app , bot , back_functions )
125- await start_backend (app , bot , config .bot .token , config .backend )
161+ await run_backend_only (app , bot , config .bot .token , config .backend )
126162
127163
128164__all__ = [
129165 "create_backend_app" ,
130166 "create_backend_bot" ,
167+ "run_backend_only" ,
131168 "run_startup_functions" ,
169+ "serve_backend" ,
132170 "setup_and_start_backend" ,
133171 "setup_backend_extensions" ,
134172 "start_backend" ,
0 commit comments