11use init4_bin_base:: utils:: from_env:: FromEnv ;
2- use signet_cold:: ColdStorageTask ;
3- use signet_cold_mdbx:: MdbxColdBackend ;
4- use signet_hot_mdbx:: { DatabaseArguments , DatabaseEnv } ;
5- use signet_storage:: UnifiedStorage ;
2+ #[ cfg( any( feature = "postgres" , feature = "sqlite" ) ) ]
3+ use signet_storage:: SqlConnector ;
4+ use signet_storage:: { DatabaseEnv , MdbxConnector , UnifiedStorage , builder:: StorageBuilder } ;
65use std:: borrow:: Cow ;
76use tokio_util:: sync:: CancellationToken ;
87
98/// Configuration for signet unified storage.
109///
11- /// Reads hot and cold MDBX paths from environment variables.
10+ /// Reads hot and cold storage configuration from environment variables.
1211///
1312/// # Environment Variables
1413///
1514/// - `SIGNET_HOT_PATH` – Path to the hot MDBX database.
16- /// - `SIGNET_COLD_PATH` – Path to the cold MDBX database.
15+ /// - `SIGNET_COLD_PATH` – Path to the cold MDBX database (mutually exclusive
16+ /// with SQL URL).
17+ /// - `SIGNET_COLD_SQL_URL` – SQL connection URL for cold storage (requires
18+ /// `postgres` or `sqlite` feature).
19+ ///
20+ /// Exactly one of `SIGNET_COLD_PATH` or `SIGNET_COLD_SQL_URL` must be set.
1721///
1822/// # Example
1923///
2024/// ```rust,no_run
2125/// # use signet_node_config::StorageConfig;
2226/// # use tokio_util::sync::CancellationToken;
23- /// # fn example(cfg: &StorageConfig) -> eyre::Result<()> {
27+ /// # async fn example(cfg: &StorageConfig) -> eyre::Result<()> {
2428/// let cancel = CancellationToken::new();
25- /// let storage = cfg.build_storage(cancel)?;
29+ /// let storage = cfg.build_storage(cancel).await ?;
2630/// # Ok(())
2731/// # }
2832/// ```
@@ -35,12 +39,22 @@ pub struct StorageConfig {
3539 /// Path to the cold MDBX database.
3640 #[ from_env( var = "SIGNET_COLD_PATH" , desc = "Path to cold MDBX storage" , infallible) ]
3741 cold_path : Cow < ' static , str > ,
42+
43+ /// SQL connection URL for cold storage (requires `postgres` or `sqlite`
44+ /// feature).
45+ #[ from_env(
46+ var = "SIGNET_COLD_SQL_URL" ,
47+ desc = "SQL connection URL for cold storage" ,
48+ infallible
49+ ) ]
50+ #[ serde( default ) ]
51+ cold_sql_url : Cow < ' static , str > ,
3852}
3953
4054impl StorageConfig {
41- /// Create a new storage configuration.
55+ /// Create a new storage configuration with MDBX cold backend .
4256 pub const fn new ( hot_path : Cow < ' static , str > , cold_path : Cow < ' static , str > ) -> Self {
43- Self { hot_path, cold_path }
57+ Self { hot_path, cold_path, cold_sql_url : Cow :: Borrowed ( "" ) }
4458 }
4559
4660 /// Get the hot storage path.
@@ -53,18 +67,49 @@ impl StorageConfig {
5367 & self . cold_path
5468 }
5569
70+ /// Get the cold SQL connection URL.
71+ pub fn cold_sql_url ( & self ) -> & str {
72+ & self . cold_sql_url
73+ }
74+
5675 /// Build unified storage from this configuration.
5776 ///
58- /// Opens an MDBX read-write environment for both hot and cold storage,
59- /// spawns the cold storage background task, and returns a
60- /// [`UnifiedStorage`] ready for use.
61- pub fn build_storage (
77+ /// Creates connectors from the configured paths, spawns the cold storage
78+ /// background task, and returns a [`UnifiedStorage`] ready for use.
79+ ///
80+ /// Exactly one of `cold_path` or `cold_sql_url` must be non-empty.
81+ pub async fn build_storage (
6282 & self ,
6383 cancel : CancellationToken ,
6484 ) -> eyre:: Result < UnifiedStorage < DatabaseEnv > > {
65- let hot = DatabaseArguments :: new ( ) . open_rw ( self . hot_path . as_ref ( ) . as_ref ( ) ) ?;
66- let cold_backend = MdbxColdBackend :: open_rw ( self . cold_path . as_ref ( ) . as_ref ( ) ) ?;
67- let cold_handle = ColdStorageTask :: spawn ( cold_backend, cancel) ;
68- Ok ( UnifiedStorage :: new ( hot, cold_handle) )
85+ let hot = MdbxConnector :: new ( self . hot_path . as_ref ( ) ) ;
86+ let has_mdbx = !self . cold_path . is_empty ( ) ;
87+ let has_sql = !self . cold_sql_url . is_empty ( ) ;
88+
89+ match ( has_mdbx, has_sql) {
90+ ( true , false ) => Ok ( StorageBuilder :: new ( )
91+ . hot ( hot)
92+ . cold ( MdbxConnector :: new ( self . cold_path . as_ref ( ) ) )
93+ . cancel_token ( cancel)
94+ . build ( )
95+ . await ?) ,
96+ #[ cfg( any( feature = "postgres" , feature = "sqlite" ) ) ]
97+ ( false , true ) => Ok ( StorageBuilder :: new ( )
98+ . hot ( hot)
99+ . cold ( SqlConnector :: new ( self . cold_sql_url . as_ref ( ) ) )
100+ . cancel_token ( cancel)
101+ . build ( )
102+ . await ?) ,
103+ #[ cfg( not( any( feature = "postgres" , feature = "sqlite" ) ) ) ]
104+ ( false , true ) => {
105+ eyre:: bail!( "SIGNET_COLD_SQL_URL requires the 'postgres' or 'sqlite' feature" )
106+ }
107+ ( true , true ) => eyre:: bail!(
108+ "both SIGNET_COLD_PATH and SIGNET_COLD_SQL_URL are set; specify exactly one"
109+ ) ,
110+ ( false , false ) => eyre:: bail!(
111+ "neither SIGNET_COLD_PATH nor SIGNET_COLD_SQL_URL is set; specify exactly one"
112+ ) ,
113+ }
69114 }
70115}
0 commit comments