Skip to content

Commit

Permalink
fix(notifications): use notification state API to check whether to di…
Browse files Browse the repository at this point in the history
…smiss callbox

Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
  • Loading branch information
Antreesy committed Dec 5, 2024
1 parent 24813c8 commit d7d57f8
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 5 deletions.
3 changes: 2 additions & 1 deletion src/callbox/callbox.window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export function createCallboxWindow(params: CallboxParams) {
window.loadURL(CALLBOX_WINDOW_WEBPACK_ENTRY + '?' + new URLSearchParams(params))

window.once('ready-to-show', () => window.showInactive())

// FIXME remove: this shows devtools with network requests made from callbox
window.webContents.openDevTools()
return window
}
52 changes: 48 additions & 4 deletions src/callbox/renderer/callbox.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import axios from '@nextcloud/axios'
import { getCurrentUser } from '@nextcloud/auth'
import { generateOcsUrl } from '@nextcloud/router'
import { appData } from '../../app/AppData.js'

import type { AxiosError } from '@nextcloud/axios'

// @talk/src/types/openapi/openapi.ts/operations['call-get-peers-for-call']['responses'][200]['content']['application/json']
// TODO: find a way to import from @talk without type errors on CI
Expand All @@ -30,7 +33,22 @@ type CallGetParticipantsForCallResponse = {
}
}

type CallNotificationStateResponse = {
ocs: {
meta: {
status: string
statuscode: number
message?: string
totalitems?: string
itemsperpage?: string
}
data: unknown
}
}

const MISSED_CALL = 'missed_call'
const STATUS_MISSED_CALL = 201
const STATUS_NOT_FOUND = 404

/**
* Get participants of a call in a conversation
Expand All @@ -41,15 +59,35 @@ async function getCallParticipants(token: string) {
return response.data.ocs.data
}

/**
* Get call notification state in a conversation
* @param token - Conversation token
*/
async function getCallNotificationState(token: string) {
return axios.get<CallNotificationStateResponse>(generateOcsUrl('apps/spreed/api/v4/call/{token}/notification-state', { token }))
}

/**
* Check if the current user has joined the call
* @param token - Conversation token
* @param supportCallNotificationStateApi - Whether server supports notification state requests
*/
async function hasCurrentUserJoinedCall(token: string) {
async function hasCurrentUserJoinedCall(token: string, supportCallNotificationStateApi: boolean) {
const user = getCurrentUser()
if (!user) {
throw new Error('Cannot check whether current join the call - no current user found')
}

if (supportCallNotificationStateApi) {
const response = await getCallNotificationState(token)
if (response.data.ocs.meta.statuscode === STATUS_MISSED_CALL) {
throw new Error('STATE - There are currently no participants in the call', { cause: MISSED_CALL })
} else {
// status code 200 returned, user not joined yet and call notification is valid
return false
}
}

const participants = await getCallParticipants(token)
if (!participants.length) {
throw new Error('There are currently no participants in the call', { cause: MISSED_CALL })
Expand All @@ -64,7 +102,9 @@ async function hasCurrentUserJoinedCall(token: string) {
*/
export async function checkCurrentUserHasPendingCall(token: string): Promise<boolean> {
try {
const response = await hasCurrentUserJoinedCall(token)
// FIXME does not work in callbox if defined outside of function scope
const supportCallNotificationStateApi = appData.capabilities?.spreed?.features?.includes('call-notification-state-api')
const response = await hasCurrentUserJoinedCall(token, supportCallNotificationStateApi)
return !response
} catch (e) {
if (e instanceof Error && e.cause === MISSED_CALL) {
Expand All @@ -84,7 +124,7 @@ export async function checkCurrentUserHasPendingCall(token: string): Promise<boo
*/
export function waitCurrentUserHasJoinedCall(token: string, limit?: number): Promise<boolean> {
const POLLING_INTERVAL = 2000

const supportCallNotificationStateApi = appData.capabilities?.spreed?.features?.includes('call-notification-state-api')
const start = Date.now()

return new Promise((resolve) => {
Expand All @@ -96,13 +136,17 @@ export function waitCurrentUserHasJoinedCall(token: string, limit?: number): Pro

try {
// Check if the user has joined the call
if (await hasCurrentUserJoinedCall(token)) {
if (await hasCurrentUserJoinedCall(token, supportCallNotificationStateApi)) {
return resolve(true)
}
} catch (e) {
if (e instanceof Error && e.cause === MISSED_CALL) {
console.debug(e)
return resolve(false)
} else if (supportCallNotificationStateApi && (e as AxiosError)?.response?.status === STATUS_NOT_FOUND) {
// status code 404 returned, user joined call already
console.debug(e)
return resolve(true)
}
console.warn('Error while checking if the user has joined the call', e)
}
Expand Down

0 comments on commit d7d57f8

Please sign in to comment.