v0.3.2-pre.005
This commit is contained in:
@@ -1,54 +1,155 @@
|
||||
// file: crates/ksp-store-lib/src/store.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
/// Opaque common Store runtime facade.
|
||||
///
|
||||
/// A successful value is returned only after the selected backend has completed its bounded readiness path. `0.3.2-pre.003` establishes the lifecycle
|
||||
/// contract but intentionally has no successful opening path until the PostgreSQL runtime foundation is materialized by later prereleases.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
pub struct Store;
|
||||
/// A successful value is returned only after the selected compiled backend has completed its bounded physical opening path. PostgreSQL pool, client, TLS and
|
||||
/// driver types remain private to the backend crate.
|
||||
pub struct Store {
|
||||
backend_kind: crate::StoreBackendKind,
|
||||
network: ksp_store_api::RawNetworkId,
|
||||
#[cfg(feature = "postgres")]
|
||||
runtime: StoreRuntime,
|
||||
shutdown_timeout: std::time::Duration,
|
||||
}
|
||||
|
||||
impl Store {
|
||||
/// Validates settings, selects the requested backend and opens a ready Store runtime.
|
||||
/// Validates settings, selects the requested backend and opens one ready Store instance for exactly one logical network.
|
||||
///
|
||||
/// A known backend whose Cargo feature is absent is rejected before any I/O. During `0.3.2-pre.003`, the compiled PostgreSQL path also stops before I/O
|
||||
/// with [`crate::ERROR_CODE_BACKEND_OPEN_FAILED`] because physical connection ownership is introduced in `pre.005`.
|
||||
/// A known backend whose Cargo feature is absent is rejected before any I/O. A successful PostgreSQL result proves that one physical pooled connection has
|
||||
/// been established under the typed TLS and timeout policy.
|
||||
pub async fn open(settings: crate::StoreSettings) -> ksp_store_api::Result<Self> {
|
||||
let validation = settings.validate();
|
||||
if let std::result::Result::Err(error) = validation {
|
||||
return std::result::Result::Err(error);
|
||||
}
|
||||
let backend_kind = settings.backend_kind();
|
||||
return match backend_kind {
|
||||
crate::StoreBackendKind::Postgres => open_postgres_contract(backend_kind).await,
|
||||
let network = settings.network().clone();
|
||||
let shutdown_timeout = settings.shutdown_timeout();
|
||||
ksp_logging_lib::debug!(
|
||||
target: crate::TRACING_TARGET,
|
||||
backend = backend_kind.code(),
|
||||
network = network.as_str(),
|
||||
"opening Store runtime"
|
||||
);
|
||||
return match settings.backend() {
|
||||
crate::StoreBackendSettings::Postgres(postgres) => open_postgres(backend_kind, network, shutdown_timeout, postgres).await,
|
||||
};
|
||||
}
|
||||
|
||||
/// Explicitly closes the Store runtime and consumes its facade handle.
|
||||
///
|
||||
/// `pre.003` cannot yet produce a successful Store instance, so the physical bounded shutdown path remains reserved for backend composition. The consuming
|
||||
/// async signature is fixed here so no pool or backend handle needs to escape later.
|
||||
/// Explicitly closes the Store runtime, consumes its facade handle and applies the configured bounded shutdown deadline.
|
||||
pub async fn close(self) -> ksp_store_api::Result<()> {
|
||||
return std::result::Result::Ok(());
|
||||
let backend_kind = self.backend_kind;
|
||||
#[cfg(feature = "postgres")]
|
||||
{
|
||||
let network = self.network;
|
||||
let shutdown_timeout = self.shutdown_timeout;
|
||||
let result = match self.runtime {
|
||||
StoreRuntime::Postgres(backend) => backend.close(shutdown_timeout).await,
|
||||
};
|
||||
return match result {
|
||||
std::result::Result::Ok(()) => {
|
||||
ksp_logging_lib::debug!(
|
||||
target: crate::TRACING_TARGET,
|
||||
backend = backend_kind.code(),
|
||||
network = network.as_str(),
|
||||
"Store runtime closed"
|
||||
);
|
||||
std::result::Result::Ok(())
|
||||
},
|
||||
std::result::Result::Err(error) => std::result::Result::Err(map_postgres_error(error, backend_kind, network.as_str())),
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "postgres"))]
|
||||
{
|
||||
return std::result::Result::Err(unavailable_runtime_error(backend_kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Store {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
return formatter
|
||||
.debug_struct("Store")
|
||||
.field("backend_kind", &self.backend_kind)
|
||||
.field("network", &self.network)
|
||||
.field("shutdown_timeout", &self.shutdown_timeout)
|
||||
.finish_non_exhaustive();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "postgres")]
|
||||
async fn open_postgres_contract(backend_kind: crate::StoreBackendKind) -> ksp_store_api::Result<Store> {
|
||||
return std::result::Result::Err(
|
||||
ksp_store_api::Error::new(crate::ERROR_CODE_BACKEND_OPEN_FAILED, "PostgreSQL Store runtime opening is not materialized in this prerelease")
|
||||
.with_context("backend", backend_kind.code())
|
||||
.with_context("stage", "runtime_foundation_pending"),
|
||||
enum StoreRuntime {
|
||||
Postgres(ksp_store_postgres_lib::PostgresBackend),
|
||||
}
|
||||
|
||||
#[cfg(feature = "postgres")]
|
||||
async fn open_postgres(
|
||||
backend_kind: crate::StoreBackendKind,
|
||||
network: ksp_store_api::RawNetworkId,
|
||||
shutdown_timeout: std::time::Duration,
|
||||
settings: &crate::PostgresStoreSettings,
|
||||
) -> ksp_store_api::Result<Store> {
|
||||
let pool = settings.pool();
|
||||
let tls_mode = match settings.tls_mode() {
|
||||
crate::PostgresTlsMode::Disabled => ksp_store_postgres_lib::PostgresBackendTlsMode::Disabled,
|
||||
crate::PostgresTlsMode::VerifyFull => ksp_store_postgres_lib::PostgresBackendTlsMode::VerifyFull,
|
||||
};
|
||||
let backend_settings = ksp_store_postgres_lib::PostgresBackendSettings::new(
|
||||
network.clone(),
|
||||
settings.connection_uri(),
|
||||
pool.max_connections(),
|
||||
pool.connect_timeout(),
|
||||
pool.wait_timeout(),
|
||||
pool.create_timeout(),
|
||||
pool.recycle_timeout(),
|
||||
tls_mode,
|
||||
);
|
||||
let opened = ksp_store_postgres_lib::PostgresBackend::open(backend_settings).await;
|
||||
return match opened {
|
||||
std::result::Result::Ok(backend) => {
|
||||
ksp_logging_lib::debug!(
|
||||
target: crate::TRACING_TARGET,
|
||||
backend = backend_kind.code(),
|
||||
network = network.as_str(),
|
||||
"Store backend is physically ready"
|
||||
);
|
||||
std::result::Result::Ok(Store { backend_kind, network, runtime: StoreRuntime::Postgres(backend), shutdown_timeout })
|
||||
},
|
||||
std::result::Result::Err(error) => std::result::Result::Err(map_postgres_error(error, backend_kind, network.as_str())),
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "postgres"))]
|
||||
async fn open_postgres_contract(backend_kind: crate::StoreBackendKind) -> ksp_store_api::Result<Store> {
|
||||
return std::result::Result::Err(
|
||||
ksp_store_api::Error::new(crate::ERROR_CODE_BACKEND_NOT_COMPILED, "Selected Store backend is not compiled")
|
||||
.with_context("backend", backend_kind.code()),
|
||||
);
|
||||
async fn open_postgres(
|
||||
backend_kind: crate::StoreBackendKind,
|
||||
_network: ksp_store_api::RawNetworkId,
|
||||
_shutdown_timeout: std::time::Duration,
|
||||
_settings: &crate::PostgresStoreSettings,
|
||||
) -> ksp_store_api::Result<Store> {
|
||||
return std::result::Result::Err(unavailable_runtime_error(backend_kind));
|
||||
}
|
||||
|
||||
#[cfg(feature = "postgres")]
|
||||
fn map_postgres_error(error: ksp_store_postgres_lib::PostgresBackendError, backend_kind: crate::StoreBackendKind, network: &str) -> ksp_store_api::Error {
|
||||
let code = match error.kind() {
|
||||
ksp_store_postgres_lib::PostgresBackendErrorKind::ConfigInvalid => crate::ERROR_CODE_POSTGRES_CONFIG_INVALID,
|
||||
ksp_store_postgres_lib::PostgresBackendErrorKind::ConnectFailed => crate::ERROR_CODE_POSTGRES_CONNECT_FAILED,
|
||||
ksp_store_postgres_lib::PostgresBackendErrorKind::PoolTimeout => crate::ERROR_CODE_POSTGRES_POOL_TIMEOUT,
|
||||
ksp_store_postgres_lib::PostgresBackendErrorKind::ShutdownTimeout => crate::ERROR_CODE_SHUTDOWN_TIMEOUT,
|
||||
ksp_store_postgres_lib::PostgresBackendErrorKind::TlsFailed => crate::ERROR_CODE_POSTGRES_TLS_FAILED,
|
||||
_ => crate::ERROR_CODE_BACKEND_OPEN_FAILED,
|
||||
};
|
||||
return ksp_store_api::Error::new(code, "PostgreSQL Store backend lifecycle operation failed")
|
||||
.with_context("backend", backend_kind.code())
|
||||
.with_context("network", network)
|
||||
.with_context("phase", error.phase());
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "postgres"))]
|
||||
fn unavailable_runtime_error(backend_kind: crate::StoreBackendKind) -> ksp_store_api::Error {
|
||||
return ksp_store_api::Error::new(crate::ERROR_CODE_BACKEND_NOT_COMPILED, "Selected Store backend is not compiled")
|
||||
.with_context("backend", backend_kind.code());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user