use crate::config::GatewayConfig;
use crate::metrics::GatewayMetrics;
use crate::tenant_directory::{SharedTenantState, TenantDirectory};
use crate::GatewayResult;
use appcore_peer_rpc::{BoundedReplayStore, PeerNonceStore, ReplayStoreConfig};
use appcore_security::HashTokenProvider;
use appcore_types::TenantId;
use parking_lot::Mutex;
use std::sync::Arc;
use tokio::sync::watch;
pub struct GatewayState {
config: GatewayConfig,
tenants: TenantDirectory,
connection_admission: Mutex<()>,
pub metrics: Arc<GatewayMetrics>,
pub token_provider: HashTokenProvider,
connection_replay: Arc<dyn PeerNonceStore>,
shutdown: watch::Sender<bool>,
}
impl GatewayState {
pub fn new(config: GatewayConfig, token_provider: HashTokenProvider) -> GatewayResult<Self> {
Self::with_replay_store(
config,
token_provider,
Arc::new(BoundedReplayStore::new(ReplayStoreConfig::default())),
)
}
pub fn with_replay_store(
config: GatewayConfig,
token_provider: HashTokenProvider,
connection_replay: Arc<dyn PeerNonceStore>,
) -> GatewayResult<Self> {
config.validate()?;
let (shutdown, _) = watch::channel(false);
Ok(Self {
config,
tenants: TenantDirectory::new(),
connection_admission: Mutex::new(()),
metrics: GatewayMetrics::new(),
token_provider,
connection_replay,
shutdown,
})
}
pub fn config(&self) -> &GatewayConfig {
&self.config
}
pub fn tenant_count(&self) -> usize {
self.tenants.len()
}
pub fn connection_count(&self) -> usize {
self.tenants.connection_count()
}
pub fn tenant_partition(&self, tenant_id: &TenantId) -> Option<SharedTenantState> {
self.tenants.get(tenant_id)
}
pub fn tenant_partition_or_insert(
&self,
tenant_id: &TenantId,
) -> GatewayResult<SharedTenantState> {
self.tenants.get_or_insert(tenant_id)
}
pub(crate) fn tenant_entries(&self) -> Vec<(TenantId, SharedTenantState)> {
self.tenants.entries()
}
pub(crate) fn lock_connection_admission(&self) -> parking_lot::MutexGuard<'_, ()> {
self.connection_admission.lock()
}
pub fn request_shutdown(&self) {
self.shutdown.send_replace(true);
}
pub fn is_shutting_down(&self) -> bool {
*self.shutdown.borrow()
}
pub(crate) fn subscribe_shutdown(&self) -> watch::Receiver<bool> {
self.shutdown.subscribe()
}
pub(crate) fn connection_replay(&self) -> &dyn PeerNonceStore {
self.connection_replay.as_ref()
}
pub(crate) async fn wait_for_shutdown(&self) {
let mut shutdown = self.subscribe_shutdown();
while !*shutdown.borrow() {
if shutdown.changed().await.is_err() {
break;
}
}
}
}