From 8e4dcdcf5858d22a9390771f24b57d6f050aef78 Mon Sep 17 00:00:00 2001 From: DarkSky Date: Thu, 12 Sep 2024 16:06:31 +0800 Subject: [PATCH] feat: make client id conflict behavior same as yjs --- y-octo-node/native/src/doc.rs | 9 +++++++++ y-octo-node/tests/doc.spec.ts | 4 +++- y-octo-node/tests/yjs/doc.spec.ts | 8 ++++---- y-octo/src/doc/document.rs | 4 ++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/y-octo-node/native/src/doc.rs b/y-octo-node/native/src/doc.rs index e283b80..8ee1748 100644 --- a/y-octo-node/native/src/doc.rs +++ b/y-octo-node/native/src/doc.rs @@ -114,8 +114,17 @@ impl YDoc { #[napi] pub fn apply_update(&mut self, update: JsBuffer) -> Result<()> { + let client = self.doc.client(); + let before_current_state = self.doc.get_state_vector().get(&client); + self.doc.apply_update_from_binary_v1(update)?; + // if update received from remote and current client state has been changed + // that means another client using same client id, we need to change the client id to avoid conflict + if self.doc.get_state_vector().get(&client) != before_current_state { + self.doc.renew_client(); + } + Ok(()) } diff --git a/y-octo-node/tests/doc.spec.ts b/y-octo-node/tests/doc.spec.ts index 10dbe0d..83e657c 100644 --- a/y-octo-node/tests/doc.spec.ts +++ b/y-octo-node/tests/doc.spec.ts @@ -44,7 +44,9 @@ test("y-octo doc update should be apply", (t) => { let map2 = doc2.getOrCreateMap("map"); let text2 = doc2.getOrCreateText("text"); - t.is(doc2.clientId, client_id); + // after apply update that include same client id's change + // the client id should be changed + t.not(doc2.clientId, client_id); t.is(array2.length, 4); t.is(array2.get(0), true); t.is(array2.get(1), false); diff --git a/y-octo-node/tests/yjs/doc.spec.ts b/y-octo-node/tests/yjs/doc.spec.ts index a656985..6f3f0f6 100644 --- a/y-octo-node/tests/yjs/doc.spec.ts +++ b/y-octo-node/tests/yjs/doc.spec.ts @@ -41,13 +41,13 @@ test.skip("testOriginInTransaction", (t) => { /** * Client id should be changed when an instance receives updates from another client using the same client id. */ -test.skip("testClientIdDuplicateChange", (t) => { +test("testClientIdDuplicateChange", (t) => { const doc1 = new Y.Doc(0); const doc2 = new Y.Doc(0); - t.assert(doc2.clientID === doc1.clientID); + t.assert(doc2.clientId === doc1.clientId); doc1.getArray("a").insert(0, [1, 2]); - Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc1)); - t.assert(doc2.clientID !== doc1.clientID); + Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc1), false); + t.assert(doc2.clientId !== doc1.clientId); }); test.skip("testGetTypeEmptyId", (t) => { diff --git a/y-octo/src/doc/document.rs b/y-octo/src/doc/document.rs index 7d8b060..f09b392 100644 --- a/y-octo/src/doc/document.rs +++ b/y-octo/src/doc/document.rs @@ -162,6 +162,10 @@ impl Doc { self.client_id = client_id; } + pub fn renew_client(&mut self) { + self.client_id = prefer_small_random(); + } + pub fn clients(&self) -> Vec { self.store.read().unwrap().clients() }