Skip to main content

actix_telepathy/utils/
custom_system_service.rs

1use actix::{Actor, Addr, ArbiterHandle, Context, Supervisor, System, SystemService};
2use once_cell::sync::Lazy;
3use parking_lot::Mutex;
4use std::any::{Any, TypeId};
5use std::collections::HashMap;
6
7static SREG: Lazy<Mutex<HashMap<usize, PatchedSystemRegistry>>> =
8    Lazy::new(|| Mutex::new(HashMap::new()));
9
10#[derive(Debug)]
11struct PatchedSystemRegistry {
12    #[allow(dead_code)]
13    system: ArbiterHandle,
14    registry: HashMap<TypeId, Box<dyn Any + Send>>,
15}
16
17impl PatchedSystemRegistry {
18    pub(crate) fn new(system: ArbiterHandle) -> Self {
19        Self {
20            system,
21            registry: HashMap::default(),
22        }
23    }
24}
25
26/// Trait defines custom system's service.
27pub trait CustomSystemService: Actor<Context = Context<Self>> + SystemService {
28    /// Construct and start system service with arguments
29    fn start_service_with(
30        f: impl Fn() -> Self + std::marker::Sync + 'static + std::marker::Send,
31    ) -> Addr<Self> {
32        let sys = System::current();
33        let arbiter = sys.arbiter();
34        let addr = Supervisor::start_in_arbiter(arbiter, move |ctx| {
35            let mut act = f();
36            act.custom_service_started(ctx);
37            act
38        });
39        Self::add_to_registry(addr)
40    }
41
42    #[allow(dead_code, unused_variables)]
43    fn custom_service_started(&mut self, ctx: &mut Context<Self>) {}
44
45    fn add_to_registry(addr: Addr<Self>) -> Addr<Self> {
46        let sys = System::current();
47        let mut sreg = SREG.lock();
48        let reg = sreg
49            .entry(sys.id())
50            .or_insert_with(|| PatchedSystemRegistry::new(sys.arbiter().clone()));
51        reg.registry
52            .insert(TypeId::of::<Self>(), Box::new(addr.clone()));
53        addr
54    }
55
56    /// Get actor's address from system registry
57    fn from_custom_registry() -> Addr<Self> {
58        let sys = System::current();
59        let mut sreg = SREG.lock();
60        let reg = sreg
61            .entry(sys.id())
62            .or_insert_with(|| PatchedSystemRegistry::new(sys.arbiter().clone()));
63
64        if let Some(addr) = reg.registry.get(&TypeId::of::<Self>())
65            && let Some(addr) = addr.downcast_ref::<Addr<Self>>()
66        {
67            return addr.clone();
68        }
69
70        panic!("Please start Actor before asking for it in registry!");
71    }
72}