Skip to main content

liter_llm_proxy/
lib.rs

1pub mod auth;
2pub mod config;
3pub mod error;
4pub mod file_store;
5pub mod mcp;
6pub mod openapi;
7pub mod routes;
8pub mod service_pool;
9pub mod state;
10pub mod streaming;
11
12use std::net::SocketAddr;
13use std::sync::Arc;
14
15use config::ProxyConfig;
16use state::AppState;
17
18/// Builder for the liter-llm proxy server.
19///
20/// Constructs the shared [`AppState`] from a [`ProxyConfig`], builds the axum
21/// router, and serves on the configured address.
22pub struct ProxyServer {
23    config: ProxyConfig,
24}
25
26impl ProxyServer {
27    /// Create a new proxy server with the given configuration.
28    pub fn new(config: ProxyConfig) -> Self {
29        Self { config }
30    }
31
32    /// Build the application state, assemble the router, and start serving.
33    pub async fn serve(self) -> Result<(), String> {
34        let service_pool = service_pool::ServicePool::from_config(&self.config)?;
35        let key_store = auth::KeyStore::from_config(self.config.general.master_key.clone(), &self.config.keys);
36        let file_store = file_store::FileStore::from_config(self.config.files.as_ref().unwrap_or(&Default::default()))?;
37
38        let state = AppState {
39            key_store: Arc::new(key_store),
40            service_pool: Arc::new(service_pool),
41            file_store: Arc::new(file_store),
42            config: Arc::new(self.config),
43        };
44
45        let addr: SocketAddr = format!("{}:{}", state.config.server.host, state.config.server.port)
46            .parse()
47            .map_err(|e| format!("invalid listen address: {e}"))?;
48
49        let router = routes::build_router(state);
50
51        tracing::info!("liter-llm proxy listening on {addr}");
52
53        let listener = tokio::net::TcpListener::bind(addr)
54            .await
55            .map_err(|e| format!("failed to bind {addr}: {e}"))?;
56
57        let shutdown = async {
58            let _ = tokio::signal::ctrl_c().await;
59            tracing::info!("shutdown signal received");
60        };
61
62        axum::serve(listener, router)
63            .with_graceful_shutdown(shutdown)
64            .await
65            .map_err(|e| format!("server error: {e}"))?;
66
67        Ok(())
68    }
69}