I'm creating a chat feature using pusher private channel. When someone from the same thread sends a message, other people in that thread receive the message.
I have created the code as bellow, but I get error messages:
Error: JSON returned from channel-authorization endpoint was invalid, yet status code was 200
Controller
public function store(Request $request)
{
$thread = Thread::findOrFail($request->thread_id);
Message::create([
'thread_id' => $thread->id,
'user_id' => Auth::id(),
'body' => $request->body,
]);
event(new NewMessage($thread->id, Auth::user()->id, $request->body));
event(new MessageCreated());
return response()->json([
'status' => 'success',
'message' => 'Your message has been sent successfully.',
]);
}
Event
<?php
namespace App\Events;
use App\Models\User;
use Cmgmyr\Messenger\Models\Thread;
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 $thread_id;
public $user_id;
public $message;
public function __construct($thread_id, $user_id, $message)
{
$this->thread_id = $thread_id;
$this->user_id = $user_id;
$this->message = $message;
}
public function broadcastOn(): array
{
return [
new PrivateChannel('my-thread.' . $this->thread_id)
];
}
public function broadcastAs(): string
{
return 'new-message';
}
}
BroadcastServiceProvider
public function boot(): void
{
Broadcast::routes(['middleware' => ['auth:sanctum']]);
require base_path('routes/channels.php');
}
Channels route
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
Broadcast::channel('my-thread.{threadId}', function ($user,$threadId) {
$thread = Thread::find($threadId);
$participant = $thread->participants()->where('user_id', $user->id)->first();
return (int) $participant->user_id === (int) $user->id;
});
pusher.js
import axios from 'axios';
window.axios = axios;
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: '21fa0caff88313',
cluster: 'mt1',
forceTLS: true,
encrypted: true,
authorizer: (channel) => {
return {
authorize: (socketId, callback) => {
axios.post('/broadcasting/auth', {
socket_id: socketId,
channel_name: channel.name
})
.then(response => {
callback(false, response.data);
})
.catch(error => {
callback(true, 'error');
});
}
};
},
});
Pusher.logToConsole = false;
window.pusher = new Pusher('21fa0caff88313', {
cluster: 'mt1',
authEndpoint: `/broadcasting/auth`,
auth: {
headers: {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json"
},
}
});
console.log('pusher.js loaded');
Blade
@vite('resources/js/pusher.js')
<script src="https://js.pusher.com/8.2.0/pusher.min.js"></script>
<script type="module">
Pusher.logToConsole = true;
var thread_id = new URL(window.location.href).searchParams.get('id');
var user_id = "{{ auth()->user()->id }}";
console.log('private-my-thread.' + thread_id);
var thread = pusher.subscribe('private-my-thread.' + thread_id);
thread.bind('new-message', function(data) {
console.log('new message', data);
// if (data.thread_id == thread_id) {
getMessages();
// }
});
var message = pusher.subscribe('my-chat');
message.bind('message-created', function(data) {
getMessages();
});
</script>
From these code examples, I tried private channels and public channels. Public channels can work, but private channels cannot work. How to fix this?
And also, in pusher.js, I put the pusher credentials directly in the file. Because if I make it like the below, the pusher can't work, or I get an error message:
- Uncaught Options object must provide a cluster
- Uncaught ReferenceError: pusher is not defined
old-pusher.js
import axios from 'axios';
window.axios = axios;
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
authorizer: (channel) => {
return {
authorize: (socketId, callback) => {
axios.post('/broadcasting/auth', {
socket_id: socketId,
channel_name: channel.name
})
.then(response => {
callback(false, response.data);
})
.catch(error => {
callback(true, error);
});
}
};
},
});
window.Pusher.logToConsole = false;
window.pusher = new window.Pusher(import.meta.env.VITE_PUSHER_APP_KEY, {
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
authEndpoint: `/broadcasting/auth`,
auth: {
headers: {
"Access-Control-Allow-Origin": "*",
}
}
});
Note: i also use laravel messenger package: https://github.com/cmgmyr/laravel-messenger
I have tried making the code as above. For public channels, it was successful, but for private channels, it was not successful.