Open mortenson opened 8 months ago
Totally other way of approaching this, which I think is better, is to use a default value for the Y.Doc but clear it before the websocket fetches data from the hocuspocus server, ex:
const pdoc = defaultMarkdownParser.parse(textarea.value);
const ydocument = prosemirrorToYDoc(pdoc);
const yXmlFragment = ydocument.get('prosemirror', Y.XmlFragment) as Y.XmlFragment;
provider = new HocuspocusProvider({
...
document: ydocument,
onConnect: () => {
yXmlFragment.delete(0, yXmlFragment.length);
},
});
But note that this example doesn't actually work because the yXmlFragment.delete
is broadcast as a state change.
Here's my OK solution for now, basically only allow the initial connection to succeed once and fallback to non-yjs editing in that initial failure case:
// Initial value based on "last saved draft", should probably initialize to current draft if one exists.
const pdoc = defaultMarkdownParser.parse(textarea.value);
let editable = false;
const webSocketProvider = new HocuspocusProviderWebsocket({
// Only try connecting once initially as to not delay editing.
maxAttempts: 1,
onConnect: () => {
editable = true;
// Once connected we're working with a semi-recent draft, no reason to fallback again.
webSocketProvider.configuration.maxAttempts = 0;
},
});
const provider = new HocuspocusProvider({
websocketProvider: webSocketProvider,
});
[...]
const view = new EditorView(editorDiv, {
state: EditorState.create({
doc: pdoc || undefined,
plugins: [<insert yjs plugins here>],
}),
editable: () => editable,
});
[...]
provider.connect().catch((e) => {
console.error(e);
editable = true;
// Replace prosemirror view state with default value and fallback to non-yjs plugins.
view.updateState(EditorState.create({
schema: view.state.schema,
doc: pdoc,
plugins: [<insert non-yjs plugins here>],
}));
});
Hey @mortenson I think there is an easier way to do this, you can just use y-indexeddb provider that keeps the document in memory. When HocusPocus provider connects, the changes will be synchronized.
In your approach there might be a problem with synchronizing content after successful connect. Your local yjs document will be different from the document on the server (even though the content is the same) and it won't be able to synchronize.
The problem I am facing I'm trying to make my implementation of the
HocuspocusProvider
more resilient to websocket issues (ex: downtime in hocuspocus server, auth issues, network connectivity) and am not sure how to handle failure states gracefully.The solution I would like It would be nice if I could catch all failure states related to the initialization of the connection - specifically the opening of the websocket and the authentication steps. If anything fails, I'd like to fallback to a default value for prosemirror (or a default Y Doc, more generically) so that the user could at least edit content instead of looking at a blank textfield. Additionally, when a failure state is captured that indicates that reconnection is unlikely, it'd be nice to tell the provider to stop trying to reconnect.
I don't really need to handle cases where the connection drops while editing, since the user already has text they're working with. This is more about the initialization of the Y doc.
Alternatives I have considered Feel like I've tried just about everything to detect the initial websocket connection failing due to connectivity issues, and nothing is working. Specifically
provider.connect().catch()
is not called, and you can't try/catch websocket connection failures.onAuthenticationFailed
seems doable but if I implement that I still don't know how to tell the provider to stop trying to reconnect.Additional context I'm using y-prosemirror.