I'm trying to send events to private channel, but I can't receive them.
Otherwise it works fine for public channels.
Here's my code :
Plugin : Echo.js
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_PUBLIC_KEY,
wsHost: process.env.VUE_APP_WEBSOCKETS_SERVER , //window.location.hostname,//
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
wsPort: 6001,
forceTLS: false,
/* key: process.env.MIX_ABLY_PUBLIC_KEY,
wsHost: 'realtime-pusher.ably.io',
wsPort: 443, */
disableStats: true,
encrypted: true,
auth: {
headers: {
'X-CSRF-TOKEN': Cookies.get('XSRF-TOKEN'),
},
},
authorizer: (channel, options) => {
return {
authorize: (socketId, callback) => {
axios.post(process.env.VUE_APP_WEBSOCKETS_SERVER+'/api/broadcasting/auth', {
socket_id: socketId,
channel_name: channel.name
})
.then(response => {
callback(false, response.data);
})
.catch(error => {
callback(true, error);
});
}
};
},
})
Laravel 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'),
'useTLS' => false,
'encrypted' => true,
'host' => '127.0.0.1',
'port' => 6001,
'scheme' => 'http',
],
Api Routes :
Broadcast::routes(['middleware' => ['auth:sanctum']]);
Client Side :
created() {
Pusher.logToConsole = true;
Echo.logToConsole = true;
window.Echo.private('shop')
.listen('MessageSent', (e) => {
console.log('Hi' + e)
})
},
I notice that pusher subscribed to the channel with no errors, but the result in console is like this :
Pusher : : ["Event sent",{"event":"pusher:subscribe","data":{"channel":"private-shop"}}]
Hi maybe this could help you. Please make sure that the response in the authorize function is used correctly. I realize after a while that the response token was send as response not response.data. Try this.
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_PUBLIC_KEY,
wsHost: process.env.VUE_APP_WEBSOCKETS_SERVER , //window.location.hostname,//
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
wsPort: 6001,
forceTLS: false,
/* key: process.env.MIX_ABLY_PUBLIC_KEY,
wsHost: 'realtime-pusher.ably.io',
wsPort: 443, */
disableStats: true,
encrypted: true,
auth: {
headers: {
'X-CSRF-TOKEN': Cookies.get('XSRF-TOKEN'),
},
},
authorizer: (channel, options) => {
return {
authorize: (socketId, callback) => {
axios.post(process.env.VUE_APP_WEBSOCKETS_SERVER+'/api/broadcasting/auth', {
socket_id: socketId,
channel_name: channel.name
})
.then(response => {
callback(false, response);
})
.catch(error => {
callback(true, error);
});
}
};
},
})
Related
I have some issues about to connect to broadcasting from React
I sure don't have any error on my code, this is my code
on my broadcast.php on config folder
'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,
'host' => '192.168.0.114',
'port' => 6001,
'scheme' => 'http'
],
],
and on my api.php on route folder i am adding
Broadcast::routes(['middleware' => ['api', 'auth:sanctum']]);
on .env file
PUSHER_APP_ID=osamah
PUSHER_APP_KEY=osamah
PUSHER_APP_SECRET=osamah
PUSHER_APP_CLUSTER=mt1
on channel.php
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
on my react listen
const echo = new Echo({
broadcaster: 'pusher',
key: 'osamah',
cluster: 'mt1',
wsHost: '192.168.0.114',
wsPort: 6001,
forceTLS: false,
disableStats: true,
authEndpoint: "http://192.168.0.114/api/broadcasting/auth",
auth: {
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer 1542|3hVrlJ3A968IeZ23kejqTp8CJ9p4RCkcj66gRK4z'
},
}
});
echo.connector.pusher.connection.bind('connected', () => {
console.log('connected');
axios.get(`http://192.168.0.114/api/count`, {
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer 1542|3hVrlJ3A968IeZ23kejqTp8CJ9p4RCkcj66gRK4z'
},
})
.then(res => {
console.log(res);
})
});
echo.private('App.Models.User.393').notification((e)=>console.log(e.user));
I want to use Laravel Echo Server as Pusher replacement
I am seeking the Laracast tutorial series for Laravel broadcasting: https://laracasts.com/series/get-real-with-laravel-echo.
I have succesfully created a testing javascript client that listens to the events for channel orders. This is the client code:
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: true
});
window.Echo.channel('orders')
.listen('OrderStatusUpdate', e => {
console.log("Status has been updated behind the scenes.")
console.log(e);
});
But the company where I work requires to have their own websocket resource, so we cannot depends upon Pusher.
Then, we are working on Laravel Echo Server: https://github.com/tlaverdure/Laravel-Echo-Server. Almost everything is working. We have changed the config/broadcasting.php options to fit to Laravel Echo Server. And successfully we can see the events being emitted inside laravel echo log, just changing some configuratons parameters in config/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'),
'useTLS' => false,
'host' => '192.168.15.36',
'port' => 6001,
'scheme' => 'http'
],
'client_options' => [
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
],
],
The address 192.168.15.36 is the local ip address.
Also changed the client code to deal with the changes:
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
forceTLS: false,
wsHost: '192.168.15.36',
wsPort: 6001,
encrypted: false,
enabledTransports: ['ws']
});
window.Echo.channel('orders')
.listen('OrderStatusUpdate', e => {
console.log("Status has been updated behind the scenes.")
console.log(e);
});
And the .env is:
PUSHER_APP_ID=5073cdd7d79e501f
PUSHER_APP_KEY=3ad3a4d1eb46d4d4794533414dce747a
PUSHER_APP_SECRET=
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
But in the client javascript (using Chrome) I see an error message in the browser console: WebSocket connection to 'ws://192.168.15.36:6001/app/3ad3a4d1eb46d4d4794533414dce747a?protocol=7&client=js&version=7.0.6&flash=false' failed: Connection closed before receiving a handshake response.
How to solve this problem? Is there something that is needed furthermore to make Laravel Echo Server works as a Pusher replacement?
May worth show here the laravel echo server settings as well:
{
"authHost": "http://192.168.15.36",
"authEndpoint": "/broadcasting/auth",
"clients": [
{
"appId": "5073cdd7d79e501f",
"key": "3ad3a4d1eb46d4d4794533414dce747a"
}
],
"database": "redis",
"databaseConfig": {
"redis": {},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
}
},
"devMode": true,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"secureOptions": 67108864,
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": "",
"subscribers": {
"http": true,
"redis": true
},
"apiOriginAllow": {
"allowCors": true,
"allowOrigin": "http://192.168.15.36:80",
"allowMethods": "GET, POST",
"allowHeaders": "Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id"
}
}
The Problem is Laravel-Websockets and Laravel-Echo combination works fine until you want to secure the connection by using SSL HTTP -> HTTPS
so I installed SSL Certificate on LocalHost (xampp, also I tried that on the live server too and got the same error) and changed the forceTLS: false to forceTLS: true, but I keep getting the Provisional headers are shown error on chrome network tab I even tried Laravel CORS
bootstrap.js be like :
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: true,
wsHost: window.location.hostname,
wsPort: 6001,
wssPort: 6001,
disableStats: true,
devMode : true,
});
broadcast.php be like :
'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,
'host' => 'websocket8.test', // I read somewhere it's better to use domain name when we are working with HTTPS
'port' => 6001,
'scheme' => env('PUSHER_SCHEME'),
'curl_options' => [
CURLOPT_SSL_VERIFYHOST => 0,
CURLOPT_SSL_VERIFYPEER => 0,
],
],
],
if you asking for .env file :
PUSHER_APP_ID={a random id}
PUSHER_APP_KEY={a random key}
PUSHER_APP_SECRET={a random secret}
PUSHER_APP_CLUSTER=mt1
PUSHER_SCHEME=http
LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT="E:/Software/Xampp/apache/conf/ssl.crt"
LARAVEL_WEBSOCKETS_SSL_LOCAL_PK="E:/Software/Xampp/apache/conf/ssl.key"
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
chrome network tab error is like this:
I'm trying to broadcasting to presence channel. But auth seems to not send a member data.
Versions
composer.json
"laravel/framework": "6.20.22",
"laravel/passport": "9.0",
"predis/predis": "1.1.7",
package.json
laravel-echo-server: 1.6.2
"socket.io-client": "2.4.0",
"laravel-echo": "1.10.0",
Server side
.env
BROADCAST_DRIVER=redis
QUEUE_CONNECTION=sync
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
REDIS_PREFIX=
laravel-echo-server.json
{
"authHost": "http://localhost:8080",
"authEndpoint": "/custom/broadcasting/auth",
"clients": [],
"database": "redis",
"databaseConfig": {
"redis": {},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
}
},
"devMode": true,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"secureOptions": 67108864,
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": "",
"subscribers": {
"http": true,
"redis": true
}
}
web.php
Route::post('/custom/broadcasting/auth', function (\Illuminate\Http\Request $request) {
Log::debug('custom auth');
$user = User::where('id', 1)->first();
return [$user->name];
});
Route::post('/messages', function (\Illuminate\Http\Request $request) {
broadcast(new \App\Events\MyEvent($request->clientId, $request->message));
return [
'message' => $request->message
];
});
MyEvent.php
class MyEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
public $clientID;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($clientID, $message)
{
$this->message = $message;
$this->clientID = $clientID;
}
public function broadcastOn()
{
return new PresenceChannel('chat.' . $this->clientID);
}
}
config/database.php
'redis' => [
'client' => env('REDIS_CLIENT', 'predis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],
],
client side
bootstrap.js
import Echo from "laravel-echo"
window.io = require('socket.io-client');
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':8080',
authEndpoint: '/custom/broadcasting/auth',
authorizer: (channel, options) => {
return {
authorize: (socketId, callback) => {
axios.post('/custom/broadcasting/auth', {
socket_id: socketId,
channel_name: channel.name
})
.then(response => {
callback(false, response.data);
})
.catch(error => {
callback(true, error);
});
}
};
},
});
client.vue
export default {
props: ['clientId'],
data: function () {
return {
messages: [],
newMessage: '',
statusMessage: 'Joined a room',
isStarted: false,
members: [],
checkedMember: '',
}
},
created() {
},
computed: {
channel() {
var joining = window.Echo.join(`chat.${this.clientId}`)
console.log(joining);
return window.Echo.join(`chat.${this.clientId}`)
}
},
mounted() {
console.log(`Joining to chat.${this.clientId}`)
console.log('this channel', this.channel);
this.channel.here((users) => {
console.log(`Joined chat.${this.clientId}`)
this.members = users;
})
.joining((user) => {
console.log('Joining ', JSON.stringify(user));
this.members.put(user)
})
.leaving((user) => {
this.members = this.members.filter(member => user.id !== member.id)
console.log(`leaved ${user.name}`);
})
.error((error) => {
console.error(error);
})
.listen('MyEvent', (e) => {
console.log(e);
this.messages.push({
message: e.message.message,
user: e.user
});
});
},
methods: {
addMessage(clientId, message) {
axios.post('/messages', {
clientId,
message
}).then(response => {
this.messages.push({
message: response.data.message.message,
// user: response.data.user
});
});
},
sendMessage() {
this.addMessage(this.clientId, this.newMessage);
this.newMessage = '';
},
sendStartMessage() {
this.statusMessage = 'Started';
this.isStarted = true;
this.addMessage(this.clientId, 'start');
},
sendStopMessage() {
this.statusMessage = 'Ready';
this.isStarted = false;
this.addMessage(this.clientId, 'stop');
}
}
}
</script>
console debug
SocketIoPresenceChannel {events: {…}, listeners: {…}, name: "presence-chat.my-client-id", socket: Socket, options: {…}, …}
ㄴ eventFormatter: EventFormatter {namespace: "App.Events"}
ㄴ events: {presence:subscribed: ƒ, presence:joining: ƒ, presence:leaving: ƒ, App\Events\MyEvent: ƒ}
ㄴ listeners: {presence:subscribed: Array(1), presence:joining: Array(1), presence:leaving: Array(1), App\Events\MyEvent: Array(1)}
name: "presence-chat.my-client-id"
ㄴ options: {auth: {…}, authEndpoint: "/custom/broadcasting/auth", broadcaster: "socket.io", csrfToken: null, host: "localhost:8080", …}
ㄴ socket: Socket {io: Manager, nsp: "/", json: Socket, ids: 0, acks: {…}, …}
__proto__: SocketIoPrivateChannel
If I try with private and public channel, It works.
But If I try with Presence channel, always not working.
laravel echo server said
Event: [object Object]
(node:75981) UnhandledPromiseRejectionWarning: TypeError: Cannot convert undefined or null to object
at /Users/myname/.nvm/versions/node/v14.5.0/lib/node_modules/laravel-echo-server/dist/channels/presence-channel.js:78:21
at processTicksAndRejections (internal/process/task_queues.js:93:5)
(node:75981) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3)
Unable to join channel. Member data for presence channel missing
And wired thing is that I can listen an event.
Could you let me know the problem?
i'm new to websockets and pusher i did follow the documentation and this tuto https://www.youtube.com/watch?v=7MvN0w5BW48 but i got this error that says Unable to retrieve auth string from auth endpoint - received status: 403 from /broadcasting/auth. Clients must be authenticated to join private or presence channels.
bootstrap.js
import Echo from "laravel-echo";
let token = localStorage.getItem("token");
window.Pusher = require("pusher-js");
window.Echo = new Echo({
broadcaster: "pusher",
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
wsHost: window.location.hostname,
wsPort: 6001,
wssPort: 6001,
forceTLS: false,
disableStats: true,
enabledTransports: ["ws", "wss"],
encrypted: false,
auth: {
headers: {
Authorization: "Bearer " + token
}
}
});
broadcasting.php
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Broadcaster
|--------------------------------------------------------------------------
|
| This option controls the default broadcaster that will be used by the
| framework when an event needs to be broadcast. You may set this to
| any of the connections defined in the "connections" array below.
|
| Supported: "pusher", "ably", "redis", "log", "null"
|
*/
'default' => env('BROADCAST_DRIVER', 'null'),
/*
|--------------------------------------------------------------------------
| Broadcast Connections
|--------------------------------------------------------------------------
|
| Here you may define all of the broadcast connections that will be used
| to broadcast events to other systems or over websockets. Samples of
| each available type of connection are provided inside this array.
|
*/
'connections' => [
'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,
'host' => '127.0.0.1',
'port' => 6001,
'scheme' => 'http',
'curl_options' => [
CURLOPT_SSL_VERIFYHOST => 0,
CURLOPT_SSL_VERIFYPEER => 0,
]
],
],
'ably' => [
'driver' => 'ably',
'key' => env('ABLY_KEY'),
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
],
'log' => [
'driver' => 'log',
],
'null' => [
'driver' => 'null',
],
],
];
channels.php
<?php
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
and this a part of createTask.vue
Echo.join('chat')
.here((users) => {
console.log("present user ",users)
})
.joining((user) => {
console.log(user.name);
})
.leaving((user) => {
console.log(user.name);
})
.error((error) => {
console.error(error);
});