Skip to main content
Question

How to verify if a websocket connection is active or not in Laravel/PHP?


Forum|alt.badge.img

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.

2 replies

PhongVu
Community Manager
Forum|alt.badge.img
  • Community Manager
  • 2312 replies
  • January 17, 2025

I don’t see any method to check the WS connection. In stead, I think you can add the EVENT_CLOSE  to the event listener to be notified if the WS connection is closed.

https://github.com/ringcentral/ringcentral-php/blob/master/src/WebSocket/WebSocketTest.php#L77


Forum|alt.badge.img
  • Author
  • New Participant
  • 1 reply
  • February 3, 2025

If my connection is already closed, will I receive this event or if EVENT_CLOSE will always be sent before it get’s disconnected?

 


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings