use crate::server::dispatcher::Dispatcher;
use crate::{EmbeddingEngine, EngineConfig, ModelConfig};
use std::path::Path;
use std::sync::{Arc, Mutex};
use tracing::info;
#[derive(Debug, Clone)]
pub struct ServerConfig {
pub worker_count: usize,
pub queue_size: usize,
pub host: String,
pub port: u16,
pub request_timeout: std::time::Duration,
pub engine_config: EngineConfig,
}
impl Default for ServerConfig {
fn default() -> Self {
let engine_config = EngineConfig::default();
Self {
worker_count: num_cpus::get(),
queue_size: 100,
host: "127.0.0.1".to_string(),
port: 8080,
request_timeout: std::time::Duration::from_secs(60),
engine_config,
}
}
}
impl ServerConfig {
pub fn builder() -> ServerConfigBuilder {
ServerConfigBuilder::default()
}
}
#[derive(Debug, Default)]
pub struct ServerConfigBuilder {
worker_count: Option<usize>,
queue_size: Option<usize>,
host: Option<String>,
port: Option<u16>,
request_timeout: Option<std::time::Duration>,
engine_config: Option<EngineConfig>,
}
impl ServerConfigBuilder {
#[must_use]
pub fn engine_config(mut self, config: EngineConfig) -> Self {
self.engine_config = Some(config);
self
}
#[must_use]
pub fn model_path(mut self, path: impl Into<String>) -> Self {
let path_str = path.into();
let model_name = Path::new(&path_str)
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or("default")
.to_string();
if let Ok(model_config) = ModelConfig::builder()
.with_model_path(path_str)
.with_model_name(&model_name)
.build()
&& let Ok(engine_config) = EngineConfig::builder()
.with_model_config(model_config)
.build()
{
self.engine_config = Some(engine_config);
}
self
}
#[must_use]
pub fn model_name(self, _name: impl Into<String>) -> Self {
self
}
#[must_use]
pub fn worker_count(mut self, count: usize) -> Self {
self.worker_count = Some(count);
self
}
#[must_use]
pub fn queue_size(mut self, size: usize) -> Self {
self.queue_size = Some(size);
self
}
#[must_use]
pub fn host(mut self, host: impl Into<String>) -> Self {
self.host = Some(host.into());
self
}
#[must_use]
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
#[must_use]
pub fn request_timeout(mut self, timeout: std::time::Duration) -> Self {
self.request_timeout = Some(timeout);
self
}
pub fn build(self) -> crate::Result<ServerConfig> {
let default = ServerConfig::default();
let engine_config = self
.engine_config
.ok_or_else(|| crate::Error::ConfigurationError {
message: "Engine configuration is required. Use .engine_config() or .model_path()"
.to_string(),
})?;
engine_config.validate()?;
let worker_count = self.worker_count.unwrap_or(default.worker_count);
let queue_size = self.queue_size.unwrap_or(default.queue_size);
if worker_count == 0 {
return Err(crate::Error::ConfigurationError {
message: "Worker count must be at least 1".to_string(),
});
}
if worker_count > 128 {
return Err(crate::Error::ConfigurationError {
message: "Worker count cannot exceed 128".to_string(),
});
}
if queue_size == 0 {
return Err(crate::Error::ConfigurationError {
message: "Queue size must be at least 1".to_string(),
});
}
if queue_size > 10000 {
return Err(crate::Error::ConfigurationError {
message: "Queue size cannot exceed 10000".to_string(),
});
}
Ok(ServerConfig {
worker_count,
queue_size,
host: self.host.unwrap_or(default.host),
port: self.port.unwrap_or(default.port),
request_timeout: self.request_timeout.unwrap_or(default.request_timeout),
engine_config,
})
}
}
#[derive(Clone)]
pub struct AppState {
pub dispatcher: Arc<Dispatcher>,
pub config: Arc<ServerConfig>,
pub engine: Arc<Mutex<EmbeddingEngine>>,
}
impl AppState {
pub fn new(config: ServerConfig) -> crate::Result<Self> {
let engine = EmbeddingEngine::get_or_init(config.engine_config.clone())?;
let n_seq_max = config.engine_config.model_config.n_seq_max.unwrap_or(8);
info!(
"Creating AppState with model '{}' (n_seq_max: {})",
config.engine_config.model_config.model_name, n_seq_max
);
let dispatcher = Dispatcher::new(n_seq_max as usize, config.queue_size);
Ok(Self {
dispatcher: Arc::new(dispatcher),
config: Arc::new(config),
engine,
})
}
pub fn model_name(&self) -> &str {
&self.config.engine_config.model_config.model_name
}
pub fn is_ready(&self) -> bool {
self.dispatcher.is_ready()
}
}