use hydracache::HydraCache;
use serde::Serialize;
use crate::config::{ServerConfig, ServerConfigError, ServerRole};
use crate::services::{DrainOutcome, GracefulShutdown, ServiceSet};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ServerState {
Created,
Running,
Draining,
Stopped,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct ServerHealth {
pub status: &'static str,
pub state: ServerState,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct ServerReadiness {
pub ready: bool,
pub storage_open: bool,
pub cluster_ready: bool,
pub accepting: bool,
}
#[derive(Debug, Clone)]
pub struct ServerRuntime {
config: ServerConfig,
cache: HydraCache,
services: ServiceSet,
state: ServerState,
storage_open: bool,
cluster_ready: bool,
accepting: bool,
flushed: bool,
}
impl ServerRuntime {
pub fn new(config: ServerConfig) -> Result<Self, ServerConfigError> {
config.validate()?;
Ok(Self {
config,
cache: HydraCache::local().build(),
services: ServiceSet::default(),
state: ServerState::Created,
storage_open: false,
cluster_ready: false,
accepting: false,
flushed: false,
})
}
pub fn start(mut self) -> Self {
self.storage_open = true;
self.cluster_ready = matches!(
self.config.role,
ServerRole::Local | ServerRole::Member | ServerRole::Client
);
self.accepting = true;
self.services.start();
self.state = ServerState::Running;
self
}
pub fn health(&self) -> ServerHealth {
ServerHealth {
status: if self.state == ServerState::Stopped {
"stopped"
} else {
"ok"
},
state: self.state,
}
}
pub fn ready(&self) -> ServerReadiness {
ServerReadiness {
ready: self.state == ServerState::Running
&& self.storage_open
&& self.cluster_ready
&& self.accepting,
storage_open: self.storage_open,
cluster_ready: self.cluster_ready,
accepting: self.accepting,
}
}
pub fn begin_request(&mut self) -> bool {
if !self.accepting {
return false;
}
self.services.begin_request();
true
}
pub fn finish_request(&mut self) {
self.services.finish_request();
}
pub fn shutdown(&mut self) -> DrainOutcome {
self.accepting = false;
self.state = ServerState::Draining;
let outcome = GracefulShutdown::new(self.config.drain_timeout()).drain(&mut self.services);
self.flushed = true;
self.storage_open = false;
self.cluster_ready = false;
self.services.stop();
self.state = ServerState::Stopped;
outcome
}
pub fn flushed(&self) -> bool {
self.flushed
}
pub fn cache(&self) -> &HydraCache {
&self.cache
}
pub fn config(&self) -> &ServerConfig {
&self.config
}
}