Actor programming


Back to index

Actor programming is a model

Actor model

  • Split your program into small pieces (called an "Actor")
  • Each actor has its own state and can change it
  • Each actor can send and receive "Messages"

That's it. That's really all there is to it

actor0.png

actor1.png

actor2.png

actor3.png

Actors in Rust

Using an actor framework will reduce boilerplate in your code! Some frameworks exist already!

  • Actix (built on Tokio)
  • Ockam Node (Also built on Tokio, but differently)

Calculator in Actix

use actix::{Actor, Handler, Context, System};

struct Calculator;

impl Actor for Calculator {
    type Context = Context<Self>;
}

#[derive(Message)]
#[rtype(result = "usize")]
struct Sum(usize, usize);

impl Handler<Sum> for Calculator {
    type Result = usize;

    fn handle(&mut self, msg: Sum, ctx: &mut Context) -> Self::Result {
        msg.0 + msg.1
    }
}

#[actix::main]
async fn main() {
    let addr = Calculator.start();
    let res = addr.send(Sum(10, 5)).await;
    println!("Result: {:?}", res);
}

Calculator with Ockam

use ockam::{Context, Message, Worker, access_control::AllowAll, Routed};
use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize, Message)]
struct SumMessage(usize, usize);

struct SumWorker;
#[ockam::worker]
impl Worker for SumWorker {
    type Context = Context;
    type Message = SumMessage;

    async fn handle_message(&mut self, ctx: &mut Context, msg: Routed<SumMessage>) -> Result<()> {
        ctx.send(msg.return_route(), (msg.0 + msg.1) as u64).await
    }
}

#[ockam::node]
async fn main(mut ctx: Context) -> Result<()> {
    ctx.start_worker("sum", SumWorker, AllowAll, AllowAll).await?;
    ctx.send("sum", SumMessage(2, 4)).await?;

    // Wait to receive a reply and print it.
    let reply = ctx.receive::<u64>().await?;
    println!("Sum: {}", reply); // should print "6"

    // Shut down everything
    ctx.stop().await
}

calypso.png

Very much not done.

https://cyberchaos.dev/kookie/calypso

Back to index