pub use near_async_derive::{MultiSend, MultiSenderFrom};
mod functional;
pub mod futures;
pub mod instrumentation;
pub mod messaging;
pub mod multithread;
pub mod test_loop;
pub mod tokio;
use crate::futures::FutureSpawner;
use crate::messaging::Actor;
use crate::multithread::runtime_handle::{MultithreadRuntimeHandle, spawn_multithread_actor};
use crate::tokio::runtime_handle::{TokioRuntimeBuilder, spawn_tokio_actor};
use crate::tokio::{CancellableFutureSpawner, TokioRuntimeHandle};
pub use near_time as time;
use parking_lot::Mutex;
use std::any::type_name;
use std::sync::Arc;
use std::sync::atomic::AtomicU64;
use tokio_util::sync::CancellationToken;
static MESSAGE_SEQUENCE_NUM: AtomicU64 = AtomicU64::new(0);
pub(crate) fn next_message_sequence_num() -> u64 {
MESSAGE_SEQUENCE_NUM.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
}
fn pretty_type_name<T>() -> &'static str {
type_name::<T>().rsplit("::").next().unwrap().trim_end_matches('>')
}
struct EmptyActor;
impl Actor for EmptyActor {}
#[derive(Clone)]
pub struct ActorSystem {
tokio_cancellation_signal: CancellationToken,
multithread_cancellation_signal: Arc<Mutex<Option<crossbeam_channel::Sender<()>>>>,
multithread_cancellation_receiver: crossbeam_channel::Receiver<()>,
}
impl ActorSystem {
pub fn new() -> Self {
let mut systems = ACTOR_SYSTEMS.lock();
let (multithread_cancellation_sender, multithread_cancellation_receiver) =
crossbeam_channel::bounded(0);
let ret = Self {
tokio_cancellation_signal: CancellationToken::new(),
multithread_cancellation_signal: Arc::new(Mutex::new(Some(
multithread_cancellation_sender,
))),
multithread_cancellation_receiver,
};
systems.push(ret.clone());
ret
}
pub fn stop(&self) {
tracing::info!("Stopping all actors in ActorSystem");
self.tokio_cancellation_signal.cancel();
self.multithread_cancellation_signal.lock().take();
}
pub fn spawn_tokio_actor<A: messaging::Actor + Send + 'static>(
&self,
actor: A,
) -> TokioRuntimeHandle<A> {
spawn_tokio_actor(
actor,
std::any::type_name::<A>().to_string(),
self.tokio_cancellation_signal.clone(),
)
}
pub fn new_tokio_builder<A: messaging::Actor + Send + 'static>(
&self,
) -> TokioRuntimeBuilder<A> {
TokioRuntimeBuilder::new(
pretty_type_name::<A>().to_string(),
self.tokio_cancellation_signal.clone(),
)
}
pub fn spawn_multithread_actor<A: messaging::Actor + Send + 'static>(
&self,
num_threads: usize,
make_actor_fn: impl Fn() -> A + Sync + Send + 'static,
) -> MultithreadRuntimeHandle<A> {
spawn_multithread_actor(
num_threads,
make_actor_fn,
self.multithread_cancellation_receiver.clone(),
None,
)
}
pub fn new_future_spawner(&self, description: &str) -> Box<dyn FutureSpawner> {
let handle = spawn_tokio_actor(
EmptyActor,
description.to_string(),
self.tokio_cancellation_signal.clone(),
);
handle.future_spawner()
}
pub fn new_multi_threaded_future_spawner(&self, description: &str) -> Box<dyn FutureSpawner> {
let handle = CancellableFutureSpawner::new(
self.tokio_cancellation_signal.clone(),
description.to_string(),
);
handle.future_spawner()
}
}
pub fn new_owned_future_spawner(description: &str) -> Box<dyn FutureSpawner> {
Box::new(OwnedFutureSpawner {
handle: spawn_tokio_actor(EmptyActor, description.to_string(), CancellationToken::new()),
})
}
pub fn new_owned_multithread_actor<A: Actor + Send + 'static>(
num_threads: usize,
make_actor_fn: impl Fn() -> A + Sync + Send + 'static,
) -> MultithreadRuntimeHandle<A> {
let (cancellation_signal, cancellation_receiver) = crossbeam_channel::bounded::<()>(0);
spawn_multithread_actor(
num_threads,
make_actor_fn,
cancellation_receiver,
Some(cancellation_signal), )
}
struct OwnedFutureSpawner {
handle: TokioRuntimeHandle<EmptyActor>,
}
impl FutureSpawner for OwnedFutureSpawner {
fn spawn_boxed(&self, description: &'static str, f: crate::futures::BoxFuture<'static, ()>) {
self.handle.future_spawner().spawn_boxed(description, f);
}
}
impl Drop for OwnedFutureSpawner {
fn drop(&mut self) {
self.handle.stop();
}
}
static ACTOR_SYSTEMS: Mutex<Vec<ActorSystem>> = Mutex::new(Vec::new());
pub fn shutdown_all_actors() {
{
let systems = ACTOR_SYSTEMS.lock();
if systems.len() > 1 {
panic!("shutdown_all_actors should not be used when there are multiple ActorSystems");
}
if let Some(system) = systems.first() {
system.stop();
}
}
}