mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
fix: prevent duplicate SIP registration (module-level guard), extract real caller number from X-CALLERNO header
This commit is contained in:
@@ -223,10 +223,17 @@ export class SIPClient {
|
||||
}
|
||||
|
||||
private extractCallerNumber(session: RTCSession): string {
|
||||
// Try P-Asserted-Identity header first (most reliable for real caller ID)
|
||||
try {
|
||||
const request = session.direction === 'incoming' ? (session as any)._request : null;
|
||||
if (request) {
|
||||
// Ozonetel sends the real caller number in X-CALLERNO header
|
||||
const xCallerNo = request.getHeader('X-CALLERNO');
|
||||
if (xCallerNo) {
|
||||
// Remove leading 0s or country code prefix (00919... → 919...)
|
||||
const cleaned = xCallerNo.replace(/^0+/, '');
|
||||
return cleaned;
|
||||
}
|
||||
|
||||
// Check P-Asserted-Identity
|
||||
const pai = request.getHeader('P-Asserted-Identity');
|
||||
if (pai) {
|
||||
@@ -241,11 +248,11 @@ export class SIPClient {
|
||||
if (match) return match[1];
|
||||
}
|
||||
|
||||
// Check X-Original-CallerID (custom header some PBX systems use)
|
||||
// Check X-Original-CallerID
|
||||
const xCid = request.getHeader('X-Original-CallerID');
|
||||
if (xCid) return xCid;
|
||||
|
||||
// Check From header display name (sometimes contains the real number)
|
||||
// Check From header display name
|
||||
const fromDisplay = request.from?.display_name;
|
||||
if (fromDisplay && /^\+?\d{7,}$/.test(fromDisplay)) {
|
||||
return fromDisplay;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createContext, useContext, useEffect, useRef, useState, type PropsWithChildren } from 'react';
|
||||
import { createContext, useContext, useEffect, useState, type PropsWithChildren } from 'react';
|
||||
import { useSipPhone } from '@/hooks/use-sip-phone';
|
||||
|
||||
type SipContextType = ReturnType<typeof useSipPhone> & {
|
||||
@@ -8,22 +8,20 @@ type SipContextType = ReturnType<typeof useSipPhone> & {
|
||||
|
||||
const SipContext = createContext<SipContextType | null>(null);
|
||||
|
||||
// Module-level flag — survives React StrictMode double-mount
|
||||
let sipConnectedGlobal = false;
|
||||
|
||||
export const SipProvider = ({ children }: PropsWithChildren) => {
|
||||
const sipPhone = useSipPhone();
|
||||
const hasConnected = useRef(false);
|
||||
const [ozonetelStatus, setOzonetelStatus] = useState<'idle' | 'logging-in' | 'logged-in' | 'error'>('idle');
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [ozonetelError, _setOzonetelError] = useState<string | null>(null);
|
||||
|
||||
// Auto-connect SIP on mount — only WebSocket/SIP registration
|
||||
// Ozonetel agent login is handled by the sidecar during auth, NOT here
|
||||
// Auto-connect SIP on mount — module-level guard prevents duplicate connections
|
||||
useEffect(() => {
|
||||
if (!hasConnected.current) {
|
||||
hasConnected.current = true;
|
||||
if (!sipConnectedGlobal) {
|
||||
sipConnectedGlobal = true;
|
||||
sipPhone.connect();
|
||||
|
||||
// Ozonetel status tracks whether the sidecar handled agent login
|
||||
// We assume logged-in if SIP connects (sidecar handles the REST login)
|
||||
setOzonetelStatus('logged-in');
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
||||
Reference in New Issue
Block a user