Skip to main content

reifydb_sub_server/
state.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4//! Application state shared across request handler.
5//!
6//! This module provides the shared state that is passed to all HTTP and WebSocket
7//! handler, including the database engine and query configuration.
8
9use std::time::Duration;
10
11use reifydb_auth::service::AuthService;
12use reifydb_engine::engine::StandardEngine;
13use reifydb_runtime::{
14	actor::system::ActorSystem,
15	context::{clock::Clock, rng::Rng},
16};
17
18use crate::interceptor::RequestInterceptorChain;
19
20/// Configuration for query execution.
21#[derive(Debug, Clone)]
22pub struct StateConfig {
23	/// Timeout for individual query execution.
24	/// If a query takes longer than this, it will be cancelled.
25	pub query_timeout: Duration,
26	/// Timeout for entire HTTP request lifecycle.
27	/// This includes reading the request, executing the query, and writing the response.
28	pub request_timeout: Duration,
29	/// Maximum concurrent connections allowed.
30	/// New connections beyond this limit will be rejected.
31	pub max_connections: usize,
32	/// Whether admin (DDL) operations are enabled on this listener.
33	pub admin_enabled: bool,
34}
35
36impl Default for StateConfig {
37	fn default() -> Self {
38		Self {
39			query_timeout: Duration::from_secs(30),
40			request_timeout: Duration::from_secs(60),
41			max_connections: 10_000,
42			admin_enabled: false,
43		}
44	}
45}
46
47impl StateConfig {
48	/// Create a new QueryConfig with default values.
49	pub fn new() -> Self {
50		Self::default()
51	}
52
53	/// Set the query timeout.
54	pub fn query_timeout(mut self, timeout: Duration) -> Self {
55		self.query_timeout = timeout;
56		self
57	}
58
59	/// Set the request timeout.
60	pub fn request_timeout(mut self, timeout: Duration) -> Self {
61		self.request_timeout = timeout;
62		self
63	}
64
65	/// Set the maximum connections.
66	pub fn max_connections(mut self, max: usize) -> Self {
67		self.max_connections = max;
68		self
69	}
70
71	/// Set whether admin operations are enabled.
72	pub fn admin_enabled(mut self, enabled: bool) -> Self {
73		self.admin_enabled = enabled;
74		self
75	}
76}
77
78/// Shared application state passed to all request handler.
79///
80/// This struct is cloneable and cheap to clone since `StandardEngine` uses
81/// `Arc` internally. Each handler receives a clone of this state.
82///
83/// # Example
84///
85/// ```ignore
86/// let state = AppState::new(actor_system, engine, QueryConfig::default(), interceptors);
87///
88/// // In an axum handler:
89/// async fn handle_query(State(state): State<AppState>, ...) {
90///     let system = state.actor_system();
91///     let engine = state.engine();
92///     // ...
93/// }
94/// ```
95#[derive(Clone)]
96pub struct AppState {
97	actor_system: ActorSystem,
98	engine: StandardEngine,
99	auth_service: AuthService,
100	config: StateConfig,
101	request_interceptors: RequestInterceptorChain,
102	clock: Clock,
103	rng: Rng,
104}
105
106impl AppState {
107	/// Create a new AppState with the given actor system, engine, configuration,
108	/// and request interceptor chain.
109	pub fn new(
110		actor_system: ActorSystem,
111		engine: StandardEngine,
112		auth_service: AuthService,
113		config: StateConfig,
114		request_interceptors: RequestInterceptorChain,
115		clock: Clock,
116		rng: Rng,
117	) -> Self {
118		Self {
119			actor_system,
120			engine,
121			auth_service,
122			config,
123			request_interceptors,
124			clock,
125			rng,
126		}
127	}
128
129	/// Clone this state with a different configuration, preserving the
130	/// interceptor chain and other shared resources.
131	pub fn clone_with_config(&self, config: StateConfig) -> Self {
132		Self {
133			actor_system: self.actor_system.clone(),
134			engine: self.engine.clone(),
135			auth_service: self.auth_service.clone(),
136			config,
137			request_interceptors: self.request_interceptors.clone(),
138			clock: self.clock.clone(),
139			rng: self.rng.clone(),
140		}
141	}
142
143	/// Get a clone of the actor system.
144	///
145	/// This is cheap since `ActorSystem` uses `Arc` internally.
146	#[inline]
147	pub fn actor_system(&self) -> ActorSystem {
148		self.actor_system.clone()
149	}
150
151	/// Get a reference to the database engine.
152	#[inline]
153	pub fn engine(&self) -> &StandardEngine {
154		&self.engine
155	}
156
157	/// Get a clone of the database engine.
158	///
159	/// This is cheap since `StandardEngine` uses `Arc` internally.
160	#[inline]
161	pub fn engine_clone(&self) -> StandardEngine {
162		self.engine.clone()
163	}
164
165	/// Get a reference to the query configuration.
166	#[inline]
167	pub fn config(&self) -> &StateConfig {
168		&self.config
169	}
170
171	/// Get the query timeout from configuration.
172	#[inline]
173	pub fn query_timeout(&self) -> Duration {
174		self.config.query_timeout
175	}
176
177	/// Get the request timeout from configuration.
178	#[inline]
179	pub fn request_timeout(&self) -> Duration {
180		self.config.request_timeout
181	}
182
183	/// Get the maximum connections from configuration.
184	#[inline]
185	pub fn max_connections(&self) -> usize {
186		self.config.max_connections
187	}
188
189	/// Get whether admin operations are enabled.
190	#[inline]
191	pub fn admin_enabled(&self) -> bool {
192		self.config.admin_enabled
193	}
194
195	/// Get a reference to the request interceptor chain.
196	#[inline]
197	pub fn request_interceptors(&self) -> &RequestInterceptorChain {
198		&self.request_interceptors
199	}
200
201	/// Get a reference to the clock.
202	#[inline]
203	pub fn clock(&self) -> &Clock {
204		&self.clock
205	}
206
207	/// Get a reference to the RNG.
208	#[inline]
209	pub fn rng(&self) -> &Rng {
210		&self.rng
211	}
212
213	/// Get a reference to the authentication service.
214	#[inline]
215	pub fn auth_service(&self) -> &AuthService {
216		&self.auth_service
217	}
218}
219
220#[cfg(test)]
221pub mod tests {
222	use super::*;
223
224	#[test]
225	fn test_query_defaults() {
226		let config = StateConfig::default();
227		assert_eq!(config.query_timeout, Duration::from_secs(30));
228		assert_eq!(config.request_timeout, Duration::from_secs(60));
229		assert_eq!(config.max_connections, 10_000);
230	}
231
232	#[test]
233	fn test_query_config_builder() {
234		let config = StateConfig::new()
235			.query_timeout(Duration::from_secs(60))
236			.request_timeout(Duration::from_secs(120))
237			.max_connections(5_000);
238
239		assert_eq!(config.query_timeout, Duration::from_secs(60));
240		assert_eq!(config.request_timeout, Duration::from_secs(120));
241		assert_eq!(config.max_connections, 5_000);
242	}
243}