Skip to content

Commit

Permalink
fix(AdminSettings): add test of websocket connection with HPB
Browse files Browse the repository at this point in the history
Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
  • Loading branch information
Antreesy committed Dec 18, 2024
1 parent bab0241 commit ca6320a
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 3 deletions.
21 changes: 18 additions & 3 deletions src/components/AdminSettings/SignalingServer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadi
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'

import { getWelcomeMessage } from '../../services/signalingService.js'
import { fetchSignalingSettings, getWelcomeMessage } from '../../services/signalingService.js'
import { createConnection } from '../../utils/SignalingStandaloneTest.js'

export default {
name: 'SignalingServer',
Expand Down Expand Up @@ -166,7 +167,6 @@ export default {

try {
const response = await getWelcomeMessage(this.index)
this.checked = true
const data = response.data.ocs.data
this.versionFound = data.version
if (data.warning === 'UPDATE_OPTIONAL') {
Expand All @@ -175,8 +175,9 @@ export default {
features: data.features.join(', '),
})
}

await this.testWebSocketConnection(this.server)
} catch (exception) {
this.checked = true
const data = exception.response.data.ocs.data
const error = data.error

Expand All @@ -198,6 +199,20 @@ export default {
} else {
this.errorMessage = t('spreed', 'Error: Unknown error occurred')
}
} finally {
this.checked = true
}
},

async testWebSocketConnection(url) {
try {
const response = await fetchSignalingSettings({ token: '' }, {})
const settings = response.data.ocs.data
const signalingTest = createConnection(settings, url)
await signalingTest.connect()
} catch (exception) {
console.error(exception)
this.errorMessage = t('spreed', 'Error: Websocket connection failed. Check browser console')
}
},
},
Expand Down
174 changes: 174 additions & 0 deletions src/utils/SignalingStandaloneTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { generateOcsUrl } from '@nextcloud/router'

/**
* This is a simplified version of Signaling prototype (see signaling.js)
* to be used for connection testing purposes (welcome, hello):
* - no internal signaling supported
* - no room events (join, leave, update) supported
*/

class StandaloneTest {

constructor(settings, url) {
this.settings = settings
this.features = null
this.version = null

this.socket = null
this.connected = false
this.url = this.getWebSocketUrl(url)

this.waitForWelcomeTimeout = null
this.welcomeTimeoutMs = 3000
}

hasFeature(feature) {
return this.features && this.features.includes(feature)
}

getWebSocketUrl(url) {
return url
.replace(/^http/, 'ws') // FIXME: not needed? request should be automatically upgraded to wss
.replace(/\/$/, '') + '/spreed'
}

getBackendUrl(baseURL = undefined) {
return generateOcsUrl('apps/spreed/api/v3/signaling/backend', {}, { baseURL })
}

connect() {
console.debug('Connecting to ' + this.url + ' with ' + this.settings)

return new Promise((resolve, reject) => {
this.socket = new WebSocket(this.url)

this.socket.onopen = (event) => {
console.debug('Connected to websocket', event)
if (this.settings.helloAuthParams['2.0']) {
this.waitForWelcomeTimeout = setTimeout(this.welcomeResponseTimeout.bind(this), this.welcomeTimeoutMs)
} else {
this.sendHello()
}
}

this.socket.onerror = (event) => {
console.error('Error on websocket', event)
this.disconnect()
}

this.socket.onclose = (event) => {
if (event.wasClean) {
console.info('Connection closed cleanly:', event)
resolve(true)
} else {
console.warn(`Closing code ${event.code}. See https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4`)
reject(event)
}
this.socket = null
}

this.socket.onmessage = (event) => {
let data = event.data
if (typeof (data) === 'string') {
data = JSON.parse(data)
}
if (OC.debug) {
console.debug('Received', data)
}

switch (data.type) {
case 'welcome':
this.welcomeResponseReceived(data)
break
case 'hello':
this.helloResponseReceived(data)
break
case 'error':
console.error('Received error', data)
break
default:
console.debug('Ignore unexpected event', data)
break
}
}
})
}

disconnect() {
if (this.socket) {
this.sendBye()
this.socket.close()
this.socket = null
}
}

welcomeResponseReceived(data) {
console.debug('Welcome received', data)
if (this.waitForWelcomeTimeout !== null) {
clearTimeout(this.waitForWelcomeTimeout)
this.waitForWelcomeTimeout = null
}

if (data.welcome && data.welcome.features) {
this.features = data.welcome.features
this.version = data.welcome.version
}

this.sendHello()
}

welcomeResponseTimeout() {
console.warn('No welcome received, assuming old-style signaling server')
this.sendHello()
}

sendHello() {
const version = this.hasFeature('hello-v2') ? '2.0' : '1.0'

const msg = {
type: 'hello',
hello: {
version,
auth: {
url: this.getBackendUrl(),
params: this.settings.helloAuthParams[version],
},
},
}

this.socket.send(JSON.stringify(msg))
}

helloResponseReceived(data) {
console.debug('Hello response received', data)
this.connected = true
this.disconnect()
}

sendBye() {
if (this.connected) {
this.socket.send(JSON.stringify({ type: 'bye', bye: {} }))
}
}

}

/**
* Returns test instance
* @param {object} settings signaling settings
* @param {string} url HPB server URL
*/
function createConnection(settings, url) {
if (!settings) {
console.error('Signaling settings are not given')
}

return new StandaloneTest(settings, url)
}

export { createConnection }

0 comments on commit ca6320a

Please sign in to comment.