fix: prevent StrictMode double-mount from killing SIP WebSocket connection

This commit is contained in:
2026-03-17 20:08:22 +05:30
parent b2cc3d7012
commit d54d54f5f3
3 changed files with 30 additions and 5 deletions

View File

@@ -71,6 +71,11 @@ export const useSipPhone = (config?: Partial<SIPConfig>) => {
return;
}
// Don't reconnect if already connected or connecting
if (sipClientRef.current?.isConnected() || sipClientRef.current?.isRegistered()) {
return;
}
if (sipClientRef.current) {
sipClientRef.current.disconnect();
}
@@ -127,11 +132,15 @@ export const useSipPhone = (config?: Partial<SIPConfig>) => {
setIsOnHold(!isOnHold);
}, [isOnHold]);
// Cleanup on unmount
// Cleanup only on actual page unload, not StrictMode remount
useEffect(() => {
return () => {
const handleUnload = () => {
sipClientRef.current?.disconnect();
};
window.addEventListener('beforeunload', handleUnload);
return () => {
window.removeEventListener('beforeunload', handleUnload);
};
}, []);
return {

View File

@@ -15,15 +15,26 @@ export class SIPClient {
) {}
connect(): void {
// Enable JsSIP debug logging to diagnose connection issues
JsSIP.debug.enable('JsSIP:*');
const socket = new JsSIP.WebSocketInterface(this.config.wsServer);
// Extract SIP ID from URI for authorization_user
// URI format: sip:521814@blr-pub-rtc4.ozonetel.com
const sipId = this.config.uri.replace('sip:', '').split('@')[0];
const configuration: UAConfiguration = {
sockets: [socket],
uri: this.config.uri,
password: this.config.password,
authorization_user: sipId,
display_name: this.config.displayName,
register: true,
register_expires: 120,
session_timers: false,
connection_recovery_min_interval: 2,
connection_recovery_max_interval: 30,
};
this.ua = new JsSIP.UA(configuration);

View File

@@ -1,4 +1,4 @@
import { createContext, useContext, useEffect, type PropsWithChildren } from 'react';
import { createContext, useContext, useEffect, useRef, type PropsWithChildren } from 'react';
import { useSipPhone } from '@/hooks/use-sip-phone';
type SipContextType = ReturnType<typeof useSipPhone>;
@@ -7,10 +7,15 @@ const SipContext = createContext<SipContextType | null>(null);
export const SipProvider = ({ children }: PropsWithChildren) => {
const sipPhone = useSipPhone();
const hasConnected = useRef(false);
// Auto-connect on mount
// Auto-connect on mount — skip StrictMode double-fire
useEffect(() => {
sipPhone.connect();
if (!hasConnected.current) {
hasConnected.current = true;
sipPhone.connect();
}
// Do NOT disconnect on cleanup — the SIP connection should persist
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);