use crate::event::handler::EventHandlerBuilder;
use crate::event::EventHandler;
use crate::Application;
use crate::Router;
use crate::SubscriberManager;
use actix::Actor;
use event_store::prelude::Storage;
use futures::Future;
use std::any::TypeId;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::pin::Pin;
use tracing::trace;
use super::InternalApplication;
#[async_trait::async_trait]
pub trait StorageConfig<S>
where
S: Storage,
{
async fn build(&self) -> S;
}
pub struct ApplicationBuilder<A: Application> {
app: std::marker::PhantomData<A>,
storage: Pin<Box<dyn Future<Output = A::Storage>>>,
event_handlers: Vec<Pin<Box<dyn Future<Output = ()>>>>,
eventmapper: HashMap<String, TypeId>,
}
impl<A: Application> std::default::Default for ApplicationBuilder<A> {
fn default() -> Self {
Self {
event_handlers: Vec::new(),
app: std::marker::PhantomData,
storage: Box::pin(async { A::Storage::default() }),
eventmapper: HashMap::new(),
}
}
}
impl<A> ApplicationBuilder<A>
where
A: Application,
{
pub fn event_handler<E: EventHandler + 'static>(mut self, handler: E) -> Self {
self.event_handlers
.push(Box::pin(EventHandlerBuilder::new(handler).register::<A>()));
self
}
pub fn with_storage_config<CFG: StorageConfig<A::Storage> + 'static>(
mut self,
storage: CFG,
) -> Self {
self.storage = Box::pin(async move { storage.build().await });
self
}
pub fn storage<F: Future<Output = Result<A::Storage, E>> + 'static, E: std::fmt::Debug>(
mut self,
storage: F,
) -> Self {
self.storage =
Box::pin(async move { storage.await.expect("Unable to connect the storage") });
self
}
#[tracing::instrument(name = "Chekov::Launch", skip(self), fields(app = %A::get_name()))]
pub async fn launch(self) {
trace!(
"Launching a new Chekov instance with {}",
std::any::type_name::<A::Storage>()
);
let storage: A::Storage = self.storage.await;
let event_store: event_store::EventStore<A::Storage> = event_store::EventStore::builder()
.storage(storage)
.build()
.await
.unwrap();
use futures::future::join_all;
join_all(self.event_handlers).await;
let event_store_addr = event_store.start();
let router = Router::<A> {
_app: std::marker::PhantomData,
_before_dispatch: vec![],
};
let addr = router.start();
let subscriber_manager_addr =
SubscriberManager::<A>::new(event_store_addr.clone(), self.eventmapper).start();
let event_store = crate::event_store::EventStore::<A> {
addr: event_store_addr,
}
.start();
::actix::SystemRegistry::set(event_store);
::actix::SystemRegistry::set(addr);
::actix::SystemRegistry::set(subscriber_manager_addr);
::actix::SystemRegistry::set(
InternalApplication::<A> {
_phantom: PhantomData,
}
.start(),
);
}
}