use std::any::Any;
use std::fmt::Debug;
use std::future::Future;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc;
use crate::endpoint::Endpoint;
use crate::lifecycle::{ActorTerminated, SystemSignal};
use crate::receptionist::Receptionist;
use crate::runtime::SpawnHandle;
use crate::wire::EnvelopeProxy;
pub trait Message: Debug + Send + 'static {
type Result: Send + 'static;
}
pub trait RemoteMessage: Message + Serialize + DeserializeOwned
where
Self::Result: Serialize + DeserializeOwned,
{
const TYPE_ID: &'static str;
}
pub trait Actor: Send + 'static {
type State: Send + 'static;
fn on_actor_terminated(&mut self, _state: &mut Self::State, _terminated: &ActorTerminated) {
}
}
pub struct ScheduleHandle {
handle: SpawnHandle,
cancel: Arc<AtomicBool>,
done: Arc<AtomicBool>,
}
impl ScheduleHandle {
pub fn cancel(self) {
self.cancel.store(true, Ordering::Relaxed);
self.handle.abort();
}
pub fn is_active(&self) -> bool {
!self.cancel.load(Ordering::Relaxed) && !self.done.load(Ordering::Relaxed)
}
}
impl Drop for ScheduleHandle {
fn drop(&mut self) {
self.cancel.store(true, Ordering::Relaxed);
self.handle.abort();
}
}
impl std::fmt::Debug for ScheduleHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ScheduleHandle")
.field("active", &self.is_active())
.finish()
}
}
pub struct ActorContext<A: Actor> {
pub(crate) label: String,
pub(crate) node_id: String,
pub(crate) mailbox_tx: mpsc::UnboundedSender<Box<dyn EnvelopeProxy<A>>>,
pub(crate) receptionist: Receptionist,
pub(crate) system_tx: mpsc::UnboundedSender<SystemSignal>,
pub(crate) reply_token: Mutex<Option<Box<dyn Any + Send>>>,
}
impl<A: Actor + 'static> ActorContext<A> {
pub fn label(&self) -> &str {
&self.label
}
pub fn node_id(&self) -> &str {
&self.node_id
}
pub fn endpoint(&self) -> Endpoint<A> {
Endpoint::local(self.mailbox_tx.clone())
}
pub fn receptionist(&self) -> &Receptionist {
&self.receptionist
}
pub fn watch(&self, label: &str) {
self.receptionist
.add_watch(label, &self.label, self.system_tx.clone());
}
pub fn watch_with_tag(&self, label: &str, tag: impl Into<String>) {
self.receptionist.add_watch_with_tag(
label,
&self.label,
self.system_tx.clone(),
tag.into(),
);
}
pub fn schedule_once<M>(&self, delay: Duration, message: M) -> ScheduleHandle
where
M: Message,
A: Handler<M>,
{
let tx = self.mailbox_tx.clone();
let runtime = self.receptionist.runtime().clone();
let timer = runtime.clone();
let cancel = Arc::new(AtomicBool::new(false));
let done = Arc::new(AtomicBool::new(false));
let (c, d) = (cancel.clone(), done.clone());
let handle = runtime.spawn(Box::pin(async move {
timer.sleep(delay).await;
if !c.load(Ordering::Relaxed) {
let (reply_tx, _reply_rx) = tokio::sync::oneshot::channel();
let envelope = crate::wire::TypedEnvelope {
message,
respond_to: reply_tx,
};
tx.send(Box::new(envelope)).ok();
}
d.store(true, Ordering::Relaxed);
}));
ScheduleHandle {
handle,
cancel,
done,
}
}
pub fn schedule_repeat<M>(&self, interval: Duration, message: M) -> ScheduleHandle
where
M: Message + Clone,
A: Handler<M>,
{
let tx = self.mailbox_tx.clone();
let runtime = self.receptionist.runtime().clone();
let timer = runtime.clone();
let cancel = Arc::new(AtomicBool::new(false));
let done = Arc::new(AtomicBool::new(false));
let (c, d) = (cancel.clone(), done.clone());
let handle = runtime.spawn(Box::pin(async move {
loop {
timer.sleep(interval).await;
if c.load(Ordering::Relaxed) {
break;
}
let (reply_tx, _reply_rx) = tokio::sync::oneshot::channel();
let envelope = crate::wire::TypedEnvelope {
message: message.clone(),
respond_to: reply_tx,
};
if tx.send(Box::new(envelope)).is_err() {
break;
}
}
d.store(true, Ordering::Relaxed);
}));
ScheduleHandle {
handle,
cancel,
done,
}
}
pub fn stop(&self) {
let _ = self.system_tx.send(SystemSignal::Stop);
}
pub fn spawn<F>(&self, future: F) -> SpawnHandle
where
F: Future<Output = ()> + Send + 'static,
{
self.receptionist.runtime().spawn(Box::pin(future))
}
pub fn actor_ref(&self) -> ActorRef<A> {
ActorRef {
label: self.label.clone(),
node_id: self.node_id.clone(),
_phantom: PhantomData,
}
}
pub fn reply<R: Send + 'static>(&self, value: R) -> bool {
let mut token = self.reply_token.lock().unwrap();
if let Some(any) = token.take() {
let sender = any
.downcast::<crate::wire::ReplySender<R>>()
.expect("ctx.reply() called with wrong type — R must match M::Result");
sender.send(value)
} else {
tracing::debug!("ctx.reply() called but reply already consumed");
false
}
}
pub fn reply_sender<R: Send + 'static>(&self) -> crate::wire::ReplySender<R> {
let mut token = self.reply_token.lock().unwrap();
if let Some(any) = token.take() {
*any.downcast::<crate::wire::ReplySender<R>>()
.expect("ctx.reply_sender() called with wrong type — R must match M::Result")
} else {
panic!("ctx.reply_sender() called but reply already consumed");
}
}
pub fn forward<B, M>(&self, endpoint: &Endpoint<B>, message: M) -> bool
where
B: Handler<M> + 'static,
M: Message + Send + 'static,
M::Result: Send + 'static,
{
let mut token = self.reply_token.lock().unwrap();
if let Some(any) = token.take() {
let sender = *any
.downcast::<crate::wire::ReplySender<M::Result>>()
.expect("ctx.forward() called with wrong result type");
endpoint.send_with_reply_sender(message, sender)
} else {
tracing::debug!("ctx.forward() called but reply already consumed");
false
}
}
}
#[derive(Debug)]
pub struct ActorRef<A: Actor> {
pub label: String,
pub node_id: String,
_phantom: PhantomData<A>,
}
impl<A: Actor> Clone for ActorRef<A> {
fn clone(&self) -> Self {
Self {
label: self.label.clone(),
node_id: self.node_id.clone(),
_phantom: PhantomData,
}
}
}
#[derive(Serialize, Deserialize)]
struct ActorRefWire {
label: String,
node_id: String,
}
impl<A: Actor> Serialize for ActorRef<A> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
ActorRefWire {
label: self.label.clone(),
node_id: self.node_id.clone(),
}
.serialize(serializer)
}
}
impl<'de, A: Actor> Deserialize<'de> for ActorRef<A> {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let wire = ActorRefWire::deserialize(deserializer)?;
Ok(ActorRef {
label: wire.label,
node_id: wire.node_id,
_phantom: PhantomData,
})
}
}
impl<A: Actor + 'static> ActorRef<A> {
pub fn new(label: impl Into<String>, node_id: impl Into<String>) -> Self {
Self {
label: label.into(),
node_id: node_id.into(),
_phantom: PhantomData,
}
}
pub fn resolve(&self, receptionist: &Receptionist) -> Option<Endpoint<A>> {
receptionist.lookup::<A>(&self.label)
}
}
pub trait MigratableActor: Actor
where
Self::State: Serialize + DeserializeOwned,
{
}
pub trait Handler<M: Message>: Actor + Sized {
fn handle(
&mut self,
ctx: &ActorContext<Self>,
state: &mut Self::State,
message: M,
) -> M::Result;
}
pub trait AsyncHandler<M: Message>: Actor + Sized {
fn handle<'a>(
&'a mut self,
ctx: &'a ActorContext<Self>,
state: &'a mut Self::State,
message: M,
) -> impl Future<Output = M::Result> + Send + 'a;
}
pub trait RemoteDispatch: Actor + Sized {
fn dispatch_remote<'a>(
&'a mut self,
ctx: &'a ActorContext<Self>,
state: &'a mut Self::State,
message_type: &'a str,
payload: &'a [u8],
) -> impl Future<Output = Result<Vec<u8>, DispatchError>> + Send + 'a;
}
#[derive(Debug, thiserror::Error)]
pub enum DispatchError {
#[error("unknown message type: {0}")]
UnknownMessageType(String),
#[error("deserialize failed: {0}")]
DeserializeFailed(String),
#[error("serialize failed: {0}")]
SerializeFailed(String),
}