跳到主要内容

可视化输出(Visible Output)

引言

背景

目前的 console 只能显示文字。接到需求,需要能够在 Cloud IDE 中显示 GUI 程序,比如桌面程序,或者输出一张图片,需要能够显示出来。

目标

能够显示图形化窗口,用于开发桌面软件。

基础能力

点击运行后,自动打开 Output 工具,显示图形化页面,并且 console 中会显示错误日志。

当用户点击运行后,系统如果检测到有图形输出,则自动打开Output工具。Output工具需要能:

  • 展示图形输出窗口
  • 能接收用户键盘输入
  • 能鼠标操作窗口,如调整窗口大小、移动窗口

高级能力

支持拖拽,交互能力,并且支持播放语音。如果桌面程序运行后会播放声音的话。支持多人连接。状态共享。

三、协同

  • 一旦工作空间内有一个协作者运行了一个GUI,那么所有协作者都会自动打开Output工具。如果进入前其他协作者已经运行起来GUI,那么协作者进入后,空间内将自动打开Output工具
  • 所有协作者看到的Output画面都一致,包括鼠标位置也是一样的。如果多人同时移动鼠标如何解决冲突,可以根据技术方案来定。

需求分析

借鉴,replit 的实现 a.gif b.gif c.gif

需要使用到

技术设计

架构设计

visible_output_arch.svg

详细设计

let
pkgs = import <nixpkgs> {};
in

pkgs.mkShell {
buildInputs = with pkgs; [
tigervnc
fluxbox
];
shellHook = ''
export DISPLAY=:1
'';
}
Xvnc -rfbport=5901 -SecurityTypes=None -BlacklistTimeout=0 -BlacklistThreshold=1000000000 -geometry 800x600 -localhost :1
RUST_LOG=debug rfbproxy --rfb-server=0.0.0.0:5901 
fluxbox

然后使用 novnc 链接

http://tenant.feiyan.ivolces.com/feiyan/vnc/vnc.html?host=172.16.48.44&autoconnect=true&reconnect=true&resize=remote

img.png

img.png

因此,后端会出个 websocket 接口。连接到 ide-server 的 screen 1 上

package http

import (
"fmt"
"net/http"
"net/http/httputil"
"net/url"
)

func OutputHandler(w http.ResponseWriter, r *http.Request) {
u, err := url.Parse(fmt.Sprintf("http://localhost:%d", 5900))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
proxy := httputil.NewSingleHostReverseProxy(u)
director := proxy.Director
proxy.Director = func(req *http.Request) {
director(req)
}
proxy.ServeHTTP(w, r)
}

效果演示

demo.gif