1 个不稳定版本

0.9.0 2020年1月20日

#58 in #actor-framework


3 个crate中使用

MIT/Apache

225KB
5K SLoC

Actori 构建状态 构建状态 codecov 加入 https://gitter.im/actori/actori 的聊天

Actori 是一个 Rust Actor 框架。


功能

  • 异步/同步 Actor。
  • 本地/线程上下文中的 Actor 通信。
  • 使用 Futures 进行异步消息处理。
  • 支持 HTTP1/HTTP2(actori-web
  • Actor 监督。
  • 类型化消息(无 Any 类型)。

使用方法

要使用 actori,请将以下内容添加到您的 Cargo.toml

[dependencies]
actori = "0.9"

初始化 Actori

为了使用 actori,您首先需要创建一个 System

fn main() {
    let system = actori::System::new("test");

    system.run();
}

Actori 使用 tokio 事件循环。 System::new() 创建一个新的事件循环并启动 System Actor。 system.run() 启动 tokio 事件循环,并在 System Actor 收到 SystemExit 消息时结束。

让我们创建一个简单的 Actor。

实现 Actor

为了定义一个actor,你需要定义一个struct,并让它实现Actor特质。

use actori::{Actor, Addr, Arbiter, Context, System};

struct MyActor;

impl Actor for MyActor {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
       println!("I am alive!");
       System::current().stop(); // <- stop system
    }
}

fn main() {
    let system = System::new("test");

    let addr = MyActor.start();

    system.run();
}

通过Actor特质的startcreate方法可以创建一个新的actor。它提供了多种创建actor的方法,具体详情请查阅文档。你可以实现Actor特质的startedstoppingstopped方法。started在actor启动时被调用,而stopping在actor结束时被调用。有关actor生命周期的更多信息,请查看API文档

处理消息

Actor通过发送消息与其他Actor通信。在actori中,所有消息都是有类型的。让我们定义一个简单的带有两个usize参数的Sum消息,以及一个可以接收此消息并返回这两个数字之和的actor。

use futures::{future, Future};
use actori::*;

// this is our Message
struct Sum(usize, usize);

// we have to define the response type for `Sum` message
impl Message for Sum {
    type Result = usize;
}

// Actor definition
struct Summator;

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

// now we need to define `MessageHandler` for the `Sum` message.
impl Handler<Sum> for Summator {
    type Result = usize;   // <- Message response type

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

fn main() {
    let sys = System::new("test");

    let addr = Summator.start();
    let res = addr.send(Sum(10, 5));  // <- send message and get future for result

    Arbiter::spawn(res.then(|res| {
        match res {
            Ok(result) => println!("SUM: {}", result),
            _ => println!("Something wrong"),
        }

        System::current().stop();
        future::result(Ok(()))
    }));

    sys.run();
}

所有与actor的通信都通过一个Addr对象进行。你可以通过do_send发送一个消息而不等待响应,或者通过send发送一个带有特定消息的actor。《Message》特质定义了消息的结果类型。

Actor状态和特定消息的订阅

你可能已经注意到,ActorHandler特质的方法定义了接受&mut self,因此你可以在actor中存储任何内容,并在必要时对其进行修改。

地址对象需要一个actor类型,但如果我们只想向可以处理该消息的actor发送特定消息,我们可以使用Recipient接口。让我们创建一个新的actor,该actor使用Recipient

use std::time::Duration;
use actori::prelude::*;

#[derive(Message)]
struct Ping { pub id: usize }

// Actor definition
struct Game {
    counter: usize,
    addr: Recipient<Ping>,
}

impl Actor for Game {
    type Context = Context<Game>;
}

// simple message handler for Ping message
impl Handler<Ping> for Game {
    type Result = ();

    fn handle(&mut self, msg: Ping, ctx: &mut Context<Self>) {
        self.counter += 1;

        if self.counter > 10 {
            System::current().stop();
        } else {
            println!("Ping received {:?}", msg.id);

            // wait 100 nanos
            ctx.run_later(Duration::new(0, 100), move |act, _| {
                act.addr.do_send(Ping{id: msg.id + 1});
            });
        }
    }
}

fn main() {
    let system = System::new("test");

    // To get a Recipient object, we need to use a different builder method
    // which will allow postponing actor creation
    let addr = Game::create(|ctx| {
        // now we can get an address of the first actor and create the second actor
        let addr = ctx.address();
        let addr2 = Game{counter: 0, addr: addr.recipient()}.start();

        // let's start pings
        addr2.do_send(Ping{id: 10});

        // now we can finally create first actor
        Game{counter: 0, addr: addr2.recipient()}
    });

    system.run();
}

聊天示例

有一个聊天示例,它提供了一个基本的网络客户端/服务器服务示例。

fectl

你可以考虑查看fectl实用程序。它是用actori编写的,展示了如何创建具有相对复杂交互的网络应用程序。

贡献

欢迎所有贡献,如果你有功能请求,请毫不犹豫地打开一个问题!

许可协议

本项目根据你的选择,许可协议为以下之一:

任选其一。

行为准则

对actori crate的贡献是在贡献者协约的条款下组织的,actori的维护者@fafhrd91承诺将介入维护该行为准则。

依赖项

~6–11MB
~197K SLoC