photon_runtime/
builder.rs1use std::sync::Arc;
4
5use photon_telemetry::{install_ops_log, OpsLog};
6
7use photon_backend::{
8 instrumentation, BackendContext, EmbeddedBackend, ExecutorServices, GenericPhotonBackend,
9 InProcStoragePort, PhotonBackend, PhotonError, Result, RetentionHook, RetentionPolicy,
10 StoragePort, TopicRegistry, TransportCrypto,
11};
12
13use crate::executor::ExecutorController;
14use crate::{Photon, PhotonRuntimeState};
15
16type BackendInstallFn =
17 Box<dyn FnOnce(BackendContext) -> Result<Arc<dyn PhotonBackend>> + Send>;
18
19#[derive(Default)]
32pub struct PhotonBuilder {
33 storage_port: Option<Arc<dyn StoragePort>>,
34 backend: Option<Arc<dyn PhotonBackend>>,
35 backend_install: Option<BackendInstallFn>,
36 use_auto_registry: bool,
37 ops_log: Option<Arc<dyn OpsLog>>,
38 retention_policy: Option<RetentionPolicy>,
39 retention_hook: Option<Arc<dyn RetentionHook>>,
40}
41
42impl PhotonBuilder {
43 #[must_use]
62 pub fn storage_port(mut self, port: Arc<dyn StoragePort>) -> Self {
63 self.storage_port = Some(port);
64 self
65 }
66
67 #[must_use]
69 pub fn backend(mut self, backend: Arc<dyn PhotonBackend>) -> Self {
70 self.backend = Some(backend);
71 self.backend_install = None;
72 self
73 }
74
75 #[must_use]
77 pub fn backend_with_context<F>(mut self, install: F) -> Self
78 where
79 F: FnOnce(BackendContext) -> Result<Arc<dyn PhotonBackend>> + Send + 'static,
80 {
81 self.backend = None;
82 self.backend_install = Some(Box::new(install));
83 self
84 }
85
86 #[must_use]
88 pub fn mem_backend(mut self) -> Self {
89 self.backend = None;
90 self.backend_install = Some(Box::new(EmbeddedBackend::install_mem));
91 self
92 }
93
94 #[must_use]
96 pub fn ops_log(mut self, log: impl OpsLog + 'static) -> Self {
97 self.ops_log = Some(Arc::new(log));
98 self
99 }
100
101 #[must_use]
103 pub fn ops_log_arc(mut self, log: Arc<dyn OpsLog>) -> Self {
104 self.ops_log = Some(log);
105 self
106 }
107
108 #[must_use]
113 pub const fn auto_registry(mut self) -> Self {
114 self.use_auto_registry = true;
115 self
116 }
117
118 #[must_use]
120 pub fn retention_policy(mut self, policy: RetentionPolicy) -> Self {
121 self.retention_policy = Some(policy);
122 self
123 }
124
125 #[must_use]
127 pub fn retention_hook(mut self, hook: Arc<dyn RetentionHook>) -> Self {
128 self.retention_hook = Some(hook);
129 self
130 }
131
132 pub fn build(self) -> Result<Photon> {
138 if let Some(log) = self.ops_log {
139 install_ops_log(log);
140 }
141
142 let registry = if self.use_auto_registry {
143 TopicRegistry::auto_discover()
144 } else {
145 TopicRegistry::new()
146 };
147
148 let port = match self.storage_port {
149 Some(port) => port,
150 None => Arc::new(InProcStoragePort::new(TransportCrypto::from_env()?)),
151 };
152
153 let ctx = BackendContext {
154 registry: registry.clone(),
155 };
156
157 let backend = match (self.backend, self.backend_install) {
158 (Some(b), None) => b,
159 (None, Some(install)) => install(ctx)?,
160 (None, None) => GenericPhotonBackend::install_with_port(
161 BackendContext { registry },
162 Arc::clone(&port),
163 )?,
164 (Some(_), Some(_)) => {
165 return Err(PhotonError::Internal(
166 "PhotonBuilder: set backend() or backend_with_context(), not both".into(),
167 ));
168 }
169 };
170
171 let retention_policy = self.retention_policy.unwrap_or_default();
172 let runtime = PhotonRuntimeState {
173 storage_port: Arc::clone(&port),
174 executor_services: Arc::new(ExecutorServices::new(
175 port,
176 retention_policy,
177 self.retention_hook,
178 )),
179 executor: Arc::new(ExecutorController::default()),
180 };
181
182 let backend = instrumentation::wrap_backend(backend);
183 Ok(Photon::new(backend, runtime))
184 }
185}