Laravel real-time notification not showing into console from Pusher - php

I'm implementing Real-Time Notification in my Laravel project. I'm very close to achieve my goal. What I have done so far is I have saved the notifications into database and now wanted to render the same notification to user using Pusher.
I got response into Pusher but the issue is I' m not able to receive the notification in my console and under the console of another user to make it work like real time.
Currently, notifications are sending to Pusher, saving into database but notification is not showing into console.
App.js
require('./bootstrap');
//getting the ID's of all logged-in users
let userId = document.head.querySelector('meta[name="user-id"]').content;
Echo.private('App.Models.User.' + userId)
.notification((notification) => {
console.log(notification.type);
});
Vue.component('example', require('./components/Example.vue'));
const app = new Vue({
el: '#app',
});
Bootstrap.js
window._ = require('lodash');
window.$ = window.jQuery = require('jquery');
require('bootstrap-sass');
window.Vue = require('vue');
require('vue-resource');
Vue.http.interceptors.push((request, next) => {
request.headers.set('X-CSRF-TOKEN', Laravel.csrfToken);
next();
});
import Echo from "laravel-echo"
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key:'8c1d04bb8d1782b874b1',
cluster: 'ap2',
encrypted: false
});
DatabaseNotification.php
<?php
class DatabaseNotification extends Notification
{
use Queueable;
private $subscription;
public function __construct($letter)
{
$this->subscription = $letter;
}
public function via($notifiable)
{
return ['database','broadcast'];
}
public function toDatabase($notifiable)
{
return [
'letter' => $this->subscription,
];
}
public function toBroadcast($notifiable)
{
return [
'letter' => $this->subscription,
'count' => $notifiable->unreadNotifications->count(),
];
}
}
Response in Pusher

Related

Why Laravel-Echo doesn't work on my stage server?

It's just not working and doesn't show any errors.
Frontend side:
import Echo from 'laravel-echo';
import axios from 'axios';
window.Pusher = require('pusher-js');
window.Pusher.logToConsole = true;
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
});
Pusher.logToConsole = true;
window.Echo.private('report-generated')
.listen('ReportGenerated', (e) => {
console.log(e);
handleResponse(e.data);
});
In the backend side I create new channel in the Event:
class ReportGenerated implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $data;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
dd($this->data);
return new PrivateChannel('report-generated');
}
}
Queues works by redis and works properly, if launch a code above we see in the console:
[2021-11-08 10:37:47][b2SKHMqqO3l2g2UN4G0bjp3bE3YGfjG3] Processing: App\Jobs\GenerateReport
[2021-11-08 10:37:47][b2SKHMqqO3l2g2UN4G0bjp3bE3YGfjG3] Processed: App\Jobs\GenerateReport
[2021-11-08 10:37:47][PdAhlQqLvEEdUtb5MfBhFy4VAyEONz9a] Processing: App\Events\ReportGenerated
array:2 [
"status" => "success"
"file" => "transactions-1636367867.pdf"
]
Of course I've tested without dd().
Seems that everything fine, but in the browser console nothing happens by this event, only these logs:
Pusher : : ["State changed","initialized -> connecting"]
pusher.js?782e:1206 Pusher : : ["Connecting",{"transport":"ws","url":"wss://ws-ap2.pusher.com:443/app/ea46c356a251f1d332eb?protocol=7&client=js&version=7.0.3&flash=false"}]
pusher.js?782e:1206 Pusher : : ["State changed","connecting -> connected with new socket ID 9001.16292364"]
pusher.js?782e:1206 Pusher : : ["Event sent",{"event":"pusher:subscribe","data":{"auth":"","channel":"report-generated"}}]
pusher.js?782e:1206 Pusher : : ["Event recd",{"event":"pusher_internal:subscription_succeeded","channel":"report-generated","data":{}}]
pusher.js?782e:1206 Pusher : : ["No callbacks on report-generated for pusher:subscription_succeeded"]
BUT ON THE LOCAL ENVIRONMENT EVERYTHING WORKS FINE! It's problem only on the stage server. I don't understand the reason of this...
Yes, I changed driver BROADCAST_DRIVER=pusher, done vendor:publish, uncommented Broadcast string in the config/app.php, permanently cleaned cache by commands: optimize, cache:clear, writed npm run dev to update js-scripts.
I even updated pusher credentials in env file for stage server cause in the local I used other credentials. (pusher app id etc..).
To sum up - queues works, event dispatches, channel creates but laravel Echo don't see anything...
Can someone tell me what step I missed?

Laravel with Pusher simply doenst listen to events

What am i missing? I did everything right but when i sent a new Event my console just doesnt log anything, here is my code:
FRONT END
I imported the required libraries:
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = Echo;
window.pusherEcho = new Echo({
broadcaster: 'pusher',
key: 'my-key',
cluster: 'us2',
forceTLS: true,
wsHost: window.location.host,
wsPort: 8000
});
BACK END
My event class:
<?php
namespace App\Events;
// ... imports
class ReceivedNotification implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('received-notification');
}
}
I registered a route just to test it:
Route::get('/event', function() {
event(new App\Events\ReceivedNotification('Hello world'));
return 'event sent';
});
FRONT END
I'm listening to events in some page with Laravel Echo:
pusherEcho.channel('received-notification')
.listen('ReceivedNotification', (e) => {
console.log(e);
});
When i go to the route /event it never triggers the console.log above, which means something is just wrong, yes my .env file is everything ok i already checked:
BROADCAST_DRIVER=pusher
.
.
.
PUSHER_APP_ID=***
PUSHER_APP_KEY=***
PUSHER_APP_SECRET=***
PUSHER_APP_CLUSTER=us2
As we can see you are creating private channel in App\Events\ReceivedNotification and listen public channel in front-end.
So change your front-end to below code :
pusherEcho.private('received-notification')
.listen('ReceivedNotification', (e) => {
console.log(e);
});
Also register your Event and Listerner in app\Providers\EventServiceProvider like :
protected $listen = [
'App\Events\ReceivedNotification' => [
'App\Listeners\ReceivedNotificationListener'
],
]

Is it possible emit data to channel in laravel echo?

I have two separate laravel project and installed on one of these project laravel-echo and on another one laravel-echo-server.
I connected this project together and transfer data from server to client but I can't emit data from client to server.
event in server:
class TestEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $prices;
/**
* Create a new event instance.
*
* #param int[] $prices
*/
public function __construct($prices = ['a' => 11000, 'b' => 420])
{
$this->prices = $prices;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PresenceChannel('bla-bla');
}
public function broadcastAs()
{
return 'financial.prices';
}
}
rotue in server:
Route::get('/fire', function () {
$prices = [
'a' => rand(11000, 120000),
'b' => rand(450, 5000)
];
event(new \App\Events\TestEvent($prices));
return 'done';
});
client:
import Echo from 'laravel-echo';
window.io = require('socket.io-client');
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001',
logToConsole: true
});
window.Echo.logToConsole = true;
window.Echo.join('bla-bla')
.here((data) => {
console.log('asdasd');
})
.joining((data) => {
console.log('asdasd');
})
.leaving((data) => {
console.log('asdasd');
});
how can I do this? It would be highly appreciated if anyone can advise me!😊
you need to use emit after connected to the socket server:
window.io = require('socket.io-client');
const socket = io('https://localhost:8080');
socket.on('connect', () => {
socket.emit('your_channel_to_emit', {your_data});
});
By default, Echo will use the /broadcasting/auth endpoint to authorize channel access. If your client side is not on the same host you will have to customize the authEndpoint of pusher. You may specify your own authorization endpoint by passing the authEndpoint configuration option to your Echo instance:
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-channels-key',
authEndpoint: '/custom/endpoint/auth', //customize here.
});
Add this to your Event (App\EventName):
public function broadcastWith()
{
return [
'data' => "your data",
'moredata' => "more data",
];
}
And access your data like this in JS:
Echo.channel('channel-name')
.listen('EventName', (event) => {
console.log(event.data);
console.log(event.moredata);
console.log(event['moredata']);
}

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

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: App\Events\NewMessage
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 App\Events;
use App\Message;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
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 \Illuminate\Broadcasting\Channel|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.
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.

Invalid key in subscription auth data , type : websocketError

I am using Laravel 5.8.*, laravel echo, pusher and vuejs for a private chat.
Trying to listen the broadcast-ed event using vuejs as frontend but no data received in callback from pusher. I can see the private channel and data sent to pusher but received empty. I see below messages in console when I connected to pusher :
Pusher : Event sent : {"event":"pusher:subscribe","data":{"auth":"460f6d3e4959b66a186a:3a759e55e46fc62d0188461344828ee4266edba8f1c0f5a5fd9743beb086d8cf","channel":"private-messages.1"}}
Pusher : Event recd : {"event":"pusher:error","data":{"code":null,"message":"Invalid key in subscription auth data: '460f6d3e4959b66a186a'"}}
Pusher : Error : {"type":"WebSocketError","error":{"type":"PusherError","data":{"code":null,"message":"Invalid key in subscription auth data: '460f6d3e4959b66a186a'"}}}
I tried all the ways I can but unable to find the reason for this subscription error. I had set all the pusher data (channel name, key, secret id, app id, cluster) correctly. I read all the other questions which already mentioned the same issue here in stackoverflow but none of them has relevant solution or answer. So again came here for some help if anyone connect remotely and check on my laptop.
ChatApp.vue
<template>
<div class="chat-app">
<Conversation :contact="selectedContact" :messages="messages" #new="saveNewMessage"/>
<ContactsList :contacts="contacts" #selected="startConversationWith"/>
</div>
</template>
<script>
import Conversation from './Conversation';
import ContactsList from './ContactsList';
export default {
props: {
user: {
type: Object,
required: true
}
},
data(){
return {
selectedContact: null,
messages: [],
contacts: []
};
},
mounted() {
Echo.private(`messages.${this.user.id}`)
.listen('NewMessage', (e) => {
console.log('listening NewMessage');
this.handleIncoming(e.message);
});
axios.get('/contacts')
.then((response)=>{
this.contacts = response.data;
});
},
methods:{
startConversationWith(contact){
this.updateUnreadCount(contact, true);
axios.get(`/conversation/${contact.id}`)
.then((response) => {
this.messages = response.data;
this.selectedContact = contact;
})
},
saveNewMessage(message){
this.messages.push(message);
},
handleIncoming(message){
if (this.selectedContact && message.from == this.selectedContact.id) {
this.saveNewMessage(message);
return;
}
this.updateUnreadCount(message.from_contact, false);
},
updateUnreadCount(contact, reset){
this.contacts = this.contacts.map((single)=>{
if (single.id !== contact.id) {
return single;
}
if (reset)
single.unread = 0;
else
single.unread += 1;
return single;
})
}
},
components: {Conversation, ContactsList}
}
</script>
<style lang="scss" scoped>
.chat-app{
display:flex;
}
</style>
EVENT
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use App\Message;
class NewMessage implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Message $message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('messages.'.$this->message->to);
}
public function broadcastWith(){
$this->message->load('fromContact');
return ["message" => $this->message];
}
}
channels.php
Broadcast::channel('messages.{id}', function ($user, $id) {
return $user->id === (int) $id;
});
broadcasting.php
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'encrypted' => true,
],
],
connection with laravel echo
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
encrypted: true
});
.env
PUSHER_APP_ID=xxxx
PUSHER_APP_KEY=dbxxxxxxxb29
PUSHER_APP_SECRET=160xxxxxxxx11af
PUSHER_APP_CLUSTER=ap2
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
BROADCAST_DRIVER=pusher
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
There are no errors in the error log of pusher dashboard.
The public key in your client JS is different from the one you have set in your .env file.
I can see from the screenshot from the client that the public key begins c07d341 wheres in your 'env file this is set as:
PUSHER_APP_SECRET=160xxxxxxxx11af
Finally the error message you are getting relates to a public key mismatch.
Have you possibly updated your keys without re-compiling your Javascript dependencies using the command
npm run dev
If that doesn't solve the issue, you may also want to check you have not hardcoded the incorrect public key in another location

Categories