use slog::trace;
use std::{
collections::HashSet,
sync::{Arc, Mutex},
};
use crate::actor_ref::{ActorRef, ActorReference, BasicActorRef};
use crate::{
actor::actor_cell::{ActorCell, ExtendedCell},
actor::*,
kernel::{kernel, mailbox::mailbox},
system::{ActorSystem, SysActors, SystemMsg},
validate::validate_name,
};
use slog::Logger;
#[derive(Clone)]
pub struct Provider {
inner: Arc<Mutex<ProviderInner>>,
log: Logger,
}
struct ProviderInner {
paths: HashSet<ActorPath>,
counter: ActorId,
}
impl Provider {
pub fn new(log: Logger) -> Self {
let inner = ProviderInner {
paths: HashSet::new(),
counter: 100, };
Self {
inner: Arc::new(Mutex::new(inner)),
log,
}
}
pub fn create_actor<A>(
&self,
props: BoxActorProd<A>,
name: &str,
parent: &BasicActorRef,
sys: &ActorSystem,
) -> Result<ActorRef<A::Msg>, CreateError>
where
A: Actor + 'static,
{
validate_name(name)?;
let path = ActorPath::new(&format!("{}/{}", parent.path(), name));
trace!(sys.log(), "Attempting to create actor at: {}", path);
let uid = self.register(&path)?;
let uri = ActorUri {
uid,
path,
name: Arc::new(name.into()),
host: sys.host(),
};
let (sender, sys_sender, mb) = mailbox::<A::Msg>(sys.sys_settings().msg_process_limit);
let cell = ExtendedCell::new(
uri.uid,
uri,
Some(parent.clone()),
sys,
Arc::new(sender.clone()),
sys_sender,
sender,
);
let k = kernel(props, cell.clone(), mb, sys)?;
let cell = cell.init(&k);
let actor = ActorRef::new(cell);
let child = BasicActorRef::from(actor.clone());
parent.cell.add_child(child);
actor.sys_tell(SystemMsg::ActorInit);
Ok(actor)
}
fn register(&self, path: &ActorPath) -> Result<ActorId, CreateError> {
match self.inner.lock() {
Ok(mut inner) => {
if inner.paths.contains(path) {
return Err(CreateError::AlreadyExists(path.clone()));
}
inner.paths.insert(path.clone());
let id = inner.counter;
inner.counter += 1;
Ok(id)
}
Err(_) => Err(CreateError::System),
}
}
pub fn unregister(&self, path: &ActorPath) {
let mut inner = self.inner.lock().unwrap();
inner.paths.remove(path);
}
}
pub fn create_root(sys: &ActorSystem) -> SysActors {
let root = root(sys);
SysActors {
root: root.clone(),
user: guardian(1, "user", "/user", &root, sys),
sysm: guardian(2, "system", "/system", &root, sys),
temp: guardian(3, "temp", "/temp", &root, sys),
}
}
fn root(sys: &ActorSystem) -> BasicActorRef {
let uri = ActorUri {
uid: 0,
name: Arc::new("root".to_string()),
path: ActorPath::new("/"),
host: Arc::new("localhost".to_string()),
};
let (sender, sys_sender, _mb) = mailbox::<SystemMsg>(100);
let bb_cell = ActorCell::new(
0,
uri.clone(),
None,
sys,
Arc::new(sender),
sys_sender,
);
let bigbang = BasicActorRef::new(bb_cell);
let props: BoxActorProd<Guardian> = Guardian::props("root".to_string(), sys.log());
let (sender, sys_sender, mb) = mailbox::<SystemMsg>(100);
let cell = ExtendedCell::new(
uri.uid,
uri,
Some(bigbang),
sys,
Arc::new(sender.clone()),
sys_sender,
sender,
);
let k = kernel(props, cell.clone(), mb, sys).unwrap();
let cell = cell.init(&k);
let actor_ref = ActorRef::new(cell);
BasicActorRef::from(actor_ref)
}
fn guardian(
uid: ActorId,
name: &str,
path: &str,
root: &BasicActorRef,
sys: &ActorSystem,
) -> BasicActorRef {
let uri = ActorUri {
uid,
name: Arc::new(name.to_string()),
path: ActorPath::new(path),
host: Arc::new("localhost".to_string()),
};
let props: BoxActorProd<Guardian> = Guardian::props(name.to_string(), sys.log());
let (sender, sys_sender, mb) = mailbox::<SystemMsg>(100);
let cell = ExtendedCell::new(
uri.uid,
uri,
Some(root.clone()),
sys,
Arc::new(sender.clone()),
sys_sender,
sender,
);
let k = kernel(props, cell.clone(), mb, sys).unwrap();
let cell = cell.init(&k);
let actor_ref = ActorRef::new(cell);
let actor = BasicActorRef::from(actor_ref);
root.cell.add_child(actor.clone());
actor
}
struct Guardian {
name: String,
log: Logger,
}
impl Guardian {
fn new((name, log): (String, Logger)) -> Self {
Self { name, log }
}
fn props(name: String, logger: Logger) -> BoxActorProd<Self> {
Props::new_args(Self::new, (name, logger))
}
}
impl Actor for Guardian {
type Msg = SystemMsg;
fn post_stop(&mut self) {
trace!(self.log, "{} guardian stopped", self.name);
}
fn recv(&mut self, _: &Context<Self::Msg>, _: Self::Msg, _: Option<BasicActorRef>) {}
}