ruvector_server/
lib.rs

1//! ruvector-server: REST API server for rUvector vector database
2//!
3//! This crate provides a REST API server built on axum for interacting with rUvector.
4
5pub mod error;
6pub mod routes;
7pub mod state;
8
9use axum::{routing::get, Router};
10use serde::{Deserialize, Serialize};
11use std::net::SocketAddr;
12use tower_http::{
13    compression::CompressionLayer,
14    cors::{Any, CorsLayer},
15    trace::TraceLayer,
16};
17
18pub use error::{Error, Result};
19pub use state::AppState;
20
21/// Server configuration
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct Config {
24    /// Server host address
25    pub host: String,
26    /// Server port
27    pub port: u16,
28    /// Enable CORS
29    pub enable_cors: bool,
30    /// Enable compression
31    pub enable_compression: bool,
32}
33
34impl Default for Config {
35    fn default() -> Self {
36        Self {
37            host: "127.0.0.1".to_string(),
38            port: 6333,
39            enable_cors: true,
40            enable_compression: true,
41        }
42    }
43}
44
45/// Main server structure
46pub struct RuvectorServer {
47    config: Config,
48    state: AppState,
49}
50
51impl RuvectorServer {
52    /// Create a new server instance with default configuration
53    pub fn new() -> Self {
54        Self {
55            config: Config::default(),
56            state: AppState::new(),
57        }
58    }
59
60    /// Create a new server instance with custom configuration
61    pub fn with_config(config: Config) -> Self {
62        Self {
63            config,
64            state: AppState::new(),
65        }
66    }
67
68    /// Build the router with all routes
69    fn build_router(&self) -> Router {
70        let mut router = Router::new()
71            .route("/health", get(routes::health::health_check))
72            .route("/ready", get(routes::health::readiness))
73            .nest("/collections", routes::collections::routes())
74            .merge(routes::points::routes())
75            .with_state(self.state.clone());
76
77        // Add middleware layers
78        router = router.layer(TraceLayer::new_for_http());
79
80        if self.config.enable_compression {
81            router = router.layer(CompressionLayer::new());
82        }
83
84        if self.config.enable_cors {
85            let cors = CorsLayer::new()
86                .allow_origin(Any)
87                .allow_methods(Any)
88                .allow_headers(Any);
89            router = router.layer(cors);
90        }
91
92        router
93    }
94
95    /// Start the server
96    ///
97    /// # Errors
98    ///
99    /// Returns an error if the server fails to bind or start
100    pub async fn start(self) -> Result<()> {
101        let addr: SocketAddr = format!("{}:{}", self.config.host, self.config.port)
102            .parse()
103            .map_err(|e| Error::Config(format!("Invalid address: {}", e)))?;
104
105        let router = self.build_router();
106
107        tracing::info!("Starting ruvector-server on {}", addr);
108
109        let listener = tokio::net::TcpListener::bind(addr)
110            .await
111            .map_err(|e| Error::Server(format!("Failed to bind to {}: {}", addr, e)))?;
112
113        axum::serve(listener, router)
114            .await
115            .map_err(|e| Error::Server(format!("Server error: {}", e)))?;
116
117        Ok(())
118    }
119}
120
121impl Default for RuvectorServer {
122    fn default() -> Self {
123        Self::new()
124    }
125}