1use std::sync::Arc;
5
6use reifydb_auth::{
7 registry::AuthenticationRegistry,
8 service::{AuthService, AuthServiceConfig},
9};
10use reifydb_core::util::ioc::IocContainer;
11use reifydb_engine::engine::StandardEngine;
12use reifydb_runtime::{
13 actor::system::ActorSpawner,
14 context::{clock::Clock, rng::Rng},
15};
16use reifydb_sub_api::subsystem::{Subsystem, SubsystemFactory};
17use reifydb_sub_server::{
18 interceptor::RequestInterceptorChain,
19 state::{AppState, StateConfig},
20};
21use reifydb_value::{Result, value::duration::Duration};
22use tokio::runtime::Handle;
23
24use crate::subsystem::HttpSubsystem;
25
26pub struct HttpConfigurator {
27 bind_addr: Option<String>,
28 admin_bind_addr: Option<String>,
29 max_connections: usize,
30 query_timeout: Duration,
31 request_timeout: Duration,
32 spawner: Option<ActorSpawner>,
33 clock: Option<Clock>,
34 rng: Option<Rng>,
35 handle: Option<Handle>,
36}
37
38impl Default for HttpConfigurator {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44impl HttpConfigurator {
45 pub fn new() -> Self {
46 Self {
47 bind_addr: None,
48 admin_bind_addr: None,
49 max_connections: 10_000,
50 query_timeout: Duration::from_seconds(30).unwrap(),
51 request_timeout: Duration::from_seconds(60).unwrap(),
52 spawner: None,
53 clock: None,
54 rng: None,
55 handle: None,
56 }
57 }
58
59 pub fn bind_addr(mut self, addr: impl Into<String>) -> Self {
60 self.bind_addr = Some(addr.into());
61 self
62 }
63
64 pub fn admin_bind_addr(mut self, addr: impl Into<String>) -> Self {
65 self.admin_bind_addr = Some(addr.into());
66 self
67 }
68
69 pub fn max_connections(mut self, max: usize) -> Self {
70 self.max_connections = max;
71 self
72 }
73
74 pub fn query_timeout(mut self, timeout: Duration) -> Self {
75 self.query_timeout = timeout;
76 self
77 }
78
79 pub fn request_timeout(mut self, timeout: Duration) -> Self {
80 self.request_timeout = timeout;
81 self
82 }
83
84 pub fn spawner(mut self, spawner: ActorSpawner) -> Self {
85 self.spawner = Some(spawner);
86 self
87 }
88
89 pub fn clock(mut self, clock: Clock) -> Self {
90 self.clock = Some(clock);
91 self
92 }
93
94 pub fn rng(mut self, rng: Rng) -> Self {
95 self.rng = Some(rng);
96 self
97 }
98
99 pub fn handle(mut self, handle: Handle) -> Self {
100 self.handle = Some(handle);
101 self
102 }
103
104 pub(crate) fn configure(self) -> HttpConfig {
105 HttpConfig {
106 bind_addr: self.bind_addr,
107 admin_bind_addr: self.admin_bind_addr,
108 max_connections: self.max_connections,
109 query_timeout: self.query_timeout,
110 request_timeout: self.request_timeout,
111 spawner: self.spawner,
112 clock: self.clock,
113 rng: self.rng,
114 handle: self.handle,
115 }
116 }
117}
118
119#[derive(Clone)]
120pub struct HttpConfig {
121 pub bind_addr: Option<String>,
122
123 pub admin_bind_addr: Option<String>,
124
125 pub max_connections: usize,
126
127 pub query_timeout: Duration,
128
129 pub request_timeout: Duration,
130
131 pub spawner: Option<ActorSpawner>,
132
133 pub clock: Option<Clock>,
134
135 pub rng: Option<Rng>,
136
137 pub handle: Option<Handle>,
138}
139
140impl Default for HttpConfig {
141 fn default() -> Self {
142 HttpConfigurator::new().configure()
143 }
144}
145
146pub struct HttpSubsystemFactory {
147 config_fn: Box<dyn FnOnce() -> HttpConfig + Send>,
148}
149
150impl HttpSubsystemFactory {
151 pub fn new<F>(configurator: F) -> Self
152 where
153 F: FnOnce(HttpConfigurator) -> HttpConfigurator + Send + 'static,
154 {
155 Self {
156 config_fn: Box::new(move || configurator(HttpConfigurator::new()).configure()),
157 }
158 }
159}
160
161type ResolvedDeps = (StandardEngine, RequestInterceptorChain, ActorSpawner, Clock, Rng, Handle);
162
163impl SubsystemFactory for HttpSubsystemFactory {
164 fn create(self: Box<Self>, ioc: &IocContainer) -> Result<Box<dyn Subsystem>> {
165 let config = (self.config_fn)();
166
167 let (engine, interceptors, spawner, clock, rng, handle) =
168 Self::resolve_deps(ioc, config.spawner, config.clock, config.rng, config.handle)?;
169
170 let state = Self::build_app_state(
171 config.query_timeout,
172 config.request_timeout,
173 config.max_connections,
174 spawner,
175 engine,
176 clock,
177 rng,
178 interceptors,
179 );
180
181 let subsystem =
182 Self::build_subsystem(config.bind_addr.clone(), config.admin_bind_addr.clone(), state, handle)?;
183
184 Ok(Box::new(subsystem))
185 }
186}
187
188impl HttpSubsystemFactory {
189 #[inline]
190 #[allow(clippy::too_many_arguments)]
191 fn resolve_deps(
192 ioc: &IocContainer,
193 spawner: Option<ActorSpawner>,
194 clock: Option<Clock>,
195 rng: Option<Rng>,
196 handle: Option<Handle>,
197 ) -> Result<ResolvedDeps> {
198 let engine = ioc.resolve::<StandardEngine>()?;
199 let interceptors = ioc.resolve::<RequestInterceptorChain>().unwrap_or_default();
200
201 let spawner = match spawner {
202 Some(spawner) => spawner,
203 None => ioc.resolve::<ActorSpawner>()?,
204 };
205 let clock = match clock {
206 Some(clock) => clock,
207 None => ioc.resolve::<Clock>()?,
208 };
209 let rng = match rng {
210 Some(rng) => rng,
211 None => ioc.resolve::<Rng>()?,
212 };
213 let handle = match handle {
214 Some(handle) => handle,
215 None => ioc.resolve::<Handle>()?,
216 };
217
218 Ok((engine, interceptors, spawner, clock, rng, handle))
219 }
220
221 #[inline]
222 #[allow(clippy::too_many_arguments)]
223 fn build_app_state(
224 query_timeout: Duration,
225 request_timeout: Duration,
226 max_connections: usize,
227 spawner: ActorSpawner,
228 engine: StandardEngine,
229 clock: Clock,
230 rng: Rng,
231 interceptors: RequestInterceptorChain,
232 ) -> AppState {
233 let query_config = StateConfig::new()
234 .query_timeout(query_timeout)
235 .request_timeout(request_timeout)
236 .max_connections(max_connections);
237
238 let auth_service = AuthService::new(
239 Arc::new(engine.clone()),
240 Arc::new(AuthenticationRegistry::new(clock.clone())),
241 rng.clone(),
242 clock.clone(),
243 AuthServiceConfig::default(),
244 );
245
246 AppState::new(spawner, engine, auth_service, query_config, interceptors, clock, rng)
247 }
248
249 #[inline]
250 fn build_subsystem(
251 bind_addr: Option<String>,
252 admin_bind_addr: Option<String>,
253 state: AppState,
254 handle: Handle,
255 ) -> Result<HttpSubsystem> {
256 HttpSubsystem::new(bind_addr, admin_bind_addr, state, handle)
257 }
258}