├── .gitignore
├── LICENSE
├── README.md
├── build.sh
├── go.mod
├── go.sum
├── index.html
├── main.go
├── node_modules
└── xterm
│ ├── css
│ └── xterm.css
│ └── lib
│ └── xterm.js
├── package-lock.json
├── package.json
├── showcase_linux_armv5.gif
└── showcase_linux_x86-64.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/*
2 | !/node_modules/xterm
3 | /node_modules/xterm/*
4 | !/node_modules/xterm/css
5 | /node_modules/xterm/css/*
6 | !/node_modules/xterm/css/xterm.css
7 | !/node_modules/xterm/lib
8 | /node_modules/xterm/lib/*
9 | !/node_modules/xterm/lib/xterm.js
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 NaisuXu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WebTerminal demo with Golang and Xterm.js
2 |
3 | ## 简介 / Brief
4 |
5 | 这是一个 `WebTerminal` 的项目演示,使用 `Golang` 和 `Xterm.js` 实现。This is a demo for `WebTerminal`, based on `Golang` and `Xterm. js` .
6 |
7 |
8 |
9 | ## 用法 / Usage
10 |
11 | 下载可执行文件到服务器设备中,然后启动服务。Download the executable file to the server device, and then start the service.
12 |
13 | ```shell
14 | chmod +x webterminal_xxxx
15 | ./webterminal_xxxx
16 | ```
17 |
18 | 在客户端浏览器中打开 `http://server_ip_address:22333/` 。Navigate your browser to `http://server_ip_address:22333/` .
19 |
20 |
21 |
22 | ## 演示 / Showcase
23 |
24 | **linux_x86-64 (Ununtu 22.04 AMD Ryzen 5 PRO 4650U):**
25 |
26 | 
27 |
28 |
29 |
30 | **linux_armv5 (NUC980 Linux buildroot 5.10.103+ armv5tejl GNU/Linux):**
31 |
32 | 
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | GOOS=linux GOARCH=amd64 go build -o webterminal_linux_x86-64
3 | GOOS=linux GOARCH=arm GOARM=7 go build -o webterminal_linux_armv7
4 | GOOS=linux GOARCH=arm GOARM=5 go build -o webterminal_linux_armv5
5 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module webterminal
2 |
3 | go 1.20
4 |
5 | require (
6 | github.com/creack/pty v1.1.18
7 | github.com/olahol/melody v1.1.3
8 | )
9 |
10 | require github.com/gorilla/websocket v1.5.0 // indirect
11 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
2 | github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
4 | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
5 | github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
6 | github.com/olahol/melody v1.1.3 h1:7Eo8egmejdrhdCM64uPgWj7NLSAVKl7Iv9NloFlzb60=
7 | github.com/olahol/melody v1.1.3/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4=
8 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
9 | github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
10 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
11 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebTerminal
6 |
7 |
8 |
9 |
10 |
11 |
15 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "embed"
5 | "net/http"
6 | "os/exec"
7 |
8 | "github.com/creack/pty"
9 | "github.com/olahol/melody"
10 | )
11 |
12 | //go:embed index.html node_modules/xterm/css/xterm.css node_modules/xterm/lib/xterm.js
13 | var content embed.FS
14 |
15 | func main() {
16 | c := exec.Command("sh") // 系统默认shell交互程序
17 | f, err := pty.Start(c) // pty用于调用系统自带的虚拟终端
18 | if err != nil {
19 | panic(err)
20 | }
21 |
22 | m := melody.New() // melody用于实现WebSocket功能
23 |
24 | go func() { // 处理来自虚拟终端的消息
25 | for {
26 | buf := make([]byte, 1024)
27 | read, err := f.Read(buf)
28 | if err != nil {
29 | return
30 | }
31 | // fmt.Println("f.Read: ", string(buf[:read]))
32 | m.Broadcast(buf[:read]) // 将数据发送给网页
33 | }
34 | }()
35 |
36 | m.HandleMessage(func(s *melody.Session, msg []byte) { // 处理来自WebSocket的消息
37 | // fmt.Println("m.HandleMessage: ", string(msg))
38 | f.Write(msg) // 将消息写到虚拟终端
39 | })
40 |
41 | http.HandleFunc("/webterminal", func(w http.ResponseWriter, r *http.Request) {
42 | m.HandleRequest(w, r) // 访问 /webterminal 时将转交给melody处理
43 | })
44 |
45 | fs := http.FileServer(http.FS(content))
46 | http.Handle("/", http.StripPrefix("/", fs)) // 设置静态文件服务
47 |
48 | http.ListenAndServe("0.0.0.0:22333", nil) // 启动服务器,访问 http://本机(服务器)IP地址:22333/ 进行测试
49 | }
50 |
--------------------------------------------------------------------------------
/node_modules/xterm/css/xterm.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2014 The xterm.js authors. All rights reserved.
3 | * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
4 | * https://github.com/chjj/term.js
5 | * @license MIT
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | * Originally forked from (with the author's permission):
26 | * Fabrice Bellard's javascript vt100 for jslinux:
27 | * http://bellard.org/jslinux/
28 | * Copyright (c) 2011 Fabrice Bellard
29 | * The original design remains. The terminal itself
30 | * has been extended to include xterm CSI codes, among
31 | * other features.
32 | */
33 |
34 | /**
35 | * Default styles for xterm.js
36 | */
37 |
38 | .xterm {
39 | cursor: text;
40 | position: relative;
41 | user-select: none;
42 | -ms-user-select: none;
43 | -webkit-user-select: none;
44 | }
45 |
46 | .xterm.focus,
47 | .xterm:focus {
48 | outline: none;
49 | }
50 |
51 | .xterm .xterm-helpers {
52 | position: absolute;
53 | top: 0;
54 | /**
55 | * The z-index of the helpers must be higher than the canvases in order for
56 | * IMEs to appear on top.
57 | */
58 | z-index: 5;
59 | }
60 |
61 | .xterm .xterm-helper-textarea {
62 | padding: 0;
63 | border: 0;
64 | margin: 0;
65 | /* Move textarea out of the screen to the far left, so that the cursor is not visible */
66 | position: absolute;
67 | opacity: 0;
68 | left: -9999em;
69 | top: 0;
70 | width: 0;
71 | height: 0;
72 | z-index: -5;
73 | /** Prevent wrapping so the IME appears against the textarea at the correct position */
74 | white-space: nowrap;
75 | overflow: hidden;
76 | resize: none;
77 | }
78 |
79 | .xterm .composition-view {
80 | /* TODO: Composition position got messed up somewhere */
81 | background: #000;
82 | color: #FFF;
83 | display: none;
84 | position: absolute;
85 | white-space: nowrap;
86 | z-index: 1;
87 | }
88 |
89 | .xterm .composition-view.active {
90 | display: block;
91 | }
92 |
93 | .xterm .xterm-viewport {
94 | /* On OS X this is required in order for the scroll bar to appear fully opaque */
95 | background-color: #000;
96 | overflow-y: scroll;
97 | cursor: default;
98 | position: absolute;
99 | right: 0;
100 | left: 0;
101 | top: 0;
102 | bottom: 0;
103 | }
104 |
105 | .xterm .xterm-screen {
106 | position: relative;
107 | }
108 |
109 | .xterm .xterm-screen canvas {
110 | position: absolute;
111 | left: 0;
112 | top: 0;
113 | }
114 |
115 | .xterm .xterm-scroll-area {
116 | visibility: hidden;
117 | }
118 |
119 | .xterm-char-measure-element {
120 | display: inline-block;
121 | visibility: hidden;
122 | position: absolute;
123 | top: 0;
124 | left: -9999em;
125 | line-height: normal;
126 | }
127 |
128 | .xterm.enable-mouse-events {
129 | /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
130 | cursor: default;
131 | }
132 |
133 | .xterm.xterm-cursor-pointer,
134 | .xterm .xterm-cursor-pointer {
135 | cursor: pointer;
136 | }
137 |
138 | .xterm.column-select.focus {
139 | /* Column selection mode */
140 | cursor: crosshair;
141 | }
142 |
143 | .xterm .xterm-accessibility,
144 | .xterm .xterm-message {
145 | position: absolute;
146 | left: 0;
147 | top: 0;
148 | bottom: 0;
149 | z-index: 10;
150 | color: transparent;
151 | }
152 |
153 | .xterm .live-region {
154 | position: absolute;
155 | left: -9999px;
156 | width: 1px;
157 | height: 1px;
158 | overflow: hidden;
159 | }
160 |
161 | .xterm-dim {
162 | opacity: 0.5;
163 | }
164 |
165 | .xterm-underline-1 { text-decoration: underline; }
166 | .xterm-underline-2 { text-decoration: double underline; }
167 | .xterm-underline-3 { text-decoration: wavy underline; }
168 | .xterm-underline-4 { text-decoration: dotted underline; }
169 | .xterm-underline-5 { text-decoration: dashed underline; }
170 |
171 | .xterm-strikethrough {
172 | text-decoration: line-through;
173 | }
174 |
175 | .xterm-screen .xterm-decoration-container .xterm-decoration {
176 | z-index: 6;
177 | position: absolute;
178 | }
179 |
180 | .xterm-decoration-overview-ruler {
181 | z-index: 7;
182 | position: absolute;
183 | top: 0;
184 | right: 0;
185 | pointer-events: none;
186 | }
187 |
188 | .xterm-decoration-top {
189 | z-index: 2;
190 | position: relative;
191 | }
192 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-terminal-demo-with-golang-and-xterm",
3 | "version": "1.0.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "web-terminal-demo-with-golang-and-xterm",
9 | "version": "1.0.0",
10 | "license": "ISC",
11 | "dependencies": {
12 | "xterm": "^5.1.0"
13 | }
14 | },
15 | "node_modules/xterm": {
16 | "version": "5.1.0",
17 | "resolved": "https://registry.npmmirror.com/xterm/-/xterm-5.1.0.tgz",
18 | "integrity": "sha512-LovENH4WDzpwynj+OTkLyZgJPeDom9Gra4DMlGAgz6pZhIDCQ+YuO7yfwanY+gVbn/mmZIStNOnVRU/ikQuAEQ=="
19 | }
20 | },
21 | "dependencies": {
22 | "xterm": {
23 | "version": "5.1.0",
24 | "resolved": "https://registry.npmmirror.com/xterm/-/xterm-5.1.0.tgz",
25 | "integrity": "sha512-LovENH4WDzpwynj+OTkLyZgJPeDom9Gra4DMlGAgz6pZhIDCQ+YuO7yfwanY+gVbn/mmZIStNOnVRU/ikQuAEQ=="
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-terminal-demo-with-golang-and-xterm",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "xterm": "^5.1.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/showcase_linux_armv5.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NaisuXu/web-terminal-demo-with-golang-and-xterm/a7c683b7be80c3d5b89870c9af6a7b872f346a31/showcase_linux_armv5.gif
--------------------------------------------------------------------------------
/showcase_linux_x86-64.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NaisuXu/web-terminal-demo-with-golang-and-xterm/a7c683b7be80c3d5b89870c9af6a7b872f346a31/showcase_linux_x86-64.gif
--------------------------------------------------------------------------------