Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tiptap collaboration - need number of users or hint if document was already created #2550

Closed
2 tasks done
thet opened this issue Feb 18, 2022 · 2 comments
Closed
2 tasks done
Assignees
Labels
Type: Bug The issue or pullrequest is related to a bug

Comments

@thet
Copy link

thet commented Feb 18, 2022

What’s the bug you are facing?

We are integrating the tiptap collaboration feature using hocuspocus.
We thought it would be the most simple solution if we would just load the document on the client instead of fetching it from the hocuspocus backend.
This would have these advantages:

  • No need to communicate with the CMS backend on hocuspocus,
  • No need to authenticate on the CMS backend via hocuspocus,
  • No need to load any of the client extensions when creating the document.

When opening the document and loading the tiptap editor, the content should be loaded into tiptap on the client side only in one of these two cases:

  • The person which is opening the document/loading the editor is the first one opening it,
    or
  • The document was not yet created on the hocuspocus server.

In these cases I would initialize the tiptap editor with the content from a textarea.
In other cases (second person opening the document, document already created on the hocuspocus server) the document would be loaded via the collaboration sync mechanism.

I would now need to know if any other person has authenticated on the hocuspocus server for the same document,
or if the document already exists on the hocuspocus server.

I tried several methods, nothing did work.

How can we reproduce the bug on our side?

First, this is our most simple hocuspocus server config:

import { Server } from "@hocuspocus/server";
import jwt from "jwt-simple";

const url = "http://info.cern.ch/hypertext/WWW/TheProject.html";

const ARGS = {};
if (process.argv.length < 4) {
    console.warn("Usage: node ./src/tiptap-collaboration-server.js PORT JWT_SECRET");
    process.exit();
}
ARGS.port = process.argv[2];
ARGS.secret = process.argv[3];

const server = Server.configure({
    port: ARGS.port,

    async onAuthenticate({ token, documentName }) {
        try {
            const decoded = jwt.decode(token, ARGS.secret);
            console.log(
                `Authentification from ${decoded.user} on document ${documentName}.`
            );
            return {
                user: {
                    name: decoded.user,
                },
            };
        } catch {
            throw new Error("Authorization failed.");
        }
    },
});

server.listen();

And this is the relevant client code for the tiptap editor:

    [...]
    const config = {};
    if (this.options.collaboration.server && this.options.collaboration.document) {
        // Random color, see: https://css-tricks.com/snippets/javascript/random-hex-color/
        const random_color = "#" + ((Math.random() * 0xffffff) << 0).toString(16);
        // Information about the current user
        const user_name = this.options.collaboration.user || random_color;
        const user_color = this.options.collaboration.color || random_color;

        // Set up the Hocuspocus WebSocket provider
        const HocuspocusProvider = (await import("@hocuspocus/provider")).HocuspocusProvider; // prettier-ignore
        const YDoc = (await import("yjs")).Doc;
        const y_doc = new YDoc();
        const provider = new HocuspocusProvider({
            url: this.options.collaboration.server,
            name: this.options.collaboration.document,
            document: y_doc,
            token: this.options.collaboration["authentication-token"],
            onAwarenessUpdate: ({ states }) => {
                collaboration_states = states;
            },
        });

        provider.setAwarenessField("user", {
            name: user_name,
            color: user_color,
            document_name: this.options.collaboration.document,
        });

        // Wait for user being authenticated
        const authenticated = () =>
            new Promise((resolve) =>
                provider.on("authenticated", resolve, { once: true })
            );
        await authenticated();

        // Wait for document being synced
        const synced = () =>
            new Promise((resolve) => provider.on("synced", resolve, { once: true }));
        await synced();

        // Attempt 1: Only if the y_doc is the same as the document on the provider object,
        //            which I believe should be returned from the hocuspocus server.
        //            The problem here is, that also for the second connection with another browser
        //            returns true for the following if clause.
        if (y_doc === provider.document) {
            // Initialize the tiptap editor later with some initial content.
            config["content"] = getText();
        }

        // Attempt 2: Only for the first connecting user.
        //            The problem here is that I apparently do not reliably get the number of connected users.
        //            With two browsers connecting, one time I get 0 users, one time 1 user, another time 2.
        const connected_users = [...provider.awareness.states.values()].map(
            (it) => it.user
        );
        if (connected_users.length === 1) {
            // Initialize the tiptap editor later with some initial content.
            config["content"] = getText();
        }
        
        // Load tiptap collaboration extensions
        // Setup collaboration cursor, etc..
        [...]
    }
    // Setup tiptap, etc.

Can you provide a CodeSandbox?

No response

What did you expect to happen?

Maybe I should just hand the document loading to the hocuspocus server.
But our attempt here has the benefit of not needing to load any client extensions,
which the hocuspocus server potentially doesn't know anything about.

Is there a better API of some hocuspocus provider callbacks or events to get notified if a call to new HocuspocusProvider initially created the document or to get a relyable number of conected users?

Anything to add? (optional)

Sorry for the bug description not really fitting the bug report questions.

Say "nay" and I will update and try to provide a minimal running sandbox.

This is the PR where I develop the collaboration feature: Patternslib/pat-tiptap#6

We are sponsoring tiptap/hocuspocus (pilz, Syslab.com) - I'm part of the Syslab.com team and implementing the tiptap integration.

Did you update your dependencies?

  • Yes, I’ve updated my dependencies to use the latest version of all packages.

Are you sponsoring us?

  • Yes, I’m a sponsor. 💖 (pilz, Syslab.com)
@thet thet added the Type: Bug The issue or pullrequest is related to a bug label Feb 18, 2022
@stale
Copy link

stale bot commented Jul 6, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Jul 6, 2022
@stale stale bot closed this as completed Jul 14, 2022
@sandercoffee
Copy link

unstale

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug The issue or pullrequest is related to a bug
Projects
None yet
Development

No branches or pull requests

3 participants