Event listener is listening but doesn’t get triggered from event

Tags: , , , ,



Hi I’m currently learning Vue.js with Laravel and tried to develop a teamchat. I used redis instead of pusher because of financial reasons and used this laravel echo server for the echo server.

The group chat connects the user with a private channel as soon as you select a team. After that it loads the messages and shows them in the frontend. When you send a message, the controller action gets successfully executed and the message is stored in the DB. However the user and other team members have to reclick on the teamname and therefore reload the messageList to get the newest message, although the event gets triggered on the echo server and redis receives the message.

This is what I get from the echo server when someone chooses a teamchat and sends a message:

[10:20:41 PM] - gK5b68mvO1goLE4nAAAI authenticated for: private-messages.11
[10:20:41 PM] - gK5b68mvO1goLE4nAAAI joined channel: private-messages.11
Channel: clash_finder_database_private-messages.11
Event: AppEventsNewMessage

This is what I get from monitoring the redis-server:

1589921588.805758 [0 127.0.0.1:37594] "PUBLISH" "clash_finder_database_private-messages.11" " 
{"event":"App\\Events\\NewMessage","data":{"message": 
{"id":9,"message":"test","team_id":11,"user_id":3,"created_at":"2020-05-19 
20:53:08","updated_at":"2020-05-19 20:53:08"},"socket":null},"socket":null}"

My NewMessage event looks like this:

namespace AppEvents;

use AppMessage;
use IlluminateBroadcastingChannel;
use IlluminateBroadcastingInteractsWithSockets;
use IlluminateBroadcastingPresenceChannel;
use IlluminateBroadcastingPrivateChannel;
use IlluminateContractsBroadcastingShouldBroadcast;
use IlluminateFoundationEventsDispatchable;
use IlluminateQueueSerializesModels;

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

public $message;

/**
 * Create a new event instance.
 *
 * @param Message $message
 */
public function __construct(Message $message)
{
    $this->message = $message;
}

/**
 * Get the channels the event should broadcast on.
 *
 * @return IlluminateBroadcastingChannel|array
 */
public function broadcastOn()
{
    return new PrivateChannel('messages.' . $this->message->team_id);
}
}

This controller action gets executed when the message has been sent:

    public function send(Request $request) {
    $message = Message::create([
        'team_id' => $request->team_id,
        'user_id' => $request->user_id,
        'message' => $request->text
    ]);
    broadcast(new NewMessage($message));
    return response()->json($message);
}

This is my vue component ChatApp.vue:

<template>
<div class="chat-container row">
    <i class="far fa-comments fa-3x"></i>
    <div id="chat-app" class="chat-app">
        <div class="row mx-0 h-100 overflow-hidden">
            <TeamList :teams="teamList" @selected="startConversationWith"/>
            <Conversation :selectedTeam="selectedTeam" :messages="messages" 
:user="user"/>
        </div>
    </div>
</div>
</template>

<script>
import MessageList from './MessageList';
import TeamList from './TeamList';
import Conversation from './Conversation';
import MessageTextBox from './MessageTextBox';

export default {
    props: {
        user: {
            type: Object,
            required: true
        }
    },
    data() {
        return {
            messages: [],
            teamList: [],
            selectedTeam: null
        }
    },
    mounted() {

        axios.get('/teams')
            .then((response) => {
                this.teamList = response.data;
            });
    },
    methods: {
        startConversationWith(team) {
            axios.get('/conversation/' + team.id)
                .then((response) => {
                    this.messages = response.data;
                    this.selectedTeam = team;
                });
            if (team.id != null) {
                if (this.selectedTeam == null) {
                    console.log("outside listener");
                    Echo.private('messages.' + team.id)
                        .listen('NewMessage', (e) => {
                            console.log("inside listener");
                            this.handleIncoming(e);
                        });
                } else if(this.selectedTeam.id !== team.id) {
                    console.log("outside listener");
                    Echo.private('messages.' + team.id)
                        .listen('NewMessage', (e) => {
                            console.log("inside listener");
                            this.handleIncoming(e);
                        });
                }
            }
        },
        saveNewMessage(message) {
            this.messages.push(message.message);
        },
        handleIncoming(message) {
            this.saveNewMessage(message);
            return;
        }
    },
    components: {TeamList, MessageList, MessageTextBox, Conversation}
}
</script>

I debugged the listener and noticed that it gets executed because my console.log right before got executed but the console.log inside listen() didn’t get output.

bootstrap.js:

import Echo from 'laravel-echo'

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

Can someone give me a hint where I can start to debug and maybe what I did wrong? Please let me know when there is missing information about my code.

Answer

I found the reason for the problem. As you can see on the redis monitoring, the channel name had a prefix. I set REDIS_PREFIX=
in .env to remove this prefix. Now I get an answer from the listener.



Source: stackoverflow