use std::fmt::{self, Debug};
use std::future;
use std::hash::Hash;
use std::sync::Arc;
use std::time::Duration;
use bytes::Bytes;
use futures_util::{FutureExt, TryFutureExt};
use tracing::Instrument;
use acktor::{
Address, Message, Recipient, SendError, Sender, SenderId,
address::{ClosedResultFuture, DoSendResult, DoSendResultFuture, SendResult, SendResultFuture},
channel::oneshot,
};
use crate::codec::{Decode, DecodeContext, Encode, EncodeContext};
use crate::remote_actor::RemoteActorRegistry;
use crate::remote_message::RemoteMessage;
use crate::session::Session;
pub struct RemoteAddress {
index: u64,
remote_actor_id: u64,
session: Address<Session>,
encode_context: EncodeContext,
}
impl Debug for RemoteAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("RemoteAddress")
.field(&self.session.index())
.field(&self.remote_actor_id)
.finish()
}
}
impl Clone for RemoteAddress {
#[inline]
fn clone(&self) -> Self {
Self {
index: self.index,
remote_actor_id: self.remote_actor_id,
session: self.session.clone(),
encode_context: self.encode_context.clone(),
}
}
}
impl PartialEq for RemoteAddress {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.remote_actor_id == other.remote_actor_id
&& self.session.index() == other.session.index()
}
}
impl Eq for RemoteAddress {}
impl Hash for RemoteAddress {
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.index.hash(state)
}
}
impl RemoteAddress {
pub const REMOTE_FLAG: u64 = 1 << 63;
pub fn new(
remote_actor_id: u64,
session: Address<Session>,
registry: RemoteActorRegistry,
) -> Self {
let index = Self::REMOTE_FLAG | ((session.index().reverse_bits() >> 1) ^ remote_actor_id);
Self {
index,
remote_actor_id,
session,
encode_context: EncodeContext::new(registry),
}
}
fn decode_context(&self) -> DecodeContext {
self.encode_context
.create_decode_context(self.session.clone())
}
pub fn closed(&self) -> impl Future<Output = ()> + Send {
self.session.closed()
}
pub fn is_closed(&self) -> bool {
self.session.is_closed()
}
pub fn capacity(&self) -> usize {
self.session.capacity()
}
}
async fn decode_and_forward<M>(
raw_rx: oneshot::Receiver<Bytes>,
tx: oneshot::Sender<M::Result>,
decode_context: DecodeContext,
) where
M: Message + Encode,
M::Result: Decode,
{
let decode_result = match raw_rx.await {
Ok(bytes) => M::Result::decode(bytes, Some(&decode_context)),
Err(e) => {
let _ = tx.send_err(e);
return;
}
};
match decode_result {
Ok(result) => {
let _ = tx.send(result);
}
Err(e) => {
let _ = tx.send_err(e);
}
}
}
impl SenderId for RemoteAddress {
#[inline]
fn index(&self) -> u64 {
self.index
}
}
impl<M> Sender<M> for RemoteAddress
where
M: Message + Encode,
M::Result: Decode,
{
fn closed(&self) -> ClosedResultFuture<'_> {
self.closed().boxed()
}
fn is_closed(&self) -> bool {
self.is_closed()
}
fn capacity(&self) -> usize {
self.capacity()
}
fn send(&self, msg: M) -> SendResultFuture<'_, M> {
let message_bytes = match msg.encode_to_bytes(Some(&self.encode_context)) {
Ok(bytes) => bytes,
Err(e) => return future::ready(Err(SendError::other(e, msg))).boxed(),
};
let (raw_tx, raw_rx) = oneshot::channel::<Bytes>();
let (tx, rx) = oneshot::channel::<M::Result>();
let decode_context = self.decode_context();
tokio::spawn(
async move {
decode_and_forward::<M>(raw_rx, tx, decode_context).await;
}
.in_current_span(),
);
self.session
.do_send(RemoteMessage::send(
self.remote_actor_id,
<M as Encode>::ID,
message_bytes,
raw_tx,
))
.map(|result| match result {
Ok(_) => Ok(rx),
Err(_) => Err(SendError::Closed(msg)),
})
.boxed()
}
fn do_send(&self, msg: M) -> DoSendResultFuture<'_, M> {
let message_bytes = match msg.encode_to_bytes(Some(&self.encode_context)) {
Ok(bytes) => bytes,
Err(e) => return future::ready(Err(SendError::other(e, msg))).boxed(),
};
self.session
.do_send(RemoteMessage::do_send(
self.remote_actor_id,
<M as Encode>::ID,
message_bytes,
))
.map_err(|_| SendError::Closed(msg))
.boxed()
}
fn try_send(&self, msg: M) -> SendResult<M> {
let message_bytes = match msg.encode_to_bytes(Some(&self.encode_context)) {
Ok(bytes) => bytes,
Err(e) => return Err(SendError::other(e, msg)),
};
let (raw_tx, raw_rx) = oneshot::channel::<Bytes>();
let (tx, rx) = oneshot::channel::<M::Result>();
let decode_context = self.decode_context();
tokio::spawn(
async move {
decode_and_forward::<M>(raw_rx, tx, decode_context).await;
}
.in_current_span(),
);
match self.session.try_do_send(RemoteMessage::send(
self.remote_actor_id,
<M as Encode>::ID,
message_bytes,
raw_tx,
)) {
Ok(_) => Ok(rx),
Err(e) => match e {
SendError::Full(_) => Err(SendError::Full(msg)),
_ => Err(SendError::Closed(msg)),
},
}
}
fn try_do_send(&self, msg: M) -> DoSendResult<M> {
let message_bytes = match msg.encode_to_bytes(Some(&self.encode_context)) {
Ok(bytes) => bytes,
Err(e) => return Err(SendError::other(e, msg)),
};
self.session
.try_do_send(RemoteMessage::do_send(
self.remote_actor_id,
<M as Encode>::ID,
message_bytes,
))
.map_err(|e| match e {
SendError::Full(_) => SendError::Full(msg),
_ => SendError::Closed(msg),
})
}
fn send_timeout(&self, msg: M, timeout: Duration) -> SendResultFuture<'_, M> {
let message_bytes = match msg.encode_to_bytes(Some(&self.encode_context)) {
Ok(bytes) => bytes,
Err(e) => return future::ready(Err(SendError::other(e, msg))).boxed(),
};
let (raw_tx, raw_rx) = oneshot::channel::<Bytes>();
let (tx, rx) = oneshot::channel::<M::Result>();
let decode_context = self.decode_context();
tokio::spawn(
async move {
decode_and_forward::<M>(raw_rx, tx, decode_context).await;
}
.in_current_span(),
);
self.session
.do_send_timeout(
RemoteMessage::send(
self.remote_actor_id,
<M as Encode>::ID,
message_bytes,
raw_tx,
),
timeout,
)
.map(|result| match result {
Ok(_) => Ok(rx),
Err(_) => Err(SendError::Closed(msg)),
})
.boxed()
}
fn do_send_timeout(&self, msg: M, timeout: Duration) -> DoSendResultFuture<'_, M> {
let message_bytes = match msg.encode_to_bytes(Some(&self.encode_context)) {
Ok(bytes) => bytes,
Err(e) => return future::ready(Err(SendError::other(e, msg))).boxed(),
};
self.session
.do_send_timeout(
RemoteMessage::do_send(self.remote_actor_id, <M as Encode>::ID, message_bytes),
timeout,
)
.map_err(|_| SendError::Closed(msg))
.boxed()
}
fn blocking_send(&self, msg: M) -> SendResult<M> {
let message_bytes = match msg.encode_to_bytes(Some(&self.encode_context)) {
Ok(bytes) => bytes,
Err(e) => return Err(SendError::other(e, msg)),
};
let (raw_tx, raw_rx) = oneshot::channel::<Bytes>();
let (tx, rx) = oneshot::channel::<M::Result>();
let decode_context = self.decode_context();
tokio::spawn(
async move {
decode_and_forward::<M>(raw_rx, tx, decode_context).await;
}
.in_current_span(),
);
match self.session.blocking_do_send(RemoteMessage::send(
self.remote_actor_id,
<M as Encode>::ID,
message_bytes,
raw_tx,
)) {
Ok(_) => Ok(rx),
Err(_) => Err(SendError::Closed(msg)),
}
}
fn blocking_do_send(&self, msg: M) -> DoSendResult<M> {
let message_bytes = match msg.encode_to_bytes(Some(&self.encode_context)) {
Ok(bytes) => bytes,
Err(e) => return Err(SendError::other(e, msg)),
};
self.session
.blocking_do_send(RemoteMessage::do_send(
self.remote_actor_id,
<M as Encode>::ID,
message_bytes,
))
.map_err(|_| SendError::Closed(msg))
}
}
impl<M> From<RemoteAddress> for Recipient<M>
where
M: Message + Encode,
M::Result: Decode,
{
fn from(address: RemoteAddress) -> Self {
Recipient(Arc::new(address))
}
}