lb_rs/model/
server_ops.rs1use super::errors::{DiffError, LbErrKind, LbResult};
2use super::meta::Meta;
3use super::server_meta::{IntoServerMeta, ServerMeta};
4use super::signed_meta::SignedMeta;
5use crate::model::clock::get_time;
6use crate::model::file_like::FileLike;
7use crate::model::file_metadata::FileDiff;
8use crate::model::lazy::{LazyStaged1, LazyTree};
9use crate::model::server_tree::ServerTree;
10use crate::model::signed_file::SignedFile;
11use crate::model::tree_like::TreeLike;
12
13type LazyServerStaged1<'a> = LazyStaged1<ServerTree<'a>, Vec<ServerMeta>>;
14
15impl<'a> LazyTree<ServerTree<'a>> {
16 pub fn stage_diff(self, changes: Vec<FileDiff<SignedFile>>) -> LbResult<LazyServerStaged1<'a>> {
19 let mut changes_meta: Vec<FileDiff<SignedMeta>> = vec![];
20 for change in changes {
21 let mut new_meta: SignedMeta = change.new.into();
22 let mut old_meta = change.old.map(SignedMeta::from);
23 if let Some(old) = &mut old_meta {
24 let current_size = *self
25 .maybe_find(old.id())
26 .ok_or(LbErrKind::Diff(DiffError::OldFileNotFound))?
27 .file
28 .timestamped_value
29 .value
30 .doc_size();
31
32 match &mut old.timestamped_value.value {
33 Meta::V1 { doc_size, .. } => {
34 *doc_size = current_size;
35 }
36 };
37
38 match &mut new_meta.timestamped_value.value {
39 Meta::V1 { doc_size, .. } => {
40 *doc_size = current_size;
41 }
42 };
43 }
44
45 changes_meta.push(FileDiff { old: old_meta, new: new_meta });
46 }
47
48 self.stage_diff_v2(changes_meta)
49 }
50
51 pub fn stage_diff_v2(
52 self, mut changes: Vec<FileDiff<SignedMeta>>,
53 ) -> LbResult<LazyServerStaged1<'a>> {
54 for change in &changes {
56 if let Some(old) = &change.old {
57 if old.id() != change.new.id() {
58 return Err(LbErrKind::Diff(DiffError::DiffMalformed))?;
59 }
60 }
61 }
62
63 for change in &changes {
65 match &change.old {
66 Some(old) => {
67 if old.timestamped_value.value.document_hmac()
68 != change.new.timestamped_value.value.document_hmac()
69 {
70 return Err(LbErrKind::Diff(DiffError::HmacModificationInvalid))?;
71 }
72
73 if old.timestamped_value.value.doc_size()
74 != change.new.timestamped_value.value.doc_size()
75 {
76 return Err(LbErrKind::Diff(DiffError::SizeModificationInvalid))?;
77 }
78 }
79 None => {
80 if change.new.timestamped_value.value.doc_size().is_some() {
81 return Err(LbErrKind::Diff(DiffError::SizeModificationInvalid))?;
82 }
83 if change.new.timestamped_value.value.document_hmac().is_some() {
84 return Err(LbErrKind::Diff(DiffError::HmacModificationInvalid))?;
85 }
86 }
87 }
88 }
89
90 for change in &mut changes {
92 match &change.old {
93 Some(old) => {
94 let current = &self
95 .maybe_find(old.id())
96 .ok_or(LbErrKind::Diff(DiffError::OldFileNotFound))?
97 .file;
98
99 if current != old {
100 return Err(LbErrKind::Diff(DiffError::OldVersionIncorrect))?;
101 }
102 }
103 None => {
104 if self.tree.files.maybe_find(change.new.id()).is_some() {
106 return Err(LbErrKind::Diff(DiffError::OldVersionRequired))?;
107 }
108 }
109 }
110 }
111
112 let now = get_time().0 as u64;
113 let changes = changes
114 .into_iter()
115 .map(|change| change.new.add_time(now))
116 .collect();
117
118 Ok(self.stage(changes))
119 }
120}