11

WebSocket allows two-way communication: the server can send messages to the browser and the browser - the client - can respond back via the same connection.

I am implementing Chat Application in Laravel 6 using:

I already get it worked that the server triggers events and the client listens to those events as following.

  1. Install Laravel WebSockets package.

composer require beyondcode/laravel-websockets

  1. Configure config/broadcasting.php.
        'pusher' => [
            'driver' => 'pusher',
            'key' => xxx,
            'secret' => xxx,
            'app_id' => xxx,
            'options' => [
                'cluster' => xxx,
                'encrypted' => true,
                'useTLS' => true, 
                'host' => '127.0.0.1',
                'port' => 6001,
                'scheme' => 'https',
            ],
        ],
    ]
  1. Configure config/websockets.php
'apps' => [
        [
            'id' => xxx,
            'name' => xxx,
            'key' => xxx,
            'secret' => xxx,
            'enable_client_messages' => true,
            'enable_statistics' => true,
        ],
    ],
  1. Install Pusher server.

composer require pusher/pusher-php-server "~3.0"

  1. Set broadcasting driver to use pusher in .env file.

BROADCAST_DRIVER=pusher

  1. Use laravel-echo and pusher-js on my client side.
import Echo from "laravel-echo"

window.Pusher = require('pusher-js');

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'your-pusher-key',
    wsHost: window.location.hostname,
    wsPort: 6001,
    disableStats: true,
});
  1. Start WebSockets server.

php artisan websockets:serve

  1. On the server-side, trigger events with an event class that implements ShouldBroadcastNow class.

event(new MyEventClass((object)$message));

Everything works fine. In step 8, I trigger events from the server-side.

Note that I am not using the official Pusher server, I just utilize the Pusher API implementations and pusher-js but point the Laravel Echo JavaScript package to the local Laravel WebSockets server, configured in step 6.

Please do not confus Laravel Echo JavaScript package with laravel-echo-server of Socket.IO Server. I am not using Socket.IO Server.

Now instead of triggering events on the server-side as shown in step 8, I want to tigger events from the client-side since WebSocket allows two-way communication. How can I do that in Laravel with Laravel Echo JavaScript Package, Laravel WebSockets PHP package?

Rwd
  • 34,180
  • 6
  • 64
  • 78
O Connor
  • 4,236
  • 15
  • 50
  • 91
  • Please can you link to the exact packages your using (Laravel Echo JavaScript Package, Laravel WebSockets and pusher-js). – Rwd Jan 15 '20 at 14:23
  • Link to Laravel Echo JavaScript Package: https://github.com/laravel/echo – O Connor Jan 15 '20 at 14:33
  • Link to Laravel WebSockets: https://docs.beyondco.de/laravel-websockets/ – O Connor Jan 15 '20 at 14:33
  • Link to pusher-js NPM package: https://www.npmjs.com/package/pusher-js – O Connor Jan 15 '20 at 14:36
  • Thanks. For some reason I thought you meant a completely different Laravel echo package. – Rwd Jan 15 '20 at 14:38
  • yes, I meant Laravel Echo JavaScript Packpage, not that laravel-echo-server maintaining Socket,IO server. – O Connor Jan 15 '20 at 14:39
  • Are you after something like this: https://laravel.com/docs/5.8/broadcasting#client-events – Rwd Jan 15 '20 at 14:46
  • Yes Something like this: To broadcast client events, you may use Echo's whisper method: `Echo.private('chat') .whisper('typing', { name: this.user.name });` To listen for client events, you may use the listenForWhisper method: `Echo.private('chat') .listenForWhisper('typing', (e) => { console.log(e.name); });` – O Connor Jan 15 '20 at 15:10
  • I could see that WebSockets server did receive message from events, but client does not hear that events. I miss something. – O Connor Jan 15 '20 at 15:12
  • @OConnor have you found a way to send message privately to server? Since any data sent to server from client gets received on web-sockets process, from there it has to be passed to laravel. I too had searched a lot for sending data from client to server but never found a way – Hášíl Páůďýál Aug 16 '20 at 14:18
  • did you somehow handle this? cause I have same problem here!!! – Siros Fakhri Oct 12 '21 at 08:42

4 Answers4

1

Refer to this documentation: https://pusher.com/docs/channels/using_channels/events#triggering-client-events

According to pusher documentation, Initialize your front end using this

 this.echo = new Pusher('mykey', {
    wsHost: 'localhost',
    wsPort: 6001,
    forceTLS: false,
    disableStats: true,
    enabledTransports: ['ws', 'wss']
  });

use this to trigger your event

var channel = this.echo.subscribe("private-channel");
channel.bind("pusher:subscription_succeeded", () => {
var triggered = channel.trigger("client-someEventName", {
   your: "data",
 });
});
0

After having initialized Echo, you need to listen on a certain channel within your frontend. I will show some Vue code, but modify accordingly:

Vue File

export default {
    methods: {
        sendCommand(command) {
            axios.post('/api/command', { 'command': command })
            .then((res) => {
                //
            })
        }
    },
    mounted() {
        Echo.channel('xxx')
        .listen('.weight-change', (e) => {
            this.weight = e.weight
        })
    }
}

In here, you can see that all the incoming messages are captured on the listen portion of the code and sending a new message is done with an api route on the backend that sends them to the Echo channel.

Please let me know if you need any clarification.

JoeGalind
  • 3,545
  • 2
  • 29
  • 33
  • 2
    This is the same as step 8 I have done, With `axios.post('/api/command')`, you make an API call to the server to trigger events. Thus events are being triggered on the server-side. I am looking for solution to trigger events on the client-side. When you invoke `sendCommand(command)` method on the client-side within a VueJs component that call `axios.post()` does not mean you trigger events on the client-side. – O Connor Jan 15 '20 at 14:45
0

For everyone that may face this issue.

You no need echo and should instantiate from the Pusher directly

const my_pusher = new Pusher("APP_KEY", {
        cluster: 'mt1',
        wsHost: window.location.hostname,
        wsPort: 6001,
        forceTLS: false,
        disableStats: true,
    });

And to send message to the server:

my_pusher.send_event('EVENT_NAME',{'ANYTHING':'YOU_WANT'})
Lessmore
  • 1,061
  • 1
  • 8
  • 12
  • You are not going to hit the server with this, its only client side. Therefor you cant do any validation or anything on the data. – Michael Andersen Jan 27 '21 at 11:52
  • @MichaelAndersen By this code, client side can send any event to server. Any validation can be provided in server side – Lessmore Jan 27 '21 at 17:32
0

I might be incorrect, but I don't believe you can push to Pusher with their pusher-js package. That's what the pusher-php-server composer package is for.

There may be a node package for this, but why are you trying to reinvent the wheel? Just use axios or a Vuex action to post to one of your routes to fire your event and then let Echo pick up the response.

You don't even need to create a controller, just use a route closure and fire your event. Axios or Vuex will both return a Promise so you can manage wait for a response in your component or your Vuex action.

I could understand if you were trying to implement a different type of driver to Broadcast with like RabbitMQ or Rachet or something, but it's designed to be a circular loop of sorts, hit your endpoint from js, fire the event from PHP, let Pusher/or websockets do it's thing, receive your broadcast back in js.

secondman
  • 3,233
  • 6
  • 43
  • 66
  • This is not the way websockets are working. There is already a ws connection. Why should i send a post request again and again to my backend? – Mike Aron Feb 18 '22 at 10:51