robots/actors/
actor_ref.rs

1use std::any::Any;
2use std::sync::Arc;
3
4use actors::{InnerMessage, Message, SystemMessage};
5use actors::actor_cell::ActorCell;
6use actors::cthulhu::Cthulhu;
7
8#[derive(Debug, Eq, Hash, PartialEq)]
9/// Path to an actor.
10///
11/// This enum contains the information for actors whether they are local or distant.
12pub enum ActorPath {
13    /// Logical path to a local actor.
14    Local(String),
15    /// Logical path and connection information for a distant actor.
16    Distant(ConnectionInfo),
17}
18
19impl ActorPath {
20    /// Creates a new local ActorPath variant with the given logical_path.
21    pub fn new_local(path: String) -> Arc<ActorPath> {
22        Arc::new(ActorPath::Local(path))
23    }
24
25    /// Creates a new distant ActorPath.
26    pub fn new_distant(distant_logical_path: String, addr_port: String) -> Arc<ActorPath> {
27        Arc::new(ActorPath::Distant(
28                ConnectionInfo {
29                    distant_logical_path: distant_logical_path,
30                    addr_port: addr_port,
31                }))
32    }
33
34    /// Gives a reference to the logical path of an actor.
35    ///
36    /// Note that this gives the local logical path whether the actor is local or not.
37    pub fn logical_path(&self) -> &String {
38        match *self {
39            ActorPath::Local(ref s) => s,
40            ActorPath::Distant(ref c) => &(c.distant_logical_path),
41        }
42    }
43
44    /// Creates an ActorPath for a child of an actor.
45    ///
46    /// This gives a Local variant, because actors are always created locally.
47    pub fn child(&self, name: String) -> Arc<ActorPath> {
48        match *self {
49            ActorPath::Local(ref s) => {
50                let path = format!("{}/{}", s, name);
51                ActorPath::new_local(path)
52            },
53            ActorPath::Distant(_) => panic!("Cannot create a child for a distant actor."),
54        }
55    }
56}
57
58#[derive(Debug, Eq, Hash, PartialEq)]
59/// This gives connection informations on how to get to the distant actors.
60///
61/// *  The distant_logical_path is something like "/user/distant/actor".
62/// *  The addr_port is something like "127.0.0.1:12345"
63///
64/// Note that the storage of the addr_port could be improved, but is not a concern for now.
65pub struct ConnectionInfo {
66    distant_logical_path: String,
67    addr_port: String,
68}
69
70
71impl ConnectionInfo {
72    /// Distant logical path.
73    pub fn distant_logical_path(&self) -> &String {
74        &self.distant_logical_path
75    }
76    /// Address and port of the distant actor.
77    pub fn addr_port(&self) -> &String {
78        &self.addr_port
79    }
80}
81
82#[derive(Clone)]
83enum InnerActor {
84    Cthulhu(Cthulhu),
85    Actor(ActorCell),
86}
87
88/// An `ActorRef` is the way used to interract with something that acts as an actor.
89///
90/// This can represent either an ACtor, a Future or Cthulhu (the original actor) whether distant or
91/// local.
92///
93/// It gives the Actor API, it can receive messages, be told to send messages, be asked something
94/// and give its ActorPath.
95pub struct ActorRef {
96    inner_actor: Option<InnerActor>,
97    path: Arc<ActorPath>,
98}
99
100impl ActorRef {
101    /// Creates a new ActorRef to a distant actor, with the given ActorPath.
102    pub fn new_distant(path: Arc<ActorPath>) -> ActorRef {
103        ActorRef {
104            inner_actor: None,
105            path: path,
106        }
107    }
108
109    /// Creates a new ActorRef to Cthulhu, this should only be called once.
110    pub fn with_cthulhu(cthulhu: Cthulhu) -> ActorRef {
111        let path = ActorPath::new_local("/".to_owned());
112        ActorRef {
113            inner_actor: Some(InnerActor::Cthulhu(cthulhu)),
114            path: path,
115        }
116    }
117
118    /// Creates a new ActorRef for a local Actor, with the given ActorCell.
119    pub fn with_cell(cell: ActorCell, path: Arc<ActorPath>) -> ActorRef {
120        ActorRef {
121            inner_actor: Some(InnerActor::Actor(cell)),
122            path: path,
123        }
124    }
125
126    /// Receives a system message such as `Start`, `Restart` or a `Failure(ActorRef)`, puts it in
127    /// the system mailbox and schedules the actor if needed.
128    pub fn receive_system_message(&self, system_message: SystemMessage) {
129        info!("{} receiving a system message", self.path().logical_path());
130        let inner = self.inner_actor.as_ref().expect("Tried to put a system message in the mailbox of a distant actor.");
131        match *inner {
132            InnerActor::Actor(ref actor) => actor.receive_system_message(system_message),
133            InnerActor::Cthulhu(ref cthulhu) => cthulhu.receive_system_message(),
134        };
135    }
136
137    /// Receives a regular message and puts it in the mailbox and schedules the actor if needed.
138    pub fn receive(&self, message: InnerMessage, sender: ActorRef) {
139        info!("{} receiving a message", self.path().logical_path());
140        let inner = self.inner_actor.as_ref().expect("Tried to put a message in the mailbox of a distant actor.");
141        match *inner {
142            InnerActor::Actor(ref actor) => actor.receive_message(message, sender),
143            InnerActor::Cthulhu(ref cthulhu) => cthulhu.receive(),
144        };
145    }
146
147    /// Handles a messages by calling the `receive` method of the underlying actor.
148    pub fn handle(&self) {
149        info!("{} handling a message", self.path().logical_path());
150        let inner = self.inner_actor.as_ref().expect("");
151        match *inner {
152            InnerActor::Actor(ref actor) => actor.handle_envelope(),
153            InnerActor::Cthulhu(ref cthulhu) => cthulhu.handle(),
154        };
155    }
156
157    /// Gives a clone of the ActorPath.
158    pub fn path(&self) -> Arc<ActorPath> {
159        self.path.clone()
160    }
161
162    /// Makes this ActorRef send a message to anther ActorRef.
163    pub fn tell_to<MessageTo: Message>(&self, to: ActorRef, message: MessageTo) {
164        info!("{} is sending a message to {}", self.path().logical_path(), to.path().logical_path());
165        let message: Box<Any + Send> = Box::new(message);
166        to.receive(InnerMessage::Message(message), self.clone())
167    }
168}
169
170impl Clone for ActorRef {
171    fn clone(&self) -> ActorRef {
172        ActorRef {
173            inner_actor: self.inner_actor.clone(),
174            path: self.path.clone(),
175        }
176    }
177}