Path: blob/develop/web/src/components/Vnc.vue
387 views
<template> <div style="width: 100%; height: 100%; background-color: #000;"> <iframe id="videoFrame" ref="videoFrame" class="frame" frameBorder="0" v-show="config.mode === 'video'" scrolling="no"></iframe> <iframe id="vncFrame" ref="vncFrame" class="frame" v-bind:class="{hiddenvnc: config.mode === 'video'}" frameBorder="0" v-show="true" scrolling="no"></iframe> </div> </template> <script> export default { name: 'Vnc', components: { }, data () { return { // stopped -> connected -> disconnected vncState: 'stopped', videoState: 'stopped', // toolbar config: { mode: 'vnc' }, stateID: -1, // retry errorMessage: '', // vnc canvas size width: 0, height: 0, // videoCurrentTime: 0, stateErrorCount: 0, timerState: null } }, created: function () { window.addEventListener('message', this.onMessage) if ('video' in this.$route.query) { this.config.mode = 'video' } }, mounted: function () { this.update_status() }, beforeDestroy: function () { clearTimeout(this.timerState) window.removeEventListener('message', this.onMessage) }, methods: { update_status: async function () { const w = this.$refs.vncFrame.clientWidth const h = this.$refs.vncFrame.clientHeight const params = { 'video': this.config.mode === 'video', 'id': this.stateID, 'w': w, 'h': h } try { const response = await this.$http.get('api/state', {params: params}) const body = response.data if (body.code !== 200) { this.stateErrorCount += 1 if (this.stateErrorCount > 10) { this.errorMessage = this.$t('serviceIsUnavailable') throw this.errorMessage } } // long polling this.stateID = body.data.id // adaptive resolution if (!body.data.config.fixedResolution && body.data.config.sizeChangedCount === 0) { const response = await this.$http.get('api/reset', {params: params}) const body = response.data if (body.code !== 200) { this.stateErrorCount += 1 if (this.stateErrorCount > 10) { this.errorMessage = this.$t('serviceIsUnavailable') throw this.errorMessage } } } if (this.vncState === 'stopped') { this.reconnect(false) } // video // try { // let flvPlayer = this.$refs.videoFrame.contentWindow.flvPlayer // let readyState = 0 // readyState = flvPlayer._mediaElement.readyState // if (readyState >= 3) { // this.videoState = 'running' // if (this.videoCurrentTime !== flvPlayer.currentTime * 1000) { // // playing // let diff = (flvPlayer._mediaElement.buffered.end(0) - flvPlayer.currentTime) * 1000 // // console.log('player diff=' + diff) // if (diff >= 2000) { // // seek to nearest // console.log('seek to nearest') // flvPlayer._mediaElement.currentTime = flvPlayer._mediaElement.buffered.end(0) // } // this.videoCurrentTime = flvPlayer.currentTime * 1000 // } else { // // stall // console.log('stall, restart') // this.videoState = 'stopped' // } // } // } catch (e) { // // mediaElement TypeError // } this.schedule_next_update_status() } catch (error) { this.stateErrorCount += 1 if (this.stateErrorCount > 10) { this.errorMessage = this.$t('serviceIsUnavailable') } else { this.schedule_next_update_status() } } }, schedule_next_update_status: function (afterMseconds = 1000) { if (this.timerState !== null) { return } this.timerState = setTimeout(() => { this.timerState = null this.update_status() }, afterMseconds) }, reconnect: function (force = false) { // console.trace() console.log(`connecting...`) this.errorMessage = '' let websockifyPath = location.pathname.substr(1) + 'websockify' if (force || this.vncState === 'stopped') { this.vncState = 'connecting' let hostname = window.location.hostname let port = window.location.port if (!port) { port = window.location.protocol[4] === 's' ? 443 : 80 } let url = 'static/vnc.html?' url += 'autoconnect=1&' url += `host=${hostname}&port=${port}&` url += `path=${websockifyPath}&title=novnc2&` url += `logging=warn` this.$refs.vncFrame.setAttribute('src', url) } if (this.config.mode === 'video') { if (force || this.videoState === 'stopped') { const w = this.$refs.vncFrame.clientWidth const h = this.$refs.vncFrame.clientHeight let url = `static/video.html?width=${w}&height=${h}&base=${window.location.host}` this.$refs.videoFrame.setAttribute('src', url) this.videoState = 'connecting' } } else { if (this.videoState !== 'stopped') { this.$refs.videoFrame.setAttribute('src', '') this.videoState = 'stopped' } } }, onMessage: function (message) { try { let data = JSON.parse(message.data) if (data.from === 'flvjs') { if (data.type === 'event') { console.log(data.eventName) if (data.eventName === 'onSourceOpen') { this.videoState = 'running' } else if (data.eventName === 'onSourceEnded') { } else if (data.eventName === 'onSourceClose') { this.videoState = 'stopped' } } } if (data.from === 'novnc') { if (data.state) { this.vncState = data.state } } } catch (exc) { // SyntaxError if JSON pasrse error } } }, computed: { }, watch: { } } </script> <style scoped> body { margin: 0px; } iframe { border-width: 0px; width: 100%; height: 100%; position: absolute; left: 0px; top: 0px; } .hiddenvnc { opacity: 0; } </style>