Module aurum_actors::core[][src]

Expand description

Aurum’s base functionality: spawning actors, binding sockets, forging actor references and sending messages.

Unifying Types

The programmer needs to enumerate to Aurum all types of messages actors can receive thoughout their whole application. All applications using Aurum must use exactly one enumeration (henceforth referred to as the UnifiedType). No more, no less. Due to the way the UnifiedType is handled, it is still possible to build and use many independent libraries on top of Aurum. The unified type is constructed with the unify macro. See the unify macro for an in-depth discussion on how it works and why we need it.

Actor References

Actor References come in 2 flavors: ActorRef and LocalRef. ActorRef is location-transparent, it accepts both local and remote messages. LocalRef is for local messages only. An ActorRef requires 2 generic parameters: the UnifiedType and the interface (not the root message type).

Creating a Message Type

Use AurumInterface to create message types for actors.

#[derive(AurumInterface)]
#[aurum(local)]
enum MyMsgType {
  #[aurum]
  MyStringInterface(String),
  #[aurum(local)]
  MyNonserializableInterface(&'static str),
  MyOtherMsg(usize),
}

A unify Example

The unify macro is responsible for constructing the UnifiedType and implementing traits for it. Arguments must include all message types (whether they are to be remotely accessed or not), and types used for remote interfaces. unify creates a type, so it should only be called once in a single application.

unify! { MyUnifiedType =
  MyMsgType |
  MyOtherMsgType |
  MsgTypeForSomeThirdPartyLibrary
  ;
  String |
  InterfaceForSomeThirdPartyLibrary
}

Spawning Actors

To spawn actors, you need to create a Node. You also need an initial instance of whatever type implements the actor trait, the string part of the actor’s name, whether the actor should be double-threaded and whether a reference to it should be sent to the registry.

struct MyActor {
  first: String,
  second: usize
}
//Don’t forget this annotation
#[async_trait]
impl Actor<MyUnifiedType, MyMsgType> for MyActor { ... }

let mut config = NodeConfig::default();
config.socket = Socket::new(...);
let node = Node::<MyUnifiedType>::new_sync(config);
let actor = MyActor {
  first: "hi  there".to_string(),
  second: 4214
};
node.spawn(
  false, // Double -threaded?1
  actor,
  "my-very-cool-actor".to_string(),
  true, // Register
);

Sending Messages

An ActorId is used to uniquely identify an actor in the registry of a Node. A Destination contains an ActorId and information on which interface it is sending messages to. A Destination can be forged, just like an ActorRef. The combination of a Socket and a Destination consitutes a complete actor address. You can construct and use these two components indepentently.

let socket = Socket::new(...);

// Forging a Destination
let dest = Destination::<MyUnifiedType, String>::new::<MyMsgType>(
  "my-very-cool-actor".to_string()
);
let msg = "My name is Baloo".to_string();
let ser = UdpSerial::new(&dest, &msg)
node.udp(&socket, &ser);

// Forging an ActorRef
let forged = ActorRef::<MyUnifiedType, String>::new::<MyMsgType>(
  "my-very-cool-actor".to_string(),
  socket.clone()
);
forged.remote_send(&node, &msg) ;

You can send a message unreliably using Node.udp_select. How messages are dropped or delayed depends on a FailureMode and a FailureConfigMap.

// Doesn’t have to be a const
const MODE: FailureMode = FailureMode :: Message ;
let mut fail_map = FailureConfigMap::default();
// Make some changes to fail_map...
let msg: String = "My name is Baloo".to_string();
let ser = UdpSerial::new(&dest, &msg);
node.udp_select(&socket , &ser, MODE, &fail_map) ;

Logging

Define a LogLevel for you environment, and call one of these log macros. They all have the same arguments.

The logger is accessible from the node, but there is nothing stopping you from spawning your own logger, it’s just an actor. The log messages can be anything that implements Display. The argument is turned into a trait object in the macro body.

use aurum_actors::{trace, warn};
use aurum_actors::testkit::LogLevel;
 
// Doesn’t have to be a const
const LEVEL: LogLevel = LogLevel::Debug ;
// Not logged, the level is Debug, which is above Trace
trace!(LEVEL, &node, "kelp") ;
// This is logged, Warn is above Debug
warn!(LEVEL, &node, "sharks") ;

Structs

Contains contextual information needed by implementors of Actor to process messages.

An identifier for actors unique in the registry of a Node.

A location-transparent local actor reference.

The local part of an actor’s messaging address.

An exclusively local actor reference.

Spawns actors and manages system-wide information.

Holds configuration options for Node.

The remote address of a Node, reachable by remoting.

A fully serialized message, to be sent over UDP.

Enums

Messages that can be sent to any actor, regardless of its receiving type.

The DNS name or IP address of the machine hosting a Node.

Constants

Traits

Defines how actors process messages.

Signifies that type S belongs to a UnifiedType.

Denotes message types that Actor receives.

Enumerates all possible message types within an application.