statamic / collaboration

Real-time, multi-user editing with Statamic via websockets
https://statamic.com/addons/statamic/collaboration
33 stars 12 forks source link

support mutiple sessions per user #52

Closed sauerbraten closed 1 year ago

sauerbraten commented 2 years ago

This PR adds ~two~ one feature:

Multiple Sessions Support

In order to sync changes between two sessions of the same user, each session must act as a separate Echo user. (Pusher does not play back events triggered by A to any of A's connections.) To pretend to Echo/Pusher that each session is a different user, we have a custom User and UserRepository class:

<?php

namespace App\Polygon\Auth;

use Statamic\Auth\File\User as StatamicUser;

class User extends StatamicUser
{
    public function getAuthIdentifierForBroadcasting()
    {
        if (request()->socket_id) {
            return parent::getAuthIdentifier() . '#' . request()->socket_id;
        }
        return parent::getAuthIdentifier();
    }
}
<?php

namespace App\Polygon\Auth;

use Statamic\Stache\Repositories\UserRepository as StatamicUserRepository;
use Statamic\Contracts\Auth\User as UserContract;

class UserRepository extends StatamicUserRepository
{
    public function make(): UserContract
    {
        return new User();
    }
}

Laravel Echo calls getAuthIdentifierForBroadcasting() if present on the user object it sees, and we include Pusher's socket_id in the ID used for broadcasting. That way, Pusher treats all websocket connections as different members of the presence channel and broadcasts changes between all of them.

In order to access the socket ID of the author of a channel event, it's necessary to use Echo's on() method with Pusher-specific event names instead of the more abstract here(), joining() or leaving() functions Echo provides.

As a rule of thumb, if user is the callback argument to a 'pusher:*' event:

Also, while collaboration sent the entire Statamic user object with each message before, now only the Pusher member ID (= Echo broadcasting ID) is sent, and clients resolve that ID locally in the user data they received when joining the channel.

Note: this solution works well with Pusher, but is untested and might break with any other Laravel broadcasting provider!

~Set-level locking in Replicator~

~While the core patch (https://github.com/sauerbraten/cms/commit/891bcc6fe03ea68f2f2b38e3e569b0a1d9f13cc1) has most of the magic, collaboration needs to support the new Pusher events 'focus-set' and 'blur-set' as well as the Vuex mutations 'lockReplicatorSet' and 'unlockReplicatorSet'.~

jasonvarga commented 2 years ago

Is it possible to split these into two separate PRs? One for the session support and one for the replicator stuff?

sauerbraten commented 2 years ago

Sure, let's start with this!

jesseleite commented 1 year ago

Given this is such an old issue, we've decided to close this. If you still need this, let us know and we'll definitely re-open and re-visit!

helloiamlukas commented 8 months ago

That's a shame, I would love to see this feature being part of the collaboration package.

Last time I checked this pull request was already working fine, what would you still need to include this into the package?