前端Vue中使用Guacamole进行远程桌面的前端部分

最近公司有个项目要求远程虚拟机,最后选择使用了Guacamole进行实现,网上搜了一下感觉资料不是很多,对guacamole-common.js里的API介绍也没查到(捂脸),可能是我的问题。网上的教程都是教后端怎么搭建远程桌面系统。对web端使用的资料很少,可能大佬们觉着不需要(╥╯^╰╥)。下面我把在项目中用到的一下方法,总结一下,万一有人也需要呐。哈哈

  1. 下载guacamole-common或者直接引入guacamole-common.js文件;
  2. 在项目中的引用
初始化Guacamole
const initGuacamole = () => {
		//	XXXXX 后端提供的连接地址
      guacamole.tunnel = new Guacamole.WebSocketTunnel('XXXXX')

      if (guacamole.client) {
        guacamole.display.scale(0)
        uninstallKeyboard()
      }

      guacamole.client = new Guacamole.Client(guacamole.tunnel)

      guacamole.tunnel.onerror = error => {
        // console.error(`Tunnel failed ${JSON.stringify(error)}`)
        // 这里是断开重连的机智 当code值是下面这些时会进行重连5次,
        if (error.code === 512 || error.code === 514 || error.code === 515 || error.code === 769 || error.code === 776) {
          if (guacamole.curRetryCount === 0) {
            guacamole.retryTask = setInterval(() => {
              if (guacamole.curRetryCount < guacamole.maxRetryCount) {
                uninstallKeyboard()
                nextTick(() => {
                  initGuacamole('error')
                })
                guacamole.curRetryCount++
              } else if (guacamole.curRetryCount >= guacamole.maxRetryCount) {
                guacamole.loading = false
                guacamole.loadingText = ''
                uninstallKeyboard()
                clearInterval(guacamole.retryTask)
                guacamole.retryTask = null
              }
            }, 3000)
          }
        }else {
          if (!guacamole.retryTask) {
            guacamole.loading = false
            guacamole.loadingText = ''
          }
        }
      }

      guacamole.tunnel.onstatechange = state => {
        // console.log('tunnel.onstatechange',Guacamole.Tunnel.State,state);
        switch (state) {
          case Guacamole.Tunnel.State.CONNECTING:
            guacamole.connectionState = TUNNEL_STATES.CONNECTING
            break;

            // Connection is established / no longer unstable
          case Guacamole.Tunnel.State.OPEN:
            guacamole.connectionState = TUNNEL_STATES.CONNECTED
            break;

            // Connection is established but misbehaving
          case Guacamole.Tunnel.State.UNSTABLE:
            // TODO
            guacamole.connectionState = '不稳定'
              // this.$message.error("不稳定")
            break;

            // Connection has closed
          case Guacamole.Tunnel.State.CLOSED:
            guacamole.connectionState = TUNNEL_STATES.DISCONNECTED
            break;
        }
      }
      guacamole.client.onstatechange = clientState => {
        // console.log('clientState', clientState,  TUNNEL_STATES);
        switch (clientState) {
          case 0:
            guacamole.connectionState = TUNNEL_STATES.IDLE
            break
          case 1:
            // connecting ignored for some reason?
            break
          case 2:
            guacamole.connectionState = TUNNEL_STATES.WAITING
            break
          case 3:
            guacamole.connectionState = TUNNEL_STATES.CONNECTED

            // 取消加载
            guacamole.loading = false
            guacamole.loadingText = ''

            // 重连清空定时器和次数
            guacamole.curRetryCount = 0
            clearInterval(guacamole.retryTask)
            guacamole.retryTask = null
			//监听视图变化,并发送最新的宽高给Guacamole进行重新绘制
            window.addEventListener('resize', resize)
          case 4:
          case 5:
            // disconnected, disconnecting
            break
        }
      }

      guacamole.client.onerror = error => {
        guacamole.client.disconnect()
        console.error(`Client error ${JSON.stringify(error)}`)
      }

      guacamole.display = guacamole.client.getDisplay()
      display.value.appendChild(guacamole.display.getElement())
      display.value.addEventListener('contextmenu', e => {
        e.stopPropagation();
        if (e.preventDefault) {
          e.preventDefault();
        }
        e.returnValue = false;
      })

	  // 后端需要的参数
      let param = {
      	userName: '',
      	password: '',
      	type: 'VNC/RDP'
      }
      guacamole.client.connect(param);
      // 视图大小发生变化时触发(rdp和VNC同时连接时rdp可以动态设置分辨率,但是VNC不可以,所以前端可以通过onresize拿到rdp连接后,VNC通道拿到流的宽高进行等比缩放)
      guacamole.display.onresize = function(width, height) {
        const resizeScale = Math.min(
          viewport.value.clientWidth / Math.max(guacamole.display.getWidth(), 1), 
          viewport.value.clientHeight / Math.max(guacamole.display.getHeight(), 1)
        )
        guacamole.display.scale(resizeScale)
      }
      window.onunload = () => guacamole.client.disconnect();

      // 解决连接多个虚拟机时有的虚拟机不能查看z-index: -1
      guacamole.client.getDisplay().scale(1)


      display.value.onclick = () => {
        display.value.focus()
      }
      display.value.onfocus = () => {
        display.value.className = 'focus'
      }
      display.value.onblur = () => {
        display.value.className = ''
      }

      guacamole.keyboard = new Guacamole.Keyboard(display.value);
      installKeyboard()
      // Mouse 参数最好使用guacamole.client.getDisplay().getElement(),之前写的是父级元素,会导致出现两个鼠标的问题
      guacamole.mouse = new Guacamole.Mouse(guacamole.client.getDisplay().getElement());
      // 鼠标离开显示器时隐藏软件光标
      guacamole.mouse.onmouseout = () => {
        if (!guacamole.display) return;
        guacamole.display.showCursor(false);
      }
      guacamole.mouse.onmousedown = guacamole.mouse.onmouseup = guacamole.mouse.onmousemove = handleMouseState
      setTimeout(() => {
        resize()
        display.value.focus()
      }, 1000);
		//居中显示(当返回的流宽高小于屏幕宽高时)
      guacamole.client.getDisplay().getElement().style.setProperty('margin', 'auto')
    }

  1. 缩放方法
const resize = () => {
      const elm = viewport.value;
      if (!elm || !elm.offsetWidth) {
        return
      }
      // let pixelDensity = window.devicePixelRatio || 1  (pixelDensity 获取当前电脑的分辨率百分比)
      let pixelDensity = 1
      const width = elm.clientWidth * pixelDensity
      const height = elm.clientHeight * pixelDensity
      if (guacamole.display.getWidth() !== width || guacamole.display.getHeight() !== height) {
        guacamole.client.sendSize(width, height)
      }
      // setting timeout so display has time to get the correct size
      setTimeout(() => {
      // 计算缩放比例
        const scale = Math.min(
            elm.clientWidth / Math.max(guacamole.display.getWidth(), 1),
            elm.clientHeight / Math.max(guacamole.display.getHeight(), 1)
        )
        // guacamole.display.scale(1)
        if (props.websocketUrl === '/webSocket') {
          guacamole.display.scale(1)
        }else {
          guacamole.display.scale(scale)
        }
      }, 1000)
    }
  1. html
<div ref="display" class="display" tabindex="0"/>

以上就是我在项目中的使用情况
1、连接Tunnel
guacamole.tunnel = new Guacamole.WebSocketTunnel(props.websocketUrl)
2、把流放到视图中
guacamole.client = new Guacamole.Client(guacamole.tunnel)
3、监听tunnel和client 的值进行状态判断
4、把流添加到视图中
guacamole.client.getDisplay().appendChild(guacamole.display.getElement())
5、给后端传参
let param = {userName: ’ ',password: ’ '}
guacamole.client.connect(param);
6、断开虚拟机连接
guacamole.client.disconnect();
7、键盘事件
// display.value div元素
new Guacamole.Keyboard(display.value)
8、鼠标事件
new Guacamole.Mouse(guacamole.client.getDisplay().getElement());

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值