How can I use request or client conn object inside bindState ? (y-websocket)

I have integrated persistence with y-mongo and y-websocket. As suggested in the docs ::

utils.setPersistence({
  bindState: async (docName, ydoc) => {        
    const persistedYdoc = await ldb.getYDoc(docName);
    const newUpdates = Y.encodeStateAsUpdate(ydoc);
    ldb.storeUpdate(docName, newUpdates)
    Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(persistedYdoc));
    ydoc.on('update', async update => {
      ldb.storeUpdate(docName, update);
    })
  },
  writeState: async (docName, ydoc) => {
    return new Prosime(resolve => {
      resolve()
    })
  }
})

How can I access the request or client conn object inside bindState or writeState as i need to save user details along.

You can modify the source code. It might make sense for you to copy the source of the y-websocket server.

Thanks @dmonad

I am using Atlaskit Editor that uses prosemirror under the hood. I need to get the HTML to send the content in mail after all clients are disconnected.

I am trying to make use of Editor Json Transformer to convert the Prosemirror Node to JSON but I am not able to access the prosemirror node in writeState.

I have tried using yDocToProsemirror func from y-prosemirror but the content seems to be always empty.

any pointers ?

Resolved it.

I think yDocToProsemirror should also expect xmlFragment as it passes ydoc to yDocToProsemirrorJSON but not the xmlFragement. So, its only working when I provide the docName as ‘prosemirror’.

Should I raise a PR for the same ?

Right, that doesn’t seem consistent.

The reason why the author of that feature used Y.Doc as a baseline (instead of Y.XmlFragment) is that it seems more convenient than working with a Yjs type in this case. But I agree with you that it should have been Y.XmlFragment instead.

Maybe you could open a PR that also allows to create a Y.XmlFragment. I.e. implement yXmlFragmentToProsemirrorJSON and prosemirrorToYXmlFragment.

Alternatively, you implement a third parameter in yDocToProsemirror(schema, ydoc, typeName = 'prosemirror').

I resolved it with third parameter option. Will open a PR this weekend.

@dmonad If you think implementing two other functions for XmlFragment would be better, then I can proceed with that approach.

Thanks @aashish-choudhary!

I think it is important to add the third parameter because I don’t want to remove the existing functions. Adding the functions for XmlFragment would be a welcoming addition as well.

Great @dmonad !

Will Raise a PR on the weekend for the same.

Hello. I believe I have a related query…

In your example…

bindState: async (docName, ydoc) => {        
    const persistedYdoc = await loadFormStore(docName); // If this throws what should happen
    const newUpdates = Y.encodeStateAsUpdate(ydoc);
    ldb.storeUpdate(docName, newUpdates)
    Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(persistedYdoc));
    ydoc.on('update', async update => {
      ldb.storeUpdate(docName, update);
    })
  },

In our app we are using a different data store, if the data store fails to load the document we throw. At the moment this fails silently and this is not ideal. The WS connection remains open but document edits are not stored.

In this scenario should we disconnect all clients connected to that docName…?

For now we have resorted to terminating client connections if bindState fails. (This is defensive coding - for the most part this error path should not happen.)

function terminateClients(wss: WS.Server, docName: string) {
    const clientsOnDoc = [...wss.clients].filter((ws: YjsWebSocket) => ws.docName === docName);
    clientsOnDoc.forEach((client) => {
       client.terminate();
    });
}


bindState: async (docName, ydoc) => {        
   try {
       const persistedYdoc = await loadFromStore(docName); // If this throws what should happen
       const newUpdates = Y.encodeStateAsUpdate(ydoc);
       ldb.storeUpdate(docName, newUpdates)
       Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(persistedYdoc));
       ydoc.on('update', async update => {
          ldb.storeUpdate(docName, update);
       })
   } catch (err) {
       // force reconnect
       terminateClients(wss, docName);
   }
},
1 Like