add import/export

This commit is contained in:
Orion Henry 2022-01-07 12:15:14 -05:00 committed by Orion Henry
parent d2a7cc5f75
commit 45ee5ddbd9
3 changed files with 58 additions and 60 deletions
automerge-wasm/src
automerge/src

View file

@ -72,12 +72,12 @@ impl SyncState {
#[wasm_bindgen(getter, js_name = lastSentHeads)]
pub fn last_sent_heads(&self) -> JsValue {
rust_to_js(self.0.last_sent_heads.as_ref()).unwrap()
rust_to_js(&self.0.last_sent_heads).unwrap()
}
#[wasm_bindgen(setter, js_name = lastSentHeads)]
pub fn set_last_sent_heads(&mut self, heads: JsValue) {
let heads: Option<Vec<ChangeHash>> = js_to_rust(&heads).unwrap();
let heads: Vec<ChangeHash> = js_to_rust(&heads).unwrap();
self.0.last_sent_heads = heads
}
@ -87,15 +87,6 @@ impl SyncState {
let hashes_set: HashSet<ChangeHash> = hashes_map.keys().cloned().collect();
self.0.sent_hashes = hashes_set
}
/*
fn decode(data: Uint8Array) -> Result<SyncState, JsValue> {
let data = data.to_vec();
let s = am::SyncState::decode(&data);
let s = s.map_err(to_js_err)?;
Ok(SyncState(s))
}
*/
}
#[derive(Debug)]
@ -454,14 +445,14 @@ impl Automerge {
#[wasm_bindgen(js_name = generateSyncMessage)]
pub fn generate_sync_message(&mut self, state: JsValue) -> Result<Array, JsValue> {
let mut state = JS(state).try_into()?;
let result = Array::new();
if let Some(message) = self.0.generate_sync_message(&mut state) {
result.push(&JS::from(state).0);
result.push(&Uint8Array::from(message.encode().map_err(to_js_err)?.as_slice()).into());
let message = if let Some(message) = self.0.generate_sync_message(&mut state) {
Uint8Array::from(message.encode().map_err(to_js_err)?.as_slice()).into()
} else {
result.push(&JS::from(state).0);
result.push(&JsValue::null());
}
JsValue::null()
};
let result = Array::new();
result.push(&JS::from(state).0);
result.push(&message);
Ok(result)
}
@ -635,6 +626,16 @@ pub fn init_sync_state() -> JsValue {
JS::from(am::SyncState::new()).0
}
#[wasm_bindgen(js_name = importSyncState)]
pub fn import_sync_state(state: JsValue) -> Result<SyncState,JsValue> {
Ok(SyncState(JS(state).try_into()?))
}
#[wasm_bindgen(js_name = exportSyncState)]
pub fn export_sync_state(state: SyncState) -> JsValue {
JS::from(state.0).into()
}
#[wasm_bindgen(js_name = encodeSyncMessage)]
pub fn encode_sync_message(message: JsValue) -> Result<Uint8Array, JsValue> {
let heads = get(&message, "heads")?.try_into()?;
@ -658,10 +659,10 @@ pub fn encode_sync_message(message: JsValue) -> Result<Uint8Array, JsValue> {
pub fn decode_sync_message(msg: Uint8Array) -> Result<JsValue, JsValue> {
let data = msg.to_vec();
let msg = am::SyncMessage::decode(&data).map_err(to_js_err)?;
let heads: Array = VH(&msg.heads).into();
let need: Array = VH(&msg.need).into();
let changes: Array = VC(&msg.changes).into();
let have: Array = VSH(&msg.have).into();
let heads = AR::from(msg.heads.as_slice());
let need = AR::from(msg.need.as_slice());
let changes = AR::from(msg.changes.as_slice());
let have = AR::from(msg.have.as_slice());
let obj = Object::new().into();
set(&obj, "heads", heads)?;
set(&obj, "need", need)?;
@ -703,8 +704,8 @@ fn to_js_err<T: Display>(err: T) -> JsValue {
js_sys::Error::new(&std::format!("{}", err)).into()
}
fn get(obj: &JsValue, prop: &str) -> Result<JS, JsValue> {
Ok(JS(Reflect::get(obj, &prop.into())?))
fn get<J: Into<JsValue>>(obj: J, prop: &str) -> Result<JS, JsValue> {
Ok(JS(Reflect::get(&obj.into(), &prop.into())?))
}
fn set<V: Into<JsValue>>(obj: &JsValue, prop: &str, val: V) -> Result<bool, JsValue> {
@ -712,6 +713,19 @@ fn set<V: Into<JsValue>>(obj: &JsValue, prop: &str, val: V) -> Result<bool, JsVa
}
struct JS(JsValue);
struct AR(Array);
impl From<AR> for JsValue {
fn from(ar: AR) -> Self {
ar.0.into()
}
}
impl From<JS> for JsValue {
fn from(js: JS) -> Self {
js.0
}
}
impl From<am::SyncState> for JS {
fn from(state: am::SyncState) -> Self {
@ -721,8 +735,7 @@ impl From<am::SyncState> for JS {
let their_need: JS = state.their_need.into();
let sent_hashes: JS = state.sent_hashes.into();
let their_have = if let Some(have) = &state.their_have {
let tmp: Array = VSH(have).into();
JsValue::from(&tmp)
JsValue::from(AR::from(have.as_slice()).0)
} else {
JsValue::null()
};
@ -828,7 +841,7 @@ impl TryFrom<JS> for am::SyncState {
fn try_from(value: JS) -> Result<Self, Self::Error> {
let value = value.0;
let shared_heads = get(&value, "sharedHeads")?.try_into()?;
let last_sent_heads = get(&value, "lastSentHeads")?.into();
let last_sent_heads = get(&value, "lastSentHeads")?.try_into()?;
let their_heads = get(&value, "theirHeads")?.into();
let their_need = get(&value, "theirNeed")?.into();
let their_have = get(&value, "theirHave")?.try_into()?;
@ -885,39 +898,28 @@ impl TryFrom<JS> for am::BloomFilter {
}
}
struct VH<'a>(&'a [ChangeHash]);
impl<'a> From<VH<'a>> for Array {
fn from(value: VH<'a>) -> Self {
let heads: Array = value
.0
impl From<&[ChangeHash]> for AR {
fn from(value: &[ChangeHash]) -> Self {
AR(value
.iter()
.map(|h| JsValue::from_str(&hex::encode(&h.0)))
.collect();
heads
.collect())
}
}
struct VC<'a>(&'a [Change]);
impl<'a> From<VC<'a>> for Array {
fn from(value: VC<'a>) -> Self {
impl From<&[Change]> for AR {
fn from(value: &[Change]) -> Self {
let changes: Array = value
.0
.iter()
.map(|c| Uint8Array::from(c.raw_bytes()))
.collect();
changes
AR(changes)
}
}
#[allow(clippy::upper_case_acronyms)]
struct VSH<'a>(&'a [am::SyncHave]);
impl<'a> From<VSH<'a>> for Array {
fn from(value: VSH<'a>) -> Self {
value
.0
impl From<&[am::SyncHave]> for AR {
fn from(value: &[am::SyncHave]) -> Self {
AR(value
.iter()
.map(|have| {
let last_sync: Array = have
@ -933,7 +935,7 @@ impl<'a> From<VSH<'a>> for Array {
Reflect::set(&obj, &"bloom".into(), &bloom.into()).unwrap();
obj
})
.collect()
.collect())
}
}

View file

@ -71,11 +71,7 @@ impl Automerge {
Vec::new()
};
let heads_unchanged = if let Some(last_sent_heads) = sync_state.last_sent_heads.as_ref() {
last_sent_heads == &our_heads
} else {
false
};
let heads_unchanged = sync_state.last_sent_heads == our_heads;
let heads_equal = if let Some(their_heads) = sync_state.their_heads.as_ref() {
their_heads == &our_heads
@ -90,7 +86,7 @@ impl Automerge {
// deduplicate the changes to send with those we have already sent
changes_to_send.retain(|change| !sync_state.sent_hashes.contains(&change.hash));
sync_state.last_sent_heads = Some(our_heads.clone());
sync_state.last_sent_heads = our_heads.clone();
sync_state
.sent_hashes
.extend(changes_to_send.iter().map(|c| c.hash));
@ -144,7 +140,7 @@ impl Automerge {
self.filter_changes(&message_heads, &mut sync_state.sent_hashes);
if changes_is_empty && message_heads == before_heads {
sync_state.last_sent_heads = Some(message_heads.clone());
sync_state.last_sent_heads = message_heads.clone();
}
let known_heads = message_heads
@ -155,7 +151,7 @@ impl Automerge {
sync_state.shared_heads = message_heads.clone();
// If the remote peer has lost all its data, reset our state to perform a full resync
if message_heads.is_empty() {
sync_state.last_sent_heads = Some(Default::default());
sync_state.last_sent_heads = Default::default();
sync_state.sent_hashes = Default::default();
}
} else {

View file

@ -8,7 +8,7 @@ const SYNC_STATE_TYPE: u8 = 0x43; // first byte of an encoded sync state, for id
#[derive(Debug, Clone)]
pub struct SyncState {
pub shared_heads: Vec<ChangeHash>,
pub last_sent_heads: Option<Vec<ChangeHash>>,
pub last_sent_heads: Vec<ChangeHash>,
pub their_heads: Option<Vec<ChangeHash>>,
pub their_need: Option<Vec<ChangeHash>>,
pub their_have: Option<Vec<SyncHave>>,
@ -46,7 +46,7 @@ impl SyncState {
let shared_heads = decode_hashes(&mut decoder)?;
Ok(Self {
shared_heads,
last_sent_heads: Some(Vec::new()),
last_sent_heads: Vec::new(),
their_heads: None,
their_need: None,
their_have: Some(Vec::new()),
@ -59,7 +59,7 @@ impl Default for SyncState {
fn default() -> Self {
Self {
shared_heads: Vec::new(),
last_sent_heads: Some(Vec::new()),
last_sent_heads: Vec::new(),
their_heads: None,
their_need: None,
their_have: None,