use crate::message::create_init_lifecycle;
use crate::message::Envelope;
use crate::message::Message;
use crate::message::MtHint;
use crate::message::NvError;
use crate::message::NvResult;
use async_trait::async_trait;
use tokio::sync::mpsc;
use tokio::sync::oneshot;
use tokio::sync::oneshot::Sender;
use tracing::error;
use tracing::instrument;
use tracing::trace;
pub type State<T> = std::collections::HashMap<i32, T>;
#[async_trait]
pub trait Actor {
async fn handle_envelope(&mut self, envelope: Envelope<f64>);
async fn start(&mut self);
async fn stop(&self);
}
#[derive(Debug)]
pub struct Handle {
#[doc(hidden)]
pub sender: mpsc::Sender<Envelope<f64>>,
}
impl<'a> Handle {
#[doc(hidden)]
#[instrument]
pub async fn send(&self, envelope: Envelope<f64>) -> NvResult<()> {
self.sender.send(envelope).await.map_err(|e| NvError {
reason: e.to_string(),
})
}
#[instrument]
pub async fn tell(&self, message: Message<f64>) -> NvResult<()> {
let envelope = Envelope {
message,
respond_to: None,
..Default::default()
};
trace!("tell sending envelope {envelope:?}");
self.send(envelope).await
}
#[instrument]
pub async fn ask(&self, message: Message<f64>) -> NvResult<Message<f64>> {
let (send, recv) = oneshot::channel();
let envelope = Envelope {
message,
respond_to: Some(send),
..Default::default()
};
trace!("ask sending envelope: {envelope:?}");
match self.send(envelope).await {
Ok(_) => recv.await.map_err(|e| NvError {
reason: e.to_string(),
})?,
Err(e) => Err(e),
}
}
#[instrument]
pub async fn integrate(
&self,
path: String,
helper: &Self,
hint: MtHint,
) -> NvResult<Message<f64>> {
type ResultSender = Sender<NvResult<Message<f64>>>;
type ResultReceiver = oneshot::Receiver<NvResult<Message<f64>>>;
type SendReceivePair = (ResultSender, ResultReceiver);
let (send, recv): SendReceivePair = oneshot::channel();
let (init_cmd, load_cmd) = create_init_lifecycle(path, 8, send, hint);
helper.send(load_cmd).await.map_err(|e| NvError {
reason: e.to_string(),
})?;
self.send(init_cmd).await.map_err(|e| NvError {
reason: e.to_string(),
})?;
recv.await.map_err(|e| NvError {
reason: e.to_string(),
})?
}
#[doc(hidden)]
#[must_use]
pub const fn new(sender: mpsc::Sender<Envelope<f64>>) -> Self {
Self { sender }
}
}
pub fn respond_or_log_error(
respond_to: Option<Sender<NvResult<Message<f64>>>>,
result: NvResult<Message<f64>>,
) {
{
if let Some(respond_to) = respond_to {
match respond_to.send(result) {
Ok(_) => (),
Err(err) => {
error!("Cannot respond to 'ask' with confirmation: {:?}", err);
}
}
}
}
}