From fb71a4106f11d6ee3b10e431e2902ff2b2645b77 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 14 Jul 2025 16:45:30 +0400 Subject: [PATCH] refac --- backend/open_webui/socket/main.py | 61 ++++++++++++++++--- .../components/common/RichTextInput.svelte | 7 ++- 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/backend/open_webui/socket/main.py b/backend/open_webui/socket/main.py index 5b0eda2da9..1591cb48ca 100644 --- a/backend/open_webui/socket/main.py +++ b/backend/open_webui/socket/main.py @@ -209,16 +209,20 @@ def get_user_id_from_session_pool(sid): return None -def get_user_ids_from_room(room): +def get_session_ids_from_room(room): + """Get all session IDs from a specific room.""" active_session_ids = sio.manager.get_participants( namespace="/", room=room, ) + return [session_id[0] for session_id in active_session_ids] + + +def get_user_ids_from_room(room): + active_session_ids = get_session_ids_from_room(room) active_user_ids = list( - set( - [SESSION_POOL.get(session_id[0])["id"] for session_id in active_session_ids] - ) + set([SESSION_POOL.get(session_id)["id"] for session_id in active_session_ids]) ) return active_user_ids @@ -384,12 +388,12 @@ async def ydoc_document_join(sid, data): # Join Socket.IO room await sio.enter_room(sid, f"doc_{document_id}") - # Send current document state as a proper Yjs update + active_session_ids = get_session_ids_from_room(f"doc_{document_id}") + + # Get the Yjs document state ydoc = Y.Doc() - if document_id in DOCUMENTS: - # If the document already exists, apply its updates - for update in DOCUMENTS[document_id]["updates"]: - ydoc.apply_update(bytes(update)) + for update in DOCUMENTS[document_id]["updates"]: + ydoc.apply_update(bytes(update)) # Encode the entire document state as an update state_update = ydoc.get_update() @@ -398,6 +402,7 @@ async def ydoc_document_join(sid, data): { "document_id": document_id, "state": list(state_update), # Convert bytes to list for JSON + "sessions": active_session_ids, }, room=sid, ) @@ -443,6 +448,44 @@ async def document_save_handler(document_id, data, user): Notes.update_note_by_id(note_id, NoteUpdateForm(data=data)) +@sio.on("ydoc:document:state") +async def yjs_document_state(sid, data): + """Send the current state of the Yjs document to the user""" + try: + document_id = data["document_id"] + room = f"doc_{document_id}" + + active_session_ids = get_session_ids_from_room(room) + print(active_session_ids) + if sid not in active_session_ids: + log.warning(f"Session {sid} not in room {room}. Cannot send state.") + return + + if document_id not in DOCUMENTS: + log.warning(f"Document {document_id} not found") + return + + # Get the Yjs document state + ydoc = Y.Doc() + for update in DOCUMENTS[document_id]["updates"]: + ydoc.apply_update(bytes(update)) + + # Encode the entire document state as an update + state_update = ydoc.get_update() + + await sio.emit( + "ydoc:document:state", + { + "document_id": document_id, + "state": list(state_update), # Convert bytes to list for JSON + "sessions": active_session_ids, + }, + room=sid, + ) + except Exception as e: + log.error(f"Error in yjs_document_state: {e}") + + @sio.on("ydoc:document:update") async def yjs_document_update(sid, data): """Handle Yjs document updates""" diff --git a/src/lib/components/common/RichTextInput.svelte b/src/lib/components/common/RichTextInput.svelte index 41a2426acd..ba8b6737d3 100644 --- a/src/lib/components/common/RichTextInput.svelte +++ b/src/lib/components/common/RichTextInput.svelte @@ -218,7 +218,7 @@ // Empty state, check if we have content to initialize // check if editor empty as well const isEmptyEditor = !editor || editor.getText().trim() === ''; - if (content && isEmptyEditor) { + if (content && isEmptyEditor && (data?.sessions ?? ['']).length === 1) { const editorYdoc = prosemirrorJSONToYDoc(editor.schema, content); if (editorYdoc) { Y.applyUpdate(this.doc, Y.encodeStateAsUpdate(editorYdoc)); @@ -231,6 +231,11 @@ this.synced = true; } catch (error) { console.error('Error applying Yjs state:', error); + + this.synced = false; + this.socket.emit('ydoc:document:state', { + document_id: this.documentId + }); } } });