0
votes

i'm trying to createa realtime chat app with laravel 5.4, laravel-echo, redis and socket-io on homestead.

Please check my code below and then my problem

ChatConversation event:

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

    public $message;

    public $user;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(Chat $message, User $user)
    {
        $this->message = message;
        //Người gửi
        $this->user = $user
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return Channel|array
     */
    public function broadcastOn()
    {
        return new PresenceChannel('chatroom');
    }
}

My web.php:

Route::post('/privatechat/{id}/{receiver_id}', function(){
        $user = Auth::user();
        $room_id = request()->segment(5);
        $rec = request()->segment(6);

        $message = Chat::create([
            'chat_room'     =>  $room_id,
            'message'       =>  request()->get('message'),
            'sender_id'     =>  $user->id,
            'receiver_id'   =>  $rec
        ]);

        broadcast(new ChatConversation($message, $user));

        return ['status' => 'OK'];
    })->middleware('auth');

My chat vue setting:

const app = new Vue({
                el: '#app',
                data: {
                    messages: [],
                    sendClass: 'chat-send'
                    //Điều kiện
                },
                methods: {
                    addMessage(message) {
                        this.messages.push(message);

                        axios.post(url_post, message);
                        /*.then(function (response) {
                            //swal('Tuyệt vời! Work like a charm!');
                            console.log(response);
                        })
                        .catch(function (error) {
                            console.log(error);
                        });*/
                    }
                },
                created() {
                    var u = url;
                    axios.get(u).then(response => {
                        //console.log(response);
                        this.messages = response.data;
                    });

                    /*Echo.join('chatroom')
                    .here()
                    .joining()
                    .leaving()
                    .listen('ChatConversation', (e) => {
                        console.log(e);
                    })*/

                    Echo.join('chatroom')
                        .listen('ChatConversation', (e) => {
                            console.log(e);
                        })
                }
            });

My bootstrap.js

import Echo from "laravel-echo"

window.Echo = new Echo({
    broadcaster:  '../socket.io-client/dist/socket.io',
    host: window.location.hostname + ':6001'
});

My laravel-echo-server.json

"devMode": true,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"sslCertPath": "",
"sslKeyPath": ""
  1. My first problem is when I use this script for accessing client library:

    src="//{{ Request::getHost() }}:6001/socket.io/socket.io.js

I get this error GET http://hgc.develop:6001/socket.io/socket.io.js net::ERR_CONNECTION_REFUSED So I had to download socket from bower and change the line above to

<script src="{{ asset('js/socket.io-client/dist/socket.io.js') }}"></script>
  1. My second problem is that when I go to my chat application page, the console show me these errors:

    app.js:35246 TypeError: Cannot read property 'presenceChannel' of undefined

    app.js:15520 Uncaught (in promise) TypeError: Cannot read property 'socketId' of undefined

One more, I follow this tutorial for creating my chat app: https://www.youtube.com/watch?v=8aTfMHg3V1Q but I use Redis and Socket.io instead of Pusher

What's wrong in my code? And how can I deal with these problems?

1

1 Answers

2
votes

I finally managed to figure this out. I looked through the JS files and managed to pin it down to the fact that the code in this line has the try catch section not actually throw errors if the Laravel channels.php check to who can listen to a channel doesn't return a user model instance as it should.

Something like this in Channels.php will throw out that error:

Broadcast::channel('users', function ($user) {
    if($user->type == 'admin'){
         return $user;
    }else{
         return false;
    }
});

If the $user doesn't pass the if check Laravel will return false. Since it's not returning JSON and simply false I think it should log that the response body did not pass the JSON.parse() function so you can see that in the terminal. Something like this:

try {
     body = JSON.parse(response.body);
} catch (e) {
     Log.warning('Response body provided is not expected JSON. Response body provided ${response.body}');
     body = response.body;
}

This way we can see if Laravel isn't returning a user model instance.

So when you don't get a user model instance as expected, there is no user object for the code to attach the sockedId to because it's undefined. There was never any JSON to make the object with.

I would think the code should stop trying to connect to the presence or private channel if you don't get a user instance either rather than trying to attach a socket ID.

Anyways, to actually return a user make sure you are logged in using Laravel's Auth system. If you didn't use that you might have to do some work around to get it to work. If you are not using it then this function in Laravel will throw a 403 error because it can't find you to be logged in.

I had to over write the function that checks the password hash algorithm to a custom algorithm with a provider so I don't mess with the Laravel core and make the user model extend the class Laravel is looking for.

Then in your channels.php file just make sure what check you're doing you're actually returning the $user in the callback function from the auth check the Broadcaster.php file does. Something like this:

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

That's a super simple private/presence channel but with a logged in user and returning the $user this will not throw out this error.

Also, make sure you're calling socket.io in your Echo instance like this:

window.Echo = new Echo({
    broadcaster:  'socket.io',
    host: window.location.hostname + ':6001'
});