use std::time::{SystemTime, UNIX_EPOCH};
use mf_model::mark::Mark;
use mf_model::tree::Tree;
use mf_state::Transaction;
use yrs_warp::AwarenessRef;
use serde_json::Value as JsonValue;
use yrs::{Map, ReadTxn as _, Transact};
use yrs::{
types::{array::ArrayRef, map::MapRef, Value},
Array, ArrayPrelim, MapPrelim, TransactionMut, WriteTxn,
};
use crate::{mapping::Mapper, ClientResult};
pub fn get_unix_time() -> u64 {
SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_millis()
as u64
}
pub async fn init_tree(
awareness_ref:AwarenessRef,
tree: &Tree,
) -> ClientResult<()> {
let mut awareness = awareness_ref.write().await;
let doc = awareness.doc_mut();
let mut txn = doc.transact_mut_with(doc.client_id().clone());
let nodes_map = txn.get_or_insert_map("nodes");
nodes_map.clear(&mut txn);
sync_tree_to_yrs(tree, &mut txn)?;
txn.commit();
tracing::info!(
"成功初始化树,包含 {} 个节点",tree.nodes.len()
);
Ok(())
}
pub fn sync_tree_to_yrs(
tree: &Tree,
txn: &mut yrs::TransactionMut,
) -> ClientResult<()> {
use mf_transform::{step::Step, node_step::AddNodeStep};
let registry = Mapper::global_registry();
if let Some(root_tree) = tree.all_children(&tree.root_id, None) {
let add_step = AddNodeStep {
parent_id: tree.root_id.clone(),
nodes: vec![root_tree],
};
if let Some(converter) =
registry.find_converter(&add_step as &dyn Step)
{
if let Err(e) =
converter.apply_to_yrs_txn(&add_step as &dyn Step, txn)
{
tracing::error!("🔄 同步树节点到 Yrs 失败: {}", e);
return Err(anyhow::anyhow!(
format!("Failed to sync tree: {}", e),
));
}
} else {
tracing::error!(
"🔄 同步树节点到 Yrs 失败: 没有找到 AddNodeStep 的转换器"
);
return Err(anyhow::anyhow!("No converter found for AddNodeStep"));
}
}
Ok(())
}
pub async fn apply_transactions_to_yrs(
awareness_ref:AwarenessRef,
transactions: &[Transaction],
) -> ClientResult<()> {
let mut awareness = awareness_ref.write().await;
let doc = awareness.doc_mut();
let mut txn = doc.transact_mut_with(doc.client_id().clone());
let registry = Mapper::global_registry();
for tr in transactions {
let steps = &tr.steps;
for step in steps {
if let Some(converter) =
registry.find_converter(step.as_ref())
{
if let Err(e) =
converter.apply_to_yrs_txn(step.as_ref(), &mut txn)
{
tracing::error!(
"🔄 应用步骤到 Yrs 事务失败: {}",
e
);
}
} else {
let type_name =
std::any::type_name_of_val(step.as_ref());
tracing::warn!(
"🔄 应用步骤到 Yrs 事务失败: 没有找到步骤的转换器: {}",
type_name
);
}
}
}
txn.commit();
tracing::debug!(
"🔄 应用 {} 个事务到文档: {}",
transactions.len(),
doc.client_id()
);
Ok(())
}
pub fn json_value_to_yrs_any(value: &JsonValue) -> yrs::Any {
match value {
JsonValue::Null => yrs::Any::Null,
JsonValue::Bool(b) => yrs::Any::Bool(*b),
JsonValue::Number(n) => {
if let Some(i) = n.as_i64() {
yrs::Any::BigInt(i)
} else if let Some(f) = n.as_f64() {
yrs::Any::Number(f)
} else {
yrs::Any::Null
}
},
JsonValue::String(s) => yrs::Any::String(s.clone().into()),
JsonValue::Array(arr) => {
let yrs_array: Vec<yrs::Any> =
arr.iter().map(json_value_to_yrs_any).collect();
yrs::Any::Array(yrs_array.into())
},
JsonValue::Object(obj) => {
let yrs_map: std::collections::HashMap<String, yrs::Any> = obj
.iter()
.map(|(k, v)| (k.clone(), json_value_to_yrs_any(v)))
.collect();
yrs::Any::Map(yrs_map.into())
},
}
}
pub fn add_mark_to_array(
marks_array: &ArrayRef,
txn: &mut TransactionMut,
mark: &Mark,
) {
let mark_map = MapPrelim::<yrs::Any>::from([
("type".to_string(), yrs::Any::String(mark.r#type.clone().into())),
("attrs".to_string(), {
let attrs_map: std::collections::HashMap<String, yrs::Any> = mark
.attrs
.iter()
.map(|(k, v)| (k.clone(), json_value_to_yrs_any(v)))
.collect();
yrs::Any::Map(attrs_map.into())
}),
]);
marks_array.push_back(txn, mark_map);
}
pub fn get_or_create_node_data_map(
nodes_map: &MapRef,
txn: &mut TransactionMut,
node_id: &str,
) -> MapRef {
if let Some(Value::YMap(map)) = nodes_map.get(txn, node_id) {
map
} else {
nodes_map.insert(txn, node_id.to_string(), MapPrelim::<yrs::Any>::new())
}
}
pub fn get_or_create_node_attrs_map(
node_data_map: &MapRef,
txn: &mut TransactionMut,
) -> MapRef {
if let Some(Value::YMap(map)) = node_data_map.get(txn, "attrs") {
map
} else {
node_data_map.insert(txn, "attrs", MapPrelim::<yrs::Any>::new())
}
}
pub fn get_or_create_marks_array(
node_data_map: &MapRef,
txn: &mut TransactionMut,
) -> ArrayRef {
if let Some(Value::YArray(array)) = node_data_map.get(txn, "marks") {
array
} else {
node_data_map.insert(
txn,
"marks",
ArrayPrelim::from(Vec::<yrs::Any>::new()),
)
}
}