Skip to content

Commit

Permalink
fix: missing phone island on incoming call (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyco97 authored Jan 20, 2025
1 parent 1ca563a commit a30e510
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 101 deletions.
190 changes: 113 additions & 77 deletions src/components/Socket.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,105 +94,141 @@ export const Socket: FC<SocketProps> = ({
// With conversation
if (res.status) {
const { extensions } = store.getState().users
const { default_device } = store.getState().currentUser
const { endpoints, username } = store.getState().currentUser
const { incoming, outgoing } = store.getState().currentCall

const hasOnlineNethlink = () => {
if (!extensions || !username) return false

// Get all extensions for current user
const userExtensions: any = Object.values(extensions).filter(
(ext) => ext?.username === username,
)

// Check if any extension is nethlink type and online
return userExtensions?.some((ext) => {
const endpointExtension = endpoints?.extension.find(
(endpoint) => endpoint.id === ext?.exten,
)
return endpointExtension?.type === 'nethlink' && ext?.status !== 'offline'
})
}
switch (res.status) {
case 'ringing':
// The name and the number are updated here not in webrtc
dispatch.currentCall.checkIncomingUpdatePlay({
conversationId: conv.id,
displayName: getDisplayName(conv),
number: `${conv.counterpartNum}`,
incomingSocket: true,
username:
`${
extensions &&
extensions[conv.counterpartNum] &&
extensions[conv.counterpartNum].username
}` || '',
ownerExtension: conv.owner,
})

eventDispatch('phone-island-call-ringing', {})

break
// @ts-ignore
case 'busy':
if (conv && conv.connected) {
// Current call accepted and update connected call
dispatch.currentCall.updateCurrentCall({
if (
(uaType === 'mobile' && hasOnlineNethlink()) ||
(uaType === 'desktop' &&
(default_device?.type === 'webrtc' ||
(default_device?.type === undefined && !hasOnlineNethlink()) ||
(!hasOnlineNethlink() && default_device?.type === 'physical')))
) {
dispatch.currentCall.checkIncomingUpdatePlay({
conversationId: conv.id,
displayName: getDisplayName(conv),
number: `${conv.counterpartNum}`,
ownerExtension: conv.owner,
incomingSocket: true,
username:
`${
extensions &&
extensions[conv.counterpartNum] &&
extensions[conv.counterpartNum].username
}` || '',
ownerExtension: conv.owner,
})
// Update the current call informations for physical devices
dispatch.currentCall.checkAcceptedUpdate({
acceptedSocket: true,
})
// Add call to transfer calls
dispatch.currentCall.addTransferCalls({
type: 'transferred',
displayName: getDisplayName(conv),
number: `${conv.counterpartNum}`,
startTime: `${getTimestampInSeconds()}`,
})
store.dispatch.island.setIslandView('call')

if (isPhysical()) {
checkDefaultDeviceConversationActive(conv)
}
if (view === 'call' && transferring) {
eventDispatch('phone-island-call-ringing', {})
}
break
// @ts-ignore
case 'busy':
if (
(uaType === 'mobile' && hasOnlineNethlink()) ||
(uaType === 'desktop' &&
(default_device?.type === 'webrtc' ||
(default_device?.type === undefined && !hasOnlineNethlink()) ||
(!hasOnlineNethlink() && default_device?.type === 'physical')))
) {
if (conv && conv.connected) {
// Current call accepted and update connected call
dispatch.currentCall.updateCurrentCall({
transferring: false,
conversationId: conv.id,
displayName: getDisplayName(conv),
number: `${conv.counterpartNum}`,
ownerExtension: conv.owner,
username:
`${
extensions &&
extensions[conv.counterpartNum] &&
extensions[conv.counterpartNum].username
}` || '',
})
}
}
// Delete transfer calls if there are more than one ( in case of call switch after transfer)
if (transferCalls.length > 1) {
dispatch.currentCall.deleteTransferCalls()
}
// Handle not connected calls
else if (conv && !conv.connected) {
if (transferring && !transferSwitching) {
// Handle hangup during transfer
const inTransferCalls = transferCalls.find(
(item) => item.number === conv.counterpartNum,
)
if (!conv.connected && inTransferCalls) {
// Update transferring data for the current call
// Update the current call informations for physical devices
dispatch.currentCall.checkAcceptedUpdate({
acceptedSocket: true,
})
// Add call to transfer calls
dispatch.currentCall.addTransferCalls({
type: 'transferred',
displayName: getDisplayName(conv),
number: `${conv.counterpartNum}`,
startTime: `${getTimestampInSeconds()}`,
})

if (isPhysical()) {
checkDefaultDeviceConversationActive(conv)
}
if (view === 'call' && transferring) {
dispatch.currentCall.updateCurrentCall({
transferring: false,
})
eventDispatch('phone-island-call-transfer-failed', {})
// Reset transfer switching
// TODO - It needs to enhance how conversation connections (conv.connected) are updated server side
// TODO - The transfer end is not handled when the an user hangups or after call switch
dispatch.currentCall.updateTransferSwitching(false)
}
}
if (conv?.counterpartName === 'REC') {
dispatch.physicalRecorder.setRecordingTempVariable(true)
// Delete transfer calls if there are more than one ( in case of call switch after transfer)
if (transferCalls.length > 1) {
dispatch.currentCall.deleteTransferCalls()
}
// Handle not connected calls
else if (conv && !conv.connected) {
if (transferring && !transferSwitching) {
// Handle hangup during transfer
const inTransferCalls = transferCalls.find(
(item) => item.number === conv.counterpartNum,
)
if (!conv.connected && inTransferCalls) {
// Update transferring data for the current call
dispatch.currentCall.updateCurrentCall({
transferring: false,
})
eventDispatch('phone-island-call-transfer-failed', {})
// Reset transfer switching
// TODO - It needs to enhance how conversation connections (conv.connected) are updated server side
// TODO - The transfer end is not handled when the an user hangups or after call switch
dispatch.currentCall.updateTransferSwitching(false)
}
}
if (conv?.counterpartName === 'REC') {
dispatch.physicalRecorder.setRecordingTempVariable(true)
}
}
// Handle outgoing call
if (conv && !conv.connected && conv.direction === 'out') {
// Update the current outgoing conversation
dispatch.currentCall.checkOutgoingUpdate({
outgoingSocket: true,
displayName: getDisplayName(conv),
number: `${conv.counterpartNum}`,
username:
`${
extensions &&
extensions[conv.counterpartNum] &&
extensions[conv.counterpartNum].username
}` || '',
})
}
}
// Handle outgoing call
if (conv && !conv.connected && conv.direction === 'out') {
// Update the current outgoing conversation
dispatch.currentCall.checkOutgoingUpdate({
outgoingSocket: true,
displayName: getDisplayName(conv),
number: `${conv.counterpartNum}`,
username:
`${
extensions &&
extensions[conv.counterpartNum] &&
extensions[conv.counterpartNum].username
}` || '',
})
}

case 'onhold':
// The new conversation during transferring
const { counterpartName, counterpartNum, startTime } = conv
Expand Down
14 changes: 10 additions & 4 deletions src/components/WebRTC.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ export const WebRTC: FC<WebRTCProps> = ({
var event = result['event']
// Get the recording state
const { recording } = store.getState().recorder
const { view } = store.getState().island

// Manage different types of events
switch (event) {
Expand Down Expand Up @@ -225,6 +226,9 @@ export const WebRTC: FC<WebRTCProps> = ({
}
// Update webrtc lastActivity time
dispatch.webrtc.updateLastActivity(new Date().getTime())
if (view !== 'call') {
dispatch.island.setIslandView('call')
}
break

// After an outgoing call start on 183 code, it means
Expand Down Expand Up @@ -271,10 +275,11 @@ export const WebRTC: FC<WebRTCProps> = ({
}

if (
(uaType === 'mobile' &&
(default_device?.type === 'nethlink' || hasOnlineNethlink())) ||
(uaType === 'mobile' && hasOnlineNethlink()) ||
(uaType === 'desktop' &&
(default_device?.type === 'webrtc' || !hasOnlineNethlink()))
(default_device?.type === 'webrtc' ||
(default_device?.type === undefined && !hasOnlineNethlink()) ||
(!hasOnlineNethlink() && default_device?.type === 'physical')))
) {
// Update webrtc state
dispatch.webrtc.updateWebRTC({ jsepGlobal: jsep })
Expand All @@ -293,12 +298,14 @@ export const WebRTC: FC<WebRTCProps> = ({
})

if (janus.current.log) {
dispatch.currentCall.updateIncoming(true)
janus.current.log('Incoming call from ' + result['username'] + '!')
}
}

// Update the webrtc last activity time
dispatch.webrtc.updateLastActivity(new Date().getTime())
store.dispatch.island.setIslandView('call')
}

break
Expand Down Expand Up @@ -575,7 +582,6 @@ export const WebRTC: FC<WebRTCProps> = ({

useEventListener('phone-island-attach', (data) => {
initWebRTC()
store.dispatch.currentUser.updateCurrentDefaultDevice(data?.deviceInformationObject)
eventDispatch('phone-island-attached', {})
})

Expand Down
10 changes: 6 additions & 4 deletions src/lib/phone/call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,12 @@ export async function blindTransfer(number: string) {
const { conversationId } = store.getState().currentCall
const { default_device } = store.getState().currentUser
// Transfer the call through blind transfer
if (conversationId && default_device?.id && number) {
let default_device_details = default_device?.id || default_device?.exten
if (conversationId && default_device_details && number) {
return await blindTransferRequest({
convid: conversationId,
to: number,
endpointId: default_device.id,
endpointId: default_device_details,
})
}
}
Expand All @@ -204,12 +205,13 @@ export async function attendedTransfer(number: string) {
// Retrieve current conversation info
const { conversationId } = store.getState().currentCall
const { default_device } = store.getState().currentUser
let default_device_details = default_device?.id || default_device?.exten
// Transfer the call through attended transfer
if (conversationId && default_device?.id && number) {
if (conversationId && default_device_details && number) {
return await attendedTransferRequest({
convid: conversationId,
to: number,
endpointId: default_device.id,
endpointId: default_device_details,
})
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/models/currentCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ export const currentCall = createModel<RootModel>()({
state.startTime = payload
return state
},
updateIncoming: (state, payload: boolean) => {
state.incoming = payload
return state
},
reset: () => {
return defaultState
},
Expand Down
35 changes: 19 additions & 16 deletions src/services/astproxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,25 +109,28 @@ export async function answerPhysical() {
// get data
const { default_device } = store.getState().currentUser

let default_device_details = default_device?.id || default_device?.exten
// compose body
let body: any = {
endpointId: default_device?.id,
endpointType: 'extension',
}
if (default_device_details !== undefined) {
let body: any = {
endpointId: default_device?.exten || default_device?.id,
endpointType: 'extension',
}

try {
const { baseURL, headers } = store.getState().fetchDefaults
const response = await fetch(`${baseURL}/astproxy/answer`, {
method: 'POST',
headers: { ...headers },
body: JSON.stringify(body),
})
if (!response.ok) {
throw new Error(response.statusText)
try {
const { baseURL, headers } = store.getState().fetchDefaults
const response = await fetch(`${baseURL}/astproxy/answer`, {
method: 'POST',
headers: { ...headers },
body: JSON.stringify(body),
})
if (!response.ok) {
throw new Error(response.statusText)
}
return true
} catch (error: any) {
throw new Error(error)
}
return true
} catch (error: any) {
throw new Error(error)
}
}

Expand Down
1 change: 1 addition & 0 deletions src/types/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface UserExtensionTypes {
hold: boolean
}
proxy_port: string | null
exten: string
}

export interface PermissionTypes {
Expand Down

0 comments on commit a30e510

Please sign in to comment.