aboutsummaryrefslogtreecommitdiffstats
path: root/src/document/changes.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-07 22:35:21 +0100
committertv <tv@krebsco.de>2026-11-07 22:35:21 +0100
commit389b11b597b6bf60f120b190002bbb76fff28dbf (patch)
tree94a9c9aac6aac510218bb454bc90bdd3a6dc920c /src/document/changes.rs
parent1a5b5ea02909e6c176ebd85d395e47fe15fcdba0 (diff)
access: screening received changes
access::screen: a batch of received changes judged change by change, those that change what rules read applied before the next is judged; a refused change stays out with whatever builds on it, kept aside for operators; changes missing dependencies wait. Auth plan M6.
Diffstat (limited to 'src/document/changes.rs')
-rw-r--r--src/document/changes.rs27
1 files changed, 27 insertions, 0 deletions
diff --git a/src/document/changes.rs b/src/document/changes.rs
index 57e2bf7..eef7dbc 100644
--- a/src/document/changes.rs
+++ b/src/document/changes.rs
@@ -240,6 +240,33 @@ pub(crate) fn misplaced_author(mut data: &[u8]) -> Option<MisplacedAuthor> {
None
}
+/// The changes in `data`, chunks as sync messages and downloads carry them: changes,
+/// compressed or not, bundles, documents. None if a chunk doesn't load.
+pub(crate) fn changes_in(mut data: &[u8]) -> Option<Vec<Change>> {
+ const MAGIC: [u8; 4] = [0x85, 0x6f, 0x4a, 0x83];
+ const HEADER: usize = 9;
+ let mut changes = Vec::new();
+ while !data.is_empty() {
+ if data.len() <= HEADER || data[..4] != MAGIC {
+ return None;
+ }
+ let kind = data[8];
+ let (length, read) = uleb128(&data[HEADER..])?;
+ let end = HEADER
+ .checked_add(read)?
+ .checked_add(usize::try_from(length).ok()?)?;
+ let chunk = data.get(..end)?;
+ data = &data[end..];
+ match kind {
+ 1 | 2 => changes.push(Change::try_from(chunk).ok()?),
+ 3 => changes.extend(automerge::Bundle::try_from(chunk).ok()?.to_changes().ok()?),
+ 0 => changes.extend(Document::load(chunk).ok()?.get_changes(&[])),
+ _ => return None,
+ }
+ }
+ Some(changes)
+}
+
/// `change`, if it names an author but isn't its actor's first (`misplaced_author`).
fn misplaced_in(change: &Change) -> Option<MisplacedAuthor> {
let author = change.author()?;