mirror of
https://github.com/fcwu/docker-ubuntu-vnc-desktop
synced 2025-12-06 08:22:31 +01:00
217 lines
6.3 KiB
Vue
217 lines
6.3 KiB
Vue
<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(process.env.PREFIX_PATH + '/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(process.env.PREFIX_PATH + '/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 = process.env.PREFIX_PATH + '/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>
|