use alloc::boxed::Box;
use alloc::string::{String, ToString};
use alloc::sync::Arc;
use alloc::vec;
use alloc::vec::Vec;
use core::future::Future;
use core::pin::Pin;
use crate::builder::AimDb;
use crate::connector::ConnectorBuilder;
use crate::session::{
pump_client, run_client, serve, ClientConfig, Dialer, Dispatch, EnvelopeCodec, Listener,
OneShot, SessionConfig,
};
use crate::{DbError, DbResult};
pub const DEFAULT_SCHEME: &str = "remote";
type BoxFuture = Pin<Box<dyn Future<Output = ()> + Send + 'static>>;
type BuildFuture<'a> = Pin<Box<dyn Future<Output = DbResult<Vec<BoxFuture>>> + Send + 'a>>;
pub struct SessionClientConnector<D, C> {
scheme: String,
dialer: OneShot<D>,
codec: C,
config: ClientConfig,
}
impl<D, C> SessionClientConnector<D, C> {
pub fn new(dialer: D, codec: C) -> Self {
Self {
scheme: DEFAULT_SCHEME.to_string(),
dialer: OneShot::new(dialer),
codec,
config: ClientConfig::default(),
}
}
pub fn scheme(mut self, scheme: impl Into<String>) -> Self {
self.scheme = scheme.into();
self
}
pub fn with_config(mut self, config: ClientConfig) -> Self {
self.config = config;
self
}
}
impl<D, C> ConnectorBuilder for SessionClientConnector<D, C>
where
D: Dialer + Send + 'static,
C: EnvelopeCodec + Clone + 'static,
{
fn build<'a>(&'a self, db: &'a AimDb) -> BuildFuture<'a> {
Box::pin(async move {
let dialer = self
.dialer
.take()
.ok_or_else(|| DbError::InvalidOperation {
operation: "SessionClientConnector::build".to_string(),
reason: "the moved-in dialer was already taken; build() ran twice".to_string(),
})?;
let (handle, engine_fut) = run_client(
dialer,
self.codec.clone(),
self.config.clone(),
db.runtime_ops(),
);
let mut futures = pump_client(db, &self.scheme, &handle);
futures.push(engine_fut);
Ok(futures)
})
}
fn scheme(&self) -> &str {
&self.scheme
}
}
pub struct SessionServerConnector<C, LF, DF> {
scheme: String,
listener_factory: LF,
codec: C,
dispatch_factory: DF,
config: SessionConfig,
}
impl<C, LF, DF> SessionServerConnector<C, LF, DF> {
pub fn new(
listener_factory: LF,
codec: C,
dispatch_factory: DF,
config: SessionConfig,
) -> Self {
Self {
scheme: DEFAULT_SCHEME.to_string(),
listener_factory,
codec,
dispatch_factory,
config,
}
}
pub fn scheme(mut self, scheme: impl Into<String>) -> Self {
self.scheme = scheme.into();
self
}
}
impl<L, C, LF, DF> ConnectorBuilder for SessionServerConnector<C, LF, DF>
where
L: Listener + 'static,
C: EnvelopeCodec + Clone + 'static,
LF: Fn() -> DbResult<L> + Send + Sync + 'static,
DF: Fn(&AimDb) -> Arc<dyn Dispatch> + Send + Sync + 'static,
{
fn build<'a>(&'a self, db: &'a AimDb) -> BuildFuture<'a> {
let listener = (self.listener_factory)();
let dispatch = (self.dispatch_factory)(db);
let codec = Arc::new(self.codec.clone());
let config = self.config.clone();
Box::pin(async move {
let listener = listener?;
let fut: BoxFuture = Box::pin(serve(listener, codec, dispatch, config));
Ok(vec![fut])
})
}
fn scheme(&self) -> &str {
&self.scheme
}
}