use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use foundation_iogate::ServerIo;
use crate::config::BackendState;
use crate::forward::SharedHttpClient;
use crate::persistence::ProxyStateStore;
use crate::router::Router;
pub struct ProxyState {
router: Arc<Router>,
client: SharedHttpClient,
scheme: String,
io_mode: ServerIo,
draining: AtomicBool,
store: Option<Arc<ProxyStateStore>>,
}
impl std::fmt::Debug for ProxyState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ProxyState")
.field("router", &self.router)
.field("scheme", &self.scheme)
.finish_non_exhaustive()
}
}
impl ProxyState {
#[must_use]
pub fn new(
router: Arc<Router>,
client: SharedHttpClient,
scheme: impl Into<String>,
io_mode: ServerIo,
) -> Self {
Self {
router,
client,
scheme: scheme.into(),
io_mode,
draining: AtomicBool::new(false),
store: None,
}
}
#[must_use]
pub fn with_store(mut self, store: Arc<ProxyStateStore>) -> Self {
self.store = Some(store);
self
}
pub fn persist_backend_state(&self, service: &str, url: &str, state: BackendState) {
if let Some(store) = &self.store {
if let Err(e) = store.save_backend_state(service, url, &state.to_string()) {
tracing::warn!(%service, %url, "failed to persist backend state: {e}");
}
}
}
pub fn start_drain(&self) {
self.draining.store(true, Ordering::SeqCst);
}
#[must_use]
pub fn is_draining(&self) -> bool {
self.draining.load(Ordering::SeqCst)
}
#[must_use]
pub fn inflight_total(&self) -> u32 {
self.router
.services()
.iter()
.flat_map(|s| s.backends())
.map(|b| b.inflight())
.sum()
}
#[must_use]
pub fn router(&self) -> &Arc<Router> {
&self.router
}
#[must_use]
pub fn client(&self) -> &SharedHttpClient {
&self.client
}
#[must_use]
pub fn scheme(&self) -> &str {
&self.scheme
}
#[must_use]
pub fn io_mode(&self) -> ServerIo {
self.io_mode
}
}