I am going through this tutorial Introducing Laravel Echo. Broadcasting thing is working perfecting fine. Whenever I execute the command php artisan chat:message "something". Event get triggered and data stores in database. But moving on to Laravel Echo. I tried a lot but I am going no where. I have put Echo in /js/app.js but in docs it mentioned that /js/bootstrap.js. Since i am following the tutorial, therefore I have put it in /js/app.js Echo is not showing data in log. I am using ubuntu.
Test Event:
class TestEvent implements ShouldBroadcast
{
use InteractsWithSockets, SerializesModels;
public $message;
public $user;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($user, $message)
{
//
$this->user = $user;
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return "chat-room";
}
}
Send Chat Command Code:
class SendChatMessage extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'chat:message {message}';
protected $description = 'Send chat message.';
public function handle()
{
// Fire off an event, just randomly grabbing the first user for now
$user = \App\User::first();
$message = \App\Message::create([
'user_id' => $user->id,
'content' => $this->argument('message')
]);
event(new \App\Events\TestEvent($message, $user));
}
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
}
Laravel Echo:
import Echo from "laravel-echo"
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'my-key'
});
window.Echo.channel('chat-room')
.listen('TestEvent', (e) => {
console.log(e.user, e.message);
});
one more thing whenever I send an event from pusher. Pusher is able to send it correctly.
Not sure if it is still relevant but might help someone.
I am using Laravel 5.4 and using 'eu' cluster in pusher. Please note that sometimes pusher goes crazy. It starts receiving broadcasted events late. So, I made my event implement ShouldBroadcastNow contract instead of ShouldBroadcast to overcome this problem. I am not using a queue to post events to pusher. Even then sometimes I notice delays in receiving events. Anyways, all well on the broadcasting part.
Now, on the client side, here is the script I am using to listen to events triggered from pusher(in my case private channel)
bootstrap.js (available by default in Laravel 5.4)
import Echo from "laravel-echo"
window.Echo = new Echo({
broadcaster: 'pusher',
key: '<your_pusher_app_key>',
csrfToken: window.Laravel.csrfToken,
cluster:'eu',
encrypted: true });
You should compile the JS if you make change to bootstrap.js else, your changes won't be packed into public folder. Laravel 5.4 uses Laravel Mix and the command to compile is "npm run dev"
In My blade template:
window.Echo.private('<channel_name_without_prefixing_private_keyword>')
.listen("<Just the event class name and not fully qualified name>", function(e){
console.log(e);
});
This worked for me. Further, ensure that, BroadcastServiceProvider is uncommented in config\app.php file. It's not enabled by default.
In routes/channels.php
Broadcast::channel('<channel_name_without_private_prefix>', function ($user) {
//Auth check
return true;
});
Related
I have successfully implemented pusher on my laravel app but I want to make, when the user succeeds in making an order the default status_message for the order is pending, the case is when the admin changes the status_message to processed, the user who has ordered gets a notification that the order he has made is processed.
this is my code but this code sends notifications to all users.
Controller
if ($data->status_message == 'processed') {
event(new OrderEvent('Hi, Your order is processed!'));
//...
}
My Event OrderEvent.php
public function broadcastOn()
{
return new Channel('notif-channel');
}
/**
* Broadcast order event.
*
* #return void
*/
public function broadcastAs()
{
return 'order-event';
}
in App blade
var channel = pusher.subscribe('notif-channel');
channel.bind('order-event', function(data) {
const obj = JSON.parse(JSON.stringify(data));
const message = obj.message;
blah blah blah
}
Both user and admin should be on the same channel. For example if user is subscribed for channel 'order-channel-SetUserID'.
Admin should send the message to that channel and you should look for it on the front end and make the changes on the DOM.
In your controller when you submit the changes of the status of the order run the event with the channel name
event(new OrderEvent($user_id, 'Hi, Your order is processed!'));
Now your event should look similar to this:
class OrderEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user_id;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($user_id, $message)
{
$this->user_id = $user_id;
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('order-channel.' . $this->user_id);
}
public function broadcastAs()
{
return 'order-event';
}
}
Of course you can change your class Name etc... I'm just giving an idea.
it's important to send the changes on the same channel with this user or else you will make changes to other users that are visiting your website.
EDITED
Here is what else you need to configure.
In app/Providers/EventServiceProvider.php
You need to put the event in protected $listen
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
OrderEvent::class => [
OrderEventListener::class,
],
];
In app/Listeners You should create OrderEventListener.php and set it up as follow:
<?php
namespace App\Listeners;
use App\Events\OrderEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Pusher;
class OrderEventListener
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param \App\Events\OrderEvent $event
* #return void
*/
public function handle(OrderEvent $event)
{
$pusher = new Pusher(env('PUSHER_APP_KEY'),
env('PUSHER_APP_SECRET'), env('PUSHER_APP_ID'), [
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => true
]);
$pusher->trigger($event->broadcastOn(),
$event->broadcastAs(), $event->data);
}
}
check your Debug Console in pusher dashboard? If you can see the event firing there all you need to do is show the message with javascript. If no event is running then something in your code is missing.
I have a very simple application that uses Laravel-echo-server with Socket.io for real-time communication, the application is working, the problem is that when I change the message of the event that is going to be executed, it completely ignores all the changes of the php file, for example I have the following class.
class PublicMessage implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct()
{
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('public-message-channel');
}
public function broadcastAs()
{
return 'MessageEvent';
}
public function broadcastWith()
{
return ['message' => "This is a public message"];
}
}
I subscribe as follows in my front end
window.Echo.channel('public-message-channel').listen('.MessageEvent', (data) => {
console.log(data);
});
then i trigger the event from a route
Route::get('/chat', function(){
event(new PublicMessage());
dd("Public event exceute successful.");
});
and i get
{"message": "This is a public message"}
but if i change the return in broadcastWith function i still get the same response, even restarting the php artisan queue:work the laravel-echo-server and my Xampp server, the only thing that makes it detect the changes is restarting the machine I'm developing on, does anyone have an idea what could be going on?
Im currently working on implementing websockets in my Nuxt App. I have a Laravel backend and im using Pusher and Laravel Echo. The problem is that, when trying to connect/subscribe to a private channel - as the client is authorized via the broadcast/auth endpoint the individual channel auth (channels.php) is not hit. So it is possible for a logged in user to access a private channel that they should not be able to access.
My code/configuration is as follows:
NUXT FRONTEND:
nuxt.config.js
echo: {
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: process.env.NODE_ENV === 'production',
authModule: true,
authEndpoint: `${process.env.API_URL}/broadcasting/auth`,
connectOnLogin: true,
disconnectOnLogout: true,
auth: {
headers: {
'X-AUTH-TOKEN': process.env.API_AUTH_TOKEN
}
}
},
LARAVEL BACKEND:
BroadcastServiceProvider.php
public function boot()
{
Broadcast::routes(['middleware' => [JWTAuthMiddleware::class]]);
require base_path('routes/channels.php');
}
AuthController.php
public function auth(Request $request): JsonResponse
{
$pusher = new Pusher(
config('broadcasting.connections.pusher.key'),
config('broadcasting.connections.pusher.secret'),
config('broadcasting.connections.pusher.app_id')
);
$auth = $pusher->socket_auth($request->input('channel_name'), $request->input('socket_id'));
return ResponseHandler::json(json_decode($auth));
}
ChatMessageEvent.php
/**
* #inheritDoc
*/
public function broadcastOn()
{
return new PrivateChannel('chat.' . $this->chatMessage->getChatId());
}
channels.php
Broadcast::channel(
'chat.{chatId}',
function (JwtUserDTO $user, int $chatId) {
Log::info('test');
return false;
}
);
As you may have noticed, we use a JWT auth strategy which is stored on the client side - so we have no sessions. But as the authorization via the auth endpoint works it should be possible to guard the individual private channels via the channels.php routing ? But as i can see in the logs, it is never reached. Am i missing some configuration ? or why am i authorized solely on the auth endpoint and not also on the individual channels routes ?
After a lot of searching I found out that the issue was with my AuthController.php as I had implemented my own auth function - which made it work in order to authenticate the user to the private channel. Unfortunately this then resulted in not leviating the BroadcastServiceProvider. So the solution was:
use Illuminate\Broadcasting\BroadcastController;
Route::post('broadcasting/auth', [BroadcastController::class, 'authenticate'])
->middleware(BroadcastMiddleware::class);
This will then use the Broadcast Facade and enable use of the channels.php for authenticating the user against the given channel.
I also had to add a middleware to set the authenticated user in the Laravel session as this is needed by the ServiceProvider.
/**
* #param Request $request
* #param Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
/** #var JwtUserDTO $jwt */
$jwt = $request->get('jwt');
// Set the user in the request to enable the auth()->user()
$request->merge(['user' => $jwt]);
$request->setUserResolver(function() use ($jwt) {
return $jwt;
});
Auth::login($jwt);
return $next($request);
}
And to do this the Model or DTO in my case had to implement the Illuminate\Contracts\Auth\Authenticatable interface. Remember to add functionality for the getAuthIdentifierName and getAuthIdentifier to return the username and user id respectivly as this is also needed if you want to play with presences channels.
i had a problem when using presence channel in Laravel Echo with pusher. when I fire an event, i get 500 error from BroadcastException without the response body which is hard for me to debug it. when i look to pusher debug console, the presence event was listened by pusher. so i assume my event has never been fired to Pusher. Here is the preview in my network tab
my controller:
public function store() {
$user = auth()->user();
$message = $user->messages()->create([
'message' => request('message')
]);
event(new MessageReceived($message, $user));
return ['status' => 'OK'];
}
the MessageReceived class
namespace App\Events;
class MessageReceived implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
public $user;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Message $message, User $user)
{
$this->message = $message;
$this->user = $user;
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return new PresenceChannel('chatroom');
}
}
and here is my vuejs
mounted() {
axios.get('/messages')
.then(response => {
this.messages = response.data
})
.catch(error => {
console.log(error)
})
Echo.join('chatroom')
.listen('MessageReceived', (e) => {
console.log(e) //never get into this
})
},
i can't find where the error is. i use cluster ap1 and is declared in broadcasting.php and in my bootstrap.js. anyone can help me out?
This can be caused by an error in your configuration. Here are some things to check:
In your .env file, make sure the pusher id, key, and secret are correctly set.
If you upgraded from Laravel 5.3 to Laravel 5.4, note that the .env variables PUSHER_KEY is now PUSHER_APP_KEY and PUSHER_SECRET is now PUSHER_APP_SECRET
In your config/broadcasting.php, make sure the cluster is set correctly.
If you are not in HTTPS, you may have to set the 'encrypted key to false
'options' => [
'cluster' => 'ap1', // change this to your app's cluster
'encrypted' => false,
],
I was broadcasting my event with help of pusher,it's worked fine but when i used queue implementation then pusher haven't receive any broadcast or may be event is not broadcasting.I'm not understand what the issue is.Code is given below please help me
Controller function
public function index()
{ $this->user_id=2;
Event::fire(new UpdateDeviceStatus($this->user_id));
}
Event file
class UpdateDeviceStatus extends Event implements ShouldBroadcast
{
use SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public $devices;
public function __construct($id)
{
$this->devices=Device::with('units')->where('user_id',$id)->get();
}
/**
* Get the channels the event should be broadcast on.
*
* #return array
*/
public function broadcastOn()
{
return ['update-status'];
}
}
js file
Pusher.logToConsole = true;
var pusher = new Pusher('key', {
encrypted: true
});
var channel = pusher.subscribe('update-status');
channel.bind('App\\Events\\UpdateDeviceStatus', function (data) {
console.log(data);
});
I had the same issue and realised that I just forgot to listen to the queue: php artisan queue:listen redis