This commit is contained in:
Timothy Jaeryang Baek 2025-07-14 16:45:30 +04:00
parent d76a3d5ce2
commit fb71a4106f
2 changed files with 58 additions and 10 deletions

View file

@ -209,16 +209,20 @@ def get_user_id_from_session_pool(sid):
return None 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( active_session_ids = sio.manager.get_participants(
namespace="/", namespace="/",
room=room, 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( active_user_ids = list(
set( set([SESSION_POOL.get(session_id)["id"] for session_id in active_session_ids])
[SESSION_POOL.get(session_id[0])["id"] for session_id in active_session_ids]
)
) )
return active_user_ids return active_user_ids
@ -384,10 +388,10 @@ async def ydoc_document_join(sid, data):
# Join Socket.IO room # Join Socket.IO room
await sio.enter_room(sid, f"doc_{document_id}") 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() ydoc = Y.Doc()
if document_id in DOCUMENTS:
# If the document already exists, apply its updates
for update in DOCUMENTS[document_id]["updates"]: for update in DOCUMENTS[document_id]["updates"]:
ydoc.apply_update(bytes(update)) ydoc.apply_update(bytes(update))
@ -398,6 +402,7 @@ async def ydoc_document_join(sid, data):
{ {
"document_id": document_id, "document_id": document_id,
"state": list(state_update), # Convert bytes to list for JSON "state": list(state_update), # Convert bytes to list for JSON
"sessions": active_session_ids,
}, },
room=sid, 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)) 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") @sio.on("ydoc:document:update")
async def yjs_document_update(sid, data): async def yjs_document_update(sid, data):
"""Handle Yjs document updates""" """Handle Yjs document updates"""

View file

@ -218,7 +218,7 @@
// Empty state, check if we have content to initialize // Empty state, check if we have content to initialize
// check if editor empty as well // check if editor empty as well
const isEmptyEditor = !editor || editor.getText().trim() === ''; const isEmptyEditor = !editor || editor.getText().trim() === '';
if (content && isEmptyEditor) { if (content && isEmptyEditor && (data?.sessions ?? ['']).length === 1) {
const editorYdoc = prosemirrorJSONToYDoc(editor.schema, content); const editorYdoc = prosemirrorJSONToYDoc(editor.schema, content);
if (editorYdoc) { if (editorYdoc) {
Y.applyUpdate(this.doc, Y.encodeStateAsUpdate(editorYdoc)); Y.applyUpdate(this.doc, Y.encodeStateAsUpdate(editorYdoc));
@ -231,6 +231,11 @@
this.synced = true; this.synced = true;
} catch (error) { } catch (error) {
console.error('Error applying Yjs state:', error); console.error('Error applying Yjs state:', error);
this.synced = false;
this.socket.emit('ydoc:document:state', {
document_id: this.documentId
});
} }
} }
}); });