Files
komari-agent/terminal/terminal_unix.go
Akizon77 e34367de69 Refactor monitoring package: remove platform-specific files and consolidate OS detection and process counting logic
- Deleted os_windows.go and process_windows.go, replacing them with platform-agnostic implementations in unit directory.
- Removed Linux-specific process counting logic from process_linux.go and integrated it into unit.
- Consolidated uptime and OS name retrieval into unit files for better organization.
- Updated update mechanism to use global variables for current version and repository.
- Introduced command-line flags for configuration, including disabling auto-update and web SSH.
- Implemented WebSocket connection handling and terminal interaction for both Unix and Windows systems.
- Added basic info upload functionality to server package, enhancing monitoring capabilities.
2025-05-16 19:56:22 +08:00

120 lines
2.3 KiB
Go

//go:build !windows
package terminal
import (
"encoding/json"
"fmt"
"os/exec"
"syscall"
"github.com/creack/pty"
"github.com/gorilla/websocket"
)
// StartTerminal 在Unix/Linux系统上启动终端
func StartTerminal(conn *websocket.Conn) {
// 获取shell
defalut_shell := []string{"zsh", "bash", "sh"}
shell := ""
for _, s := range defalut_shell {
if _, err := exec.LookPath(s); err == nil {
shell = s
break
}
}
if shell == "" {
conn.WriteMessage(websocket.TextMessage, []byte("No supported shell found."))
return
}
// 创建进程
cmd := exec.Command(shell)
cmd.Env = append(cmd.Env, "TERM=xterm-256color")
tty, err := pty.Start(cmd)
if err != nil {
conn.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("Error: %v\r\n", err)))
return
}
defer tty.Close()
// 设置终端大小
pty.Setsize(tty, &pty.Winsize{
Rows: 24,
Cols: 80,
X: 0,
Y: 0,
})
terminateConn := func() {
pgid, err := syscall.Getpgid(cmd.Process.Pid)
if err != nil {
cmd.Process.Kill()
}
syscall.Kill(-pgid, syscall.SIGKILL)
if conn != nil {
conn.Close()
}
}
err_chan := make(chan error, 1)
// 从WebSocket读取数据并写入pty
go func() {
for {
t, p, err := conn.ReadMessage()
if err != nil {
err_chan <- err
return
}
if t == websocket.TextMessage {
var cmd struct {
Type string `json:"type"`
Cols int `json:"cols,omitempty"`
Rows int `json:"rows,omitempty"`
Input string `json:"input,omitempty"`
}
if err := json.Unmarshal(p, &cmd); err == nil {
switch cmd.Type {
case "resize":
if cmd.Cols > 0 && cmd.Rows > 0 {
pty.Setsize(tty, &pty.Winsize{
Rows: uint16(cmd.Rows),
Cols: uint16(cmd.Cols),
})
}
case "input":
if cmd.Input != "" {
tty.Write([]byte(cmd.Input))
}
}
} else {
tty.Write(p)
}
}
if t == websocket.BinaryMessage {
tty.Write(p)
}
}
}()
go func() {
buf := make([]byte, 4096)
for {
n, err := tty.Read(buf)
if err != nil {
err_chan <- err
return
}
err = conn.WriteMessage(websocket.BinaryMessage, buf[:n])
if err != nil {
err_chan <- err
return
}
}
}()
err = <-err_chan
if err != nil && conn != nil {
conn.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("Error: %v\r\n", err)))
}
terminateConn()
}