I'm attempting to use laravel-echo-server (socket.io) I'm getting a roadblock where the client-side doesn't appear to be getting any broadcasted events.
Everything seems to be connected fine and socket.io server is reporting that it's connecting and authorising the user however when I broadcast a message nothing seems to happen. The event is appearing on Laravel Horizon but otherwise, nothing happens. Here is my code:
server.js to run the laravel-echo-server:
require('dotenv').config();
const env = process.env;
require('laravel-echo-server').run({
authHost: env.APP_URL,
devMode: env.APP_DEBUG,
database: "redis",
databaseConfig: {
redis: {
host: env.REDIS_HOST_PUBLIC,
port: env.REDIS_PORT,
}
}
});
My channel in channel.php
Broadcast::channel('message.pushed', function () {
return true;
});
My event:
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class MessagePushed implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct()
{
$this->message = "My New Message";
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('message.pushed');
}
}
My event listener within app.js
import Echo from 'laravel-echo';
window.io = require('socket.io-client');
if (typeof io !== 'undefined') {
var token = $('meta[name="_token"]').attr('content')
window.Echo = new Echo({
auth : {
headers: {
Authorization: `Bearer ${token}`,
},
},
broadcaster: 'socket.io',
host : window.location.hostname + ':6001',
});
}
function listenForBroadcast() {
Echo.private('message.pushed')
.listen('MessagePushed', (e) => {
console.log(e)
console.log("Listened")
});
}
listenForBroadcast();
Lastly the route sending the message:
Route::get('/event-test', function () {
broadcast(new App\Events\MessagePushed());
});
I am not quite sure where i have gone wrong or why nothing is being picked up by the client.
While looking in laravel-echo-server the command line is echoing:
Channel: laravel_database_private-message.pushed
Event: App\Events\MessagePushed
In you browser you need to listen on Channel as shown by redis and also listen to the event as shown by redis, so changing your listenForBroadcast() method may help.
In the code, Channel name changed from message.pushed to laravel_database_private-message.pushed and Event name changed from MessagePushed to .App\Events\MessagePushed ( Do not miss dot prefix to App )
function listenForBroadcast() {
Echo.private('laravel_database_private-message.pushed')
.listen('.App\\Events\\MessagePushed', (e) => {
console.log(e)
console.log("Listened")
});
}
I tried this solution based on the solution given in the following link and it worked for me
laravel Echo does not listen to channel and events
Related
Here is my .env code->
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=xxxxx
PUSHER_APP_KEY=xxxxx
PUSHER_APP_SECRET=xxxxx
PUSHER_APP_CLUSTER=xxxxx
Here is my config code ->
'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'),
'useTLS' => true,
'encrypted' => true,
],
],
Here is my event code ->
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class orderEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public $text;
public function __construct($text)
{
$this->text = $text;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('fish20');
}
}
and finally here is my route for testing from which i trigger the event but nothing actually happens :( . ->
Route::get('/get', function () {
$text = 'New order received.';
event(new orderEvent($text));
});
I cannot see any event triggered on debug console
of my pusher channel.
You should use broadcast(new orderEvent($text)); instead of event(new orderEvent($text)); in your route.
I got the solution. for some reason laravel uses Queue in events and my queue connection was database so like this -> QUEUE_CONNECTION=database and i removed that and made it sync so that it gets trigger and dosent queue it for later like this -> QUEUE_CONNECTION=sync
Also there is another way on your event file instead of ShouldBroadcast use this -> ShouldBroadcastNow
You need to share your client side code too.
If you forgot to implement the client code, you can read the official document about Broadcasting. I also found this tutorial which uses an older version of Laravel, but the concept hasn't changed much.
I am using Laravel Websockets package.Everything looks great on server side but Laravel Echo is not listening to events..
MySocketEvent.php:
<?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;
class MySocketEvent 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()
{
return new Channel('DemoChannel.1');
}
public function broadcastAs()
{
return 'testing';
}
}
Web.php
Route::get('tests',function(){
$arr=['some'=>'some'];
broadcast(new \App\Events\MySocketEvent($arr));
return view('hi');
});
Bootstrap.js
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
//key: process.env.MIX_PUSHER_APP_KEY,
key: 'my-key',
wsHost: window.location.hostname,
wsPort: 6001,
wssPort: 6001,
disableStats: true,
cluster: 'ap2',
//cluster: process.env.MIX_PUSHER_APP_CLUSTER,
//encrypted: true
});
//subscribe-for-the-test-demo-channel-and-listen
window.Echo.channel('DemoChannel.1')
.listen('.testing', (e) => {
console.log("Received Data: ");
console.log(e);
});
I see the data sent from server by using php artisan WebSockets:serve but Laravel Echo does not listen. Please help. I'm 100% sure problem is with Laravel Echo.
The "dot" before "testing"
Broadcasting As "testing"
Listening For ".testing"
Replace this
window.Echo.channel('DemoChannel.1')
.listen('.testing', (e) => {
console.log("Received Data: ");
console.log(e);
});
To this
window.Echo.channel('DemoChannel.1')
.listen('testing', (e) => {
console.log("Received Data: ");
console.log(e);
});
Update:
Add this line to your event file
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
Replace this
class MySocketEvent implements ShouldBroadcast
To this
class MySocketEvent implements ShouldBroadcastNow
I was able to get Echo working by downgrading pusher to 4.4.0
npm install pusher-js#4.4.0
This is app.js file;
const MyTest = require('./testApp');
const App = new MyTest();
App.on('ready', () => {
console.log('Hello World');
});
Package.json file. (in) ./testApp/package.json;
{
...
"main": "main.js"
...
}
This is ./testApp/main.js file;
const EventEmitter = require('events'); // node event module
class Client extends EventEmitter {
constructor() {
super();
this.sendReady();
}
sendReady() {
this.emit('ready');
}
}
module.exports = Client;
If "App" is successfully installed in the app.js file, I want the console to write " Hello World". I've changed a few times this content because I want to more simple.
I want to trigger App.on in app.js from ./testApp/main.js
If I define a function in the constructor, I can get it by calling "App." In this case this = App
Then, why don't emit anything?
Note: this app files working locally.
The emit call is in Client's constructor, i.e. it gets called when you invoke
const helper = new pulseHelper.Client();
However, you only register the ready handler after that. EventEmitters don't buffer their events; only listeners registered during the emit call will ever be able to act on the events.
EDIT: to clarify what I'm talking about, see this example:
const EventEmitter = require('events');
class Client extends EventEmitter {
constructor() {
super();
this.emit('ready', 'I\'m Ready!');
}
boom() {
this.emit('ready', 'Boom!');
}
emit(event, payload) {
console.log('Emitting', event, ':', payload);
super.emit(event, payload);
}
}
const c = new Client();
c.on('ready', (payload) => console.log(payload));
c.boom();
This prints (with annotations):
# client constructed, it emits an event but no one is listening.
# however the "debug" emit() implementation prints this:
Emitting ready : I'm Ready!
# the listener has been registered, now let's call .boom()!
# the "debug" emit() implementation prints this:
Emitting ready : Boom!
# and the handler prints the following:
Boom!
The basic XMPP with strophe and javascript wants to convert to AngularJS.
.controller('loginCtrl', function(xmppAuth) {
xmppAuth.auth(login, password);
})
and in service:
.service('xmppAuth', function() {
.return {
auth: function(login, password) {
connect = new Strophe.Connection(domain);
connect.connect(login, password, function (status) {
if (status === Strophe.Status.CONNECTED) {
connect.addHandler(on_roster_changed,"jabber:iq:roster", "iq", "set");
connect.addHandler(on_iq, null, "iq","");
connect.addHandler(on_presence, null, "presence");
connect.addHandler(on_message, null, 'message', '');
}
}
}
}
})
in js file
var on_presence = function(presence){
code
}
when i run this there is no error. But all handling events like on_presence() method called only once. this is handler event of Strophe Connection object. Is there is any remain in this code or what should i do for handling strophes event with angularJS?
I refered This Link but it not works.
See the Strophe.js docs for addHandler:
The handler should return true if it is to be invoked again; returning false will remove the handler after it returns.
Therefore, your on_presence code should return true if you want it to be invoked again:
var on_presence = function(presence) {
// do some stuff
return true;
};
I have a basic XMPP client working on strophe.js.
On login I create handlers such as
connect = new Strophe.Connection('http://localhost/http-bind');
...
...
connect.addHandler(on_message, null, "message", "chat");
connect.addHandler(on_presence, null, "presence");
...
...
and then I "listen" to those
function on_presence(presence) {
// handling presence
}
function on_message(presence) {
// handling presence
}
So I am trying to "convert" it into AngularJS. The first part is pretty straight forward. I have a controller which handles the login part just fine:
angular.module('app').controller('loginCtrl', function($scope) {
connect = new Strophe.Connection('http://website.com/http-bind');
connect.connect(data.jid, data.password, function (status) {
if (status === Strophe.Status.CONNECTED) {
connect.addHandler(on_message, null, "message", "chat");
connect.addHandler(on_presence, null, "presence");
}
}
})
But how do I actually begin listening to those events (on_message, on_presence) in the context of angular across all the controllers I have.
Wrap Strophe in an Angular Service. Angular Services are meant to be use as singletons, so you will be able to instantiate the Strophe Service once, and use it everywhere (using Dependency Injection).
As suggested above (or bellow) I wrapped strophe in a service so my login "mechanism" looks like this:
.controller('loginCtrl', function(xmppAuth) {
xmppAuth.auth(login, password);
})
any my service:
.service('xmppAuth', function() {
return {
auth: function(login, password) {
connect = new Strophe.Connection('http://mydomain.net/http-bind');
connect.connect(login, password, function (status) {
if (status === Strophe.Status.CONNECTED) {
// we are in, addHandlers and stuff
}
}
}
}
})
Or may be you can create a module for Strophe and then include the module in your app, and then include strophe as a variable where ever you want to use it.