reifydb_sub_server/
state.rs1use reifydb_auth::service::AuthService;
5use reifydb_core::actors::server::ServerMessage;
6use reifydb_engine::engine::StandardEngine;
7use reifydb_runtime::{
8 actor::{
9 mailbox::ActorRef,
10 system::{ActorHandle, ActorSpawner},
11 },
12 context::{clock::Clock, rng::Rng},
13};
14use reifydb_value::value::duration::Duration;
15use tracing::instrument;
16
17use crate::{actor::ServerActor, interceptor::RequestInterceptorChain};
18
19#[derive(Debug, Clone)]
20pub struct StateConfig {
21 pub query_timeout: Duration,
22
23 pub request_timeout: Duration,
24
25 pub max_connections: usize,
26
27 pub admin_enabled: bool,
28
29 pub subscribe_max_hydration_rows: u64,
30
31 pub subscribe_min_throttle: Duration,
32
33 pub subscribe_min_linger: Duration,
34}
35
36impl Default for StateConfig {
37 fn default() -> Self {
38 Self {
39 query_timeout: Duration::from_seconds(30).unwrap(),
40 request_timeout: Duration::from_seconds(60).unwrap(),
41 max_connections: 10_000,
42 admin_enabled: false,
43 subscribe_max_hydration_rows: 10_000,
44 subscribe_min_throttle: Duration::from_milliseconds(50).unwrap(),
45 subscribe_min_linger: Duration::zero(),
46 }
47 }
48}
49
50impl StateConfig {
51 pub fn new() -> Self {
52 Self::default()
53 }
54
55 pub fn query_timeout(mut self, timeout: Duration) -> Self {
56 self.query_timeout = timeout;
57 self
58 }
59
60 pub fn request_timeout(mut self, timeout: Duration) -> Self {
61 self.request_timeout = timeout;
62 self
63 }
64
65 pub fn max_connections(mut self, max: usize) -> Self {
66 self.max_connections = max;
67 self
68 }
69
70 pub fn admin_enabled(mut self, enabled: bool) -> Self {
71 self.admin_enabled = enabled;
72 self
73 }
74
75 pub fn subscribe_max_hydration_rows(mut self, n: u64) -> Self {
76 self.subscribe_max_hydration_rows = n;
77 self
78 }
79
80 pub fn subscribe_min_throttle(mut self, interval: Duration) -> Self {
81 self.subscribe_min_throttle = interval;
82 self
83 }
84
85 pub fn subscribe_min_linger(mut self, interval: Duration) -> Self {
86 self.subscribe_min_linger = interval;
87 self
88 }
89}
90
91#[derive(Clone)]
92pub struct AppState {
93 spawner: ActorSpawner,
94 engine: StandardEngine,
95 auth_service: AuthService,
96 config: StateConfig,
97 request_interceptors: RequestInterceptorChain,
98 clock: Clock,
99 rng: Rng,
100}
101
102impl AppState {
103 pub fn new(
104 spawner: ActorSpawner,
105 engine: StandardEngine,
106 auth_service: AuthService,
107 config: StateConfig,
108 request_interceptors: RequestInterceptorChain,
109 clock: Clock,
110 rng: Rng,
111 ) -> Self {
112 Self {
113 spawner,
114 engine,
115 auth_service,
116 config,
117 request_interceptors,
118 clock,
119 rng,
120 }
121 }
122
123 pub fn clone_with_config(&self, config: StateConfig) -> Self {
124 Self {
125 spawner: self.spawner.clone(),
126 engine: self.engine.clone(),
127 auth_service: self.auth_service.clone(),
128 config,
129 request_interceptors: self.request_interceptors.clone(),
130 clock: self.clock.clone(),
131 rng: self.rng.clone(),
132 }
133 }
134
135 #[inline]
136 pub fn spawner(&self) -> ActorSpawner {
137 self.spawner.clone()
138 }
139
140 #[inline]
141 pub fn engine(&self) -> &StandardEngine {
142 &self.engine
143 }
144
145 #[inline]
146 pub fn engine_clone(&self) -> StandardEngine {
147 self.engine.clone()
148 }
149
150 #[inline]
151 pub fn config(&self) -> &StateConfig {
152 &self.config
153 }
154
155 #[inline]
156 pub fn query_timeout(&self) -> Duration {
157 self.config.query_timeout
158 }
159
160 #[inline]
161 pub fn request_timeout(&self) -> Duration {
162 self.config.request_timeout
163 }
164
165 #[inline]
166 pub fn max_connections(&self) -> usize {
167 self.config.max_connections
168 }
169
170 #[inline]
171 pub fn admin_enabled(&self) -> bool {
172 self.config.admin_enabled
173 }
174
175 #[inline]
176 pub fn subscribe_max_hydration_rows(&self) -> u64 {
177 self.config.subscribe_max_hydration_rows
178 }
179
180 #[inline]
181 pub fn subscribe_min_throttle(&self) -> Duration {
182 self.config.subscribe_min_throttle
183 }
184
185 pub fn clamp_throttle(&self, requested: Option<Duration>) -> Duration {
186 match requested {
187 Some(d) if !d.is_zero() => d.max(self.config.subscribe_min_throttle),
188 _ => Duration::zero(),
189 }
190 }
191
192 #[inline]
193 pub fn subscribe_min_linger(&self) -> Duration {
194 self.config.subscribe_min_linger
195 }
196
197 pub fn clamp_linger(&self, requested: Option<Duration>) -> Duration {
198 match requested {
199 Some(d) if !d.is_zero() => d.max(self.config.subscribe_min_linger),
200 _ => Duration::zero(),
201 }
202 }
203
204 #[inline]
205 pub fn request_interceptors(&self) -> &RequestInterceptorChain {
206 &self.request_interceptors
207 }
208
209 #[inline]
210 pub fn clock(&self) -> &Clock {
211 &self.clock
212 }
213
214 #[inline]
215 pub fn rng(&self) -> &Rng {
216 &self.rng
217 }
218
219 #[inline]
220 pub fn auth_service(&self) -> &AuthService {
221 &self.auth_service
222 }
223
224 #[instrument(name = "actor::spawn_server", level = "info", skip_all)]
225 pub fn spawn_server_actor(&self) -> (ActorRef<ServerMessage>, ActorHandle<ServerMessage>) {
226 let actor = ServerActor::new(self.engine.clone(), self.auth_service.clone(), self.clock.clone());
227 let handle = self.spawner.spawn_query("server-req", actor);
228 let actor_ref = handle.actor_ref().clone();
229 (actor_ref, handle)
230 }
231}
232
233#[cfg(test)]
234pub mod tests {
235 use super::*;
236
237 #[test]
238 fn test_query_defaults() {
239 let config = StateConfig::default();
240 assert_eq!(config.query_timeout, Duration::from_seconds(30).unwrap());
241 assert_eq!(config.request_timeout, Duration::from_seconds(60).unwrap());
242 assert_eq!(config.max_connections, 10_000);
243 assert_eq!(config.subscribe_max_hydration_rows, 10_000);
244 assert_eq!(config.subscribe_min_throttle, Duration::from_milliseconds(50).unwrap());
245 assert_eq!(config.subscribe_min_linger, Duration::zero());
246 }
247
248 #[test]
249 fn test_query_config_builder() {
250 let config = StateConfig::new()
251 .query_timeout(Duration::from_seconds(60).unwrap())
252 .request_timeout(Duration::from_seconds(120).unwrap())
253 .max_connections(5_000)
254 .subscribe_max_hydration_rows(50_000)
255 .subscribe_min_throttle(Duration::from_milliseconds(200).unwrap())
256 .subscribe_min_linger(Duration::from_milliseconds(20).unwrap());
257
258 assert_eq!(config.query_timeout, Duration::from_seconds(60).unwrap());
259 assert_eq!(config.request_timeout, Duration::from_seconds(120).unwrap());
260 assert_eq!(config.max_connections, 5_000);
261 assert_eq!(config.subscribe_max_hydration_rows, 50_000);
262 assert_eq!(config.subscribe_min_throttle, Duration::from_milliseconds(200).unwrap());
263 assert_eq!(config.subscribe_min_linger, Duration::from_milliseconds(20).unwrap());
264 }
265}