18

I want to trigger an event to pusher private channel and my server side language is laravel I reviewed a lot of resources, but I did not find a comprehensive approach which covers both the server side and the front side Finally I got this solution in the first step :

 export const SendChat = () => {
    try {
        var pusher = new Pusher('YOUR_APP_KEY', {
            cluster: 'ap2',
            forceTLS: true,
            authTransport: 'jsonp',
            authEndpoint: `${baseUrl}pusher/auth`,
        });
        var channel = pusher.subscribe('private-channel');
        channel.bind('pusher:subscription_succeeded', function() {
            var triggered = channel.trigger('client-EVENT_NAME', { 'message': 'Hi ....' });
            console.log(triggered)
        });

    } catch (error) {
        console.error(error);
    }
}

and call it somewhere

<Button onClick={this.props.SendChat}  waves='light' >Send</Button>

you must Enable client events in pusher account setting

login to your pusher account -> select the channel ->App Settings -> select Enable client events -> update

add your app key, channel name and event name after that we need authorization in server side this is sample laravel code first add this route in web.php

Route::get('pusher/auth', 'PusherController@pusherAuth');

make PusherController.php like this :

public function pusherAuth()
{
    $user = auth()->user();

    if ($user) {
        $pusher = new Pusher('auth_key', 'secret', 'app_id');
        $auth= $pusher->socket_auth(Input::get('channel_name'), Input::get('socket_id'));
        $callback = str_replace('\\', '', $_GET['callback']);
        header('Content-Type: application/javascript');
        echo($callback . '(' . $auth . ');');
        return;
    }else {
        header('', true, 403);
        echo "Forbidden";
        return;
    }
}

test it you should see something like this

 Pusher : State changed : connecting -> connected with new socket ID 3953.****556
Pusher : Event sent : {"event":"pusher:subscribe","data":{"auth":"83045ed1350e63c912f5:328fb78165d01f7d6ef3bb6d4a30e07c9c0ad0283751fc2c34d484d4fd744be2","channel":"private-chat"}}
Pusher : Event sent : {"event":"client-MessageSent","data":{"message":"Hi ...."},"channel":"private-chat"}
true
Bakhtiar
  • 661
  • 5
  • 18

2 Answers2

1

It doesn't matter much which client-side language you are using. Angular, Vue, React they all are JS framework and libraries. And, you can consider using a generic JS code which you can place in all 3 apps.

Let me try to give you a detailed answer I can give as per my knowledge.

In order to get started, you should first complete try to complete Chat scenario without pusher. i.e: user should be able to send a message from front-end via the API and it should be stored inside the database.

Once you have done this it is very easy to include pusher in the flow. ( In simple words, you'll have to broadcast an event and that'll inform the Socket Server to broadcast a message to all/other user(s) on the channel )

For Pusher Authentication, you don't need to explicitly create a route and a method. Once you have uncommented BroadcastServiceProvider inside config/app.php. You can run:

php artisan route:list

and, you'll see a route for broadcast broadcasting/auth.

You can use this route to authenticate. Although, you can make few changes and prepend /api before this.

Go into BroadcastServiceProvider.php and replace your boot method with:

public function boot()
    {
        Broadcast::routes(
            [
                'prefix' => 'api',
                'as' => 'api.broadcasting.auth',
                'middleware' => ['auth:sanctum'],
            ]
        );

        require base_path('routes/channels.php');
    }

I assume you're using Laravel Sanctum for Authentication. If not you need to change the authentication middleware to your provider.

Once done, you can authenticate from frontend using this auth route. So, what I have done is created a service in ReactJS and in the constructor I have created a Pusher instance :

this.pusher = new Pusher(PUSHER_APP_KEY, {
        authEndpoint: 'http:localhost:8000/api/broadcasting/auth',
        cluster: PUSHER_CLUSTER,
        useTLS: true,
        auth: {
            headers: {
                Authorization: 'Bearer ' + authHeader
            }
        }
    });

You only need to instantiate your Pusher once and use this instance throughout the app. So, that's why I have created a service class for Pusher.

If you want things to be simple for now you need to execute this code on the page where you will use pusher. Once the Page load, you need to call this code. So, you'll do:

let pusher = null;

useEffect(() => {
  pusher = new Pusher(PUSHER_APP_KEY, {
            authEndpoint: 'http:localhost:8000/api/broadcasting/auth',
            cluster: PUSHER_CLUSTER,
            useTLS: true,
            auth: {
                headers: {
                    Authorization: 'Bearer ' + authHeader
                }
            }
        });
}, []);

So, this way we have an instance of Pusher in our functional component or page.

Now, we need to subscribe to channel.

Using this instance of pusher we can subscribe to channels. If you have followed the useEffect approach on the same page then, right after getting the instance you can subscribe to channels and bind to events using this code:

const channel = pusher.subscribe('private-chat.' + channelName)

And, to bind to an event you can do:

channel.bind('event.name', function(data) {
  console.log(data);
});

Make sure to replace "channelName" and "event.name" with your channel and event name respectively.

Now you'll be able to listen to your event once broadcasted from the backend.

So, you'll do something like this from the backend. You'll have a method that will store the message inside the database so, let's say that code is:

public function sendMessage (Request $request){
  //.... Rest of the logic

  $user = $request->user();

  // Store the message
  $chatMessage = $chat->messages()->create([
      'message' => $message,
      'sender_id' => $user->id
  ]);
  
  broadcast(new NewMessage($user, $chatMessage))->toOthers();
  
  //... Rest of the logic
}

This broadcast message will send this message to other user in the chat.

I hope this answer gives you a good idea and direction.

Hesan Naveed
  • 199
  • 5
-1

For work with WebSockets via Pusher on Laravel, I recommended using the package Laravel Echo for React part. And on the backend side in config/broadcasting.php setup configuration for Pusher. See more detail on official documentation Laravel how to use Pusher on the backend side and frontend side. https://laravel.com/docs/8.x/broadcasting#pusher-channels