1use std::sync::Arc;
2
3use rivet_foundation::{defaults, Config, Container, ServiceProvider};
4
5use crate::application::Application;
6use crate::error::{BuildError, RivetError};
7use crate::module::RivetModule;
8use crate::state::Build;
9
10pub type ProviderFactory = fn() -> Box<dyn ServiceProvider>;
12
13pub struct Builder {
21 modules: Vec<Box<dyn RivetModule>>,
22 provider_factories: Vec<ProviderFactory>,
23 container: Arc<dyn Container>,
24 config: Box<dyn Config>,
25}
26
27impl Builder {
28 pub fn with_defaults() -> Self {
30 let (container, config) = defaults();
31 Self::new(container, config)
32 }
33
34 pub fn new(container: Arc<dyn Container>, config: Box<dyn Config>) -> Self {
36 Self {
37 modules: Vec::new(),
38 provider_factories: Vec::new(),
39 container,
40 config,
41 }
42 }
43
44 pub fn with_module(mut self, module: Box<dyn RivetModule>) -> Self {
46 self.modules.push(module);
47 self
48 }
49
50 pub fn with_provider(mut self, provider: ProviderFactory) -> Self {
52 self.provider_factories.push(provider);
53 self
54 }
55
56 pub fn with_providers(mut self, providers: &[ProviderFactory]) -> Self {
58 self.provider_factories.extend(providers.iter().copied());
59 self
60 }
61
62 pub fn module_count(&self) -> usize {
64 self.modules.len()
65 }
66
67 #[tracing::instrument(skip(self), level = "debug")]
69 pub fn build(self) -> Result<Application, RivetError> {
70 let mut state = Build::new(self.container, self.config);
71 tracing::debug!(
72 module_count = self.modules.len(),
73 "starting rivet-core build"
74 );
75
76 Self::run_config_stage(&self.modules, &mut state)?;
77 Self::run_provider_stage(&self.modules, &self.provider_factories, &mut state)?;
78 Self::run_route_and_middleware_stage(&self.modules, &mut state)?;
79
80 Ok(Application::from_state(state.into_runtime()))
81 }
82
83 fn run_config_stage(
84 modules: &[Box<dyn RivetModule>],
85 state: &mut Build,
86 ) -> Result<(), RivetError> {
87 tracing::debug!("starting config stage");
88
89 for module in modules {
90 tracing::debug!(module = module.name(), "configuring module");
91 module
92 .configure(state.config_mut())
93 .map_err(|err| BuildError::Configure {
94 module: module.name(),
95 message: err.to_string(),
96 })?;
97 }
98
99 tracing::debug!("finished config stage");
100 Ok(())
101 }
102
103 fn run_provider_stage(
104 modules: &[Box<dyn RivetModule>],
105 provider_factories: &[ProviderFactory],
106 state: &mut Build,
107 ) -> Result<(), RivetError> {
108 tracing::debug!("starting provider stage");
109
110 for module in modules {
111 tracing::debug!(module = module.name(), "collecting module providers");
112 for provider in module.providers() {
113 state.push_provider(provider);
114 }
115 }
116
117 for factory in provider_factories {
118 state.push_provider(factory());
119 }
120
121 for provider in state.providers() {
122 tracing::debug!(provider = provider.name(), "registering provider");
123 provider
124 .register(state.container())
125 .map_err(|err| BuildError::ProviderRegister {
126 provider: provider.name().to_string(),
127 source: err,
128 })?;
129 }
130
131 for provider in state.providers() {
132 tracing::debug!(provider = provider.name(), "booting provider");
133 provider
134 .boot(state.container())
135 .map_err(|err| BuildError::ProviderBoot {
136 provider: provider.name().to_string(),
137 source: err,
138 })?;
139 }
140
141 tracing::debug!("finished provider stage");
142 Ok(())
143 }
144
145 fn run_route_and_middleware_stage(
146 modules: &[Box<dyn RivetModule>],
147 state: &mut Build,
148 ) -> Result<(), RivetError> {
149 tracing::debug!("starting routes+middleware stage");
150
151 for module in modules {
152 tracing::debug!(module = module.name(), "collecting module routes");
153 module
154 .routes(state.routes_mut())
155 .map_err(|err| BuildError::Routes {
156 module: module.name(),
157 message: err.to_string(),
158 })?;
159 }
160
161 for module in modules {
162 tracing::debug!(module = module.name(), "collecting module middleware");
163 state.extend_middleware(module.middleware());
164 }
165
166 tracing::debug!("finished routes+middleware stage");
167 Ok(())
168 }
169}