liveblocks / liveblocks

Liveblocks is the platform for adding collaborative editing, comments, and notifications into your application.
https://liveblocks.io
Apache License 2.0
3.51k stars 281 forks source link

Preparing a room's storage #33

Closed steveruizok closed 2 years ago

steveruizok commented 2 years ago

Is there a way to populate the storage for a room on the server?

What I'm after

For TLDraw, I'd like to implement a "copy to multiplayer file" feature, where a use can create a new multiplayer file with the content of their current file. Usually, this would be for turning an offline file into a new multiplayer one, but it could also be used to "fork" multiplayer projects.

image

There are probably a few different ways to do this. Since I'm using Next.js, my idea was to send the current document to an endpoint that would reply with the room id; which I could then navigate to.

  const handleCopyToMultiplayerRoom = React.useCallback(async () => {
    const res = await fetch('http://tldraw.com/api/create-multiplayer-room', {
      // ...
      body: JSON.stringify(state.document),
    }).then((res) => res.json())

    window.location.href = `http://tldraw.com/r/${res.roomId}`
  }, [])

The endpoint would then authenticate with Liveblocks and enter a new room with data from that document as part of its defaultStorageRoot. This would "prepare" the room with content; and once it was ready, the endpoint would return the roomId and the client would take it from there.

When the user arrives at the room, their content would be waiting for them.

What I tried

My first naive attempt at this didn't work—I could create the room on the server, however the room state would never change and room.getStorage promise would never resolve. Either way, the content wouldn't be there when the user arrived.

Perhaps you know a better way to do it?

(The alternative I'm considering would be to save the JSON in a separate database and then request it in the getServerSideProps of the room's dynamic route and use it as the defaultStorageRoot for that route; however I'd like to avoid it if possible.)

GuillaumeSalles commented 2 years ago

Hey @steveruizok,

Initializing room storage from the server is not easily doable because the client depends on WebSocket. However, I have some good news for you. We started to work on HTTP APIs to interact with Liveblocks rooms & storage. Last week @ofoucherot finalized the security (the difficult part), and he is currently focused on building get/put/delete room's storage.

You will be able to generate a token with @liveblocks/node and initialize the room's storage with PUT /api/v1/rooms/{id}/storage. The URL might slightly change. We're still not sure if this endpoint will accept a JSON (array will be converted to LiveList and object to LiveObject) or/and if it will accept LiveObject/LiveMap/LiveList. Could this solution work for you?

On a side note, these API will let you do backup on your own storage if necessary or even let you show a read-only mode of the Storage when too many people are connected in the room (like google doc).

steveruizok commented 2 years ago

That's great, I had a separate question about exactly that: backing up users' storage. Looking forward to testing the API when it's ready.

steveruizok commented 2 years ago

Just shipped this feature on tldraw, closing this issue. 👍