laravel / reverb

Laravel Reverb provides a real-time WebSocket communication backend for Laravel applications.
https://reverb.laravel.com
MIT License
1.05k stars 76 forks source link

Broadcast message toOthers throws ApiException in pusher #121

Closed cryptoprof closed 5 months ago

cryptoprof commented 5 months ago

Reverb Version

1.0.0-beta4

Laravel Version

11.1.0

PHP Version

8.3.4

Description

When i try to send broadcast message via my Event like this broadcast(new MyEvent())->toOthers() I receive an Exception

[2024-03-28 16:26:08] local.ERROR: Pusher error: Internal server error.. {"exception":"[object] (Illuminate\\Broadcasting\\BroadcastException(code: 0): Pusher error: Internal server error.. at /home/ss/workspace/chat/vendor/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php:164)
[stacktrace]
#0 /home/ss/workspace/chat/vendor/laravel/framework/src/Illuminate/Broadcasting/BroadcastEvent.php(92): Illuminate\\Broadcasting\\Broadcasters\\PusherBroadcaster->broadcast()

In laravel-websockets, which i used before, same method work without errors.

Steps To Reproduce

broadcast(new MyEvent())->toOthers() receive exception

[2024-03-28 16:26:08] local.ERROR: Pusher error: Internal server error.. {"exception":"[object] (Illuminate\\Broadcasting\\BroadcastException(code: 0): Pusher error: Internal server error.. at /home/ss/workspace/chat/vendor/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php:164)
[stacktrace]
#0 /home/ss/workspace/chat/vendor/laravel/framework/src/Illuminate/Broadcasting/BroadcastEvent.php(92): Illuminate\\Broadcasting\\Broadcasters\\PusherBroadcaster->broadcast()

When i add in Reverb inside handleRequest method of Laravel\Reverb\Servers\Reverb\Http\Server $this->close($connection, 500, $e->getMessage());

instead of $this->close($connection, 500, 'Internal server error.'); Which a give ZERO info about what happening inside this error I receive some more info

message
: 
"Pusher error: Undefined array key \"875833828.561499442\"."

Maybe problem in line isset($payload['socket_id']) ? $this->channels->connections()[$payload['socket_id']]->connection() : null But didn't understand what is wrong. When remove ->toOthers() - all work good Thank you

cryptoprof commented 5 months ago

https://github.com/laravel/reverb/pull/122 Maybe I'm missing something, but for some reason, my socket_id is not present in the connections when I use toOthers. However, I haven't encountered this issue when working with laravel-websockets. Please don't judge my English harshly, and thank you for the great product.

Riari commented 5 months ago

I'm seeing the exact same issue with Laravel 11.0.7 and Reverb 1.0.0-beta3. Unfortunately the changes in #122 don't appear to have any effect for me.

I assume socket IDs are necessary for toOthers() to work correctly, but I don't see any socket IDs being passed around anywhere (no X-Socket-ID headers, no "socket" field in websocket payloads, etc). Not sure what's responsible for assigning them. In my case, I'm using Reverb with Livewire in case that's relevant.

cryptoprof commented 5 months ago

Hm, I need some more time to debug. It seems that the socket_id was sent to Pusher inside the payload over the API. The problem is that $this->channels->connections() is returning an empty array. When I add a check for null, this probably just muting the error. Will look after work, time to xdebug)

cryptoprof commented 5 months ago

Made a few changes to my branch https://github.com/cryptoprof/reverb/tree/fix-issue-121 (I checked it on my branch, it works, but it fails the tests - can somebody help?) The problem is in EventController probably. When i send my Event ->toOthers in EventController $this->channels->connections() contains {"684284594.574173138":{"Laravel\\Reverb\\Protocols\\Pusher\\Channels\\ChannelConnection":[]}}

$payload['socket_id'] contains "270200814.539673629"

So when we try to call $this->channels?->connections()[$payload['socket_id']]->connection()

We get an error, in connections there are no this socket_id as a key

When remove toOthers, there is no any $payload['socket_id'], so it returns null.

cryptoprof commented 5 months ago

In Laravel WebSockets, the TriggerEventController contains a method that broadcasts an event to everyone except a specific socket ID:

optional($channel)->broadcastToEveryoneExcept([
    'channel' => $channelName,
    'event' => $request->json()->get('name'),
    'data' => $request->json()->get('data'),
], $request->json()->get('socket_id'));

However, I couldn't find any implementation of the PresenceChannel in the Reverb package that allows us to check for the socket ID in the payload and broadcast to everyone except that socket ID. It seems that this functionality is not available in Reverb.

The payload with the socket_id is only used in the EventsController, if I'm not mistaken. But the problem is that there is simply no connection with that specific socket_id. I tried to debug it with Xdebug, and it seems that connections are formed in the ArrayChannelConnectionManager. I don't understand why that socket_id is not present in the list of connections, and should it be there? Based on the check condition in the EventsController, I assume that it should be. If it shouldn't be there, then the issue can be resolved with my fix.