Skip to main content

linkrs_server/http/
server.rs

1//! HTTP server
2//!
3//! Provides an HTTP-based interface to Linkrs services
4
5use crate::auth::PasswordAuthenticator;
6use crate::batch::BatchManager;
7use crate::config::Config;
8use crate::graph_service::GraphService;
9use crate::query::executor::expression::functions::FunctionRegistry;
10use crate::session::GraphSessionManager;
11use crate::storage::{
12    StorageClient, StorageOperationContextOps, StorageSchemaContextOps, StorageSyncContextOps,
13};
14use linkrs_api::api_core::{QueryApi, SchemaApi, TransactionApi};
15use linkrs_transaction::TransactionManager;
16use parking_lot::RwLock;
17use std::sync::Arc;
18
19/// HTTP server
20///
21/// Note: HttpServer relies on GraphService for the Rights Manager and Statistics Manager.
22/// The session manager is accessed through the GraphService
23pub struct HttpServer<
24    S: StorageClient
25        + StorageSchemaContextOps
26        + StorageSyncContextOps
27        + StorageOperationContextOps
28        + Clone
29        + 'static,
30> {
31    graph_service: Arc<GraphService<S>>,
32    query_api: QueryApi<S>,
33    txn_manager: Arc<TransactionManager>,
34    txn_api: TransactionApi,
35    schema_api: SchemaApi<S>,
36    auth_service: PasswordAuthenticator,
37    batch_manager: Arc<BatchManager<S>>,
38    storage: Arc<RwLock<S>>,
39    /// Live configuration. Mutated by config-write endpoints and persisted
40    /// to `config_path` when one was retained at startup.
41    config: Arc<RwLock<Config>>,
42    /// Config file the running config was loaded from, if any. Updates are
43    /// written back here; `None` means memory-only updates.
44    config_path: Option<std::path::PathBuf>,
45    function_registry: Arc<RwLock<FunctionRegistry>>,
46    rebuild_tasks: super::handlers::rebuild::RebuildTaskRegistry,
47}
48
49impl<
50        S: StorageClient
51            + StorageSchemaContextOps
52            + StorageSyncContextOps
53            + StorageOperationContextOps
54            + Clone
55            + 'static,
56    > HttpServer<S>
57{
58    /// Create a new HTTP server
59    pub fn new(
60        graph_service: Arc<GraphService<S>>,
61        storage: Arc<RwLock<S>>,
62        txn_manager: Arc<TransactionManager>,
63        config: &Config,
64        config_path: Option<std::path::PathBuf>,
65    ) -> Self {
66        // Use the shared StatsManager from GraphService
67        let stats_manager = graph_service.get_stats_manager().clone();
68        Self {
69            graph_service: graph_service.clone(),
70            query_api: QueryApi::new(storage.clone(), stats_manager)
71                .with_password_history_depth(config.server.security.password_policy.history_size),
72            txn_manager: txn_manager.clone(),
73            txn_api: TransactionApi::new(txn_manager),
74            schema_api: SchemaApi::new(storage.clone()),
75            auth_service: PasswordAuthenticator::new_default(config.server.auth.clone()),
76            batch_manager: Arc::new(BatchManager::new(storage.clone())),
77            storage: storage.clone(),
78            config: Arc::new(RwLock::new(config.clone())),
79            config_path,
80            function_registry: Arc::new(RwLock::new(FunctionRegistry::new())),
81            rebuild_tasks: super::handlers::rebuild::RebuildTaskRegistry::default(),
82        }
83    }
84
85    /// Get GraphService
86    pub fn get_graph_service(&self) -> Arc<GraphService<S>> {
87        self.graph_service.clone()
88    }
89
90    /// Get Session Manager (via GraphService)
91    pub fn get_session_manager(&self) -> &GraphSessionManager {
92        self.graph_service.get_session_manager()
93    }
94
95    /// Getting the Query API
96    pub fn get_query_api(&self) -> &QueryApi<S> {
97        &self.query_api
98    }
99
100    /// Getting the Transaction Manager
101    pub fn get_txn_manager(&self) -> Arc<TransactionManager> {
102        self.txn_manager.clone()
103    }
104
105    /// Getting the Transaction API (core layer)
106    pub fn get_txn_api(&self) -> &TransactionApi {
107        &self.txn_api
108    }
109
110    /// Getting the Schema API
111    pub fn get_schema_api(&self) -> &SchemaApi<S> {
112        &self.schema_api
113    }
114
115    /// Access to Certification Services
116    pub fn get_auth_service(&self) -> &PasswordAuthenticator {
117        &self.auth_service
118    }
119
120    /// Get Bulk Task Manager
121    pub fn get_batch_manager(&self) -> Arc<BatchManager<S>> {
122        self.batch_manager.clone()
123    }
124
125    /// Getting the Statistics Manager (via GraphService)
126    pub fn get_stats_manager(&self) -> &Arc<linkrs_metrics::StatsManager> {
127        self.graph_service.get_stats_manager()
128    }
129
130    /// Getting the Storage Client
131    pub fn get_storage(&self) -> Arc<RwLock<S>> {
132        self.storage.clone()
133    }
134
135    /// Get live configuration (read guard; reflects applied updates).
136    pub fn get_config(&self) -> parking_lot::RwLockReadGuard<'_, Config> {
137        self.config.read()
138    }
139
140    /// Config file updates are written back to, if one was retained.
141    pub fn get_config_path(&self) -> Option<std::path::PathBuf> {
142        self.config_path.clone()
143    }
144
145    /// Live configuration store for config-write endpoints.
146    pub(crate) fn config_store(&self) -> Arc<RwLock<Config>> {
147        Arc::clone(&self.config)
148    }
149
150    /// Build the engine-facing migration config from live settings.
151    ///
152    /// Directory fields fall back to `migration/` subdirectories of the
153    /// storage data directory; an empty data directory leaves that
154    /// capability disabled instead of failing.
155    pub fn migration_config(&self) -> linkrs_migration::MigrationConfig {
156        let guard = self.config.read();
157        let settings = &guard.common.migration;
158        let data_dir = guard.common.database.storage_path.as_str();
159        linkrs_migration::MigrationConfig {
160            batch_size: settings.batch_size,
161            lock_ttl_secs: 300,
162            checkpoint_dir: settings.resolved_checkpoint_dir(data_dir),
163            lock_path: settings.resolved_lock_path(data_dir),
164            min_free_bytes: settings.min_free_bytes,
165            drain_timeout_ms: settings.drain_timeout_ms,
166            backup_dir: settings.resolved_backup_dir(data_dir),
167        }
168    }
169
170    /// Get function registry
171    pub fn get_function_registry(&self) -> Arc<RwLock<FunctionRegistry>> {
172        self.function_registry.clone()
173    }
174
175    /// Async index rebuild task registry.
176    pub fn rebuild_tasks(&self) -> super::handlers::rebuild::RebuildTaskRegistry {
177        self.rebuild_tasks.clone()
178    }
179}