use futures::Future;
use std::sync::{Arc, Mutex};
use std::time::{self, Duration};
use super::super::core_broker::CoreBrokerPtr;
use crate::brokers::{Broker, CRUDBroker};
use crate::prelude::*;
use juiz_sdk::anyhow::anyhow;
use tokio::runtime;
#[allow(unused)]
pub struct CRUDBrokerHolder<F, Fut>
where
F: Fn(Value, Arc<Mutex<CRUDBroker>>) -> Fut + Send + Sync + Copy + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
impl_class_name: String,
type_name: String,
manifest: Value,
crud_broker: Arc<Mutex<CRUDBroker>>,
thread_handle: Option<tokio::task::JoinHandle<()>>,
tokio_runtime: runtime::Runtime,
on_start_function: F,
identifier: String,
}
impl<F, Fut> std::fmt::Debug for CRUDBrokerHolder<F, Fut>
where
F: Fn(Value, Arc<Mutex<CRUDBroker>>) -> Fut + Send + Sync + Copy + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CRUDBrokerHolder")
.field("impl_class_name", &self.impl_class_name)
.field("type_name", &self.type_name)
.field("manifest", &self.manifest)
.field("crud_broker", &self.crud_broker)
.field("thread_handle", &self.thread_handle)
.field("tokio_runtime", &self.tokio_runtime)
.field("identifier", &self.identifier)
.finish()
}
}
impl<F, Fut> CRUDBrokerHolder<F, Fut>
where
F: Fn(Value, Arc<Mutex<CRUDBroker>>) -> Fut + Send + Sync + Copy + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
pub fn new(
impl_class_name: &'static str,
type_name: &'static str,
core_broker: CoreBrokerPtr,
on_start_function: F,
manifest: Value,
) -> JuizResult<Self> {
Ok(CRUDBrokerHolder {
impl_class_name: impl_class_name.to_owned(),
type_name: type_name.to_owned(),
identifier: "".to_owned(),
crud_broker: Arc::new(Mutex::new(CRUDBroker::new(core_broker, manifest.clone())?)),
thread_handle: None,
tokio_runtime: runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap(),
on_start_function,
manifest,
})
}
}
impl<F, Fut> Broker for CRUDBrokerHolder<F, Fut>
where
F: Fn(Value, Arc<Mutex<CRUDBroker>>) -> Fut + Send + Sync + Copy + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
fn start(&mut self) -> JuizResult<()> {
let type_name = self.identifier().type_name;
log::trace!("CRUDBrokerHolder::start(type_name={type_name}) called");
let crud = self.crud_broker.clone();
let manifest = self.crud_broker.lock().unwrap().manifest();
let on_start = self.on_start_function; self.thread_handle = Some(self.tokio_runtime.spawn(async move {
on_start(manifest, crud).await;
}));
log::trace!("CRUDBrokerHolder::start(type_name={type_name}) exit");
Ok(())
}
fn wait_until_started(&mut self, timeout: Duration) -> JuizResult<()> {
let start_time = time::Instant::now();
loop {
match self.crud_broker.lock() {
Ok(crud) => {
if crud.is_started() {
return Ok(());
}
let duration = start_time.elapsed();
if duration > timeout {
log::error!("wait_until_started failed. Timeout");
return Err(anyhow!(JuizError::TimeoutError {}));
}
}
Err(e) => {
panic!("Error lock is poisoned (Error{e:?})")
}
}
}
}
fn stop(&mut self) -> JuizResult<()> {
let type_name = self.identifier().type_name.clone();
log::trace!("CRUDBrokerHolder::stop(type_name={type_name}) called");
self.thread_handle.take().unwrap().abort();
log::trace!("CRUDBrokerHolder::stop(type_name={type_name}) exit");
Ok(())
}
fn identifier(&self) -> BrokerIdentifier {
log::trace!("CRUDBrokerHolder::identifier() called");
self.crud_broker.lock().unwrap().identifier()
}
fn profile(&self) -> BrokerProfile {
log::trace!("CRUDBrokerHolder::profile() called");
self.crud_broker.lock().unwrap().profile()
}
}