229 lines
5.8 KiB
Rust
Raw Normal View History

2022-01-02 22:23:33 +08:00
use crate::{
2022-01-21 21:41:24 +08:00
entities::{
folder::{FolderDelta, FolderInfo},
2022-01-21 21:41:24 +08:00
revision::{RepeatedRevision, Revision},
2022-07-19 11:31:04 +08:00
text_block::DocumentPB,
2022-01-21 21:41:24 +08:00
},
2022-01-02 22:23:33 +08:00
errors::{CollaborateError, CollaborateResult},
};
2022-03-04 18:11:12 +08:00
use dissimilar::Chunk;
2022-08-01 11:32:25 +08:00
use lib_ot::core::{DeltaBuilder, OTString};
2022-01-02 22:23:33 +08:00
use lib_ot::{
2022-08-01 09:31:40 +08:00
core::{Attributes, Delta, OperationTransform, NEW_LINE, WHITESPACE},
2022-01-02 22:23:33 +08:00
rich_text::RichTextDelta,
};
2022-01-20 23:51:11 +08:00
use serde::de::DeserializeOwned;
2022-07-19 13:07:30 +08:00
use std::sync::atomic::{AtomicI64, Ordering::SeqCst};
#[inline]
2022-01-23 12:14:00 +08:00
pub fn find_newline(s: &str) -> Option<usize> {
s.find(NEW_LINE)
}
#[inline]
2022-01-23 12:14:00 +08:00
pub fn is_newline(s: &str) -> bool {
s == NEW_LINE
}
#[inline]
2022-01-23 12:14:00 +08:00
pub fn is_whitespace(s: &str) -> bool {
s == WHITESPACE
}
#[inline]
2022-01-23 12:14:00 +08:00
pub fn contain_newline(s: &str) -> bool {
s.contains(NEW_LINE)
}
#[inline]
pub fn md5<T: AsRef<[u8]>>(data: T) -> String {
let md5 = format!("{:x}", md5::compute(data));
md5
}
#[derive(Debug)]
2021-11-13 11:11:24 +08:00
pub struct RevIdCounter(pub AtomicI64);
impl RevIdCounter {
2022-01-23 12:14:00 +08:00
pub fn new(n: i64) -> Self {
Self(AtomicI64::new(n))
}
pub fn next(&self) -> i64 {
let _ = self.0.fetch_add(1, SeqCst);
self.value()
}
2022-01-23 12:14:00 +08:00
pub fn value(&self) -> i64 {
self.0.load(SeqCst)
}
2022-01-23 12:14:00 +08:00
pub fn set(&self, n: i64) {
let _ = self.0.fetch_update(SeqCst, SeqCst, |_| Some(n));
}
}
2022-01-02 22:23:33 +08:00
2022-03-01 23:38:26 +08:00
#[tracing::instrument(level = "trace", skip(revisions), err)]
2022-01-20 23:51:11 +08:00
pub fn make_delta_from_revisions<T>(revisions: Vec<Revision>) -> CollaborateResult<Delta<T>>
where
T: Attributes + DeserializeOwned,
{
let mut delta = Delta::<T>::new();
2022-01-02 22:23:33 +08:00
for revision in revisions {
2022-01-25 20:37:48 +08:00
if revision.delta_data.is_empty() {
tracing::warn!("revision delta_data is empty");
}
2022-01-20 23:51:11 +08:00
let revision_delta = Delta::<T>::from_bytes(revision.delta_data).map_err(|e| {
2022-01-02 22:23:33 +08:00
let err_msg = format!("Deserialize remote revision failed: {:?}", e);
CollaborateError::internal().context(err_msg)
})?;
delta = delta.compose(&revision_delta)?;
2022-01-02 22:23:33 +08:00
}
Ok(delta)
2022-01-02 22:23:33 +08:00
}
2022-01-03 12:20:06 +08:00
2022-07-19 13:07:30 +08:00
pub fn make_delta_from_revision_pb<T>(revisions: Vec<Revision>) -> CollaborateResult<Delta<T>>
2022-01-20 23:51:11 +08:00
where
T: Attributes + DeserializeOwned,
{
2022-01-15 11:20:28 +08:00
let mut new_delta = Delta::<T>::new();
2022-01-03 12:20:06 +08:00
for revision in revisions {
2022-01-15 11:20:28 +08:00
let delta = Delta::<T>::from_bytes(revision.delta_data).map_err(|e| {
2022-01-03 12:20:06 +08:00
let err_msg = format!("Deserialize remote revision failed: {:?}", e);
CollaborateError::internal().context(err_msg)
})?;
new_delta = new_delta.compose(&delta)?;
}
Ok(new_delta)
}
2022-07-19 13:07:30 +08:00
pub fn pair_rev_id_from_revision_pbs(revisions: &[Revision]) -> (i64, i64) {
2022-01-03 12:20:06 +08:00
let mut rev_id = 0;
revisions.iter().for_each(|revision| {
if rev_id < revision.rev_id {
rev_id = revision.rev_id;
}
});
if rev_id > 0 {
(rev_id - 1, rev_id)
} else {
(0, rev_id)
}
}
pub fn pair_rev_id_from_revisions(revisions: &[Revision]) -> (i64, i64) {
let mut rev_id = 0;
revisions.iter().for_each(|revision| {
if rev_id < revision.rev_id {
rev_id = revision.rev_id;
}
});
if rev_id > 0 {
(rev_id - 1, rev_id)
} else {
(0, rev_id)
}
}
2022-01-11 22:23:19 +08:00
#[inline]
2022-01-21 21:41:24 +08:00
pub fn make_folder_from_revisions_pb(
folder_id: &str,
2022-07-19 13:07:30 +08:00
revisions: RepeatedRevision,
2022-07-19 11:31:04 +08:00
) -> Result<Option<FolderInfo>, CollaborateError> {
2022-07-19 13:07:30 +08:00
let revisions = revisions.into_inner();
2022-01-21 21:41:24 +08:00
if revisions.is_empty() {
return Ok(None);
}
let mut folder_delta = FolderDelta::new();
let mut base_rev_id = 0;
let mut rev_id = 0;
for revision in revisions {
base_rev_id = revision.base_rev_id;
rev_id = revision.rev_id;
if revision.delta_data.is_empty() {
tracing::warn!("revision delta_data is empty");
}
let delta = FolderDelta::from_bytes(revision.delta_data)?;
folder_delta = folder_delta.compose(&delta)?;
}
2022-08-02 09:11:04 +08:00
let text = folder_delta.json_str();
2022-07-19 11:31:04 +08:00
Ok(Some(FolderInfo {
folder_id: folder_id.to_string(),
text,
rev_id,
base_rev_id,
}))
2022-01-21 21:41:24 +08:00
}
#[inline]
2022-07-19 11:31:04 +08:00
pub fn make_document_from_revision_pbs(
2022-01-11 22:23:19 +08:00
doc_id: &str,
2022-07-19 13:07:30 +08:00
revisions: RepeatedRevision,
2022-07-19 11:31:04 +08:00
) -> Result<Option<DocumentPB>, CollaborateError> {
2022-07-19 13:07:30 +08:00
let revisions = revisions.into_inner();
2022-01-11 22:23:19 +08:00
if revisions.is_empty() {
return Ok(None);
}
2022-07-19 11:31:04 +08:00
let mut delta = RichTextDelta::new();
2022-01-11 22:23:19 +08:00
let mut base_rev_id = 0;
let mut rev_id = 0;
for revision in revisions {
base_rev_id = revision.base_rev_id;
rev_id = revision.rev_id;
if revision.delta_data.is_empty() {
tracing::warn!("revision delta_data is empty");
}
2022-07-19 11:31:04 +08:00
let new_delta = RichTextDelta::from_bytes(revision.delta_data)?;
delta = delta.compose(&new_delta)?;
2022-01-11 22:23:19 +08:00
}
2022-08-02 09:11:04 +08:00
let text = delta.json_str();
2022-07-19 11:31:04 +08:00
Ok(Some(DocumentPB {
block_id: doc_id.to_owned(),
text,
rev_id,
base_rev_id,
}))
2022-01-11 22:23:19 +08:00
}
2022-01-21 21:41:24 +08:00
#[inline]
pub fn rev_id_from_str(s: &str) -> Result<i64, CollaborateError> {
let rev_id = s
.to_owned()
.parse::<i64>()
.map_err(|e| CollaborateError::internal().context(format!("Parse rev_id from {} failed. {}", s, e)))?;
Ok(rev_id)
}
2022-03-04 18:11:12 +08:00
pub fn cal_diff<T: Attributes>(old: String, new: String) -> Option<Delta<T>> {
let chunks = dissimilar::diff(&old, &new);
let mut delta_builder = DeltaBuilder::<T>::new();
for chunk in &chunks {
match chunk {
Chunk::Equal(s) => {
2022-08-01 11:32:25 +08:00
delta_builder = delta_builder.retain(OTString::from(*s).utf16_len());
2022-03-04 18:11:12 +08:00
}
Chunk::Delete(s) => {
2022-08-01 11:32:25 +08:00
delta_builder = delta_builder.delete(OTString::from(*s).utf16_len());
2022-03-04 18:11:12 +08:00
}
Chunk::Insert(s) => {
delta_builder = delta_builder.insert(*s);
}
}
}
let delta = delta_builder.build();
if delta.is_empty() {
None
} else {
Some(delta)
}
}