I’ve been trying to implement websocket in Laravel app. I’ve SMS UI ready but in order to make it work live I wanted to use ringcentral websocket.
I made a scheduler command which when run should invoke connection while keep checking if it is active every 5 sec.
<?php
namespace App\Console\Commands;
use App\Services\RCWebSocketService;
use Exception;
use Illuminate\Console\Command;
class RunRingCentralWebSocket extends Command
{
protected $signature = 'ringcentral:websocket';
protected $description = 'Run RingCentral WebSocket listener';
public function handle()
{
$service = new RCWebSocketService();
try {
if ($service->initializeConnection()) {
$this->info('WebSocket connected successfully');
while (true) {
try {
if (!$service->isConnected()) {
$this->warn('Connection or subscription lost, attempting to reconnect...');
$service->keepAlive();
}
sleep(5); // Check every 5 seconds
} catch (Exception $e) {
$this->error('Error in connection loop: ' . $e->getMessage());
// Wait a bit longer before retrying after an error
sleep(10);
}
}
} else {
$this->error('Failed to connect to WebSocket');
return 1;
}
} catch (Exception $e) {
$this->error('Fatal error: ' . $e->getMessage());
return 1;
}
}
}
Now obviously we can work around the time of rechecking and it would increase it(although would like to know what is the ideal time here?).
This is the ringcentral service, on which above commad relies on.
<?php
namespace App\Services;
use RingCentral\SDK\WebSocket\WebSocket;
use RingCentral\SDK\WebSocket\Subscription;
use RingCentral\SDK\WebSocket\Events\NotificationEvent;
use RingCentral\SDK\SDK;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;
use Exception;
class RCWebSocketService
{
private $rcsdk;
private $platform;
private $websocket;
private $subscription;
public function __construct()
{
$this->rcsdk = new SDK(
config('services.ring_central.websocket.client_id'),
config('services.ring_central.websocket.client_secret'),
config('services.ring_central.websocket.server_url')
);
}
public function initializeConnection()
{
try {
$this->platform = $this->rcsdk->platform();
$this->platform->login(["jwt" => config('services.ring_central.websocket.jwt')]);
$this->websocket = $this->rcsdk->initWebSocket();
// Add event listeners before connecting
$this->setupWebSocketListeners();
// Connect to WebSocket
$this->websocket->connect();
// Setup subscription after connection
$this->setupSubscription();
Cache::put('ringcentral_websocket_status', 'connected', now()->addHours(12));
return true;
} catch (Exception $e) {
Log::error('RingCentral WebSocket Connection Error: ' . $e->getMessage());
Cache::put('ringcentral_websocket_status', 'error', now()->addHours(1));
return false;
}
}
private function setupWebSocketListeners()
{
// Listen for WebSocket ready event
$this->websocket->addListener(WebSocket::EVENT_READY, function($event) {
Log::info('WebSocket connection ready');
});
// Listen for WebSocket errors
$this->websocket->addListener(WebSocket::EVENT_ERROR, function($event) {
Log::error('WebSocket Error: ' . $event->exception()->getMessage());
Cache::put('ringcentral_websocket_status', 'error', now()->addHours(1));
});
// Listen for WebSocket close
$this->websocket->addListener(WebSocket::EVENT_CLOSE, function($event) {
Log::info('WebSocket Connection Closed', [
'code' => $event->code(),
'reason' => $event->reason()
]);
Cache::put('ringcentral_websocket_status', 'closed', now()->addHours(1));
});
}
private function setupSubscription()
{
try {
$this->subscription = $this->rcsdk->createSubscription();
$this->subscription->addEvents(['/restapi/v1.0/account/~/extension/~/message-store/instant?type=SMS']);
// Add notification listener
$this->subscription->addListener(Subscription::EVENT_NOTIFICATION, function (NotificationEvent $e) {
$this->handleNotification($e->payload());
});
// Add subscription success listener
$this->subscription->addListener(Subscription::EVENT_SUBSCRIBE_SUCCESS, function($event) {
Log::info('Subscription successful', ['subscription_id' => $this->subscription->subscribed()]);
});
// Add subscription error listener
$this->subscription->addListener(Subscription::EVENT_SUBSCRIBE_ERROR, function($event) {
Log::error('Subscription error: ' . $event->exception()->getMessage());
});
$this->subscription->register();
} catch (Exception $e) {
Log::error('RingCentral Subscription Error: ' . $e->getMessage());
throw $e;
}
}
private function handleNotification(array $payload)
{
try {
Log::info('RingCentral Notification Received', ['payload' => $payload]);
event(new \App\Events\RingCentralMessageReceived($payload));
broadcast(new \App\Events\RingCentralMessageReceived($payload))->toOthers();
} catch (Exception $e) {
Log::error('Error handling RingCentral notification: ' . $e->getMessage(), [
'payload' => $payload
]);
}
}
public function keepAlive()
{
try {
// Check WebSocket connection
if (!$this->websocket || !$this->websocket->ready()) {
Log::info('WebSocket not ready, attempting to reconnect...');
return $this->initializeConnection();
}
// Check subscription status
if ($this->subscription && !$this->subscription->alive()) {
Log::info('Subscription not alive, attempting to resubscribe...');
$this->subscription->register();
}
return true;
} catch (Exception $e) {
Log::error('Error in keepAlive: ' . $e->getMessage());
return false;
}
}
public function disconnect()
{
try {
if ($this->websocket) {
$this->websocket->close();
Cache::put('ringcentral_websocket_status', 'disconnected', now()->addHours(1));
}
} catch (Exception $e) {
Log::error('Error disconnecting WebSocket: ' . $e->getMessage());
}
}
public function isConnected()
{
return $this->websocket && $this->websocket->ready() &&
$this->subscription && $this->subscription->subscribed();
}
}
The issue is related to isConnected method. I don’t think this works for PHP SDK. Is there a better way to check whether current connection isConnected or not. I don’t find any method in SDK to check that. Please help.