For the first time attempt with laravel and socket-io I am trying to send very simple notification to admins. So far my event is firing but I need help with receiving event notifications.
Logic
It's very basic because I want to understand the process.
User opens page Add Product
Admin gets notification that user X is in App Product page.
So far
So far I can fire event and get user data (user that is in Add Product page)
Need help for
I need help to understand the way that admin receives notifications.
Code
Component script
created() {
let user = JSON.parse(localStorage.getItem("user"))
this.listenForBroadcast(user);
},
methods: {
listenForBroadcast(user) {
Echo.join('userInAddProduct')
.here((Loggeduser) => {
console.log('My user data', Loggeduser);
});
}
}
Result of code above
My user data [{…}]
0:
id: 1
name: "Test User"
photo: "User-1588137335.png"
__ob__: Observer {value: {…}, dep: Dep, vmCount: 0}
get id: ƒ reactiveGetter()
set id: ƒ reactiveSetter(newVal)
get name: ƒ reactiveGetter()
set name: ƒ reactiveSetter(newVal)
get photo: ƒ reactiveGetter()
set photo: ƒ reactiveSetter(newVal)
__proto__: Object
length: 1
__proto__: Array(0)
Channels route
Broadcast::channel('userInAddProduct', function ($user) {
return [
'id' => $user->id,
'photo' => $user->photo,
'name' => $user->name
];
});
MessagePushed (event file)
class MessagePushed implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function broadcastOn()
{
return new PresenceChannel('userInAddProduct');
}
}
Question
How can I receive notification about this event fire? I want to notify my admin users that user x is in page Add Product?
Update
Since I published this question I've made some changes and here is my latest code + questions.
bootstrap.js
window.io = require('socket.io-client');
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001',
auth: { // added authentication token (because all my events are private)
headers: {
Authorization: localStorage.getItem('access_token'),
},
},
});
Add.vue (add product component where event has to be fired)
listenForBroadcast(user) {
let ui = JSON.parse(localStorage.getItem("user"))
Echo.join('userInAddProduct')
.here((users) => {
console.log('My user data', users)
})
.joining((user) => {
this.$notify({
title: '',
message: user + 'joining',
offset: 100,
type: 'success'
});
})
.leaving((user) => {
this.$notify({
title: '',
message: user + 'is leaving new product',
offset: 100,
type: 'warning'
});
})
.whisper('typing', (e) => {
this.$notify({
title: '',
message: ui.username + 'is adding new product',
offset: 100,
type: 'success'
})
})
.listenForWhisper('typing', (e) => {
console.log(e)
this.$notify({
title: '',
message: ui.username + 'is entered add new product page.',
offset: 100,
type: 'success'
});
})
.notification((notification) => {
console.log('noitication listener: ', notification.type);
});
},
Then I've made 4 files to handle events:
Event (passing data)
Event Listener (process the database storage and showing notifications to online admins)
Observer (firing event)
Notification (store data to database for admins in case when event fire they're not online so they can see notifications later on)
Event file
class MessagePushed extends Event implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public $product;
public function __construct(User $user, Product $product)
{
$this->user = $user;
$this->product = $product;
}
public function broadcastOn()
{
return new PresenceChannel('userInAddProduct');
}
}
Listener file
class ThingToDoAfterEventWasFired implements ShouldQueue
{
public function handle(MessagePushed $event)
{
//Log testing purpose only
$user = $event->user->username;
$product = $event->product->name;
// Real data that should be broadcasts
$user2 = $event->user;
$product2 = $event->product;
// inform all admins and authorized staffs about new product
$admins = User::role(['admin', 'staff'])->get();
foreach($admins as $admin) {
$admin->notify(new UserAddProduct($user2, $product2));
}
Log::info("Product $product was Created, by worker: $user");
}
}
Notification
class UserAddProduct extends Notification implements ShouldQueue
{
use Queueable;
protected $product;
protected $user;
public function __construct(User $user, Product $product)
{
$this->product = $product;
$this->user = $user;
}
public function via($notifiable)
{
return ['database', 'broadcast'];
}
public function toDatabase($notifiable)
{
return [
'user_id' => $this->user->id,
'user_username' => $this->user->username,
'product_id' => $this->product->id,
'product_name' => $this->product->name,
];
}
public function toArray($notifiable)
{
return [
'id' => $this->id,
'read_at' => null,
'data' => [
'user_id' => $this->user->id,
'user_username' => $this->user->username,
'product_id' => $this->product->id,
'product_name' => $this->product->name,
],
];
}
}
Observer
public function created(Product $product)
{
$user = Auth::user();
event(new MessagePushed($user, $product));
}
Questions
How can I return live notifications as soon as event is fired in whole app? currently as my code is placed in add.vue component admins get notify IF they are in same page only :/
How do I get notifications of multiple event? let say I have another event, listener, observer for other page actions I want admin be notified of both product event and other event in whole app.
thanks
We differentiate channel types like public and private.
Public: Illuminate\Broadcasting\Channel. It works without any authentication, so anonymus users can listen to this broadcast. Like football match scores available for everyone.
Private: Illuminate\Broadcasting\PrivateChannel. It works with an authentication, so only authenticated users can listen to this broadcast. Like admins watching what specific users do or user watching their orders status.
On the otherhand there is another private channel which is Illuminate\Broadcasting\PresenceChannel. Also require authentication. In example would be much like an any chat room. Ex.: only authenticated users can communicate with each other.
So these types will define your method. And you have to follow different paths. I am very suggesting to read the Laravel documentation (https://laravel.com/docs/broadcasting), it will guide you very carefully.
In the routes/channels.php you have to decide or verify if the authenticated user can listen on this particular channel. So you have to return boolean value (true or false). So here, you are not returning any value to the client side.
Every public property in your MessagePushed broadcast event will be serialized and sent to the client side. You have to give every informational data to the MessagePushed constructor and set to property/properties. Now you can handle the received data by like that, ex:
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001',
auth: {
headers: {
'X-Auth-Token': "<token>"
}
}
});
window.Echo.private('userInAddProduct')
.listen('MessagePushed ', (e) => {
console.log(e.auction);
});
I recommend to create custom authentication with token usage. Above I sent token to the server to authenticate user. https://laravel.com/docs/authentication#adding-custom-guards
In your situation I would separate these two mechanism.
check the user for going to the App Product page
notify the admin
For the 2. point would be enough to use the Illuminate\Broadcasting\PrivateChannel. So there is need for websocket on the admin page.
The 1. point could be tricky, because it's depends on your requirments. It is enough to notify the admin about user goes to exact App Product page?
If yes, then you will trigger this broadcast event in your controller when user goes to that page.
If not enough, then you need another websocket on the user page to "poll" your server and send tick broadcast to the admin in every X seconds.
Trigger broadcast event:
broadcast(new App\Events\MessagePushed($user));
My taste of usage is:
client side: socket.io-client
sever side: laravel-echo-server
redis broadcaster
custom authentication mechanism
Hope, I could help!
Solved
Here is how I done it based on my need and my question (it might be somehow different if your case is different than mine)
In component that activity happens (in my case Add.vue)
Echo.join('userInAddProduct')
.here((users) => {
console.log('here: ', users);
})
.joining((user) => {
console.log('joining: ', user);
})
.leaving((user) => {
console.log('leaving: ', user);
})
.whisper('typing', {data: notf}) // this part sends my data
.notification((notification) => {
console.log('noitication listener1: ', notification.type);
});
As I needed my notification be visible in all pages to admins I've added my socket emit (i.e. Echo.listenForWhisper) into my navbar component.
mounted() {
this.notifs();
window.Echo.join('userInAddProduct')
// listen to broadcast from Add.vue
.listenForWhisper('typing', (product) => {
// add it into my navbar notifications list
this.notifications.unshift(product);
});
}
Now each time user adds new product to server admin gets notified.
note To see my other settings for this function to happen please scroll back to my update part and see Event, Listener & Observe files code. (you make those files and all this codes above to your preferred components then you'll have real time notifications).
I recently wrote an article How to use Laravel WebSockets for NuxtJs notifications where I described in sufficient detail including the event setting for Laravel WebSockets. I hope you find it useful.
Related
What i'am trying to do is setting up an authentication system for my website using Laravel passport as back-end and Angular as front-end
From the official documentation I understood that I first need to make a GET Request to /oauth/authorize route with the following data:
'client_id' : 1,
'redirect_uri' : `${this.baseURL}`,
'response_type' : 'code',
'scope' : '',
'state' : random_string(40)
and then make a POST request to /oauth/token endpoint with the code generated from the previous response to require an access_token
At the current state thou when I make the first request (/oauth/authorize) using postman, Laravel responds with this error:
Route [login] not defined.
From what I reed, I need first to authenticate the user in some ways before requesting for authorization to the endpoint but I cannot find out how to do this.
Do I need to define some login logic? like a login function in my controller that should do something with my user data?
ADDITIONAL INFOS:
-I am trying to authenticate users coming from my front-end so they are first-party users
-I don't want to use "password grant tokens" as it's not recommended by the docs
You do not have to send a GET request every time to receive tokens of the authentication system, since they are static and are generated when the command is executed: php artisan passport:install.
This data is stored in a table (schema) of the database oauth_clients.
You can write them, for example, in the environments of the Angular app and use them without making unnecessary requests to the server and database every time. If, of course, Personal Access Client and Password Grant Client tokens are constantly updated, for example, by CRON, then of course, in this case it is necessary and it makes sense to send a preliminary GET request to the server.
And the code for the client part of the authentication system will be as follows:
services/auth/auth.service
import { Injectable } from '#angular/core'
import { HttpClient } from '#angular/common/http'
import { catchError, tap } from 'rxjs/operators'
interface IResponseHTTPLogin { // can be placed in a separate module or model at the discretion
token_type: string
expires_in: number
access_token: string
refresh_token: string
}
#Injectable({
providedIn: 'root'
})
export class AuthService {
/**
* Auth Laravel Passport: Password Grant Client
*
* #private
*/
private clientSecret: string = 'YOUR client secret token from oauth_clients table()' // <-- add enviroments
private clientId: number = 2 // <-- id client from oauth_clients table() | add enviroments
constructor (private http: HttpClient) {}
/**
* Login in cabinet.
*
* #param email
* #param password
*/
login (email: string, password: string) {
return this.http.post<IResponseHTTPLogin>('/oauth/token', {
grant_type: 'password',
client_id: this.clientId,
client_secret: this.clientSecret,
username: email,
password
})
.pipe(
tap(({ access_token, refresh_token }) => {
if (access_token) {
this.setToken(access_token)
this.setRefreshToken(refresh_token)
}
}),
catchError((err) => {
throw new Error(err)
})
)
}
getToken (): string {
return sessionStorage.getItem('token') ?? ''
}
getRefreshToken (): string {
return sessionStorage.getItem('token_refresh') ?? ''
}
protected setToken (token: string): void {
sessionStorage.setItem('token', token) // OR use localStorage
}
protected setRefreshToken (refresh_token: string): void {
sessionStorage.setItem('token_refresh', refresh_token)
}
isAuthenticate (): boolean {
return !!sessionStorage.getItem('token')
}
logout (): void {
sessionStorage.removeItem('token')
sessionStorage.removeItem('token_refresh')
}
}
interceptor/token.interceptor
import { Injectable } from '#angular/core'
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '#angular/common/http'
import { Observable } from 'rxjs'
import { AuthService } from '../../services/auth/auth.service'
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor (private authService: AuthService) {}
intercept (request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
if (this.authService.isAuthenticate()) {
request = request.clone({ setHeaders: { Authorization: `Bearer ${this.authService.getToken()}` } })
}
return next.handle(request)
}
}
Very important! In order for your authorization request to be fulfilled and there are no CORS errors, it must be redirected to your backend, for example using the following approach using a proxy.
At the root of the project, create a proxy.conf.json file. Where to add the following code:
{
"/oauth/token": {
"target": "ADRESS YOR DOMAIN",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
},
"/api/*": {
"target": "ADRESS YOR DOMAIN",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
},
}
Next, tell Angular that all requests need to be proxied, for this, in package.json in the scripts section, specify:
...
"start": "ng serve --proxy-config proxy.conf.json", <------
...
In the AuthServiceProvider backend you can customize your tokens in the boot() method:
...
Passport::tokensExpireIn(now()->addHours(24));
Passport::refreshTokensExpireIn(now()->addDays(30));
Passport::personalAccessTokensExpireIn(now()->addDays(30));
...
Functionality testing in development environment:
Laravel ^9.48
laravel-passport ^11.5.1
Angular ^15
I think you will find my answer helpful. If something is not clear, ask!
I can create Notifications In laravel and in React. I have followed the tutorials, but I don't know how to send the notification from laravel to my react application. This is the code that I got in my Laravel Controller.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Feature\HttpHandler;
use App\Notifications\PushDemo;
use App\Models\Users;
use Illuminate\Support\Facades\Auth;
use Notification;
use Illuminate\Support\Facades\Log;
use NotificationChannels\WebPush\PushSubscription;
use Illuminate\Support\Facades\Http;
use App\Feature\ApiResponse;
class PushController extends Controller
{
use ApiResponse;
use HttpHandler;
public function __construct(){
}
public function push(){
Log::info('Push push function called');
$users = Users::all();
Notification::send($users,new PushDemo);
return redirect()->back();
}
public function store(Request $request)
{
Log::info('Push store called');
// get user from request
//$user = Users::findOrFail($request->userId);
$user = Users::whereUrl($request->post('URL'))->firstOrFail();
$b = $request['body'];
// create PushSubscription and connect to this user
$pushsub = $user->updatePushSubscription($request->body['endpoint'], $request->body['keys']['p256dh'], $request->body['keys']['auth']);
Log::info('WORKED');
return $pushsub;
}
}
The store function works.
In react I have this piece of code in my service-worker.js to listen to a event. (this is the piece of code that needs to work, but it says unexpected use of 'self' no restriced-globals)
self.addEventListener('push', function (e) {
console.log('push');
if (!(self.Notification && self.Notification.permission === 'granted')) {
//notifications aren't supported or permission not granted!
return;
}
if (e.data) {
var msg = e.data.json();
console.log(msg)
e.waitUntil(self.registration.showNotification(msg.title, {
body: msg.body,
icon: msg.icon,
actions: msg.actions
}));
}
});
This code is never called it seems but it should be called when I click on this button:
<button onClick={() => test()}>
test notification
</button>
This is the function to go through the Laravel application:
function test(){
console.log('test');
workerApi.makePushNotification({ URL, token})
.then(response => {
if (response.hasOwnProperty('message') && response.hasOwnProperty('type')) {
}
else {
console.log(JSON.stringify(response.data));
}
})
})
}
This function call works. only it seemd like the service worker function is never called and it doesn't send the notification to my react application. How do I solve this?
hey you should use some real-time library for listener real-time events like pusher then you can send the message from the server to the frontend
for installing pusher on laravel application please check this article
https://www.codecheef.org/article/real-time-event-broadcasting-with-laravel-6-and-pusher
and for your react app
npm install --save pusher-js
your component file
import Pusher from 'pusher-js';
useEffect(() => {
var pusher = new Pusher("your-pusher-key", {
cluster: "ap2",
encrypted: true,
});
var channel = pusher.subscribe("notifyChannel");
channel.bind("notifyChannel", async function (response) {
alert('some notification');
})
});
I'm working on a rest api project, I'm using Laravel and Angular. To resume, my project is like a project manager. I've got 4 tables: user, project, project_user and status. So when a user create a project, he writes just the name and the project is created. The creator_id is the current user id. For the backend, I'm using Laravel JWT for the auth. And this is the code of the controller to create a project:
Project model:
class Project extends Model
{
protected $fillable = [
'name', 'creator_id', 'status_id'
];
protected $hidden = [
'created_at', 'updated_at'
];
protected $table = 'projects';
public function users()
{
return $this->belongsToMany(User::class)->select( 'email', 'date_of_birth', 'firstname', 'lastname');
}
public function status()
{
return $this->belongsTo(Status::class);
}
}
So the route in backend works, I tried with Postman and all is good. But I've got a problem with this route to create a project in frontend. It doesn't work and I've got the error 500 (Internal Server Error). When I inspect the web page, in security, I've got this message:
This is my angular code:
export class AddProjectComponent implements OnInit {
project = {
name: '',
};
submitted = false;
constructor(private projectService: ProjectService) { }
ngOnInit() {
}
createProject(): void {
const data = {
name: this.project.name,
};
this.projectService.create(data)
.subscribe(
response => {
console.log(response);
this.submitted = true;
},
error => {
console.log(error);
}
);
}
newProject(): void {
this.submitted = false;
this.project = {
name: ''
};
}
}
project.service.ts
create(data): Observable<any>{
return this.http.post(`http://localhost:8000/api/projects/`, data);
}
I don't know why it doesn't work because my user is well connected, i've got his auth_token in the local storage.
Someone can help me pls ? ^^
I think I have put the most useful files but if they are missing I can add them to you.
Thanks in advance
Issue is with $request-request->add(['creator_id'=>Auth::id()])
instead of that use request merge.
$request->merge(['creator_id'=>Auth::id()])
Your answer is right there in the error message. creator_id does not have a default value which means you HAVE to pass a value to it for it to create the row in the DB
I have created an Event called UserWalletNewTransaction.php and added this to it:
public $transaction;
public function __construct($transaction) {
$this->$transaction = $transaction;
}
Now in order to fire this event at the Controller, I coded this:
$newTransaction = UserWalletTransaction::create(['user_id' => $user_id, 'wallet_id' => $wallet_id, 'creator_id' => $creator_id, 'amount' => $amount_add_value, 'description' => $trans_desc]);
event(new UserWalletNewTransaction($newTransaction));
Then at the Listener, UserWalletNotification.php, I tried:
public function handle(UserWalletNewTransaction $event) {
$uid = $event->transaction->user_id;
$user = User::find($uid);
// now sends alert message to the user
}
So the scenario is, when Admins create a new Transaction for a custom user, a new alert message must be sent for him/her to let him/her know that new transaction was added for him/her.
But I don't really know how to do that.. So if you know, please let me know, I would really appreciate that...
Thanks in advance.
If by alert you mean showing a message on the web interface, use flash data.
https://laravel.com/docs/5.8/session#flash-data
$newTransaction = UserWalletTransaction::create(...);
event(new UserWalletNewTransaction($newTransaction));
$request->session()->flash('status', 'Transaction done.');
return view(...)
<span>{{ session('status') }}</span>
If you mean sending an email, just use the Mail facade in your listener to send a mailable.
https://laravel.com/docs/5.8/mail#sending-mail
public function handle(UserWalletNewTransaction $event) {
$uid = $event->transaction->user_id;
$user = User::find($uid);
Mail::to($user)->send(new TransactionDoneMail($event->transaction)); // TransactionDoneMail being your mailable class, made with "php artisan make:email TransactionDoneMail"
}
There are nice examples on how to build a mailable class in the documentation.
https://laravel.com/docs/5.8/mail#writing-mailables
There are many different things you can do in terms of "alerting" the customer.
One route would be to send an email or text message in your event listener. See https://laravel.com/docs/5.8/mail for help doing it via email.
Another way would be using browser push notifications. You could use OneSignal for this. You would setup the front end to display an alert to a customer user asking if they would like to subscribe to push notifications. When they subscribe, you will get back an ID for that specific user. Make an API call to your Laravel app, and store that ID in the users table (you will need a migration). Then from within your event listener, you can make a call to OneSignal's API and send the user a notification, which will popup on their computer.
Here is an example of using OneSignal to send an event to a user via the API:
Your OneSignal service:
<?php
namespace App\Services;
use App\User;
use GuzzleHttp\Client;
class OneSignalService
{
public function sendNotificationToUser(User $user, string $title, string $message, string $url, string $subtitle = null)
{
if (!$user->one_signal_id) {
return;
}
$fields = [
'app_id' => config('services.onesignal.app_id'),
'include_player_ids' => [$user->one_signal_id],
'headings' => ['en' => $title],
'contents' => ['en' => $message],
'url' => $url,
];
if ($subtitle) {
$fields['subtitle'] = ['en' => $subtitle];
}
$client = new Client([
'base_uri' => 'https://onesignal.com/api/v1/',
'headers' => [
'Content-Type' => 'application/json; charset=utf-8',
'Authorization' => 'Basic <<API_KEY>>',
]
]);
$client->request('POST', 'notifications', [
'json' => $fields
])
}
}
UserWalletNotification:
public function handle(UserWalletNewTransaction $event) {
$uid = $event->transaction->user_id;
$user = User::find($uid);
// now sends alert message to the user
$oneSignal = new OneSignalService();
$oneSignal->sendNotificationToUser($user, 'New Transaction', 'You have a new transaction', 'yourwebsite.com');
}
The way I would go about this would be via broadcasting, which would use websockets to instantly send the customer user an alert to their browser, in which you could then display a popup of some sort. You could install Laravel Echo Server, but to keep things simple you can use Pusher. Follow the guide to install on the front end of your website.
Then, create a private channel specific to a customer user "transaction.created.{{USER ID}}" and listen for it on your front end.
Within Laravel you will install the PHP Pusher SDK via composer.
Then within your .env file set:
BROADCAST_DRIVER=pusher
Next, open up channels.php within your routes directory in Laravel and add:
Broadcast::channel('transaction.created.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
This will verify authentication for your user to the private channel.
Create an Laravel Event:
<?php
namespace App\Events;
use App\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class TransactionCreated implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user = null;
public $transaction = null;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(User $user, UserWalletTransaction $transaction)
{
$this->user = $user;
$this->transaction = $transaction;
}
public function broadcastWith(): array
{
return $this->transaction->toArray(); //Or whatever information you want to send to the front end
}
public function broadcastAs(): string
{
return 'TransactionCreated';
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('transaction.created.' . $this->user->id);
}
}
Fire the event from UserWalletNotification:
public function handle(UserWalletNewTransaction $event) {
$uid = $event->transaction->user_id;
$user = User::find($uid);
// now sends alert message to the user
event(new TransactionCreated($user, $event->transaction));
}
Lastly, create some sort of popup and display it on the front end when your callback function for the private channel is hit.
If you need anymore help, feel free to comment.
What you want to do I believe, is asynchronous notifications.
Well, if you really mean flash messages - those who are stored in session - it will not be so easy.
Normal steps are create flash message for the user currently logged in on a website, stored in session that is unique for the current user. It can be shown only for this user.
What you want is to create flash message as the admin (from admin perspective) , then only to admin it can be shown.
I would do this, create new table, when these notification messages will be stored. Some table with columns like id, user_id, message, type, created_date, shown_date. Admins will put alert/notification messages for each user. Then create class (can be in controller for example) that will check this table for each user and if there is new not already shown message, show it normally in flash message for that current user. Dont forget to mark that message as shown. That is it.
So much for custom solution. I belive there must be some for example jQuery/other Jvascript plugins or Laravel plugins for asynchronous notifications, please check those.
I'm trying to join a presence channel (Public channels work well), but I can't get this to work:
Vue code:
mounted(){
Echo.join('game.' + "0").here((users) => {
alert("In the channel!");
})
.joining((user) => {
console.log("Someone entered");
})
.leaving((user) => {
console.log(user.name);
})
.listen('GameEvent', (e) => {
console.log("Hey")
});
Echo.channel('NewSentence')
.listen('NewSentence',(sentence)=>{
alert("HOLA");
});
}
I'm trying to join the channel "game.0". As I'm using Laravel Passport I need to authenticate myself with a token, and that is working. Sending the auth request for Laravel Echo returns a key, but the JavaScript events are not triggering .here(), .listening() ....
BroadcastService provider boot function:
public function boot() {
Broadcast::routes(["middleware" => "auth:api"]);
require base_path('routes/channels.php');
}
channels.php
Broadcast::channel('game.0', function ($user,$id) {
return ['id' => $user->id];
});
The auth route:
Route::post('/broadcasting/auth', function(Request $request){
$pusher = new Pusher\Pusher(
env('PUSHER_APP_KEY'),
env('PUSHER_APP_SECRET'),
env('PUSHER_APP_ID'),
array(
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => false,
'host' => '127.0.0.1',
'port' => 6001,
'scheme' => 'http',
)
);
return $pusher->socket_auth($request->request->get('channel_name'),$request->request->get('socket_id'));
});
Do I need to do something extra to make it work? This is the auth request:
EDIT:
GameEvent event:
class GameEvent implements ShouldBroadcastNow {
use Dispatchable, InteractsWithSockets, SerializesModels;
public $gameEvent;
public $gameId;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($gameEvent, $gameId) {
//
$this->gameEvent = $gameEvent;
$this->gameId = $gameId;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\PresenceChannel|array
*/
public function broadcastOn() {
//return new PrivateChannel('channel-name');
return new PresenceChannel('game.0');
}
public function broadcastWith() {
return $this->gameEvent;
}
}
EDIT:
I've hardcoded the names: 'game.0' is now hardcoded in the routes/channels.php route, in the Echo connection and in the GameEvent. I also removed broadcastAs(). After entering the laravel-websockets debugging dashboard I found that the channel I want to subscribe doesn't even appear. It looks like it won't start a connection, but I can't figure out what it going on.
I hardcoded the
The problem here seems to be that the Echo is not listening on proper channel. First of all the Echo.join is using channel game.0 in which 0 is a user's id, and i don't think that there is actually a user with id 0. Secondly, you are broadcasting as
GameEvent
and Echo is connecting to channel named game.{id} I suggest that you either remove the broadcastAs() function from your event file or listen on GameEvent. Also use the websocket dashboard for testing this. The dashboard will be available at
/laravel-websockets
route automatically, which is available only for local environment so make sure that environment is local in your .env.
Use the debugging dashboard provided by laravel-websockets to send data to channels, first connect to your web socket within the dashboard then just enter the channel name, event name and data in JSON format and hit send on the dashboard.
Try finding out if that helps with resolving your problem.
I also recommend thoroughly reading laravel's official documentation on broadcasting as well as laravel-websockets debugging dashboard guide.
Also update what you got in result to this question.