util.rs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. use crate::server_folder::FolderOperations;
  2. use crate::{
  3. entities::{
  4. document::DocumentPayloadPB,
  5. folder::FolderInfo,
  6. revision::{RepeatedRevision, Revision},
  7. },
  8. errors::{CollaborateError, CollaborateResult},
  9. };
  10. use dissimilar::Chunk;
  11. use lib_ot::core::{OTString, OperationAttributes, OperationBuilder};
  12. use lib_ot::{
  13. core::{DeltaOperations, OperationTransform, NEW_LINE, WHITESPACE},
  14. text_delta::TextOperations,
  15. };
  16. use serde::de::DeserializeOwned;
  17. use std::sync::atomic::{AtomicI64, Ordering::SeqCst};
  18. #[inline]
  19. pub fn find_newline(s: &str) -> Option<usize> {
  20. s.find(NEW_LINE)
  21. }
  22. #[inline]
  23. pub fn is_newline(s: &str) -> bool {
  24. s == NEW_LINE
  25. }
  26. #[inline]
  27. pub fn is_whitespace(s: &str) -> bool {
  28. s == WHITESPACE
  29. }
  30. #[inline]
  31. pub fn contain_newline(s: &str) -> bool {
  32. s.contains(NEW_LINE)
  33. }
  34. #[inline]
  35. pub fn md5<T: AsRef<[u8]>>(data: T) -> String {
  36. let md5 = format!("{:x}", md5::compute(data));
  37. md5
  38. }
  39. #[derive(Debug)]
  40. pub struct RevIdCounter(pub AtomicI64);
  41. impl RevIdCounter {
  42. pub fn new(n: i64) -> Self {
  43. Self(AtomicI64::new(n))
  44. }
  45. pub fn next(&self) -> i64 {
  46. let _ = self.0.fetch_add(1, SeqCst);
  47. self.value()
  48. }
  49. pub fn value(&self) -> i64 {
  50. self.0.load(SeqCst)
  51. }
  52. pub fn set(&self, n: i64) {
  53. let _ = self.0.fetch_update(SeqCst, SeqCst, |_| Some(n));
  54. }
  55. }
  56. #[tracing::instrument(level = "trace", skip(revisions), err)]
  57. pub fn make_operations_from_revisions<T>(revisions: Vec<Revision>) -> CollaborateResult<DeltaOperations<T>>
  58. where
  59. T: OperationAttributes + DeserializeOwned,
  60. {
  61. let mut new_operations = DeltaOperations::<T>::new();
  62. for revision in revisions {
  63. if revision.bytes.is_empty() {
  64. tracing::warn!("revision delta_data is empty");
  65. continue;
  66. }
  67. let operations = DeltaOperations::<T>::from_bytes(revision.bytes).map_err(|e| {
  68. let err_msg = format!("Deserialize remote revision failed: {:?}", e);
  69. CollaborateError::internal().context(err_msg)
  70. })?;
  71. new_operations = new_operations.compose(&operations)?;
  72. }
  73. Ok(new_operations)
  74. }
  75. pub fn pair_rev_id_from_revision_pbs(revisions: &[Revision]) -> (i64, i64) {
  76. let mut rev_id = 0;
  77. revisions.iter().for_each(|revision| {
  78. if rev_id < revision.rev_id {
  79. rev_id = revision.rev_id;
  80. }
  81. });
  82. if rev_id > 0 {
  83. (rev_id - 1, rev_id)
  84. } else {
  85. (0, rev_id)
  86. }
  87. }
  88. pub fn pair_rev_id_from_revisions(revisions: &[Revision]) -> (i64, i64) {
  89. let mut rev_id = 0;
  90. revisions.iter().for_each(|revision| {
  91. if rev_id < revision.rev_id {
  92. rev_id = revision.rev_id;
  93. }
  94. });
  95. if rev_id > 0 {
  96. (rev_id - 1, rev_id)
  97. } else {
  98. (0, rev_id)
  99. }
  100. }
  101. #[inline]
  102. pub fn make_folder_from_revisions_pb(
  103. folder_id: &str,
  104. revisions: RepeatedRevision,
  105. ) -> Result<Option<FolderInfo>, CollaborateError> {
  106. let revisions = revisions.into_inner();
  107. if revisions.is_empty() {
  108. return Ok(None);
  109. }
  110. let mut folder_delta = FolderOperations::new();
  111. let mut base_rev_id = 0;
  112. let mut rev_id = 0;
  113. for revision in revisions {
  114. base_rev_id = revision.base_rev_id;
  115. rev_id = revision.rev_id;
  116. if revision.bytes.is_empty() {
  117. tracing::warn!("revision delta_data is empty");
  118. }
  119. let delta = FolderOperations::from_bytes(revision.bytes)?;
  120. folder_delta = folder_delta.compose(&delta)?;
  121. }
  122. let text = folder_delta.json_str();
  123. Ok(Some(FolderInfo {
  124. folder_id: folder_id.to_string(),
  125. text,
  126. rev_id,
  127. base_rev_id,
  128. }))
  129. }
  130. #[inline]
  131. pub fn make_document_from_revision_pbs(
  132. doc_id: &str,
  133. revisions: RepeatedRevision,
  134. ) -> Result<Option<DocumentPayloadPB>, CollaborateError> {
  135. let revisions = revisions.into_inner();
  136. if revisions.is_empty() {
  137. return Ok(None);
  138. }
  139. let mut delta = TextOperations::new();
  140. let mut base_rev_id = 0;
  141. let mut rev_id = 0;
  142. for revision in revisions {
  143. base_rev_id = revision.base_rev_id;
  144. rev_id = revision.rev_id;
  145. if revision.bytes.is_empty() {
  146. tracing::warn!("revision delta_data is empty");
  147. }
  148. let new_delta = TextOperations::from_bytes(revision.bytes)?;
  149. delta = delta.compose(&new_delta)?;
  150. }
  151. let text = delta.json_str();
  152. Ok(Some(DocumentPayloadPB {
  153. doc_id: doc_id.to_owned(),
  154. content: text,
  155. rev_id,
  156. base_rev_id,
  157. }))
  158. }
  159. #[inline]
  160. pub fn rev_id_from_str(s: &str) -> Result<i64, CollaborateError> {
  161. let rev_id = s
  162. .to_owned()
  163. .parse::<i64>()
  164. .map_err(|e| CollaborateError::internal().context(format!("Parse rev_id from {} failed. {}", s, e)))?;
  165. Ok(rev_id)
  166. }
  167. pub fn cal_diff<T: OperationAttributes>(old: String, new: String) -> Option<DeltaOperations<T>> {
  168. let chunks = dissimilar::diff(&old, &new);
  169. let mut delta_builder = OperationBuilder::<T>::new();
  170. for chunk in &chunks {
  171. match chunk {
  172. Chunk::Equal(s) => {
  173. delta_builder = delta_builder.retain(OTString::from(*s).utf16_len());
  174. }
  175. Chunk::Delete(s) => {
  176. delta_builder = delta_builder.delete(OTString::from(*s).utf16_len());
  177. }
  178. Chunk::Insert(s) => {
  179. delta_builder = delta_builder.insert(*s);
  180. }
  181. }
  182. }
  183. let delta = delta_builder.build();
  184. if delta.is_empty() {
  185. None
  186. } else {
  187. Some(delta)
  188. }
  189. }