use microservices::esb;
use crate::bus::{ctl, info, p2p, sync, BusMsg, ServiceBus};
use crate::Endpoints;
use crate::LogStyle;
use crate::ServiceId;
pub trait StateMachineExecutor<
Runtime: esb::Handler<ServiceBus>,
Error: std::error::Error,
T: StateMachine<Runtime, Error>,
> where
esb::Error<ServiceId>: From<<Runtime as esb::Handler<ServiceBus>>::Error>,
{
fn execute(
runtime: &mut Runtime,
endpoints: &mut Endpoints,
source: ServiceId,
request: BusMsg,
sm: T,
) -> Result<Option<T>, Error> {
let event = Event::with(endpoints, runtime.identity(), source, request);
let sm_display = sm.to_string();
let sm_name = sm.name();
let sm_log_level = sm.log_level();
if let Some(new_sm) = sm.next(event, runtime)? {
let new_sm_display = new_sm.to_string();
if new_sm_display == sm_display {
debug!(
"{} state self transition {}",
new_sm.name(),
new_sm.bright_green_bold()
);
} else {
log!(
new_sm.log_level(),
"{} state transition {} -> {}",
new_sm.name(),
sm_display.red_bold(),
new_sm.bright_green_bold()
);
}
Ok(Some(new_sm))
} else {
log!(
sm_log_level,
"{} state machine ended {} -> {}",
sm_name,
sm_display.red_bold(),
"End".to_string().bright_green_bold()
);
Ok(None)
}
}
}
pub trait StateMachine<Runtime: esb::Handler<ServiceBus>, Error: std::error::Error>:
std::fmt::Display
where
esb::Error<ServiceId>: From<<Runtime as esb::Handler<ServiceBus>>::Error>,
{
fn next(self, event: Event, runtime: &mut Runtime) -> Result<Option<Self>, Error>
where
Self: Sized;
fn name(&self) -> String;
fn log_level(&self) -> log::Level {
log::Level::Info
}
}
pub struct Event<'esb> {
pub endpoints: &'esb mut Endpoints,
pub service: ServiceId,
pub source: ServiceId,
pub request: BusMsg,
}
impl<'esb> Event<'esb> {
pub fn with(
endpoints: &'esb mut Endpoints,
service: ServiceId,
source: ServiceId,
request: BusMsg,
) -> Self {
Event {
endpoints,
service,
source,
request,
}
}
pub fn complete_ctl(self, request: ctl::CtlMsg) -> Result<(), esb::Error<ServiceId>> {
self.endpoints.send_to(
ServiceBus::Ctl,
self.service,
self.source,
BusMsg::Ctl(request),
)
}
pub fn complete_client_ctl(self, request: ctl::CtlMsg) -> Result<(), esb::Error<ServiceId>> {
let bus = ServiceBus::Ctl;
if let ServiceId::GrpcdClient(_) = self.source {
self.endpoints
.send_to(bus, self.source, ServiceId::Grpcd, BusMsg::Ctl(request))?;
} else {
self.endpoints
.send_to(bus, self.service, self.source, BusMsg::Ctl(request))?;
}
Ok(())
}
pub fn complete_info(self, request: info::InfoMsg) -> Result<(), esb::Error<ServiceId>> {
self.endpoints.send_to(
ServiceBus::Info,
self.service,
self.source,
BusMsg::Info(request),
)
}
pub fn complete_client_info(self, request: info::InfoMsg) -> Result<(), esb::Error<ServiceId>> {
let bus = ServiceBus::Info;
if let ServiceId::GrpcdClient(_) = self.source {
self.endpoints
.send_to(bus, self.source, ServiceId::Grpcd, BusMsg::Info(request))?;
} else {
self.endpoints
.send_to(bus, self.service, self.source, BusMsg::Info(request))?;
}
Ok(())
}
pub fn complete_ctl_service(
self,
service: ServiceId,
request: ctl::CtlMsg,
) -> Result<(), esb::Error<ServiceId>> {
self.endpoints
.send_to(ServiceBus::Ctl, self.service, service, BusMsg::Ctl(request))
}
pub fn complete_sync_service(
self,
service: ServiceId,
request: sync::SyncMsg,
) -> Result<(), esb::Error<ServiceId>> {
self.endpoints.send_to(
ServiceBus::Sync,
self.service,
service,
BusMsg::Sync(request),
)
}
pub fn send_ctl_service(
&mut self,
service: ServiceId,
request: ctl::CtlMsg,
) -> Result<(), esb::Error<ServiceId>> {
self.endpoints.send_to(
ServiceBus::Ctl,
self.service.clone(),
service,
BusMsg::Ctl(request),
)
}
pub fn send_info_service(
&mut self,
service: ServiceId,
request: info::InfoMsg,
) -> Result<(), esb::Error<ServiceId>> {
self.endpoints.send_to(
ServiceBus::Info,
self.service.clone(),
service,
BusMsg::Info(request),
)
}
pub fn send_sync_service(
&mut self,
service: ServiceId,
request: sync::SyncMsg,
) -> Result<(), esb::Error<ServiceId>> {
self.endpoints.send_to(
ServiceBus::Sync,
self.service.clone(),
service,
BusMsg::Sync(request),
)
}
pub fn send_client_info(
&mut self,
service: ServiceId,
request: info::InfoMsg,
) -> Result<(), esb::Error<ServiceId>> {
let bus = ServiceBus::Info;
if let ServiceId::GrpcdClient(_) = service {
self.endpoints
.send_to(bus, service, ServiceId::Grpcd, BusMsg::Info(request))?;
} else {
self.endpoints
.send_to(bus, self.service.clone(), service, BusMsg::Info(request))?;
}
Ok(())
}
pub fn send_client_ctl(
&mut self,
service: ServiceId,
request: ctl::CtlMsg,
) -> Result<(), esb::Error<ServiceId>> {
let bus = ServiceBus::Ctl;
if let ServiceId::GrpcdClient(_) = service {
self.endpoints
.send_to(bus, service, ServiceId::Grpcd, BusMsg::Ctl(request))?;
} else {
self.endpoints
.send_to(bus, self.service.clone(), service, BusMsg::Ctl(request))?;
}
Ok(())
}
pub fn send_msg_service(
&mut self,
service: ServiceId,
request: p2p::PeerMsg,
) -> Result<(), esb::Error<ServiceId>> {
self.endpoints.send_to(
ServiceBus::Msg,
self.service.clone(),
service,
BusMsg::P2p(request),
)
}
}