Skip to main content

RustSyncManager

Struct RustSyncManager 

Source
pub struct RustSyncManager<FS: AsyncFileSystem> { /* private fields */ }
Expand description

Unified sync manager for workspace and body synchronization.

This struct replaces all TypeScript sync bridges with a single unified Rust implementation. It handles:

  • Workspace metadata sync via Y-sync protocol
  • Per-file body sync via Y-sync protocol
  • Sync completion tracking
  • Echo detection to avoid processing our own updates
  • File locking to prevent concurrent modifications

Implementations§

Source§

impl<FS: AsyncFileSystem> RustSyncManager<FS>

Source

pub fn new( workspace_crdt: Arc<WorkspaceCrdt>, body_manager: Arc<BodyDocManager>, sync_handler: Arc<SyncHandler<FS>>, ) -> Self

Create a new sync manager.

Source

pub fn set_event_callback( &self, callback: Arc<dyn Fn(&FileSystemEvent) + Send + Sync>, )

Set the event callback for emitting filesystem events.

This callback is used to emit SendSyncMessage events to TypeScript, which then sends the bytes over WebSocket to the sync server.

Important: This also sets up the body sync observer callback on the body_manager, so that local body changes automatically emit sync messages via the Yrs observer pattern.

Source

pub fn clear_event_callback(&self)

Clear the event callback.

Call this when stopping sync to prevent sending to a disconnected channel.

Source

pub fn emit_workspace_update(&self) -> Result<()>

Create and emit a workspace sync message.

Call this after updating the workspace CRDT to send the changes to the sync server via TypeScript WebSocket.

Source

pub fn emit_body_update(&self, doc_name: &str, content: &str) -> Result<()>

Create and emit a body sync message.

Call this after updating a body CRDT to send the changes to the sync server via TypeScript WebSocket.

IMPORTANT: This assumes the body CRDT has already been updated via set_body(). It only encodes the current state - it does NOT call set_body() again.

The doc_name is the canonical file path (e.g., “workspace/notes.md”). The content is used only for echo detection tracking.

This method uses delta encoding: it tracks the last-sent state vector and only sends changes since then, not the full document state.

Source

pub async fn handle_workspace_message( &self, message: &[u8], write_to_disk: bool, ) -> Result<SyncMessageResult>

Handle an incoming WebSocket message for workspace sync.

Returns a SyncMessageResult containing:

  • Optional response bytes to send back
  • List of changed file paths
  • Whether sync is now complete

If write_to_disk is true, changed files will be written to disk via the SyncHandler.

Source

pub fn create_workspace_sync_step1(&self) -> Vec<u8>

Create a SyncStep1 message for workspace sync.

Source

pub fn create_workspace_update( &self, since_state_vector: Option<&[u8]>, ) -> Result<Vec<u8>>

Create an update message for local workspace changes.

If since_state_vector is provided, returns only updates since that state. Otherwise returns the full state.

Source

pub fn is_workspace_synced(&self) -> bool

Check if workspace sync is complete.

Source

pub fn init_body_sync(&self, doc_name: &str)

Initialize body sync for a document.

Ensures the body document exists and is ready for sync.

Source

pub fn close_body_sync(&self, doc_name: &str)

Close body sync for a document.

Source

pub fn unload_body_doc(&self, doc_name: &str)

Unload a body doc from memory to free RAM.

Saves the doc to storage first, then evicts it from the in-memory cache. Clears tracking state (last_known_content, last_sent_body_sv, last_synced_body_svs) but does NOT clear body_synced — the doc was synced, just evicted.

The doc will be reloaded from storage on next access (get_or_create).

Source

pub async fn handle_body_message( &self, doc_name: &str, message: &[u8], write_to_disk: bool, ) -> Result<BodySyncResult>

Handle an incoming WebSocket message for body sync.

Returns a BodySyncResult containing:

  • Optional response bytes to send back
  • New content if it changed
  • Whether this is an echo of our own update
Source

pub fn create_body_sync_step1(&self, doc_name: &str) -> Vec<u8>

Create a SyncStep1 message for body sync.

Source

pub async fn ensure_body_content_loaded(&self, doc_name: &str) -> Result<bool>

Ensure body content is populated from disk before sync.

This method reads the file content from disk and sets it into the body CRDT. It should be called before create_body_sync_step1() to ensure the body CRDT has content to sync (rather than sending an empty state vector).

Returns true if content was loaded, false if the body doc already had content or the file doesn’t exist.

Source

pub fn create_body_update( &self, doc_name: &str, content: &str, ) -> Result<Vec<u8>>

Create an update message for local body changes.

Source

pub fn is_body_synced(&self, doc_name: &str) -> bool

Check if body sync is complete for a document.

Source

pub fn clear_body_synced(&self, doc_name: &str)

Clear the body_synced flag for a document so it can be re-subscribed.

Source

pub fn is_body_loaded(&self, doc_name: &str) -> bool

Check if a body document is currently loaded in memory.

Source

pub async fn file_exists_for_sync(&self, canonical_path: &str) -> bool

Check whether a canonical path currently exists in the backing filesystem.

Source

pub fn workspace_state_changed(&self) -> bool

Check if workspace state has changed since last successful sync.

Returns true if:

  • This is the first sync (no cached state)
  • The local state vector differs from the cached state after last SyncStep2

Used to skip sending SyncStep1 on reconnect when state hasn’t changed.

Source

pub fn body_state_changed(&self, doc_name: &str) -> bool

Check if body doc state has changed since last successful sync.

Returns true if:

  • This is the first sync for this doc (no cached state)
  • The doc is not loaded yet
  • The local state vector differs from the cached state after last SyncStep2

Used to skip sending SyncStep1 on reconnect when state hasn’t changed.

Source

pub fn is_echo(&self, path: &str, content: &str) -> bool

Check if content change is an echo of our own edit.

Source

pub fn track_content(&self, path: &str, content: &str)

Track content for echo detection.

Source

pub fn clear_tracked_content(&self, path: &str)

Clear tracked content (e.g., when closing a file).

Source

pub fn is_metadata_echo(&self, path: &str, metadata: &FileMetadata) -> bool

Check if metadata change is an echo of our own edit (ignoring modified_at).

Source

pub fn track_metadata(&self, path: &str, metadata: &FileMetadata)

Track metadata for echo detection.

Source

pub fn clear_tracked_metadata(&self, path: &str)

Clear tracked metadata (e.g., when closing a file).

Source

pub fn get_all_file_paths(&self) -> Vec<String>

Get all active file paths in the workspace CRDT.

Used by SyncClient to initiate body sync for all files after the body connection is established.

Source

pub fn mark_sync_complete(&self)

Mark initial sync as complete.

Source

pub fn is_sync_complete(&self) -> bool

Check if initial sync is complete.

Source

pub fn get_active_syncs(&self) -> Vec<String>

Get list of body docs that have completed initial sync.

Source

pub fn set_focused_files(&self, files: &[String])

Set the files this client is focused on.

This is used to track focus for reconnection - when the client reconnects, it should re-focus on these files.

Source

pub fn get_focused_files(&self) -> Vec<String>

Get the files this client is focused on.

Returns the list of files to re-focus on after reconnection.

Source

pub fn add_focused_files(&self, files: &[String])

Add files to the focus list.

Source

pub fn remove_focused_files(&self, files: &[String])

Remove files from the focus list.

Source

pub fn is_file_focused(&self, file: &str) -> bool

Check if a file is in the focus list.

Source

pub fn get_storage_path(&self, canonical_path: &str) -> PathBuf

Get the storage path for a canonical path.

Source

pub fn get_canonical_path(&self, storage_path: &str) -> String

Get the canonical path from a storage path.

Source

pub fn is_guest(&self) -> bool

Check if we’re in guest mode.

Source

pub async fn handle_crdt_state(&self, state: &[u8]) -> Result<usize>

Handle the CrdtState message from the server’s handshake protocol.

This is called after the client has downloaded all files (via HTTP or batch request) and sent the FilesReady message. The server then sends the full CRDT state which is applied to the workspace.

Important: This method is designed for new clients with empty workspaces. When the local workspace is empty, applying the server’s full state via apply_update works correctly without tombstoning issues. The handshake protocol ensures files are downloaded BEFORE this state is applied, so the CRDT state and filesystem are consistent.

§Arguments
  • state - The full CRDT state as bytes (Y-update v1 encoded)
§Returns

The number of files in the workspace after applying the state

Source

pub fn is_workspace_empty(&self) -> bool

Check if the workspace CRDT is empty (no files).

Used to determine if this is a “new client” that needs the handshake protocol to prevent CRDT corruption.

Source

pub fn rebuild_uuid_maps(&self)

Rebuild the bidirectional UUID ↔ path mapping from the workspace CRDT.

Should be called after any workspace CRDT mutation (handle_workspace_message, handle_crdt_state, or local metadata changes).

Source

pub fn resolve_path(&self, uuid: &str) -> Option<String>

Resolve a UUID to its current filesystem path.

Source

pub fn resolve_uuid(&self, path: &str) -> Option<String>

Resolve a filesystem path to its UUID in the workspace CRDT.

Source

pub fn get_all_file_uuids(&self) -> Vec<String>

Get all active file UUIDs in the workspace CRDT.

Source

pub fn reset(&self)

Reset all sync state.

Trait Implementations§

Source§

impl<FS: AsyncFileSystem> Debug for RustSyncManager<FS>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<FS> !Freeze for RustSyncManager<FS>

§

impl<FS> !RefUnwindSafe for RustSyncManager<FS>

§

impl<FS> Send for RustSyncManager<FS>

§

impl<FS> Sync for RustSyncManager<FS>

§

impl<FS> Unpin for RustSyncManager<FS>

§

impl<FS> UnsafeUnpin for RustSyncManager<FS>

§

impl<FS> !UnwindSafe for RustSyncManager<FS>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.