pub mod macros;
pub mod tracking;
pub use tracking::{LatencyTracker, ServletMetrics, UtilizationReporter};
use core::convert::TryFrom;
use core::future::Future;
use core::marker::PhantomData;
use core::pin::Pin;
use std::any::Any;
use std::collections::HashMap;
use std::sync::Arc;
use crate::colony::hive::HiveContext;
use crate::colony::servlet::servlet_runtime::rt;
use crate::colony::worker::Worker;
use crate::colony::worker::WorkerMetadata;
use crate::core::{Inflator, Message};
use crate::crypto::aead::Decryptor;
use crate::crypto::profiles::DefaultCryptoProvider;
use crate::policy::GatePolicy;
use crate::router::RouterError;
use crate::trace::TraceCollector;
use crate::transport::Protocol;
use crate::transport::TightBeamAddress;
use crate::utils::BasisPoints;
use crate::{Frame, TightBeamError};
#[cfg(feature = "x509")]
mod x509 {
pub use crate::crypto::key::SigningKeyProvider;
pub use crate::crypto::profiles::CryptoProvider;
pub use crate::crypto::x509::policy::CertificateValidation;
pub use crate::crypto::x509::{Certificate, CertificateSpec};
pub use crate::transport::handshake::HandshakeKeyManager;
pub use crate::transport::TransportEncryptionConfig;
}
#[cfg(feature = "x509")]
use x509::*;
pub mod servlet_runtime {
pub use crate::runtime::rt;
}
pub type WorkerBoxStartFuture = Pin<Box<dyn Future<Output = Result<Box<dyn WorkerBox>, TightBeamError>> + Send>>;
pub trait WorkerBox: Send + Sync + core::any::Any {
fn start_boxed(self: Box<Self>, trace: Arc<TraceCollector>) -> WorkerBoxStartFuture;
}
impl<W: Worker + 'static> WorkerBox for W {
fn start_boxed(self: Box<Self>, trace: Arc<TraceCollector>) -> WorkerBoxStartFuture {
Box::pin(async move {
let started = (*self).start(trace).await?;
Ok(Box::new(started) as Box<dyn WorkerBox>)
})
}
}
impl dyn WorkerBox {
pub fn downcast_ref<W: 'static>(&self) -> Option<&W> {
(self as &dyn core::any::Any).downcast_ref()
}
}
pub struct ServletContext {
trace: Arc<TraceCollector>,
env_config: Arc<dyn Any + Send + Sync>,
workers: HashMap<String, Box<dyn WorkerBox>>,
hive_context: Option<Arc<dyn HiveContext>>,
message_decryptor: Option<Arc<dyn Decryptor + Send + Sync>>,
message_inflator: Option<Arc<dyn Inflator + Send + Sync>>,
}
impl ServletContext {
pub fn new(
trace: Arc<TraceCollector>,
env_config: Arc<dyn Any + Send + Sync>,
workers: HashMap<String, Box<dyn WorkerBox>>,
hive_context: Option<Arc<dyn HiveContext>>,
) -> Self {
Self {
trace,
env_config,
workers,
hive_context,
message_decryptor: None,
message_inflator: None,
}
}
#[must_use]
pub fn with_message_decryptor(mut self, decryptor: Option<Arc<dyn Decryptor + Send + Sync>>) -> Self {
self.message_decryptor = decryptor;
self
}
#[must_use]
pub fn with_message_inflator(mut self, inflator: Option<Arc<dyn Inflator + Send + Sync>>) -> Self {
self.message_inflator = inflator;
self
}
pub fn message_decryptor(&self) -> Option<&dyn Decryptor> {
self.message_decryptor.as_deref().map(|decryptor| decryptor as &dyn Decryptor)
}
pub fn message_inflator(&self) -> Option<&dyn Inflator> {
self.message_inflator.as_deref().map(|inflator| inflator as &dyn Inflator)
}
pub fn trace(&self) -> &Arc<TraceCollector> {
&self.trace
}
pub fn env_config<T: 'static>(&self) -> Result<&T, TightBeamError> {
self.env_config.downcast_ref().ok_or(TightBeamError::MissingConfiguration)
}
pub fn hive_context(&self) -> Option<&Arc<dyn HiveContext>> {
self.hive_context.as_ref()
}
pub fn worker<W: 'static>(&self, name: &str) -> Option<&W> {
self.workers.get(name)?.downcast_ref()
}
pub async fn relay<W>(&self, input: Arc<W::Input>) -> Result<W::Output, TightBeamError>
where
W: Worker + WorkerMetadata + 'static,
{
let name = W::name();
let worker = self.worker::<W>(name).ok_or(TightBeamError::MissingConfiguration)?;
worker.relay(input).await.map_err(|e| e.into())
}
}
pub fn prepare_typed_frame(frame: &mut Frame, ctx: &ServletContext) -> Result<(), TightBeamError> {
if frame.metadata.confidentiality.is_some() {
let decryptor = ctx.message_decryptor().ok_or(RouterError::ConfidentialFrame)?;
frame.decrypt_in_place(decryptor, ctx.message_inflator())?;
return Ok(());
}
if frame.metadata.compactness.is_some() {
let inflator = ctx.message_inflator().ok_or(RouterError::CompressedFrame)?;
frame.inflate_in_place(inflator)?;
}
Ok(())
}
#[cfg(feature = "x509")]
pub struct ServletConf<P, M, C: CryptoProvider = DefaultCryptoProvider>
where
P: Protocol,
M: Message,
{
pub(crate) _protocol: PhantomData<P>,
pub(crate) _message: PhantomData<M>,
pub(crate) _crypto: PhantomData<C>,
pub(crate) x509_config: Option<TransportEncryptionConfig<C>>,
pub(crate) servlet_config: Option<Arc<dyn Any + Send + Sync>>,
pub(crate) hive_context: Option<Arc<dyn HiveContext>>,
pub(crate) workers: HashMap<String, Box<dyn WorkerBox>>,
pub(crate) collector_gates: Vec<Arc<dyn GatePolicy + Send + Sync>>,
pub(crate) message_decryptor: Option<Arc<dyn Decryptor + Send + Sync>>,
pub(crate) message_inflator: Option<Arc<dyn Inflator + Send + Sync>>,
}
#[cfg(not(feature = "x509"))]
pub struct ServletConf<P, M>
where
P: Protocol,
M: Message,
{
pub(crate) _protocol: PhantomData<P>,
pub(crate) _message: PhantomData<M>,
pub(crate) servlet_config: Option<Arc<dyn Any + Send + Sync>>,
pub(crate) hive_context: Option<Arc<dyn HiveContext>>,
pub(crate) workers: HashMap<String, Box<dyn WorkerBox>>,
pub(crate) collector_gates: Vec<Arc<dyn GatePolicy + Send + Sync>>,
pub(crate) message_decryptor: Option<Arc<dyn Decryptor + Send + Sync>>,
pub(crate) message_inflator: Option<Arc<dyn Inflator + Send + Sync>>,
}
#[cfg(feature = "x509")]
pub struct ServletConfBuilder<P, M, C: CryptoProvider = DefaultCryptoProvider>
where
P: Protocol,
M: Message,
{
x509_config: Option<TransportEncryptionConfig<C>>,
servlet_config: Option<Arc<dyn Any + Send + Sync>>,
hive_context: Option<Arc<dyn HiveContext>>,
workers: HashMap<String, Box<dyn WorkerBox>>,
collector_gates: Vec<Arc<dyn GatePolicy + Send + Sync>>,
message_decryptor: Option<Arc<dyn Decryptor + Send + Sync>>,
message_inflator: Option<Arc<dyn Inflator + Send + Sync>>,
_phantom: PhantomData<(P, M, C)>,
}
#[cfg(not(feature = "x509"))]
pub struct ServletConfBuilder<P, M>
where
P: Protocol,
M: Message,
{
servlet_config: Option<Arc<dyn Any + Send + Sync>>,
hive_context: Option<Arc<dyn HiveContext>>,
workers: HashMap<String, Box<dyn WorkerBox>>,
collector_gates: Vec<Arc<dyn GatePolicy + Send + Sync>>,
message_decryptor: Option<Arc<dyn Decryptor + Send + Sync>>,
message_inflator: Option<Arc<dyn Inflator + Send + Sync>>,
_phantom: PhantomData<(P, M)>,
}
#[cfg(feature = "x509")]
impl<P, M, C> ServletConf<P, M, C>
where
P: Protocol,
M: Message,
C: CryptoProvider + Send + Sync + 'static,
{
pub fn builder() -> ServletConfBuilder<P, M, C> {
ServletConfBuilder::default()
}
pub fn worker<W: 'static>(&self, name: &str) -> Option<&W> {
self.workers.get(name)?.downcast_ref()
}
pub fn to_encryption_config_ref(&self) -> Option<&TransportEncryptionConfig<C>> {
self.x509_config.as_ref()
}
pub fn to_env_config_ref<Cfg: 'static>(&self) -> Option<&Arc<Cfg>> {
self.servlet_config.as_ref()?.downcast_ref()
}
pub fn to_servlet_conf_ref(&self) -> Option<&Arc<dyn Any + Send + Sync>> {
self.servlet_config.as_ref()
}
pub fn to_workers(self) -> HashMap<String, Box<dyn WorkerBox>> {
self.workers
}
pub fn to_collector_gates(self) -> Vec<Arc<dyn GatePolicy + Send + Sync>> {
self.collector_gates
}
pub fn collector_gates_ref(&self) -> &[Arc<dyn GatePolicy + Send + Sync>] {
&self.collector_gates
}
pub fn hive_context(&self) -> Option<&Arc<dyn HiveContext>> {
self.hive_context.as_ref()
}
pub fn to_message_decryptor(&self) -> Option<Arc<dyn Decryptor + Send + Sync>> {
self.message_decryptor.as_ref().map(Arc::clone)
}
pub fn to_message_inflator(&self) -> Option<Arc<dyn Inflator + Send + Sync>> {
self.message_inflator.as_ref().map(Arc::clone)
}
}
#[cfg(not(feature = "x509"))]
impl<P, M> ServletConf<P, M>
where
P: Protocol,
M: Message,
{
pub fn builder() -> ServletConfBuilder<P, M> {
ServletConfBuilder::default()
}
pub fn worker<W: 'static>(&self, name: &str) -> Option<&W> {
self.workers.get(name)?.downcast_ref()
}
pub fn to_env_config_ref<Cfg: 'static>(&self) -> Option<&Arc<Cfg>> {
self.servlet_config.as_ref()?.downcast_ref()
}
pub fn to_servlet_conf_ref(&self) -> Option<&Arc<dyn Any + Send + Sync>> {
self.servlet_config.as_ref()
}
pub fn to_workers(self) -> HashMap<String, Box<dyn WorkerBox>> {
self.workers
}
pub fn to_collector_gates(self) -> Vec<Arc<dyn GatePolicy + Send + Sync>> {
self.collector_gates
}
pub fn collector_gates_ref(&self) -> &[Arc<dyn GatePolicy + Send + Sync>] {
&self.collector_gates
}
pub fn hive_context(&self) -> Option<&Arc<dyn HiveContext>> {
self.hive_context.as_ref()
}
pub fn to_message_decryptor(&self) -> Option<Arc<dyn Decryptor + Send + Sync>> {
self.message_decryptor.as_ref().map(Arc::clone)
}
pub fn to_message_inflator(&self) -> Option<Arc<dyn Inflator + Send + Sync>> {
self.message_inflator.as_ref().map(Arc::clone)
}
}
#[cfg(feature = "x509")]
impl<P, M, C> Default for ServletConf<P, M, C>
where
P: Protocol,
M: Message,
C: CryptoProvider + Send + Sync + 'static,
{
fn default() -> Self {
Self {
_protocol: PhantomData,
_message: PhantomData,
_crypto: PhantomData,
x509_config: None,
servlet_config: Some(Arc::new(())),
hive_context: None,
workers: HashMap::new(),
collector_gates: Vec::new(),
message_decryptor: None,
message_inflator: None,
}
}
}
#[cfg(not(feature = "x509"))]
impl<P, M> Default for ServletConf<P, M>
where
P: Protocol,
M: Message,
{
fn default() -> Self {
Self {
_protocol: PhantomData,
_message: PhantomData,
servlet_config: Some(Arc::new(())),
hive_context: None,
workers: HashMap::new(),
collector_gates: Vec::new(),
message_decryptor: None,
message_inflator: None,
}
}
}
#[cfg(feature = "x509")]
impl<P, M, C> Default for ServletConfBuilder<P, M, C>
where
P: Protocol,
M: Message,
C: CryptoProvider + Send + Sync + 'static,
{
fn default() -> Self {
Self {
x509_config: None,
servlet_config: None,
hive_context: None,
workers: HashMap::new(),
collector_gates: Vec::new(),
message_decryptor: None,
message_inflator: None,
_phantom: PhantomData,
}
}
}
#[cfg(not(feature = "x509"))]
impl<P, M> Default for ServletConfBuilder<P, M>
where
P: Protocol,
M: Message,
{
fn default() -> Self {
Self {
servlet_config: None,
hive_context: None,
workers: HashMap::new(),
collector_gates: Vec::new(),
message_decryptor: None,
message_inflator: None,
_phantom: PhantomData,
}
}
}
#[cfg(feature = "x509")]
impl<P, M, C> ServletConfBuilder<P, M, C>
where
P: Protocol,
M: Message,
C: CryptoProvider + Send + Sync + 'static,
{
pub fn with_certificate(
mut self,
cert: CertificateSpec,
key: Arc<dyn SigningKeyProvider>,
validators: Vec<Arc<dyn CertificateValidation>>,
) -> Result<Self, TightBeamError> {
let certificate = Certificate::try_from(cert)?;
let key_manager: HandshakeKeyManager<C> = HandshakeKeyManager::new(key);
let encryption_config = TransportEncryptionConfig::new(certificate, key_manager);
self.x509_config = Some(encryption_config.with_client_validators(validators));
Ok(self)
}
#[must_use]
pub fn with_config<Cfg: Send + Sync + 'static>(mut self, config: Arc<Cfg>) -> Self {
self.servlet_config = Some(config);
self
}
pub fn with_worker<W>(mut self, worker: W) -> Self
where
W: Worker + WorkerMetadata + 'static,
{
self.workers
.insert(W::name().to_string(), Box::new(worker) as Box<dyn WorkerBox>);
self
}
pub fn with_collector_gate<G>(mut self, gate: G) -> Self
where
G: GatePolicy + Send + Sync + 'static,
{
let gate = Arc::new(gate);
self.collector_gates.push(gate);
self
}
#[must_use]
pub fn with_hive_context(mut self, ctx: Arc<dyn HiveContext>) -> Self {
self.hive_context = Some(ctx);
self
}
pub fn with_message_decryptor<D>(mut self, decryptor: D) -> Self
where
D: Decryptor + Send + Sync + 'static,
{
let decryptor = Arc::new(decryptor);
self.message_decryptor = Some(decryptor);
self
}
pub fn with_message_inflator<I>(mut self, inflator: I) -> Self
where
I: Inflator + Send + Sync + 'static,
{
let inflator = Arc::new(inflator);
self.message_inflator = Some(inflator);
self
}
pub fn build(self) -> ServletConf<P, M, C> {
ServletConf {
_protocol: PhantomData,
_message: PhantomData,
_crypto: PhantomData,
x509_config: self.x509_config,
servlet_config: self.servlet_config,
hive_context: self.hive_context,
workers: self.workers,
collector_gates: self.collector_gates,
message_decryptor: self.message_decryptor,
message_inflator: self.message_inflator,
}
}
}
#[cfg(not(feature = "x509"))]
impl<P, M> ServletConfBuilder<P, M>
where
P: Protocol,
M: Message,
{
#[must_use]
pub fn with_config<Cfg: Send + Sync + 'static>(mut self, config: Arc<Cfg>) -> Self {
self.servlet_config = Some(config);
self
}
pub fn with_worker<W>(mut self, worker: W) -> Self
where
W: Worker + WorkerMetadata + 'static,
{
self.workers
.insert(W::name().to_string(), Box::new(worker) as Box<dyn WorkerBox>);
self
}
pub fn with_collector_gate<G>(mut self, gate: G) -> Self
where
G: GatePolicy + Send + Sync + 'static,
{
let gate = Arc::new(gate);
self.collector_gates.push(gate);
self
}
#[must_use]
pub fn with_hive_context(mut self, ctx: Arc<dyn HiveContext>) -> Self {
self.hive_context = Some(ctx);
self
}
pub fn with_message_decryptor<D>(mut self, decryptor: D) -> Self
where
D: Decryptor + Send + Sync + 'static,
{
let decryptor = Arc::new(decryptor);
self.message_decryptor = Some(decryptor);
self
}
pub fn with_message_inflator<I>(mut self, inflator: I) -> Self
where
I: Inflator + Send + Sync + 'static,
{
let inflator = Arc::new(inflator);
self.message_inflator = Some(inflator);
self
}
pub fn build(self) -> ServletConf<P, M> {
ServletConf {
_protocol: PhantomData,
_message: PhantomData,
servlet_config: self.servlet_config,
hive_context: self.hive_context,
workers: self.workers,
collector_gates: self.collector_gates,
message_decryptor: self.message_decryptor,
message_inflator: self.message_inflator,
}
}
}
pub trait Servlet<I> {
type Conf;
type Address: TightBeamAddress;
fn start(
trace: Arc<TraceCollector>,
config: Option<Self::Conf>,
) -> impl Future<Output = Result<Self, TightBeamError>> + Send
where
Self: Sized;
fn addr(&self) -> Self::Address;
fn stop(self);
fn join(self) -> impl Future<Output = Result<(), rt::JoinError>> + Send;
fn utilization(&self) -> Option<BasisPoints> {
None
}
}