laravel / reverb

Laravel Reverb provides a real-time WebSocket communication backend for Laravel applications.

Home Page:https://reverb.laravel.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add backend listener for presence channel events to log user attendance

xaniuskarlhall opened this issue · comments

I am using this package to handle WebSocket connections and manage presence channels for a livestream feature in my application. I would like to log user attendance by tracking when users join or leave the livestream.
Is there a way to set up a listener or hook in the backend to capture the events when a user joins or leaves a presence channel? Ideally, I would like to be able to:

  1. Detect when a user joins a presence channel and log their user ID, timestamp, and any other relevant information to track their attendance.
  2. Detect when a user leaves a presence channel (either by explicitly leaving or due to disconnection) and log the corresponding information to mark the end of their attendance.
  3. Store these attendance logs in a database or suitable storage mechanism for later analysis or reporting.

If there is a built-in way to achieve this using the Reverb package, please let me know. Otherwise, I would greatly appreciate any guidance or suggestions on how I can extend the package or implement a custom solution to log user attendance based on presence channel events.

You could inspect the MessageReceived event, which fires every time a user sends a message (such as requesting to join a channel). However, be wary that any action you carry out when this event is fired will block other messages flowing through the server from being processed.

But, currently, there is no event similar to pusher:unsubscribe. How can disconnection events be handled?

Reverb handles the unsubscribe event:

'unsubscribe' => $this->unsubscribe($connection, $payload['channel']),

Hello @joedixon, I have a similar problem, I'm trying to use Reverb for detecting the "online" state of users. But what I see, is that Reverb handles unsubscribe events, which we can listen to through MessageReceived, but we can't listen to unsubscription event which is invoked after client disconnection

public function close(Connection $connection): void

As a result, we can't detect when the user goes to "offline" status

Thanks @Merraclius - can you provide a scenario where the unsubscription event which is invoked after client disconnection?

The most simple case.

  1. User open the page, we joining him to presence room.
  2. He close the tab/window Reverb catch the connection close event which fire unsubscribe event.
    But this event only broadcasting the information about unsubscription to other clients (through broadcastInternally) but can't be catched inside our application

Reverb will still dispatch the MessageReceived event, so you can hook into that?

No, because MessageReceived is dispatched only on receiving the message

MessageReceived::dispatch($from, $message);
, but in this case, the Reverb server doesn't receive any messages. It just detects that the connection is closing and no messages

Gotcha - that's handled by the close method rather than on message receipt

https://github.com/laravel/reverb/blob/main/src/Protocols/Pusher/Server.php#L73-L85

I'll give this some thought, but I'm wary of adding more events due to the potential to block the event loop.

Thank you for the additional feedback 👍

It would be great to be able to catch and somehow react to connection termination directly on the server. For example, it would be possible to create a dashboard with real-time information about the status of devices if they are online or offline (2 frontend applications in total - administration app and device app).

Maybe I'm wrong now, but I've been solving this very problem with event trapping and connection termination for about a week now. For example, if I have information about device changes under company.{companyId}, but I can detect connection closure on device.{deviceId} then I can send a message to company.{companyId} that the device is already offline or online or other data and notify administration app. Thus, a dashboard that lists all devices under company (1:N) would have only one open WS connection and would not need to implement N connections + Heatbeat + CRON to detect device disconnection.

I also tried PresenceChannel, but the current implementation is more for chat applications and cannot be used for anything else since it is built directly on user ID and this authorization. This greatly limits the possibilities, as for example there may be a 1:N binding where there are N devices under 1 company, and in the company I want to see which devices are currently online or offline.

If you have any ideas on how to achieve this without the "Heartbeat + CRON" of the app representing the device, that would be great.

I have created a fork and will prepare a PR when I add more event features, tests and I am sure it works fine. If you want to test the functionality of the event that is called when a connection is closed Laravel\Reverb\Events\ChannelDisconnected; https://github.com/jakubforman/reverb