1use std::collections::HashMap;
2use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
3use std::sync::{Arc, Mutex};
4
5use crate::app::errors::{AppError, AppResult};
6use crate::component::constants::DEFAULT_ENTRY_NAME;
7use crate::component::types::DynService;
8use crate::component::{Component, ComponentContainer};
9
10#[allow(dead_code)]
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct VersionService {
13 pub library: String,
14 pub version: String,
15}
16
17#[allow(dead_code)]
18pub trait PlatformLoggerService: Send + Sync {
19 fn platform_info_string(&self) -> String;
20}
21
22pub trait HeartbeatService: Send + Sync {
23 fn trigger_heartbeat(&self) -> AppResult<()>;
24 #[allow(dead_code)]
25 fn heartbeats_header(&self) -> AppResult<Option<String>>;
26}
27
28pub trait HeartbeatStorage: Send + Sync {
29 fn read(&self) -> AppResult<HeartbeatsInStorage>;
30 fn overwrite(&self, value: &HeartbeatsInStorage) -> AppResult<()>;
31}
32
33#[derive(Clone, Debug, Default, PartialEq, Eq)]
34pub struct HeartbeatsInStorage {
35 pub last_sent_heartbeat_date: Option<String>,
36 pub heartbeats: Vec<SingleDateHeartbeat>,
37}
38
39#[derive(Clone, Debug, PartialEq, Eq)]
40pub struct SingleDateHeartbeat {
41 pub agent: String,
42 pub date: String,
43}
44
45#[derive(Clone, Debug, Default, PartialEq, Eq)]
46pub struct FirebaseOptions {
47 pub api_key: Option<String>,
48 pub auth_domain: Option<String>,
49 pub database_url: Option<String>,
50 pub project_id: Option<String>,
51 pub storage_bucket: Option<String>,
52 pub messaging_sender_id: Option<String>,
53 pub app_id: Option<String>,
54 pub measurement_id: Option<String>,
55}
56
57#[derive(Clone, Debug, PartialEq, Eq, Default)]
58pub struct FirebaseAppSettings {
59 pub name: Option<String>,
60 pub automatic_data_collection_enabled: Option<bool>,
61}
62
63#[derive(Clone, Debug, PartialEq, Eq)]
64pub struct FirebaseAppConfig {
65 pub name: Arc<str>,
66 pub automatic_data_collection_enabled: bool,
67}
68
69#[derive(Clone, Debug, PartialEq, Eq, Default)]
70pub struct FirebaseServerAppSettings {
71 pub automatic_data_collection_enabled: Option<bool>,
72 pub auth_id_token: Option<String>,
73 pub app_check_token: Option<String>,
74 pub release_on_deref: Option<bool>,
75}
76
77#[derive(Clone)]
78pub struct FirebaseApp {
79 inner: Arc<FirebaseAppInner>,
80}
81
82struct FirebaseAppInner {
83 options: FirebaseOptions,
84 config: FirebaseAppConfig,
85 automatic_data_collection_enabled: Mutex<bool>,
86 is_deleted: AtomicBool,
87 container: ComponentContainer,
88}
89
90impl FirebaseApp {
91 pub fn new(
93 options: FirebaseOptions,
94 config: FirebaseAppConfig,
95 container: ComponentContainer,
96 ) -> Self {
97 let automatic = config.automatic_data_collection_enabled;
98 let inner = Arc::new(FirebaseAppInner {
99 options,
100 config,
101 automatic_data_collection_enabled: Mutex::new(automatic),
102 is_deleted: AtomicBool::new(false),
103 container,
104 });
105 let app = Self {
106 inner: inner.clone(),
107 };
108 let dyn_service: DynService = Arc::new(app.clone());
109 app.inner.container.attach_root_service(dyn_service);
110 app
111 }
112
113 pub fn name(&self) -> &str {
115 &self.inner.config.name
116 }
117
118 pub fn options(&self) -> FirebaseOptions {
120 self.inner.options.clone()
121 }
122
123 pub fn config(&self) -> FirebaseAppConfig {
125 self.inner.config.clone()
126 }
127
128 pub fn automatic_data_collection_enabled(&self) -> bool {
130 *self
131 .inner
132 .automatic_data_collection_enabled
133 .lock()
134 .unwrap_or_else(|poison| poison.into_inner())
135 }
136
137 pub fn set_automatic_data_collection_enabled(&self, value: bool) {
139 *self
140 .inner
141 .automatic_data_collection_enabled
142 .lock()
143 .unwrap_or_else(|poison| poison.into_inner()) = value;
144 }
145
146 pub fn container(&self) -> ComponentContainer {
148 self.inner.container.clone()
149 }
150
151 pub fn add_component(&self, component: Component) -> AppResult<()> {
153 self.check_destroyed()?;
154 self.inner
155 .container
156 .add_component(component)
157 .map_err(AppError::from)
158 }
159
160 pub fn add_or_overwrite_component(&self, component: Component) -> AppResult<()> {
162 self.check_destroyed()?;
163 self.inner.container.add_or_overwrite_component(component);
164 Ok(())
165 }
166
167 pub fn remove_service_instance(&self, name: &str, identifier: Option<&str>) {
169 let provider = self.inner.container.get_provider(name);
170 if let Some(id) = identifier {
171 provider.clear_instance(id);
172 } else {
173 provider.clear_instance(DEFAULT_ENTRY_NAME);
174 }
175 }
176
177 pub fn is_deleted(&self) -> bool {
179 self.inner.is_deleted.load(Ordering::SeqCst)
180 }
181
182 pub fn set_is_deleted(&self, value: bool) {
184 self.inner.is_deleted.store(value, Ordering::SeqCst);
185 }
186
187 pub fn check_destroyed(&self) -> AppResult<()> {
189 if self.is_deleted() {
190 return Err(AppError::AppDeleted {
191 app_name: self.name().to_owned(),
192 });
193 }
194 Ok(())
195 }
196}
197
198impl std::fmt::Debug for FirebaseApp {
199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200 f.debug_struct("FirebaseApp")
201 .field("name", &self.name())
202 .field(
203 "automatic_data_collection_enabled",
204 &self.automatic_data_collection_enabled(),
205 )
206 .finish()
207 }
208}
209
210impl FirebaseAppConfig {
211 pub fn new(name: impl Into<String>, automatic: bool) -> Self {
213 Self {
214 name: to_arc_str(name),
215 automatic_data_collection_enabled: automatic,
216 }
217 }
218}
219
220#[derive(Clone)]
221pub struct FirebaseServerApp {
222 inner: Arc<FirebaseServerAppInner>,
223}
224
225struct FirebaseServerAppInner {
226 base: FirebaseApp,
227 settings: FirebaseServerAppSettings,
228 ref_count: AtomicUsize,
229}
230
231impl FirebaseServerApp {
232 pub fn new(base: FirebaseApp, settings: FirebaseServerAppSettings) -> Self {
234 Self {
235 inner: Arc::new(FirebaseServerAppInner {
236 base,
237 settings,
238 ref_count: AtomicUsize::new(1),
239 }),
240 }
241 }
242
243 pub fn base(&self) -> &FirebaseApp {
245 &self.inner.base
246 }
247
248 pub fn settings(&self) -> FirebaseServerAppSettings {
250 self.inner.settings.clone()
251 }
252
253 pub fn name(&self) -> &str {
255 self.inner.base.name()
256 }
257
258 pub fn inc_ref_count(&self) {
260 self.inner.ref_count.fetch_add(1, Ordering::SeqCst);
261 }
262
263 pub fn dec_ref_count(&self) -> usize {
265 self.inner.ref_count.fetch_sub(1, Ordering::SeqCst) - 1
266 }
267}
268
269#[allow(dead_code)]
270pub fn is_browser() -> bool {
272 false
273}
274
275#[allow(dead_code)]
276pub fn is_web_worker() -> bool {
278 false
279}
280
281pub fn get_default_app_config() -> Option<FirebaseOptions> {
283 None
284}
285
286pub fn deep_equal_options(a: &FirebaseOptions, b: &FirebaseOptions) -> bool {
288 a == b
289}
290
291#[allow(dead_code)]
292#[derive(Clone, Debug)]
293pub struct FirebaseAuthTokenData {
294 pub access_token: String,
295}
296
297#[allow(dead_code)]
298pub trait FirebaseServiceInternals: Send + Sync {
299 fn delete(&self) -> AppResult<()>;
300}
301
302#[allow(dead_code)]
303pub trait FirebaseService: Send + Sync {
304 fn app(&self) -> FirebaseApp;
305 fn internals(&self) -> Option<&dyn FirebaseServiceInternals> {
306 None
307 }
308}
309
310#[allow(dead_code)]
311pub type AppHook = Arc<dyn Fn(&str, &FirebaseApp) + Send + Sync>;
312
313#[allow(dead_code)]
314pub type FirebaseServiceFactory<T> = Arc<
315 dyn Fn(
316 &FirebaseApp,
317 Option<Arc<dyn Fn(&HashMap<String, serde_json::Value>) + Send + Sync>>,
318 Option<&str>,
319 ) -> T
320 + Send
321 + Sync,
322>;
323
324#[allow(dead_code)]
325pub type FirebaseServiceNamespace<T> = Arc<dyn Fn(Option<&FirebaseApp>) -> T + Send + Sync>;
326
327#[allow(dead_code)]
328pub trait FirebaseAppInternals: Send + Sync {
329 fn get_token(&self, refresh_token: bool) -> AppResult<Option<FirebaseAuthTokenData>>;
330 fn get_uid(&self) -> Option<String>;
331 fn add_auth_token_listener(&self, listener: Arc<dyn Fn(Option<String>) + Send + Sync>);
332 fn remove_auth_token_listener(&self, listener_id: usize);
333 fn log_event(
334 &self,
335 event_name: &str,
336 event_params: HashMap<String, serde_json::Value>,
337 global: bool,
338 );
339}
340
341pub fn deep_equal_config(a: &FirebaseAppConfig, b: &FirebaseAppConfig) -> bool {
343 a == b
344}
345
346fn to_arc_str(value: impl Into<String>) -> Arc<str> {
347 Arc::from(value.into().into_boxed_str())
348}