use crate::actor::Actor;
use crate::actor::ActorHandle;
use crate::message::Message;
use crate::message::MessageEnvelope;
use crate::state_actor;
use async_trait::async_trait;
use std::collections::HashMap;
use tokio::sync::mpsc;
pub struct Director {
pub receiver: mpsc::Receiver<MessageEnvelope>,
pub store_actor: Option<ActorHandle>,
pub output: Option<ActorHandle>,
pub actors: HashMap<String, ActorHandle>,
namespace: String,
}
#[async_trait]
impl Actor for Director {
async fn stop(&mut self) {}
async fn handle_envelope(&mut self, envelope: MessageEnvelope) {
let MessageEnvelope {
message,
respond_to,
..
} = envelope;
match &message {
Message::Update { path, .. } | Message::Query { path } => {
let response = self.update_actor(path, message.clone()).await;
if let Message::Update { path: _, .. } = message {
if let Some(store_actor) = &self.store_actor {
_ = store_actor.ask(message).await; }
}
if let Some(respond_to) = respond_to {
respond_to
.send(response.clone())
.expect("can not reply to ask");
}
if let Some(o) = &self.output {
let senv = MessageEnvelope {
message: response,
respond_to: None,
..Default::default()
};
o.send(senv).await;
}
}
Message::EndOfStream {} => {
log::debug!("complete");
if let Some(a) = &self.output {
let senv = MessageEnvelope {
message,
respond_to,
..Default::default()
};
a.send(senv).await
} else if let Some(respond_to) = respond_to {
respond_to.send(message).expect("can not reply to ask");
}
}
m => log::warn!("unexpected message: {:?}", m),
}
}
}
impl Director {
fn new(
namespace: String,
receiver: mpsc::Receiver<MessageEnvelope>,
output: Option<ActorHandle>,
store_actor: Option<ActorHandle>,
) -> Self {
Director {
namespace,
actors: HashMap::new(),
receiver,
output,
store_actor,
}
}
async fn update_actor(&mut self, path: &String, message: Message) -> Message {
let actor_is_in_init = self.actors.get(path).is_none();
let actor = self
.actors
.entry(path.clone())
.or_insert_with(|| state_actor::new(path.clone(), 8, None));
match &self.store_actor {
Some(store_actor) if actor_is_in_init => {
log::debug!(
"{} handling actor '{}' messsage w/ actor init via store",
self.namespace,
path
);
actor
.integrate(message.clone(), String::from(path), store_actor)
.await
}
_ => {
log::debug!("{} handling actor '{}' messsage", self.namespace, path);
actor.ask(message.clone()).await
}
}
}
}
pub fn new(
namespace: String,
bufsz: usize,
output: Option<ActorHandle>,
store_actor: Option<ActorHandle>,
) -> ActorHandle {
async fn start(mut actor: Director) {
while let Some(envelope) = actor.receiver.recv().await {
actor.handle_envelope(envelope).await;
}
}
let (sender, receiver) = mpsc::channel(bufsz);
let actor = Director::new(namespace.clone(), receiver, output, store_actor);
let actor_handle = ActorHandle::new(sender);
tokio::spawn(start(actor));
log::debug!("{} started", namespace);
actor_handle
}