laravel / reverb

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

Reverb not sending any event to client #178

Closed crazynds closed 2 months ago

crazynds commented 2 months ago

Reverb Version

v1.0.0-beta9

Laravel Version

v11.5.0

PHP Version

8.3.3

Description

I have setup a basic project following the steps to configure reverb and their functionalities, but nothing I do work to send any event to the client listening in the socket. The event is dispatched, and the client socket is connected in the reverb:start server, but when I dispatch some event, the worker show that it work in this event but the reverb dont show anything (with --debug flag) that it has sended the event to the clients, the only output log is over time the ping sended and recived.

I created a public repo with just a base laravel configuration and reverb that I'm using for this test to create a simple application to broadcast a message to all connected clients.

I'm using windows 11 if that change anything.

Steps To Reproduce

  1. Create a clean laravel 11 project and add the basic auth ui and install:broadcast.

  2. Create the following classes:

(Create the model Message with migrations, but not necessary to add the code in this issue)

Event:

class GotMessage implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(public array $message)
    {
        //
    }

    public function broadcastOn(): array
    {
        // $this->message is available here
        return [
            new PrivateChannel("channel_for_everyone"),
        ];
    }
}

Job:

class SendMessage implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(public Message $message)
    {
        //
    }

    public function handle(): void
    {
        GotMessage::dispatch([
            'id' => $this->message->id,
            'user_id' => $this->message->user_id,
            'text' => $this->message->text,
            'time' => $this->message->time,
        ]);
    }
}

Command to create a job to dispatch an event:

class Test extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:test';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $message = Message::create([
            'user_id' => User::query()->first()->id,
            'text' => 'mensagem to all',
        ]);
        SendMessage::dispatch($message);
    }
}

channels.php

use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('channel_for_everyone', function ($user) {
    return true;
});

In home.blade.php add the following script:

    <script>
        window.addEventListener("load", function() {
            window.Echo.channel('channel_for_everyone')
                .listenToAll((event, data) => {
                    // do what you need to do based on the event name and data
                    console.log(event, data)
                })
        })
    </script>
  1. Start the aplication:

php artisan serve php artisan reverb:start --debug php artisan queue:listen

  1. Go to dashboard page (Register + login)

  2. On this screen you can use f12 to see if the socket is connected: image

  3. Run the command to send an event:

php artisan app:test

  1. The event is not pushed to client.

My thoughts

I think that the event is probably not being sent to the thread that is executing reverb:start, but I don't know how the events are dispatched between threads (whether via cache, database, filesystem,...). Without knowing how events are dispatched, I can't debug what my error might be.

I actually tried to make an laravel application from scratch following several tutorials, including the one on the official Laravel YouTube page, and with none of them I managed to get the event distributed via broadcast.

I'm 99.9% sure that it could be my error, but I've already reread the documentation and haven't had any success. The documentation for using broadcast is also very confusing as it is divided into 3 (Event Docs, Broadcast Docs and Reverb Docs), and makes it difficult to know what I am doing wrong.

sinnbeck commented 2 months ago

You are broadcasting the event to a private channel (PrivateChannel) but you are listing on a public channel (Echo.channel())

Change PrivateChannel to Channel or change Echo.channel() to Echo.private()

driesvints commented 2 months ago

Thanks @sinnbeck

crazynds commented 2 months ago

@sinnbeck Thanks for the feedback.

Replacing PrivateChannel to Channel doesnt seen to work either.

image

As you can see in the image, the reverb server didn't send any mensage after the subscribe, even when the GotMessage was dispatched after that.

And replacing .channel to .private the only different behaviour is when opened a connection the client didn't subricribe at any channel: image

<script>
        window.addEventListener("load", function() {
            window.Echo.private(`channel_for_everyone`)
                .listen('GotMessage', (e) => {
                    console.log(e.order);
                });
         });
</script>

I have found the repo of the laracast presentation of reverb. I will explore this repo and see if I can found whats wrong.

*sorry for the images, i couldn't copy these output to paste as text.

crazynds commented 2 months ago

I cloned the repository "exploring-laravel-reverb" and only updated the reverb package (because of the #76 bug in windows), but didn't work for me either.

Same behaviour as when I used Echo.private, start socket connection but dont send any subscribe: image

I rec a video of my test:

https://github.com/laravel/reverb/assets/36674096/d273bc32-bbd4-4ea2-bfd1-da041807fb6a

Am I missing something? 🤔

joedixon commented 2 months ago

@crazynds do you see a request to the broadcasting/auth endpoint of your application? You won't be able to join the private channel if your application is not first returning a valid auth token.

crazynds commented 2 months ago

@joedixon Thanks for the reply.

I will use the repo "exploring-laravel-reverb" as the reference here, because if I resolve the problem in the repo, I can resolve in the other too.

When I enter in the dashboard and every action I do in the podcast screen the software calls /broadcasting/auth endpoint as follow: image

The request:

Request URL: http://localhost:8000/broadcasting/auth
Request Method: POST
Status Code: 200 OK
Remote Address: 127.0.0.1:8000
Referrer Policy: strict-origin-when-cross-origin

Payload: socket_id=958458997.935671138&channel_name=private-App.Models.User.1

The response is a empty body.

joedixon commented 2 months ago

It's not actually Reverb which handles that endpoint - it's part of the framework itself. Looks like that's why you're not able to auth with the private channel though.

Did you run the install:broadcasting command?

crazynds commented 2 months ago

Did you run the install:broadcasting command?

Yes, if I run this command again this is the output.

$ php artisan install:broadcasting

   ERROR  The 'broadcasting' configuration file already exists.

   ERROR  Broadcasting routes file already exists.

  Would you like to install and build the Node dependencies required for broadcasting? (yes/no) [yes]
❯ no

It's not actually Reverb which handles that endpoint - it's part of the framework itself. Looks like that's why you're not able to auth with the private channel though.

But one think I notice with this comment is that if I change my broadcast route to:

Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
    dd('ok');
    return (int) $user->id === (int) $id;
});

It didn't print the 'ok' debug message in the route /broadcast/auth.

If I execute the command route:list I get the /broadcast/auth route:

  GET|HEAD  / ............................................................................................................  
  POST      _ignition/execute-solution ..... ignition.executeSolution › Spatie\LaravelIgnition › ExecuteSolutionController  
  GET|HEAD  _ignition/health-check ................. ignition.healthCheck › Spatie\LaravelIgnition › HealthCheckController  
  POST      _ignition/update-config .............. ignition.updateConfig › Spatie\LaravelIgnition › UpdateConfigController  
  GET|POST|HEAD broadcasting/auth ............................. Illuminate\Broadcasting › BroadcastController@authenticate  
  GET|HEAD  confirm-password .................................. password.confirm › Auth\ConfirmablePasswordController@show  
  POST      confirm-password .................................................... Auth\ConfirmablePasswordController@store  
  GET|HEAD  dashboard .......................................................................................... dashboard  
  POST      email/verification-notification ....... verification.send › Auth\EmailVerificationNotificationController@store  
  GET|HEAD  forgot-password ................................... password.request › Auth\PasswordResetLinkController@create  
  POST      forgot-password ...................................... password.email › Auth\PasswordResetLinkController@store  
  GET|HEAD  login ..................................................... login › Auth\AuthenticatedSessionController@create  
  POST      login .............................................................. Auth\AuthenticatedSessionController@store  
  POST      logout .................................................. logout › Auth\AuthenticatedSessionController@destroy  
  PUT       password .................................................... password.update › Auth\PasswordController@update  
  GET|HEAD  podcasts ...................................................................................... podcasts.index  
  PUT       podcasts/{podcast}/publish .................................................................. podcasts.publish  
  GET|HEAD  profile ................................................................ profile.edit › ProfileController@edit  
  PATCH     profile ............................................................ profile.update › ProfileController@update  
  DELETE    profile .......................................................... profile.destroy › ProfileController@destroy  
  GET|HEAD  register ..................................................... register › Auth\RegisteredUserController@create  
  POST      register ................................................................. Auth\RegisteredUserController@store  
  POST      reset-password ............................................. password.store › Auth\NewPasswordController@store  
  GET|HEAD  reset-password/{token} .................................... password.reset › Auth\NewPasswordController@create  
  GET|HEAD  sanctum/csrf-cookie ........................ sanctum.csrf-cookie › Laravel\Sanctum › CsrfCookieController@show  
  GET|HEAD  up ...........................................................................................................  
  GET|HEAD  verify-email .................................... verification.notice › Auth\EmailVerificationPromptController  
  GET|HEAD  verify-email/{id}/{hash} .................................... verification.verify › Auth\VerifyEmailController  

                                                                                                       Showing [28] routes  

But I don't understand why, even when the broadcast is installed. 🤔

crazynds commented 2 months ago

Ok, now I get it, this is really my fault when I cloned the repo from laracast. At my .env file:

BROADCAST_CONNECTION=log

Should be:

BROADCAST_CONNECTION=reverb

This makes the response works. I only get this reading the source code of \Illuminate\Broadcasting\BroadcastController. Rereading the documentation of broadcasting I notice the only one driver that dont tell to change the .env variable BROADCAST_CONNECTION is the Reverb, even in the Reverb docs, so that's probably why I didn't realize.

Thanks for the time! @joedixon @driesvints @sinnbeck

crazynds commented 2 months ago

Maybe this env var should be setted in the reverb:install command or added to the docs.

joedixon commented 2 months ago

The BROADCAST_CONNECTION variable does get set in the install command so not sure why that wasn't applied for you

https://github.com/laravel/reverb/blob/main/src/Console/Commands/InstallCommand.php#L173-L187

When I get some time, I will pull down that example repo and give it a try.

iamvinny commented 11 hours ago

The BROADCAST_CONNECTION variable does get set in the install command so not sure why that wasn't applied for you

https://github.com/laravel/reverb/blob/main/src/Console/Commands/InstallCommand.php#L173-L187

When I get some time, I will pull down that example repo and give it a try.

In my case it didn't get set because I deployed my project to production and when I did cp .env.example .env it was not included in the example env.