pet-house/core/helper/global/ssh.go

215 lines
4.9 KiB
Go

package global
import (
"errors"
"fmt"
"net"
"regexp"
"strconv"
"strings"
"time"
"log"
"github.com/shopspring/decimal"
"golang.org/x/crypto/ssh"
)
var (
ErrConnectFail = errors.New("SSH 连接失败")
ErrNewSessionFail = errors.New("SSH 新建会话失败")
ErrRunCommandFail = errors.New("SSH 执行命令失败")
)
type Cli struct {
IP string //IP地址
Username string //用户名
Password string //密码
Port int //端口号
client *ssh.Client //ssh客户端
LastResult string //最近一次Run的结果
Debug bool
}
// 创建命令行对象
// @param ip IP地址
// @param username 用户名
// @param password 密码
// @param debug 是否调试
// @param port 端口号,默认22
func NewSSH(ip string, username string, password string, debug bool, port ...int) *Cli {
cli := new(Cli)
cli.IP = ip
cli.Username = username
cli.Password = password
cli.Debug = debug
if len(port) <= 0 {
cli.Port = 22
} else {
cli.Port = port[0]
}
return cli
}
// 执行shell
// @param shell shell脚本命令
func (c Cli) Run(shell string) (string, error) {
if c.client == nil {
if err := c.connect(); err != nil {
if c.Debug {
log.Println(err.Error())
}
return "", ErrConnectFail
}
}
defer c.client.Close()
session, err := c.client.NewSession()
if err != nil {
if c.Debug {
log.Println(err.Error())
}
return "", ErrNewSessionFail
}
defer session.Close()
buf, err := session.CombinedOutput(shell)
if err != nil {
if c.Debug {
log.Println(err.Error())
}
return "", ErrRunCommandFail
}
c.LastResult = string(buf)
return c.LastResult, nil
}
// 连接
func (c *Cli) connect() error {
config := ssh.ClientConfig{
User: c.Username,
Auth: []ssh.AuthMethod{ssh.Password(c.Password)},
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil
},
Timeout: 10 * time.Second,
}
addr := fmt.Sprintf("%s:%d", c.IP, c.Port)
sshClient, err := ssh.Dial("tcp", addr, &config)
if err != nil {
if c.Debug {
log.Println(err.Error())
}
return err
}
c.client = sshClient
return nil
}
type DeviceMem struct {
Free decimal.Decimal
Total decimal.Decimal
FreeRound decimal.Decimal
}
// GetMem 内存信息
func (c *Cli) GetMem() (DeviceMem, error) {
var deviceMen DeviceMem
totalDec, err := c.getMenInfo("cat /proc/meminfo | grep -w MemTotal", "MemTotal:")
if err != nil {
return deviceMen, fmt.Errorf("memTotal %w", err)
}
freeDec, err := c.getMenInfo("cat /proc/meminfo | grep -w MemFree", "MemFree:")
if err != nil {
return deviceMen, fmt.Errorf("memFree %w", err)
}
buffersDec, err := c.getMenInfo("cat /proc/meminfo | grep -w Buffers", "Buffers:")
if err != nil {
return deviceMen, fmt.Errorf("buffers %w", err)
}
cachedDec, err := c.getMenInfo("cat /proc/meminfo | grep -w Cached", "Cached:")
if err != nil {
return deviceMen, fmt.Errorf("cached %w", err)
}
deviceMen.Total = totalDec
deviceMen.Free = freeDec.Add(buffersDec).Add(cachedDec)
deviceMen.FreeRound = deviceMen.Free.DivRound(deviceMen.Total, 2)
return deviceMen, nil
}
// getMenInfo 内存信息
func (c *Cli) getMenInfo(cmd, key string) (decimal.Decimal, error) {
info, err := c.Run(cmd)
if err != nil {
return decimal.Zero, fmt.Errorf("%s %w", cmd, err)
}
dec, err := decimal.NewFromString(strings.TrimSpace(strings.ReplaceAll(strings.ReplaceAll(info, key, ""), "kB", "")))
if err != nil {
return decimal.Zero, fmt.Errorf("NewFromString %w", err)
}
return dec, err
}
// GetDf 硬盘率
func (c *Cli) GetDf() (string, error) {
total, err := c.Run("df /sdcard -h")
if err != nil {
return "", fmt.Errorf("df /sdcard -h %w", err)
}
flysnowRegexp := regexp.MustCompile(`(100|[1-9]?\d(\.\d\d?\d?)?)%`)
params := flysnowRegexp.FindStringSubmatch(total)
if len(params) > 0 {
return params[0], nil
}
return "", nil
}
// GetSignal wifi信号
func (c *Cli) GetSignal() (string, error) {
signal, err := c.Run("iw dev wlan0 link | grep -w signal:")
if err != nil {
return "", fmt.Errorf("iw dev wlan0 link | grep -w signal: %w", err)
}
return strings.TrimSpace(strings.ReplaceAll(signal, "signal:", "")), nil
}
// GetDatetime 当前时间
func (c *Cli) GetDatetime() (string, error) {
datetime, err := c.Run("date +'%Y/%m/%d %T %Z'")
if err != nil {
return "", fmt.Errorf("date %w", err)
}
return datetime, nil
}
// GetCpuTemp CPU温度
func (c *Cli) GetCpuTemp() (float64, error) {
var ct float64
cmd := "acpi -t"
cpuTemp, err := c.Run(cmd)
if err != nil {
return 0, fmt.Errorf("%s : %w", cmd, err)
}
cpuTemps := strings.Split(cpuTemp, "\n")
for _, v := range cpuTemps {
flysnowRegexp := regexp.MustCompile(`[1-9]\d*\.\d*|0\.\d*[1-9]\d*`)
params := flysnowRegexp.FindStringSubmatch(v)
if len(params) > 0 {
f, err := strconv.ParseFloat(strings.Trim(params[0], "\n"), 64)
if err != nil {
return 0, fmt.Errorf("ParseFloat %w", err)
}
current := f / 100
if current > ct {
ct = current
}
}
}
return ct, nil
}