1 个不稳定版本

0.3.0 2024 年 5 月 5 日

WebSocket 中排名 #275

MIT 许可证

90KB
1.5K SLoC

Aper

GitHub Repo stars crates.io docs.rs wokflow state

Cartoonized face of an ape.

Aper 是一个 Rust 库,用于使用 状态机 进行数据同步。Aper 提供了表示常见数据结构的机制,以及一个与传输无关的协议,用于在网络中保持多个状态机的同步。

使用案例包括在共享状态上运行的实时多人应用、希望增量且双向共享状态更新的客户端-服务器应用,以及多人回合制游戏。

什么是状态机?

在 Aper 的用途中,状态机就是一个实现 structenum 的结构,它实现了 StateMachine 并具有以下属性

  • 它定义了一个 StateMachine::Transition 类型,通过它可以描述状态的每一种可能变化。这通常是一个 enum 类型,但不是必需的。
  • 它定义了一个 StateMachine::Conflict 类型,用于描述在应用无效的转换时可能出现的冲突。对于不可能出现冲突的简单类型,您可以为此使用 NeverConflict
  • 所有状态更新都是确定性的:如果您克隆一个 StateMachine 和一个 Transition,将克隆的转换应用于克隆的状态的结果必须与将原始转换应用于原始状态的结果相同。

以下是一个实现计数的 StateMachine 的示例

use aper::{StateMachine, NeverConflict};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
struct Counter { value: i64 }

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
enum CounterTransition {
    Reset,
    Increment(i64),
    Decrement(i64),
}

impl StateMachine for Counter {
    type Transition = CounterTransition;
    type Conflict = NeverConflict;

    fn apply(&self, event: &CounterTransition) -> Result<Counter, NeverConflict> {
        match event {
            CounterTransition::Reset => Ok(Counter {value: 0}),
            CounterTransition::Increment(amount) => Ok(Counter {value: self.value + amount}),
            CounterTransition::Decrement(amount) => Ok(Counter {value: self.value - amount}),
        }
    }
}

为什么不使用 CRDT?

无冲突复制数据类型(Conflict-free replicated data types,CRDTs)是一种表示对等间共享数据的高效方式。为了避免需要中央“真理来源”,CRDTs 要求更新操作(即状态转换)必须是交换律的。这使得它们可以表示许多常见的数据结构,但不允许表示任意复杂的更新逻辑。通过依赖中央权威,状态机方法允许您实现具有任意更新逻辑的数据结构,例如在两个数据结构之间原子地移动值,或棋盘游戏的规则。


Aper 正在快速发展。请将此视为技术预览。查看1.0 版本待解决的问题列表

依赖项

~13–18MB
~326K SLoC