51 lines
1.7 KiB
Rust
51 lines
1.7 KiB
Rust
|
|
//! Write path: create, sign, apply, persist, and broadcast a CRDT op.
|
||
|
|
//!
|
||
|
|
//! [`apply_and_persist`] is the single entry point for all CRDT mutations.
|
||
|
|
//! It invokes the caller's op-factory closure, signs the resulting op, applies
|
||
|
|
//! it to the live document, sends it to the persistence channel, and broadcasts
|
||
|
|
//! it to sync peers via [`super::SYNC_TX`].
|
||
|
|
|
||
|
|
use bft_json_crdt::json_crdt::JsonValue;
|
||
|
|
use bft_json_crdt::op::Op;
|
||
|
|
|
||
|
|
use super::super::types::CrdtEvent;
|
||
|
|
use super::{CrdtState, statics};
|
||
|
|
|
||
|
|
/// Create a CRDT op via `op_fn`, sign it, apply it, and send it to the
|
||
|
|
/// persistence channel. The closure receives `&mut CrdtState` so it can
|
||
|
|
/// mutably access the CRDT document, while `sign` only needs `&keypair`.
|
||
|
|
pub(in crate::crdt_state) fn apply_and_persist<F>(state: &mut CrdtState, op_fn: F)
|
||
|
|
where
|
||
|
|
F: FnOnce(&mut CrdtState) -> Op<JsonValue>,
|
||
|
|
{
|
||
|
|
let raw_op = op_fn(state);
|
||
|
|
let signed = raw_op.sign(&state.keypair);
|
||
|
|
state.crdt.apply(signed.clone());
|
||
|
|
if state.persist_tx.send(signed.clone()).is_err() {
|
||
|
|
let op_type = if signed.inner.is_deleted {
|
||
|
|
"Delete"
|
||
|
|
} else {
|
||
|
|
"Insert"
|
||
|
|
};
|
||
|
|
let seq = signed.inner.seq;
|
||
|
|
crate::slog_warn!(
|
||
|
|
"[crdt_persist] persist channel send failed: op_type={op_type} seq={seq}"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Track in ALL_OPS + VECTOR_CLOCK, then broadcast to sync peers.
|
||
|
|
if let Ok(json) = serde_json::to_string(&signed) {
|
||
|
|
statics::track_op(&signed, json);
|
||
|
|
}
|
||
|
|
if let Some(tx) = statics::SYNC_TX.get() {
|
||
|
|
let _ = tx.send(signed);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Broadcast a CRDT event to all subscribers.
|
||
|
|
pub(in crate::crdt_state) fn emit_event(event: CrdtEvent) {
|
||
|
|
if let Some(tx) = statics::CRDT_EVENT_TX.get() {
|
||
|
|
let _ = tx.send(event);
|
||
|
|
}
|
||
|
|
}
|