stateset_embedded/commerce/
mod.rs1mod accessors;
4mod builder;
5mod constructors;
6mod events;
7mod introspection;
8
9#[cfg(all(test, feature = "sqlite"))]
10mod tests;
11
12use std::sync::Arc;
13
14#[cfg(feature = "postgres")]
15use stateset_core::CommerceError;
16use stateset_db::Database;
17#[cfg(feature = "postgres")]
18use stateset_db::PostgresDatabase;
19use stateset_observability::Metrics;
20
21#[cfg(feature = "events")]
22use crate::events::EventSystem;
23
24#[cfg(feature = "sqlite")]
25use stateset_db::SqliteDatabase;
26
27pub use builder::CommerceBuilder;
28pub use introspection::CommerceHealth;
29
30#[cfg(feature = "postgres")]
31fn new_postgres_runtime() -> Result<tokio::runtime::Runtime, CommerceError> {
32 tokio::runtime::Runtime::new()
33 .map_err(|e| CommerceError::Internal(format!("Failed to create runtime: {e}")))
34}
35
36#[cfg(feature = "postgres")]
37fn block_on_postgres_connect(url: String) -> Result<PostgresDatabase, CommerceError> {
38 match tokio::runtime::Handle::try_current() {
39 Ok(handle)
40 if matches!(handle.runtime_flavor(), tokio::runtime::RuntimeFlavor::MultiThread) =>
41 {
42 tokio::task::block_in_place(|| handle.block_on(PostgresDatabase::connect(url)))
43 }
44 Ok(_) => std::thread::spawn(move || {
45 let rt = new_postgres_runtime()?;
46 rt.block_on(PostgresDatabase::connect(url))
47 })
48 .join()
49 .map_err(|_| {
50 CommerceError::Internal("PostgreSQL initialization thread panicked".to_string())
51 })?,
52 Err(_) => {
53 let rt = new_postgres_runtime()?;
54 rt.block_on(PostgresDatabase::connect(url))
55 }
56 }
57}
58
59#[cfg(feature = "postgres")]
60fn block_on_postgres_connect_with_options(
61 url: String,
62 max_connections: u32,
63 acquire_timeout_secs: u64,
64) -> Result<PostgresDatabase, CommerceError> {
65 match tokio::runtime::Handle::try_current() {
66 Ok(handle)
67 if matches!(handle.runtime_flavor(), tokio::runtime::RuntimeFlavor::MultiThread) =>
68 {
69 tokio::task::block_in_place(|| {
70 handle.block_on(PostgresDatabase::connect_with_options(
71 url,
72 max_connections,
73 acquire_timeout_secs,
74 ))
75 })
76 }
77 Ok(_) => std::thread::spawn(move || {
78 let rt = new_postgres_runtime()?;
79 rt.block_on(PostgresDatabase::connect_with_options(
80 url,
81 max_connections,
82 acquire_timeout_secs,
83 ))
84 })
85 .join()
86 .map_err(|_| {
87 CommerceError::Internal("PostgreSQL initialization thread panicked".to_string())
88 })?,
89 Err(_) => {
90 let rt = new_postgres_runtime()?;
91 rt.block_on(PostgresDatabase::connect_with_options(
92 url,
93 max_connections,
94 acquire_timeout_secs,
95 ))
96 }
97 }
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102#[non_exhaustive]
103pub enum CommerceBackend {
104 Sqlite,
106 Postgres,
108 External,
110}
111
112pub struct Commerce {
134 db: Arc<dyn Database>,
135 backend: CommerceBackend,
136 metrics: Metrics,
137 #[cfg(feature = "events")]
138 event_system: Arc<EventSystem>,
139 #[cfg(feature = "sqlite")]
140 sqlite_db: Option<Arc<SqliteDatabase>>,
141 #[cfg(feature = "sqlite")]
145 sqlite_path: Option<String>,
146}
147
148impl std::fmt::Debug for Commerce {
149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150 f.debug_struct("Commerce").field("backend", &self.backend).finish_non_exhaustive()
151 }
152}