use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::HashMap;
use std::default::Default;
use std::rc::Rc;
use actix_rt::{Arbiter, System};
use parking_lot::Mutex;
use crate::actor::{Actor, Supervised};
use crate::address::Addr;
use crate::context::Context;
use crate::supervisor::Supervisor;
type AnyMap = HashMap<TypeId, Box<dyn Any>>;
#[derive(Clone)]
pub struct Registry {
registry: Rc<RefCell<AnyMap>>,
}
thread_local! {
static AREG: Registry = {
Registry {
registry: Rc::new(RefCell::new(AnyMap::new()))
}
};
}
#[allow(unused_variables)]
pub trait ArbiterService: Actor<Context = Context<Self>> + Supervised + Default {
fn start_service() -> Addr<Self> {
Supervisor::start(|ctx| {
let mut act = Self::default();
act.service_started(ctx);
act
})
}
fn service_started(&mut self, ctx: &mut Context<Self>) {}
fn from_registry() -> Addr<Self> {
AREG.with(|reg| reg.get())
}
}
impl Registry {
pub fn get<A: ArbiterService + Actor<Context = Context<A>>>(&self) -> Addr<A> {
let id = TypeId::of::<A>();
if let Some(addr) = self.registry.borrow().get(&id) {
if let Some(addr) = addr.downcast_ref::<Addr<A>>() {
return addr.clone();
}
}
let addr: Addr<A> = A::start_service();
self.registry
.borrow_mut()
.insert(id, Box::new(addr.clone()));
addr
}
pub fn query<A: ArbiterService + Actor<Context = Context<A>>>(
&self,
) -> Option<Addr<A>> {
let id = TypeId::of::<A>();
if let Some(addr) = self.registry.borrow().get(&id) {
if let Some(addr) = addr.downcast_ref::<Addr<A>>() {
return Some(addr.clone());
}
}
None
}
pub fn set<A: ArbiterService + Actor<Context = Context<A>>>(addr: Addr<A>) {
AREG.with(|reg| {
let id = TypeId::of::<A>();
if let Some(addr) = reg.registry.borrow().get(&id) {
if addr.downcast_ref::<Addr<A>>().is_some() {
panic!("Actor already started");
}
}
reg.registry.borrow_mut().insert(id, Box::new(addr));
})
}
}
#[derive(Debug)]
pub struct SystemRegistry {
system: Arbiter,
registry: HashMap<TypeId, Box<dyn Any + Send>>,
}
lazy_static::lazy_static! {
static ref SREG: Mutex<HashMap<usize, SystemRegistry>> = {
Mutex::new(HashMap::new())
};
}
#[allow(unused_variables)]
pub trait SystemService: Actor<Context = Context<Self>> + Supervised + Default {
fn start_service(sys: &Arbiter) -> Addr<Self> {
Supervisor::start_in_arbiter(sys, |ctx| {
let mut act = Self::default();
act.service_started(ctx);
act
})
}
fn service_started(&mut self, ctx: &mut Context<Self>) {}
fn from_registry() -> Addr<Self> {
System::with_current(|sys| {
let mut sreg = SREG.lock();
let reg = sreg
.entry(sys.id())
.or_insert_with(|| SystemRegistry::new(sys.arbiter().clone()));
if let Some(addr) = reg.registry.get(&TypeId::of::<Self>()) {
if let Some(addr) = addr.downcast_ref::<Addr<Self>>() {
return addr.clone();
}
}
let addr = Self::start_service(System::current().arbiter());
reg.registry
.insert(TypeId::of::<Self>(), Box::new(addr.clone()));
addr
})
}
}
impl SystemRegistry {
pub(crate) fn new(system: Arbiter) -> Self {
Self {
system,
registry: HashMap::default(),
}
}
pub fn get<A: SystemService + Actor<Context = Context<A>>>(&mut self) -> Addr<A> {
if let Some(addr) = self.registry.get(&TypeId::of::<A>()) {
match addr.downcast_ref::<Addr<A>>() {
Some(addr) => return addr.clone(),
None => panic!("Got unknown value: {:?}", addr),
}
}
let addr = A::start_service(&self.system);
self.registry
.insert(TypeId::of::<A>(), Box::new(addr.clone()));
addr
}
pub fn query<A: SystemService + Actor<Context = Context<A>>>(
&self,
) -> Option<Addr<A>> {
if let Some(addr) = self.registry.get(&TypeId::of::<A>()) {
match addr.downcast_ref::<Addr<A>>() {
Some(addr) => return Some(addr.clone()),
None => return None,
}
}
None
}
pub fn set<A: SystemService + Actor<Context = Context<A>>>(addr: Addr<A>) {
System::with_current(|sys| {
let mut sreg = SREG.lock();
let reg = sreg
.entry(sys.id())
.or_insert_with(|| SystemRegistry::new(sys.arbiter().clone()));
if let Some(addr) = reg.registry.get(&TypeId::of::<A>()) {
if addr.downcast_ref::<Addr<A>>().is_some() {
panic!("Actor already started");
}
}
reg.registry.insert(TypeId::of::<A>(), Box::new(addr));
})
}
}