1use std::{future::Future, pin::Pin, sync::Arc};
22
23use async_trait::async_trait;
24use choir_oplog::{OpEntry, Witness, FORMAT_VERSION};
25use rivetkit::{action, Action, Actor, Ctx, Handles};
26use serde::{Deserialize, Serialize};
27
28type BoxFuture<T> = Pin<Box<dyn Future<Output = anyhow::Result<T>> + Send>>;
29
30#[derive(Debug, Default, Serialize, Deserialize)]
34pub struct LogState {
35 pub entries: Vec<OpEntry>,
37}
38
39#[derive(Debug, Serialize, Deserialize)]
42pub struct SubmitOp {
43 #[serde(rename = "workspace")]
46 pub channel: String,
47 pub payload: Vec<u8>,
49 pub author_sig: Option<Witness>,
51}
52
53#[derive(Debug, Serialize, Deserialize)]
55pub struct SubmitReply {
56 pub seq: u64,
58 pub hash_hex: String,
60}
61
62impl Action for SubmitOp {
63 type Output = SubmitReply;
64 const NAME: &'static str = "submit";
65}
66
67#[derive(Debug, Serialize, Deserialize)]
70pub struct DumpLog;
71
72impl Action for DumpLog {
73 type Output = Vec<OpEntry>;
74 const NAME: &'static str = "dump";
75}
76
77pub struct SequencerActor;
79
80#[async_trait]
81impl Actor for SequencerActor {
82 type State = LogState;
83 type Input = ();
84 type Actions = (SubmitOp, DumpLog);
85 type Events = ();
86 type Queue = ();
87 type ConnParams = ();
88 type ConnState = ();
89 type Action = action::Raw;
90
91 async fn create_state(_ctx: &Ctx<Self>, _input: Self::Input) -> anyhow::Result<Self::State> {
92 Ok(LogState::default())
93 }
94
95 async fn create(_ctx: &Ctx<Self>) -> anyhow::Result<Self> {
96 Ok(Self)
97 }
98}
99
100impl Handles<SubmitOp> for SequencerActor {
101 type Future = BoxFuture<SubmitReply>;
102
103 fn handle(self: Arc<Self>, ctx: Ctx<Self>, op: SubmitOp) -> Self::Future {
104 Box::pin(async move {
105 let mut state = ctx.state_mut();
106 let parent = state.entries.last().map(OpEntry::content_hash);
107 let seq = state.entries.len() as u64;
108 let entry = OpEntry {
109 format_version: FORMAT_VERSION,
110 parent,
111 seq,
112 channel: op.channel,
113 payload: op.payload,
114 witnesses: Vec::new(),
115 author_sig: op.author_sig,
116 };
117 let hash_hex = entry.content_hash().to_hex();
118 state.entries.push(entry);
119 Ok(SubmitReply { seq, hash_hex })
120 })
121 }
122}
123
124impl Handles<DumpLog> for SequencerActor {
125 type Future = BoxFuture<Vec<OpEntry>>;
126
127 fn handle(self: Arc<Self>, ctx: Ctx<Self>, _op: DumpLog) -> Self::Future {
128 Box::pin(async move { Ok(ctx.state().entries.clone()) })
129 }
130}
131
132pub fn register(registry: &mut rivetkit::Registry) {
134 registry.register_actor::<SequencerActor>("choirSequencer");
135}