✨ v0.9.22 WebSSH
This commit is contained in:
		
							parent
							
								
									9bf536b68a
								
							
						
					
					
						commit
						8ca11d4760
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -14,3 +14,4 @@
 | 
				
			|||||||
/data
 | 
					/data
 | 
				
			||||||
/dist
 | 
					/dist
 | 
				
			||||||
.DS_Store
 | 
					.DS_Store
 | 
				
			||||||
 | 
					/main
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  <br>
 | 
					  <br>
 | 
				
			||||||
  <small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
 | 
					  <small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
 | 
				
			||||||
  <br><br>
 | 
					  <br><br>
 | 
				
			||||||
<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Dashboard%20image?label=Dash%20v0.9.21&logo=github&style=for-the-badge"> <img src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&label=Agent&style=for-the-badge&logo=github"> <img src="https://img.shields.io/github/workflow/status/naiba/nezha/Agent%20release?label=Agent%20CI&logo=github&style=for-the-badge"> <img src="https://img.shields.io/badge/Installer-v0.6.7-brightgreen?style=for-the-badge&logo=linux">
 | 
					<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Dashboard%20image?label=Dash%20v0.9.22&logo=github&style=for-the-badge"> <img src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&label=Agent&style=for-the-badge&logo=github"> <img src="https://img.shields.io/github/workflow/status/naiba/nezha/Agent%20release?label=Agent%20CI&logo=github&style=for-the-badge"> <img src="https://img.shields.io/badge/Installer-v0.6.7-brightgreen?style=for-the-badge&logo=linux">
 | 
				
			||||||
  <br>
 | 
					  <br>
 | 
				
			||||||
  <br>
 | 
					  <br>
 | 
				
			||||||
  <p>:trollface: <b>哪吒监控</b> 一站式轻监控轻运维系统。支持系统状态、HTTP(SSL 证书变更、即将到期、到期)、TCP、Ping 监控报警,命令批量执行和计划任务。</p>	
 | 
					  <p>:trollface: <b>哪吒监控</b> 一站式轻监控轻运维系统。支持系统状态、HTTP(SSL 证书变更、即将到期、到期)、TCP、Ping 监控报警,命令批量执行和计划任务。</p>	
 | 
				
			||||||
 | 
				
			|||||||
@ -14,20 +14,18 @@ import (
 | 
				
			|||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/exec"
 | 
						"os/exec"
 | 
				
			||||||
	"runtime"
 | 
					 | 
				
			||||||
	"syscall"
 | 
					 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
	"unsafe"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/blang/semver"
 | 
						"github.com/blang/semver"
 | 
				
			||||||
	"github.com/genkiroid/cert"
 | 
						"github.com/genkiroid/cert"
 | 
				
			||||||
	"github.com/go-ping/ping"
 | 
						"github.com/go-ping/ping"
 | 
				
			||||||
	"github.com/gorilla/websocket"
 | 
						"github.com/gorilla/websocket"
 | 
				
			||||||
	"github.com/kr/pty"
 | 
					 | 
				
			||||||
	"github.com/p14yground/go-github-selfupdate/selfupdate"
 | 
						"github.com/p14yground/go-github-selfupdate/selfupdate"
 | 
				
			||||||
	"google.golang.org/grpc"
 | 
						"google.golang.org/grpc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/naiba/nezha/cmd/agent/monitor"
 | 
						"github.com/naiba/nezha/cmd/agent/monitor"
 | 
				
			||||||
 | 
						"github.com/naiba/nezha/cmd/agent/processgroup"
 | 
				
			||||||
 | 
						"github.com/naiba/nezha/cmd/agent/pty"
 | 
				
			||||||
	"github.com/naiba/nezha/model"
 | 
						"github.com/naiba/nezha/model"
 | 
				
			||||||
	"github.com/naiba/nezha/pkg/utils"
 | 
						"github.com/naiba/nezha/pkg/utils"
 | 
				
			||||||
	pb "github.com/naiba/nezha/proto"
 | 
						pb "github.com/naiba/nezha/proto"
 | 
				
			||||||
@ -97,6 +95,8 @@ func run() {
 | 
				
			|||||||
		ClientSecret: clientSecret,
 | 
							ClientSecret: clientSecret,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go pty.DownloadDependency()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 上报服务器信息
 | 
						// 上报服务器信息
 | 
				
			||||||
	go reportState()
 | 
						go reportState()
 | 
				
			||||||
	// 更新IP信息
 | 
						// 更新IP信息
 | 
				
			||||||
@ -311,7 +311,7 @@ func handleCommandTask(task *pb.Task, result *pb.TaskResult) {
 | 
				
			|||||||
	startedAt := time.Now()
 | 
						startedAt := time.Now()
 | 
				
			||||||
	var cmd *exec.Cmd
 | 
						var cmd *exec.Cmd
 | 
				
			||||||
	var endCh = make(chan struct{})
 | 
						var endCh = make(chan struct{})
 | 
				
			||||||
	pg, err := utils.NewProcessExitGroup()
 | 
						pg, err := processgroup.NewProcessExitGroup()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		// 进程组创建失败,直接退出
 | 
							// 进程组创建失败,直接退出
 | 
				
			||||||
		result.Data = err.Error()
 | 
							result.Data = err.Error()
 | 
				
			||||||
@ -345,6 +345,11 @@ func handleCommandTask(task *pb.Task, result *pb.TaskResult) {
 | 
				
			|||||||
	result.Delay = float32(time.Since(startedAt).Seconds())
 | 
						result.Delay = float32(time.Since(startedAt).Seconds())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type WindowSize struct {
 | 
				
			||||||
 | 
						Cols uint32
 | 
				
			||||||
 | 
						Rows uint32
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func handleTerminalTask(task *pb.Task) {
 | 
					func handleTerminalTask(task *pb.Task) {
 | 
				
			||||||
	var terminal model.TerminalTask
 | 
						var terminal model.TerminalTask
 | 
				
			||||||
	err := json.Unmarshal([]byte(task.GetData()), &terminal)
 | 
						err := json.Unmarshal([]byte(task.GetData()), &terminal)
 | 
				
			||||||
@ -365,36 +370,18 @@ func handleTerminalTask(task *pb.Task) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	defer conn.Close()
 | 
						defer conn.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var cmd *exec.Cmd
 | 
						tty, err := pty.Start()
 | 
				
			||||||
	var shellPath string
 | 
					 | 
				
			||||||
	if runtime.GOOS == "windows" {
 | 
					 | 
				
			||||||
		shellPath, err = exec.LookPath("powershell.exe")
 | 
					 | 
				
			||||||
		if err != nil || shellPath == "" {
 | 
					 | 
				
			||||||
			shellPath = "cmd.exe"
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		shellPath = os.Getenv("SHELL")
 | 
					 | 
				
			||||||
		if shellPath == "" {
 | 
					 | 
				
			||||||
			shellPath = "sh"
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	cmd = exec.Command(shellPath)
 | 
					 | 
				
			||||||
	cmd.Env = append(os.Environ(), "TERM=xterm")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tty, err := pty.Start(cmd)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		println("Terminal pty.Start失败:", err)
 | 
							println("Terminal pty.Start失败:", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		cmd.Process.Kill()
 | 
					 | 
				
			||||||
		cmd.Process.Wait()
 | 
					 | 
				
			||||||
		tty.Close()
 | 
							tty.Close()
 | 
				
			||||||
		conn.Close()
 | 
							conn.Close()
 | 
				
			||||||
		println("terminal exit", terminal.Session)
 | 
							println("terminal exit", terminal.Session)
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	println("terminal init", terminal.Session, shellPath)
 | 
						println("terminal init", terminal.Session)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		for {
 | 
							for {
 | 
				
			||||||
@ -434,17 +421,12 @@ func handleTerminalTask(task *pb.Task) {
 | 
				
			|||||||
			io.Copy(tty, reader)
 | 
								io.Copy(tty, reader)
 | 
				
			||||||
		case 1:
 | 
							case 1:
 | 
				
			||||||
			decoder := json.NewDecoder(reader)
 | 
								decoder := json.NewDecoder(reader)
 | 
				
			||||||
			resizeMessage := windowSize{}
 | 
								var resizeMessage WindowSize
 | 
				
			||||||
			err := decoder.Decode(&resizeMessage)
 | 
								err := decoder.Decode(&resizeMessage)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			syscall.Syscall(
 | 
								tty.Setsize(resizeMessage.Cols, resizeMessage.Rows)
 | 
				
			||||||
				syscall.SYS_IOCTL,
 | 
					 | 
				
			||||||
				tty.Fd(),
 | 
					 | 
				
			||||||
				syscall.TIOCSWINSZ,
 | 
					 | 
				
			||||||
				uintptr(unsafe.Pointer(&resizeMessage)),
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
// +build !windows
 | 
					// +build !windows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package utils
 | 
					package processgroup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"os/exec"
 | 
						"os/exec"
 | 
				
			||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
// +build windows
 | 
					// +build windows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package utils
 | 
					package processgroup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
							
								
								
									
										52
									
								
								cmd/agent/pty/pty.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								cmd/agent/pty/pty.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					//go:build !windows
 | 
				
			||||||
 | 
					//+build !windows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package pty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"os/exec"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opty "github.com/creack/pty"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Pty struct {
 | 
				
			||||||
 | 
						tty *os.File
 | 
				
			||||||
 | 
						cmd *exec.Cmd
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func DownloadDependency() {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Start() (*Pty, error) {
 | 
				
			||||||
 | 
						shellPath := os.Getenv("SHELL")
 | 
				
			||||||
 | 
						if shellPath == "" {
 | 
				
			||||||
 | 
							shellPath = "sh"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cmd := exec.Command(shellPath)
 | 
				
			||||||
 | 
						cmd.Env = append(os.Environ(), "TERM=xterm")
 | 
				
			||||||
 | 
						tty, err := opty.Start(cmd)
 | 
				
			||||||
 | 
						return &Pty{tty: tty, cmd: cmd}, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (pty *Pty) Write(p []byte) (n int, err error) {
 | 
				
			||||||
 | 
						return pty.tty.Write(p)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (pty *Pty) Read(p []byte) (n int, err error) {
 | 
				
			||||||
 | 
						return pty.tty.Read(p)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (pty *Pty) Setsize(cols, rows uint32) error {
 | 
				
			||||||
 | 
						return opty.Setsize(pty.tty, &opty.Winsize{
 | 
				
			||||||
 | 
							Cols: uint16(cols),
 | 
				
			||||||
 | 
							Rows: uint16(rows),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (pty *Pty) Close() error {
 | 
				
			||||||
 | 
						if err := pty.tty.Close(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return pty.cmd.Process.Kill()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										96
									
								
								cmd/agent/pty/pty_windows.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								cmd/agent/pty/pty_windows.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					// go:build windows
 | 
				
			||||||
 | 
					// +build windows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package pty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"os/exec"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/artdarek/go-unzip"
 | 
				
			||||||
 | 
						"github.com/iamacarpet/go-winpty"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Pty struct {
 | 
				
			||||||
 | 
						tty *winpty.WinPTY
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func DownloadDependency() {
 | 
				
			||||||
 | 
						resp, err := http.Get("https://dn-dao-github-mirror.daocloud.io/rprichard/winpty/releases/download/0.4.3/winpty-0.4.3-msvc2015.zip")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Println("wintty 下载失败", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer resp.Body.Close()
 | 
				
			||||||
 | 
						content, err := ioutil.ReadAll(resp.Body)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Println("wintty 下载失败", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := ioutil.WriteFile("./wintty.zip", content, os.FileMode(0777)); err != nil {
 | 
				
			||||||
 | 
							log.Println("wintty 写入失败", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := unzip.New("./wintty.zip", "./wintty").Extract(); err != nil {
 | 
				
			||||||
 | 
							fmt.Println("wintty 解压失败", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						arch := "x64"
 | 
				
			||||||
 | 
						if runtime.GOARCH != "amd64" {
 | 
				
			||||||
 | 
							arch = "ia32"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						executablePath, err := getExecutableFilePath()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							fmt.Println("wintty 获取文件路径失败", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						os.Rename("./wintty/"+arch+"/bin/winpty-agent.exe", filepath.Join(executablePath, "winpty-agent.exe"))
 | 
				
			||||||
 | 
						os.Rename("./wintty/"+arch+"/bin/winpty.dll", filepath.Join(executablePath, "winpty.dll"))
 | 
				
			||||||
 | 
						os.RemoveAll("./wintty")
 | 
				
			||||||
 | 
						os.RemoveAll("./wintty.zip")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getExecutableFilePath() (string, error) {
 | 
				
			||||||
 | 
						ex, err := os.Executable()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return filepath.Dir(ex), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Start() (*Pty, error) {
 | 
				
			||||||
 | 
						shellPath, err := exec.LookPath("powershell.exe")
 | 
				
			||||||
 | 
						if err != nil || shellPath == "" {
 | 
				
			||||||
 | 
							shellPath = "cmd.exe"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						path, err := getExecutableFilePath()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tty, err := winpty.Open(path, shellPath)
 | 
				
			||||||
 | 
						return &Pty{tty: tty}, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (pty *Pty) Write(p []byte) (n int, err error) {
 | 
				
			||||||
 | 
						return pty.tty.StdIn.Read(p)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (pty *Pty) Read(p []byte) (n int, err error) {
 | 
				
			||||||
 | 
						return pty.tty.StdOut.Read(p)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (pty *Pty) Setsize(cols, rows uint32) error {
 | 
				
			||||||
 | 
						pty.tty.SetSize(cols, rows)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (pty *Pty) Close() error {
 | 
				
			||||||
 | 
						pty.tty.Close()
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,191 +1,7 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import "github.com/naiba/nezha/cmd/agent/pty"
 | 
				
			||||||
	"context"
 | 
					 | 
				
			||||||
	"crypto/tls"
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"io"
 | 
					 | 
				
			||||||
	"log"
 | 
					 | 
				
			||||||
	"net"
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"os/exec"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/genkiroid/cert"
 | 
					 | 
				
			||||||
	"github.com/go-ping/ping"
 | 
					 | 
				
			||||||
	"github.com/shirou/gopsutil/v3/cpu"
 | 
					 | 
				
			||||||
	"github.com/shirou/gopsutil/v3/disk"
 | 
					 | 
				
			||||||
	"github.com/shirou/gopsutil/v3/host"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/naiba/nezha/pkg/utils"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	// icmp()
 | 
						pty.DownloadDependency()
 | 
				
			||||||
	// tcpping()
 | 
					 | 
				
			||||||
	// httpWithSSLInfo()
 | 
					 | 
				
			||||||
	// sysinfo()
 | 
					 | 
				
			||||||
	// cmdExec()
 | 
					 | 
				
			||||||
	// resolveIP("ipapi.co", true)
 | 
					 | 
				
			||||||
	// resolveIP("ipapi.co", false)
 | 
					 | 
				
			||||||
	log.Println(exec.LookPath("powershell.exe"))
 | 
					 | 
				
			||||||
	defaultShell := os.Getenv("SHELL")
 | 
					 | 
				
			||||||
	if defaultShell == "" {
 | 
					 | 
				
			||||||
		defaultShell = "sh"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	cmd := exec.Command(defaultShell)
 | 
					 | 
				
			||||||
	cmd.Stdin = os.Stdin
 | 
					 | 
				
			||||||
	stdoutReader, err := cmd.StdoutPipe()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		println("Terminal StdoutPipe:", err)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	stderrReader, err := cmd.StderrPipe()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		println("Terminal StderrPipe: ", err)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	readers := []io.Reader{stdoutReader, stderrReader}
 | 
					 | 
				
			||||||
	for i := 0; i < len(readers); i++ {
 | 
					 | 
				
			||||||
		go func(j int) {
 | 
					 | 
				
			||||||
			data := make([]byte, 2048)
 | 
					 | 
				
			||||||
			for {
 | 
					 | 
				
			||||||
				count, err := readers[j].Read(data)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					panic(err)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				os.Stdout.Write(data[:count])
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}(i)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.Run()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func resolveIP(addr string, ipv6 bool) {
 | 
					 | 
				
			||||||
	url := strings.Split(addr, ":")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dnsServers := []string{"2606:4700:4700::1001", "2001:4860:4860::8844", "2400:3200::1", "2400:3200:baba::1"}
 | 
					 | 
				
			||||||
	if !ipv6 {
 | 
					 | 
				
			||||||
		dnsServers = []string{"1.0.0.1", "8.8.4.4", "223.5.5.5", "223.6.6.6"}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	log.Println(net.LookupIP(url[0]))
 | 
					 | 
				
			||||||
	for i := 0; i < len(dnsServers); i++ {
 | 
					 | 
				
			||||||
		dnsServer := dnsServers[i]
 | 
					 | 
				
			||||||
		if ipv6 {
 | 
					 | 
				
			||||||
			dnsServer = "[" + dnsServer + "]"
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		r := &net.Resolver{
 | 
					 | 
				
			||||||
			PreferGo: true,
 | 
					 | 
				
			||||||
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
 | 
					 | 
				
			||||||
				d := net.Dialer{
 | 
					 | 
				
			||||||
					Timeout: time.Second * 10,
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				return d.DialContext(ctx, "udp", dnsServer+":53")
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		log.Println(r.LookupIP(context.Background(), "ip", url[0]))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func tcpping() {
 | 
					 | 
				
			||||||
	start := time.Now()
 | 
					 | 
				
			||||||
	conn, err := net.DialTimeout("tcp", "example.com:80", time.Second*10)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		panic(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	conn.Write([]byte("ping\n"))
 | 
					 | 
				
			||||||
	conn.Close()
 | 
					 | 
				
			||||||
	fmt.Println(time.Since(start).Microseconds(), float32(time.Since(start).Microseconds())/1000.0)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func sysinfo() {
 | 
					 | 
				
			||||||
	hi, _ := host.Info()
 | 
					 | 
				
			||||||
	var cpuType string
 | 
					 | 
				
			||||||
	if hi.VirtualizationSystem != "" {
 | 
					 | 
				
			||||||
		cpuType = "Virtual"
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		cpuType = "Physical"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	cpuModelCount := make(map[string]int)
 | 
					 | 
				
			||||||
	ci, _ := cpu.Info()
 | 
					 | 
				
			||||||
	for i := 0; i < len(ci); i++ {
 | 
					 | 
				
			||||||
		cpuModelCount[ci[i].ModelName]++
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var cpus []string
 | 
					 | 
				
			||||||
	for model, count := range cpuModelCount {
 | 
					 | 
				
			||||||
		cpus = append(cpus, fmt.Sprintf("%s %d %s Core", model, count, cpuType))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	os.Exit(0)
 | 
					 | 
				
			||||||
	// 硬盘信息,不使用的原因是会重复统计 Linux、Mac
 | 
					 | 
				
			||||||
	dparts, _ := disk.Partitions(false)
 | 
					 | 
				
			||||||
	for _, part := range dparts {
 | 
					 | 
				
			||||||
		u, _ := disk.Usage(part.Mountpoint)
 | 
					 | 
				
			||||||
		if u != nil {
 | 
					 | 
				
			||||||
			log.Printf("%s %d %d", part.Device, u.Total, u.Used)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func httpWithSSLInfo() {
 | 
					 | 
				
			||||||
	// 跳过 SSL 检查
 | 
					 | 
				
			||||||
	transCfg := &http.Transport{
 | 
					 | 
				
			||||||
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	httpClient := &http.Client{Transport: transCfg, CheckRedirect: func(req *http.Request, via []*http.Request) error {
 | 
					 | 
				
			||||||
		return http.ErrUseLastResponse
 | 
					 | 
				
			||||||
	}}
 | 
					 | 
				
			||||||
	url := "https://ops.naibahq.com"
 | 
					 | 
				
			||||||
	resp, err := httpClient.Get(url)
 | 
					 | 
				
			||||||
	fmt.Println(err, resp)
 | 
					 | 
				
			||||||
	// SSL 证书信息获取
 | 
					 | 
				
			||||||
	c := cert.NewCert(url[8:])
 | 
					 | 
				
			||||||
	fmt.Println(c.Error)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func icmp() {
 | 
					 | 
				
			||||||
	pinger, err := ping.NewPinger("10.10.10.2")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		panic(err) // Blocks until finished.
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	pinger.Count = 3000
 | 
					 | 
				
			||||||
	pinger.Timeout = 10 * time.Second
 | 
					 | 
				
			||||||
	if err = pinger.Run(); err != nil {
 | 
					 | 
				
			||||||
		panic(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	fmt.Println(pinger.PacketsRecv, float32(pinger.Statistics().AvgRtt.Microseconds())/1000.0)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func cmdExec() {
 | 
					 | 
				
			||||||
	execFrom, err := os.Getwd()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		panic(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var cmd *exec.Cmd
 | 
					 | 
				
			||||||
	pg, err := utils.NewProcessExitGroup()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		panic(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if utils.IsWindows() {
 | 
					 | 
				
			||||||
		cmd = exec.Command("cmd", "/c", os.Args[1])
 | 
					 | 
				
			||||||
		// cmd = exec.Command("cmd", "/c", execFrom+"/cmd/playground/example.sh hello asd")
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		cmd = exec.Command("sh", "-c", execFrom+`/cmd/playground/example.sh hello && \
 | 
					 | 
				
			||||||
			echo world!`)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	pg.AddProcess(cmd)
 | 
					 | 
				
			||||||
	go func() {
 | 
					 | 
				
			||||||
		time.Sleep(time.Second * 10)
 | 
					 | 
				
			||||||
		if err = pg.Dispose(); err != nil {
 | 
					 | 
				
			||||||
			panic(err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		fmt.Println("killed")
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
	output, err := cmd.Output()
 | 
					 | 
				
			||||||
	log.Println("output:", string(output))
 | 
					 | 
				
			||||||
	log.Println("err:", err)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
									
									
									
									
								
							@ -4,7 +4,9 @@ go 1.13
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48
 | 
						code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48
 | 
				
			||||||
 | 
						github.com/artdarek/go-unzip v1.0.0
 | 
				
			||||||
	github.com/blang/semver v3.5.1+incompatible
 | 
						github.com/blang/semver v3.5.1+incompatible
 | 
				
			||||||
 | 
						github.com/creack/pty v1.1.14
 | 
				
			||||||
	github.com/fsnotify/fsnotify v1.4.9
 | 
						github.com/fsnotify/fsnotify v1.4.9
 | 
				
			||||||
	github.com/genkiroid/cert v0.0.0-20191007122723-897560fbbe50
 | 
						github.com/genkiroid/cert v0.0.0-20191007122723-897560fbbe50
 | 
				
			||||||
	github.com/gin-contrib/pprof v1.3.0
 | 
						github.com/gin-contrib/pprof v1.3.0
 | 
				
			||||||
@ -14,7 +16,7 @@ require (
 | 
				
			|||||||
	github.com/google/go-github v17.0.0+incompatible
 | 
						github.com/google/go-github v17.0.0+incompatible
 | 
				
			||||||
	github.com/gorilla/websocket v1.4.2
 | 
						github.com/gorilla/websocket v1.4.2
 | 
				
			||||||
	github.com/hashicorp/go-uuid v1.0.1
 | 
						github.com/hashicorp/go-uuid v1.0.1
 | 
				
			||||||
	github.com/kr/pty v1.1.1
 | 
						github.com/iamacarpet/go-winpty v1.0.2
 | 
				
			||||||
	github.com/onsi/ginkgo v1.7.0 // indirect
 | 
						github.com/onsi/ginkgo v1.7.0 // indirect
 | 
				
			||||||
	github.com/onsi/gomega v1.4.3 // indirect
 | 
						github.com/onsi/gomega v1.4.3 // indirect
 | 
				
			||||||
	github.com/ory/graceful v0.1.1
 | 
						github.com/ory/graceful v0.1.1
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								go.sum
									
									
									
									
									
								
							@ -45,6 +45,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
 | 
				
			|||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 | 
					github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 | 
				
			||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 | 
					github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 | 
				
			||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 | 
					github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 | 
				
			||||||
 | 
					github.com/artdarek/go-unzip v1.0.0 h1:Ja9wfhiXyl67z5JT37rWjTSb62KXDP+9jHRkdSREUvg=
 | 
				
			||||||
 | 
					github.com/artdarek/go-unzip v1.0.0/go.mod h1:KhX4LV7e4UwWCTo7orBYnJ6LJ/dZTI6jXxUg69hO/C8=
 | 
				
			||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 | 
					github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 | 
				
			||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 | 
					github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 | 
				
			||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 | 
					github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 | 
				
			||||||
@ -63,6 +65,8 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
 | 
				
			|||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 | 
					github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 | 
				
			||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 | 
					github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 | 
				
			||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 | 
					github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 | 
				
			||||||
 | 
					github.com/creack/pty v1.1.14 h1:55VbUWoBxE1iTAh3B6JztD6xyQ06CvW/31oD6rYwrtY=
 | 
				
			||||||
 | 
					github.com/creack/pty v1.1.14/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
 | 
				
			||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
					github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
				
			||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
					github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
				
			||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
					github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
				
			||||||
@ -193,6 +197,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
 | 
				
			|||||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
 | 
					github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
 | 
				
			||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 | 
					github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 | 
				
			||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 | 
					github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 | 
				
			||||||
 | 
					github.com/iamacarpet/go-winpty v1.0.2 h1:jwPVTYrjAHZx6Mcm6K5i9G4opMp5TblEHH5EQCl/Gzw=
 | 
				
			||||||
 | 
					github.com/iamacarpet/go-winpty v1.0.2/go.mod h1:/GHKJicG/EVRQIK1IQikMYBakBkhj/3hTjLgdzYsmpI=
 | 
				
			||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 | 
					github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 | 
				
			||||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8=
 | 
					github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8=
 | 
				
			||||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
 | 
					github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
 | 
				
			||||||
@ -216,7 +222,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
 | 
				
			|||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 | 
					github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 | 
				
			||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 | 
					github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 | 
				
			||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 | 
					github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 | 
				
			||||||
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
 | 
					 | 
				
			||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 | 
					github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 | 
				
			||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 | 
					github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 | 
				
			||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 | 
					github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
    <meta charset="UTF-8">
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
					    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
				
			||||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
				
			||||||
    <title>Terminal - {{.Title}}</title>
 | 
					    <title>tty#{{.SessionID}} - {{.Title}}</title>
 | 
				
			||||||
    <link rel="shortcut icon" type="image/png" href="/static/logo.svg?v20210804" />
 | 
					    <link rel="shortcut icon" type="image/png" href="/static/logo.svg?v20210804" />
 | 
				
			||||||
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@4.13.0/css/xterm.css">
 | 
					    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@4.13.0/css/xterm.css">
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
@ -22,7 +22,7 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<body>
 | 
					<body onresize="onResize()">
 | 
				
			||||||
    <div id="terminal-container"></div>
 | 
					    <div id="terminal-container"></div>
 | 
				
			||||||
    <script src="https://cdn.jsdelivr.net/npm/xterm@4.13.0/lib/xterm.min.js"></script>
 | 
					    <script src="https://cdn.jsdelivr.net/npm/xterm@4.13.0/lib/xterm.min.js"></script>
 | 
				
			||||||
    <script src="https://cdn.jsdelivr.net/npm/xterm-addon-attach@0.6.0/lib/xterm-addon-attach.min.js"></script>
 | 
					    <script src="https://cdn.jsdelivr.net/npm/xterm-addon-attach@0.6.0/lib/xterm-addon-attach.min.js"></script>
 | 
				
			||||||
@ -39,7 +39,22 @@
 | 
				
			|||||||
        term.loadAddon(attachAddon);
 | 
					        term.loadAddon(attachAddon);
 | 
				
			||||||
        term.loadAddon(fitAddon);
 | 
					        term.loadAddon(fitAddon);
 | 
				
			||||||
        term.open(document.getElementById('terminal-container'));
 | 
					        term.open(document.getElementById('terminal-container'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function onResize() {
 | 
				
			||||||
            fitAddon.fit()
 | 
					            fitAddon.fit()
 | 
				
			||||||
 | 
					            const w = fitAddon.proposeDimensions();
 | 
				
			||||||
 | 
					            const prefix = new Int8Array([1]);
 | 
				
			||||||
 | 
					            const resizeMessage = new TextEncoder().encode(JSON.stringify({
 | 
				
			||||||
 | 
					                Rows: w.rows,
 | 
				
			||||||
 | 
					                Cols: w.cols,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var msg = new Int8Array(prefix.length + resizeMessage.length);
 | 
				
			||||||
 | 
					            msg.set(prefix);
 | 
				
			||||||
 | 
					            msg.set(resizeMessage, prefix.length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            socket.send(msg)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    </script>
 | 
					    </script>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,7 @@ import (
 | 
				
			|||||||
	pb "github.com/naiba/nezha/proto"
 | 
						pb "github.com/naiba/nezha/proto"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var Version = "v0.9.21" // !!记得修改 README 中的 badge 版本!!
 | 
					var Version = "v0.9.22" // !!记得修改 README 中的 badge 版本!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	Conf  *model.Config
 | 
						Conf  *model.Config
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user