Initial commit
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
package arr
|
||||
|
||||
import "sync"
|
||||
|
||||
type ArrayType interface {
|
||||
Add(value interface{})
|
||||
Check(value interface{}) bool
|
||||
Len() int
|
||||
Values() map[interface{}]bool
|
||||
}
|
||||
|
||||
// CheckType type for check array data
|
||||
type CheckArrayType struct {
|
||||
values map[interface{}]bool
|
||||
sm sync.Mutex
|
||||
len int
|
||||
}
|
||||
|
||||
// NewCheckArrayType
|
||||
func NewCheckArrayType(len int) *CheckArrayType {
|
||||
return &CheckArrayType{values: make(map[interface{}]bool, len)}
|
||||
}
|
||||
|
||||
// Add
|
||||
func (ct *CheckArrayType) Add(value interface{}) {
|
||||
defer ct.sm.Unlock()
|
||||
ct.sm.Lock()
|
||||
ct.values[value] = true
|
||||
ct.len++
|
||||
}
|
||||
|
||||
// AddMutil
|
||||
func (ct *CheckArrayType) AddMutil(values ...interface{}) {
|
||||
for _, v := range values {
|
||||
v := v
|
||||
ct.Add(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Check
|
||||
func (ct *CheckArrayType) Check(value interface{}) bool {
|
||||
defer ct.sm.Unlock()
|
||||
ct.sm.Lock()
|
||||
if b, ok := ct.values[value]; ok && b {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Len
|
||||
func (ct *CheckArrayType) Len() int {
|
||||
defer ct.sm.Unlock()
|
||||
ct.sm.Lock()
|
||||
return ct.len
|
||||
}
|
||||
|
||||
// Values
|
||||
func (ct *CheckArrayType) Values() map[interface{}]bool {
|
||||
defer ct.sm.Unlock()
|
||||
ct.sm.Lock()
|
||||
return ct.values
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package arr
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCheckArrayType(t *testing.T) {
|
||||
t.Run("check array type test with string", func(t *testing.T) {
|
||||
arrayType := NewCheckArrayType(10)
|
||||
arrayType.Add("1")
|
||||
if !arrayType.Check("1") {
|
||||
t.Errorf("1 should be in array type,but it is not in.")
|
||||
}
|
||||
if arrayType.Check("2") {
|
||||
t.Errorf("2 should not be in array type,but it is in.")
|
||||
}
|
||||
if arrayType.Check(1) {
|
||||
t.Errorf("int 1 should not be in array type,but it is in.")
|
||||
}
|
||||
if arrayType.Len() != 1 {
|
||||
t.Errorf("array type len should be 1 ,but get array type len is %d.", arrayType.Len())
|
||||
}
|
||||
arrayType.AddMutil("2", "3", "4")
|
||||
if arrayType.Len() != 4 {
|
||||
t.Errorf("array type len should be 4 ,but get array type len is %d.", arrayType.Len())
|
||||
}
|
||||
for i, v := range arrayType.Values() {
|
||||
log.Println(v)
|
||||
if !arrayType.Check(i) {
|
||||
t.Errorf("%v should be in array type,but it is not in", i)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("check array type test with uint", func(t *testing.T) {
|
||||
arrayType := NewCheckArrayType(10)
|
||||
var one uint = 1
|
||||
var two uint = 2
|
||||
var three uint = 3
|
||||
var four uint = 4
|
||||
arrayType.Add(one)
|
||||
if !arrayType.Check(one) {
|
||||
t.Errorf("1 should be in array type,but it is not in.")
|
||||
}
|
||||
if arrayType.Check(two) {
|
||||
t.Errorf("2 should not be in array type,but it is in.")
|
||||
}
|
||||
if arrayType.Len() != 1 {
|
||||
t.Errorf("array type len should be 1 ,but get array type len is %d.", arrayType.Len())
|
||||
}
|
||||
arrayType.AddMutil(two, three, four)
|
||||
if arrayType.Len() != 4 {
|
||||
t.Errorf("array type len should be 4 ,but get array type len is %d.", arrayType.Len())
|
||||
}
|
||||
for i, v := range arrayType.Values() {
|
||||
log.Println(v)
|
||||
if !arrayType.Check(i) {
|
||||
t.Errorf("%v should be in array type,but it is not in", i)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("check array type test with int", func(t *testing.T) {
|
||||
arrayType := NewCheckArrayType(10)
|
||||
arrayType.Add(1)
|
||||
if !arrayType.Check(1) {
|
||||
t.Errorf("1 should be in array type,but it is not in.")
|
||||
}
|
||||
if arrayType.Check(2) {
|
||||
t.Errorf("2 should not be in array type,but it is in.")
|
||||
}
|
||||
if arrayType.Check("1") {
|
||||
t.Errorf("string 1 should not be in array type,but it is in.")
|
||||
}
|
||||
if arrayType.Len() != 1 {
|
||||
t.Errorf("array type len should be 1 ,but get array type len is %d.", arrayType.Len())
|
||||
}
|
||||
arrayType.AddMutil(2, 3, 4)
|
||||
if arrayType.Len() != 4 {
|
||||
t.Errorf("array type len should be 4 ,but get array type len is %d.", arrayType.Len())
|
||||
}
|
||||
for i, v := range arrayType.Values() {
|
||||
log.Println(v)
|
||||
if !arrayType.Check(i) {
|
||||
t.Errorf("%v should be in array type,but it is not in", i)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package arr
|
||||
|
||||
import "strconv"
|
||||
|
||||
// 连接 unit slice 为字符串
|
||||
func UnitJoin(ss []uint, sep string) string {
|
||||
var rs string
|
||||
for index, item := range ss {
|
||||
itemS := strconv.FormatUint(uint64(item), 10)
|
||||
if index < len(ss)-1 {
|
||||
rs += itemS + sep
|
||||
} else {
|
||||
rs += itemS
|
||||
}
|
||||
}
|
||||
return rs
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package arr
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestUnitJoin(t *testing.T) {
|
||||
type args struct {
|
||||
ss []uint
|
||||
sep string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
args: struct {
|
||||
ss []uint
|
||||
sep string
|
||||
}{ss: []uint{1, 2, 3, 4}, sep: ","},
|
||||
want: "1,2,3,4",
|
||||
},
|
||||
{
|
||||
name: "success",
|
||||
args: struct {
|
||||
ss []uint
|
||||
sep string
|
||||
}{ss: []uint{1, 2, 3, 4}, sep: "||"},
|
||||
want: "1||2||3||4",
|
||||
},
|
||||
{
|
||||
name: "success",
|
||||
args: struct {
|
||||
ss []uint
|
||||
sep string
|
||||
}{ss: []uint{1, 2, 3, 4}, sep: "-"},
|
||||
want: "1-2-3-4",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := UnitJoin(tt.args.ss, tt.args.sep); got != tt.want {
|
||||
t.Errorf("UnitJoin() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
package dir
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// GetCurrentAbPath 项目根目录绝对路径
|
||||
func GetCurrentAbPath() string {
|
||||
dir := GetCurrentAbPathByExecutable()
|
||||
tmpDir, _ := filepath.EvalSymlinks(os.TempDir())
|
||||
if strings.Contains(dir, tmpDir) {
|
||||
wd, _ := os.Getwd()
|
||||
return wd
|
||||
}
|
||||
if strings.Contains(dir, "/tmp") {
|
||||
return filepath.Dir(dir)
|
||||
}
|
||||
|
||||
return dir
|
||||
}
|
||||
|
||||
// GetCurrentAbPathByExecutable 当前执行文件目录
|
||||
func GetCurrentAbPathByExecutable() string {
|
||||
exePath, err := os.Executable()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
res, _ := filepath.EvalSymlinks(filepath.Dir(exePath))
|
||||
return res
|
||||
}
|
||||
|
||||
// GetCurrentFuncNameByCaller 当前方法执行函数名
|
||||
func GetCurrentFuncNameByCaller() string {
|
||||
pc := make([]uintptr, 1)
|
||||
runtime.Callers(2, pc)
|
||||
f := runtime.FuncForPC(pc[0])
|
||||
return f.Name()
|
||||
}
|
||||
|
||||
// RealPath 基于构件执行文件的绝对文件路径
|
||||
func RealPath(fp string) (string, error) {
|
||||
if path.IsAbs(fp) {
|
||||
return fp, nil
|
||||
}
|
||||
wd, err := os.Getwd()
|
||||
return path.Join(wd, fp), err
|
||||
}
|
||||
|
||||
// SelfPath 完整的执行文件绝对路径
|
||||
func SelfPath() string {
|
||||
path, _ := filepath.Abs(os.Args[0])
|
||||
return path
|
||||
}
|
||||
|
||||
// SelfDir 执行文件目录完整路径
|
||||
func SelfDir() string {
|
||||
return filepath.Dir(SelfPath())
|
||||
}
|
||||
|
||||
// Basename 从路径中提取文件名
|
||||
func Basename(fp string) string {
|
||||
return path.Base(fp)
|
||||
}
|
||||
|
||||
// Dir 从路径中获取目录路径
|
||||
func Dir(fp string) string {
|
||||
return path.Dir(fp)
|
||||
}
|
||||
|
||||
//InsureDir 新建不存在的文件夹
|
||||
func InsureDir(fp string) error {
|
||||
if IsExist(fp) {
|
||||
return nil
|
||||
}
|
||||
return os.MkdirAll(fp, os.ModePerm)
|
||||
}
|
||||
|
||||
// IsExist 检测文件或者目录是否存在
|
||||
// 不存在的时候将返回 fasle
|
||||
func IsExist(fp string) bool {
|
||||
_, err := os.Stat(fp)
|
||||
return err == nil || os.IsExist(err)
|
||||
}
|
||||
|
||||
// IsFile checks whether the path is a file,
|
||||
// it returns false when it's a directory or does not exist.
|
||||
func IsFile(fp string) bool {
|
||||
f, e := os.Stat(fp)
|
||||
if e != nil {
|
||||
return false
|
||||
}
|
||||
return !f.IsDir()
|
||||
}
|
||||
|
||||
func Remove(filename string) error {
|
||||
if IsFile(filename) && IsExist(filename) {
|
||||
return os.Remove(filename)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadBytes(cpath string) ([]byte, error) {
|
||||
if !IsExist(cpath) {
|
||||
return nil, fmt.Errorf("%s not exists", cpath)
|
||||
}
|
||||
|
||||
if !IsFile(cpath) {
|
||||
return nil, fmt.Errorf("%s not file", cpath)
|
||||
}
|
||||
|
||||
return ioutil.ReadFile(cpath)
|
||||
}
|
||||
|
||||
func ReadString(cpath string) (string, error) {
|
||||
bs, err := ReadBytes(cpath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(bs), nil
|
||||
}
|
||||
|
||||
func ReadStringTrim(cpath string) (string, error) {
|
||||
out, err := ReadString(cpath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return strings.TrimSpace(out), nil
|
||||
}
|
||||
|
||||
func ReadYaml(cpath string, cptr interface{}) error {
|
||||
bs, err := ReadBytes(cpath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot read %s: %s", cpath, err.Error())
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(bs, cptr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse %s: %s", cpath, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadJson(cpath string, cptr interface{}) error {
|
||||
os.MkdirAll(path.Dir(cpath), os.ModePerm)
|
||||
bs, err := ReadBytes(cpath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot read %s: %s", cpath, err.Error())
|
||||
}
|
||||
|
||||
err = json.Unmarshal(bs, cptr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse %s: %s", cpath, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteBytes(filePath string, b []byte) (int, error) {
|
||||
os.MkdirAll(path.Dir(filePath), os.ModePerm)
|
||||
fw, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer fw.Close()
|
||||
return fw.Write(b)
|
||||
}
|
||||
|
||||
func WriteString(filePath, s string) (int, error) {
|
||||
return WriteBytes(filePath, []byte(s))
|
||||
}
|
||||
|
||||
func MD5(file string) (string, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
r := bufio.NewReader(f)
|
||||
h := md5.New()
|
||||
|
||||
_, err = io.Copy(h, r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
func Md5Byte(p []byte) (string, error) {
|
||||
h := md5.New()
|
||||
_, err := h.Write(p)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
func OpenLogFile(fp string) (*os.File, error) {
|
||||
os.MkdirAll(path.Dir(fp), os.ModePerm)
|
||||
return os.OpenFile(fp, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
}
|
||||
|
||||
// 添加文本
|
||||
func AppendFile(filePath string, b []byte) error {
|
||||
os.MkdirAll(path.Dir(filePath), os.ModePerm)
|
||||
f, err := os.OpenFile(filePath, os.O_APPEND|os.O_RDWR|os.O_CREATE, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
f.WriteString(string(b) + "\r\n\r\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// list dirs under dirPath
|
||||
func DirsUnder(dirPath string) ([]string, error) {
|
||||
if !IsExist(dirPath) {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
fs, err := ioutil.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
sz := len(fs)
|
||||
if sz == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
ret := make([]string, 0, sz)
|
||||
for i := 0; i < sz; i++ {
|
||||
if fs[i].IsDir() {
|
||||
name := fs[i].Name()
|
||||
if name != "." && name != ".." {
|
||||
ret = append(ret, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// list files under dirPath
|
||||
func FilesUnder(dirPath string) ([]string, error) {
|
||||
if !IsExist(dirPath) {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
fs, err := ioutil.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
sz := len(fs)
|
||||
if sz == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
ret := make([]string, 0, sz)
|
||||
for i := 0; i < sz; i++ {
|
||||
if !fs[i].IsDir() {
|
||||
ret = append(ret, fs[i].Name())
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"pet-house.com/core/helper/arr"
|
||||
)
|
||||
|
||||
func GetMacAddr() string {
|
||||
if getMacAddrInterface() == nil {
|
||||
return ""
|
||||
}
|
||||
addr := getMacAddrInterface().HardwareAddr.String()
|
||||
if len(addr) > 0 {
|
||||
addr = strings.ReplaceAll(addr, ":", "")
|
||||
addr = strings.ToUpper(addr)
|
||||
return addr
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getMacAddrInterface() *net.Interface {
|
||||
netInterfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
re, err := regexp.Compile(`^(ens|eth|waln|以太网|Ethernet)[0-9]*`)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
nameCheck := arr.NewCheckArrayType(0)
|
||||
nameCheck.AddMutil("eth0", "waln0", "以太网", "Ethernet", "ens0")
|
||||
for _, netInterface := range netInterfaces {
|
||||
if nameCheck.Check(netInterface.Name) {
|
||||
return &netInterface
|
||||
}
|
||||
}
|
||||
for _, netInterface := range netInterfaces {
|
||||
if re.MatchString(netInterface.Name) {
|
||||
return &netInterface
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func check(ip, network string) bool {
|
||||
parseIp, subnet, err := net.ParseCIDR(network)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if ip == parseIp.String() {
|
||||
return false
|
||||
}
|
||||
return subnet.Contains(net.ParseIP(ip))
|
||||
}
|
||||
|
||||
func LocalIP(network string) string {
|
||||
ip := ""
|
||||
if addrs, err := net.InterfaceAddrs(); err == nil {
|
||||
for i, addr := range addrs {
|
||||
i += 1
|
||||
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && !ipnet.IP.IsMulticast() && !ipnet.IP.IsLinkLocalUnicast() && !ipnet.IP.IsLinkLocalMulticast() && ipnet.IP.To4() != nil {
|
||||
ip = ipnet.IP.String()
|
||||
if len(ip) > 0 && check(ip, network) {
|
||||
return ip
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
func IsPortInUse(host string, port int64) bool {
|
||||
conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, fmt.Sprintf("%d", port)), time.Second*1)
|
||||
if err == nil {
|
||||
conn.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var network = "10.0.0.1/22"
|
||||
|
||||
func TestLocalIP(t *testing.T) {
|
||||
want := "172.18.236.240"
|
||||
t.Run("test get local ip", func(t *testing.T) {
|
||||
ip := LocalIP(network)
|
||||
if ip != want {
|
||||
t.Errorf("LocalIP() want get %s but get %s", want, ip)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetMacAddrs(t *testing.T) {
|
||||
want := "00155DDB2E65"
|
||||
t.Run("test get mac addr", func(t *testing.T) {
|
||||
mac := GetMacAddr()
|
||||
if mac != strings.ToUpper(want) {
|
||||
t.Errorf("GetMacAddr() want get %s but get %s", want, mac)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetMacAddrInterface(t *testing.T) {
|
||||
want := "eth0"
|
||||
t.Run("test get mac addr interface", func(t *testing.T) {
|
||||
mai := getMacAddrInterface()
|
||||
if mai == nil {
|
||||
t.Error("mac addr interface is nil")
|
||||
return
|
||||
}
|
||||
if mai.Name != want {
|
||||
t.Errorf("getMacAddrInterface() want get %s but get %s", want, mai.Name)
|
||||
}
|
||||
})
|
||||
}
|
||||
func TestCheck(t *testing.T) {
|
||||
t.Run("test ip check", func(t *testing.T) {
|
||||
if !check("10.0.1.1", network) {
|
||||
t.Error("ip check is fail")
|
||||
return
|
||||
}
|
||||
if check("192.168.0.1", network) {
|
||||
t.Error("ip check is fail")
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsPortInUse(t *testing.T) {
|
||||
t.Run("test is port in use", func(t *testing.T) {
|
||||
if !IsPortInUse("10.0.0.26", 9092) {
|
||||
t.Errorf("IsPortInUse(9092) must be return ture but return false")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_NewSSH(t *testing.T) {
|
||||
sshPwd := os.Getenv("sshPwd")
|
||||
t.Run("测试新建ssh链接", func(t *testing.T) {
|
||||
ip := "10.0.1.14"
|
||||
name := "root"
|
||||
sshClient := NewSSH(ip, name, sshPwd, true, 2022)
|
||||
if sshClient == nil {
|
||||
t.Errorf("客户端为空")
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
func Test_GetMem(t *testing.T) {
|
||||
sshPwd := os.Getenv("sshPwd")
|
||||
t.Run("测试获取设备内存", func(t *testing.T) {
|
||||
ip := "10.0.1.14"
|
||||
name := "root"
|
||||
sshClient := NewSSH(ip, name, sshPwd, true, 2022)
|
||||
if sshClient == nil {
|
||||
t.Errorf("客户端为空")
|
||||
return
|
||||
}
|
||||
mem, err := sshClient.GetMem()
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
log.Println(mem.Total.String())
|
||||
})
|
||||
}
|
||||
func Test_GetDf(t *testing.T) {
|
||||
sshPwd := os.Getenv("sshPwd")
|
||||
t.Run("测试获取设备硬盘使用", func(t *testing.T) {
|
||||
ip := "10.0.1.14"
|
||||
name := "root"
|
||||
sshClient := NewSSH(ip, name, sshPwd, true, 2022)
|
||||
if sshClient == nil {
|
||||
t.Errorf("客户端为空")
|
||||
return
|
||||
}
|
||||
_, err := sshClient.GetDf()
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
func Test_GetSignal(t *testing.T) {
|
||||
sshPwd := os.Getenv("sshPwd")
|
||||
t.Run("测试获取设备信号使用", func(t *testing.T) {
|
||||
ip := "10.0.1.14"
|
||||
name := "root"
|
||||
sshClient := NewSSH(ip, name, sshPwd, true, 2022)
|
||||
if sshClient == nil {
|
||||
t.Errorf("客户端为空")
|
||||
return
|
||||
}
|
||||
_, err := sshClient.GetSignal()
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetDatetime(t *testing.T) {
|
||||
sshPwd := os.Getenv("sshPwd")
|
||||
t.Run("测试获取设备时间使用", func(t *testing.T) {
|
||||
ip := "10.0.1.14"
|
||||
name := "root"
|
||||
sshClient := NewSSH(ip, name, sshPwd, true, 2022)
|
||||
if sshClient == nil {
|
||||
t.Errorf("客户端为空")
|
||||
return
|
||||
}
|
||||
_, err := sshClient.GetDatetime()
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
func Test_GetCpuTemp(t *testing.T) {
|
||||
sshPwd := os.Getenv("sshPwd")
|
||||
t.Run("测试获取设备时间使用", func(t *testing.T) {
|
||||
ip := "10.0.1.14"
|
||||
name := "root"
|
||||
sshClient := NewSSH(ip, name, sshPwd, true, 2022)
|
||||
if sshClient == nil {
|
||||
t.Errorf("客户端为空")
|
||||
return
|
||||
}
|
||||
cpuTemp, err := sshClient.GetCpuTemp()
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
if cpuTemp <= 0 {
|
||||
t.Errorf("cpu temp is 0")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DateTime 自定义事件类型
|
||||
type DateTime time.Time
|
||||
|
||||
// 日期格式
|
||||
const (
|
||||
DateLayout = "2006-01-02"
|
||||
DateTimeLayout = "2006-01-02 15:04:05"
|
||||
TimeLayout = "15:04:05"
|
||||
BuildTimeLayout = "2006.0102.150405"
|
||||
TimestampLayout = "20060102150405"
|
||||
)
|
||||
|
||||
var StartTime = time.Now()
|
||||
|
||||
func (dt *DateTime) UnmarshalJSON(data []byte) (err error) {
|
||||
value := strings.Trim(string(data), "\"")
|
||||
now, err := time.ParseInLocation(DateTimeLayout, value, time.Local)
|
||||
*dt = DateTime(now)
|
||||
return
|
||||
}
|
||||
|
||||
func (dt DateTime) MarshalJSON() ([]byte, error) {
|
||||
b := make([]byte, 0, len(DateTimeLayout)+2)
|
||||
b = append(b, '"')
|
||||
b = time.Time(dt).AppendFormat(b, DateTimeLayout)
|
||||
b = append(b, '"')
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (dt DateTime) Value() (driver.Value, error) {
|
||||
var zeroTime time.Time
|
||||
ti := time.Time(dt)
|
||||
if ti.UnixNano() == zeroTime.UnixNano() {
|
||||
return nil, nil
|
||||
}
|
||||
return ti, nil
|
||||
}
|
||||
|
||||
func (dt *DateTime) Scan(v interface{}) error {
|
||||
if value, ok := v.(time.Time); ok {
|
||||
*dt = DateTime(value)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dt DateTime) String() string {
|
||||
return time.Time(dt).Format(DateTimeLayout)
|
||||
}
|
||||
|
||||
func UpTime() time.Duration {
|
||||
return time.Since(StartTime)
|
||||
}
|
||||
|
||||
func UpTimeString() string {
|
||||
d := UpTime()
|
||||
days := d / (time.Hour * 24)
|
||||
d -= days * 24 * time.Hour
|
||||
hours := d / time.Hour
|
||||
d -= hours * time.Hour
|
||||
minutes := d / time.Minute
|
||||
d -= minutes * time.Minute
|
||||
seconds := d / time.Second
|
||||
return fmt.Sprintf("%d Days %d Hours %d Mins %d Secs", days, hours, minutes, seconds)
|
||||
}
|
||||
|
||||
// 获取时区
|
||||
func GetLocation() (*time.Location, error) {
|
||||
location, err := time.LoadLocation("Local")
|
||||
if err != nil {
|
||||
return location, nil
|
||||
}
|
||||
return location, nil
|
||||
}
|
||||
|
||||
func GetDuration(t int64, v string) time.Duration {
|
||||
switch v {
|
||||
case "h":
|
||||
return time.Hour * time.Duration(t)
|
||||
case "m":
|
||||
return time.Minute * time.Duration(t)
|
||||
case "s":
|
||||
return time.Second * time.Duration(t)
|
||||
default:
|
||||
return time.Minute * time.Duration(t)
|
||||
}
|
||||
}
|
||||
|
||||
func SleepRandomDuration() {
|
||||
ns := int64(5) * 1000000000
|
||||
// 以当前时间为随机数种子,如果所有 log-agent-updater 在同一时间启动,系统时间是相同的,那么随机种子就是一样的
|
||||
// 问题不大,批量ssh去启动 log-agent-updater 的话也是一个顺次的过程
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
d := time.Duration(r.Int63n(ns)) * time.Nanosecond
|
||||
time.Sleep(d)
|
||||
}
|
||||
|
||||
// OverTimeNow 超时比较
|
||||
func OverTimeNow(compareTime, subTime time.Time, sub int64) (bool, int64, error) {
|
||||
location, err := GetLocation()
|
||||
if err != nil {
|
||||
return false, 0, err
|
||||
}
|
||||
subT := compareTime.In(location).Sub(subTime)
|
||||
abs := int64(math.Abs(math.Ceil(subT.Minutes())))
|
||||
if abs > sub {
|
||||
return true, abs, nil
|
||||
}
|
||||
return false, abs, nil
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"pet-house.com/core/helper/str"
|
||||
)
|
||||
|
||||
var ErrInvalidDataStruct = errors.New("invalid response data struct")
|
||||
var ErrBaseAuthConfig = errors.New("base auth config is error")
|
||||
var ErrEmptyFileNameField = errors.New("must set field filename")
|
||||
|
||||
type client struct {
|
||||
config *Config
|
||||
cookie *http.Cookie
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
TimeOver int64
|
||||
TimeOut int64
|
||||
Headers map[string]string // request headers
|
||||
CookieName string
|
||||
Host string
|
||||
}
|
||||
|
||||
// BaseAuth
|
||||
type BaseAuth struct {
|
||||
Enable bool
|
||||
Account string
|
||||
Pwd string
|
||||
}
|
||||
|
||||
// NewClient
|
||||
func NewClient(configs ...*Config) *client {
|
||||
var config *Config
|
||||
if len(configs) == 0 || configs[0] == nil {
|
||||
config = &Config{TimeOut: 30, TimeOver: 5, Headers: map[string]string{}}
|
||||
} else {
|
||||
config = configs[0]
|
||||
}
|
||||
if config.TimeOut == 0 {
|
||||
config.TimeOut = 30
|
||||
}
|
||||
if config.TimeOver == 0 {
|
||||
config.TimeOver = 5
|
||||
}
|
||||
if config.Host == "" {
|
||||
config.Host = "http://127.0.0.1:7777"
|
||||
}
|
||||
return &client{config: config}
|
||||
}
|
||||
|
||||
// NewResponse
|
||||
func NewResponse(path string) *ServerResponse {
|
||||
return &ServerResponse{path: path}
|
||||
}
|
||||
|
||||
type ServerResponse struct {
|
||||
path string
|
||||
baseAuth *BaseAuth
|
||||
Data interface{} `json:"data"`
|
||||
body io.Reader
|
||||
fields map[string]string
|
||||
}
|
||||
|
||||
// SetBaseAuth
|
||||
func (sr *ServerResponse) SetBaseAuth(account, pwd string) {
|
||||
sr.baseAuth = &BaseAuth{
|
||||
Enable: true,
|
||||
Account: account,
|
||||
Pwd: pwd,
|
||||
}
|
||||
}
|
||||
|
||||
// BaseAuth
|
||||
func (sr *ServerResponse) BaseAuth() *BaseAuth {
|
||||
return sr.baseAuth
|
||||
}
|
||||
|
||||
// SetFields
|
||||
func (sr *ServerResponse) SetFields(fields map[string]string) {
|
||||
sr.fields = fields
|
||||
}
|
||||
|
||||
// GetFields
|
||||
func (sr *ServerResponse) GetFields() map[string]string {
|
||||
return sr.fields
|
||||
}
|
||||
|
||||
// SetUploadFile
|
||||
func (sr *ServerResponse) SetUploadFile(name string) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
sr.body = f
|
||||
}
|
||||
|
||||
// Close
|
||||
func (sr *ServerResponse) Close() {
|
||||
if f, ok := sr.body.(*os.File); ok && f != nil {
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (n *client) GetCookie() *http.Cookie {
|
||||
return n.cookie
|
||||
}
|
||||
|
||||
// Check
|
||||
func (n *client) Check(sr *ServerResponse) error {
|
||||
ba := sr.BaseAuth()
|
||||
if ba == nil {
|
||||
return nil
|
||||
}
|
||||
if ba.Enable && (ba.Account == "" || ba.Pwd == "") {
|
||||
return ErrBaseAuthConfig
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getFullPath
|
||||
func (n *client) getFullPath(path string) string {
|
||||
log.Println("fullpath:", path)
|
||||
return str.Join(n.config.Host, path)
|
||||
}
|
||||
|
||||
// Post
|
||||
func (n *client) Post(sr *ServerResponse, data string) ([]byte, error) {
|
||||
err := n.Check(sr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := n.request("POST", n.getFullPath(sr.path), sr.BaseAuth(), strings.NewReader(data))
|
||||
if len(result) == 0 {
|
||||
return result, fmt.Errorf("Post %s 没有返回数据", n.getFullPath(sr.path))
|
||||
}
|
||||
if !json.Valid(result) || sr.Data == nil {
|
||||
sr.Data = string(result)
|
||||
return result, nil
|
||||
}
|
||||
err = json.Unmarshal(result, sr.Data)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("执行解码失败: %s 错误:%w ,结果: %v", n.getFullPath(sr.path), err, string(result))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetFile
|
||||
func (n *client) GetFile(sr *ServerResponse) error {
|
||||
err := n.Check(sr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = n.request("GET", n.getFullPath(sr.path), sr.BaseAuth(), nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Upload 上传文件
|
||||
func (n *client) Upload(sr *ServerResponse) ([]byte, error) {
|
||||
err := n.Check(sr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if sr.fields == nil {
|
||||
return nil, ErrEmptyFileNameField
|
||||
}
|
||||
if filename, ok := sr.fields["filename"]; !ok || filename == "" {
|
||||
return nil, ErrEmptyFileNameField
|
||||
}
|
||||
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
fw, err := writer.CreateFormFile("file", sr.fields["filename"])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create form file %v", err)
|
||||
}
|
||||
|
||||
_, err = io.Copy(fw, sr.body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("copying fileWriter %v", err)
|
||||
}
|
||||
|
||||
for k, v := range sr.fields {
|
||||
_ = writer.WriteField(k, v)
|
||||
}
|
||||
|
||||
err = writer.Close() // close writer before POST request
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("writerClose: %v", err)
|
||||
}
|
||||
|
||||
n.config.Headers["Content-Type"] = writer.FormDataContentType()
|
||||
|
||||
result := n.request("POST", n.getFullPath(sr.path), sr.BaseAuth(), body)
|
||||
if len(result) == 0 {
|
||||
return result, fmt.Errorf("Upload %s 没有返回数据", n.getFullPath(sr.path))
|
||||
}
|
||||
|
||||
if !json.Valid(result) || sr.Data == nil {
|
||||
sr.Data = string(result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
err = json.Unmarshal(result, sr.Data)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("执行解码失败: %s 错误:%w ,结果: %v", n.getFullPath(sr.path), err, string(result))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Get 获取数据
|
||||
func (n *client) Get(sr *ServerResponse) ([]byte, error) {
|
||||
err := n.Check(sr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := n.request("GET", n.getFullPath(sr.path), sr.BaseAuth(), nil)
|
||||
if len(result) == 0 {
|
||||
return result, fmt.Errorf("Get %s 没有返回数据", n.getFullPath(sr.path))
|
||||
}
|
||||
if !json.Valid(result) || sr.Data == nil {
|
||||
sr.Data = string(result)
|
||||
return result, nil
|
||||
}
|
||||
err = json.Unmarshal(result, sr.Data)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("执行解码失败: %s 获取服务解析返回内容报错 %w : ,结果:[%s]", n.getFullPath(sr.path), err, string(result))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (n *client) request(method, fullpath string, ba *BaseAuth, body io.Reader) []byte {
|
||||
result := make(chan []byte, 30)
|
||||
T := time.NewTicker(time.Duration(n.config.TimeOver) * time.Second)
|
||||
go func() {
|
||||
t := time.Duration(n.config.TimeOut) * time.Second
|
||||
Client := http.Client{Timeout: t}
|
||||
req, err := http.NewRequest(method, fullpath, body)
|
||||
if err != nil {
|
||||
result <- nil
|
||||
return
|
||||
}
|
||||
|
||||
if len(n.config.Headers) > 0 {
|
||||
for key, value := range n.config.Headers {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
} else {
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
|
||||
}
|
||||
if ba != nil && ba.Enable {
|
||||
req.SetBasicAuth(ba.Account, ba.Pwd)
|
||||
}
|
||||
var resp *http.Response
|
||||
resp, err = Client.Do(req)
|
||||
if err != nil {
|
||||
result <- nil
|
||||
return
|
||||
}
|
||||
if n.config.CookieName != "" && resp.Cookies() != nil {
|
||||
for _, cookie := range resp.Cookies() {
|
||||
if cookie.Name == n.config.CookieName {
|
||||
n.cookie = cookie
|
||||
}
|
||||
}
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
io.Copy(buf, resp.Body)
|
||||
result <- buf.Bytes()
|
||||
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case x := <-result:
|
||||
return x
|
||||
case <-T.C:
|
||||
return []byte("请求超时")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func startGin() {
|
||||
r := gin.Default()
|
||||
gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
|
||||
log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers)
|
||||
}
|
||||
|
||||
r.POST("/foo", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, "foo")
|
||||
})
|
||||
|
||||
r.GET("/bar", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, "bar")
|
||||
})
|
||||
|
||||
r.GET("/status", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, "ok")
|
||||
})
|
||||
r.StaticFS("/txt", http.Dir("./txt"))
|
||||
|
||||
r.MaxMultipartMemory = 8 << 20 // 8 MiB
|
||||
r.POST("/upload", func(c *gin.Context) {
|
||||
// single file
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, "upload failed!")
|
||||
return
|
||||
}
|
||||
|
||||
// Upload the file to specific dst.
|
||||
c.SaveUploadedFile(file, "./txt")
|
||||
|
||||
c.JSON(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
|
||||
})
|
||||
|
||||
// Listen and Server in http://0.0.0.0:7777
|
||||
r.Run(":7777")
|
||||
}
|
||||
|
||||
func TestNewClient(t *testing.T) {
|
||||
|
||||
client := NewClient()
|
||||
t.Run("test new client", func(t *testing.T) {
|
||||
if client == nil {
|
||||
t.Error("client is nil")
|
||||
return
|
||||
}
|
||||
if client.config.TimeOut != 30 {
|
||||
t.Errorf("client default timeout want %d but get %d", 30, client.config.TimeOut)
|
||||
return
|
||||
}
|
||||
if client.config.TimeOver != 5 {
|
||||
t.Errorf("client default timeover want %d but get %d", 5, client.config.TimeOver)
|
||||
return
|
||||
}
|
||||
if client.config.Host != "http://127.0.0.1:7777" {
|
||||
t.Errorf("client default timeover want %s but get %s", "http://127.0.0.1:7777", client.config.Host)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
response := NewResponse("/foo")
|
||||
fullpath := client.getFullPath("/fullpath")
|
||||
if client.getFullPath("/fullpath") != "http://127.0.0.1:7777/fullpath" {
|
||||
t.Errorf("client default timeover want %s but get %s", "http://127.0.0.1:7777", fullpath)
|
||||
return
|
||||
}
|
||||
t.Run("test new response", func(t *testing.T) {
|
||||
if response == nil {
|
||||
t.Error("response is nil")
|
||||
return
|
||||
}
|
||||
if response.path != "/foo" {
|
||||
t.Errorf("response default path want %s but get %s", "/foo", response.path)
|
||||
}
|
||||
if response.Data != nil {
|
||||
t.Errorf("response default data is not nil")
|
||||
}
|
||||
ba := response.BaseAuth()
|
||||
if ba != nil {
|
||||
t.Errorf("response default baseauth is not nil")
|
||||
}
|
||||
response.SetBaseAuth("account", "pwd")
|
||||
ba = response.BaseAuth()
|
||||
if ba.Account != "account" {
|
||||
t.Errorf("response baseauth default accout is not account")
|
||||
}
|
||||
if ba.Pwd != "pwd" {
|
||||
t.Errorf("response baseauth default password is not pwd")
|
||||
}
|
||||
if !ba.Enable {
|
||||
t.Errorf("response baseauth default enable is not true")
|
||||
}
|
||||
fields := response.GetFields()
|
||||
if fields != nil {
|
||||
t.Errorf("response default fields is not nil")
|
||||
}
|
||||
f := map[string]string{
|
||||
"a": "a",
|
||||
"b": "b",
|
||||
}
|
||||
response.SetFields(f)
|
||||
fields = response.GetFields()
|
||||
if !reflect.DeepEqual(f, fields) {
|
||||
t.Error("fields is set failed")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test get file", func(t *testing.T) {
|
||||
response := NewResponse("/txt/file.txt")
|
||||
err := client.GetFile(response)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
return
|
||||
}
|
||||
})
|
||||
t.Run("test upload file", func(t *testing.T) {
|
||||
response := NewResponse("/upload")
|
||||
response.SetUploadFile("./upload.txt")
|
||||
defer response.Close()
|
||||
response.SetFields(map[string]string{"filename": "upload.txt"})
|
||||
_, err := client.Upload(response)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test get", func(t *testing.T) {
|
||||
response := NewResponse("/bar")
|
||||
_, err := client.Get(response)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test post", func(t *testing.T) {
|
||||
response := NewResponse("/foo")
|
||||
b, err := json.Marshal(map[string]interface{}{
|
||||
"a": "a",
|
||||
"b": "b",
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
return
|
||||
}
|
||||
_, err = client.Post(response, string(b))
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
go startGin()
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"pet-house.com/core/helper/ping"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ip := "10.0.0.113"
|
||||
ok, msg := ping.GetPingMsg(ip)
|
||||
if !ok {
|
||||
fmt.Printf("%s ping is fault,get msg %s \n", ip, msg)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package ping
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-ping/ping"
|
||||
)
|
||||
|
||||
// GetPingMsg ping 检查网络情况
|
||||
// icmp 检查5次,每次300毫秒超时,一共1500毫秒超时
|
||||
// 只要有一个次响应就成功
|
||||
func GetPingMsg(devIp string) (bool, string) {
|
||||
if devIp == "" {
|
||||
return false, "设备ip为空,请检查设备是否绑定ip"
|
||||
}
|
||||
pinger, err := ping.NewPinger(devIp)
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
pinger.Count = 3
|
||||
// 修改相关问题https://githubmemory.com/repo/go-ping/ping/issues/168
|
||||
pinger.Size = 548
|
||||
pinger.Interval = time.Duration(500 * time.Millisecond)
|
||||
pinger.Timeout = time.Duration(1500 * time.Millisecond)
|
||||
pinger.SetPrivileged(true)
|
||||
err = pinger.Run()
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
stats := pinger.Statistics()
|
||||
if stats.PacketsRecv >= 1 {
|
||||
return true, fmt.Sprintf("设备ip(%s)可以访问", devIp)
|
||||
}
|
||||
return false, fmt.Sprintf("设备(%s)可能已离线或者网络不稳定", devIp)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package ping
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_GetPingMsg(t *testing.T) {
|
||||
ips := []string{"www.weibo.com", "www.qq.com", "www.baidu.com"}
|
||||
for _, ip := range ips {
|
||||
t.Run("测试 ping 方法:"+ip, func(t *testing.T) {
|
||||
ok, msg := GetPingMsg(ip)
|
||||
if !ok {
|
||||
t.Errorf("%s ping is fault,get msg %s", ip, msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package str
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type StringArray string
|
||||
|
||||
func (r StringArray) MarshalJSON() ([]byte, error) {
|
||||
items := []string{}
|
||||
if string(r) != "" {
|
||||
items = strings.Split(string(r), ",")
|
||||
}
|
||||
for _, item := range items {
|
||||
item = strings.TrimSpace(item)
|
||||
}
|
||||
return json.Marshal(items)
|
||||
}
|
||||
|
||||
func Ellipsis(text string, length int) string {
|
||||
r := []rune(text)
|
||||
if len(r) > length {
|
||||
return string(r[0:length]) + "..."
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
func HasChinese(str string) bool {
|
||||
for _, r := range str {
|
||||
if unicode.Is(unicode.Scripts["Han"], r) || (regexp.MustCompile("[\u3002\uff1b\uff0c\uff1a\u201c\u201d\uff08\uff09\u3001\uff1f\u300a\u300b]").MatchString(string(r))) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func IsGBK(data []byte) bool {
|
||||
length := len(data)
|
||||
var i int = 0
|
||||
for i < length {
|
||||
if data[i] <= 0x7f {
|
||||
//编码0~127,只有一个字节的编码,兼容ASCII码
|
||||
i++
|
||||
continue
|
||||
} else {
|
||||
//大于127的使用双字节编码,落在gbk编码范围内的字符
|
||||
if data[i] >= 0x81 &&
|
||||
data[i] <= 0xfe &&
|
||||
data[i+1] >= 0x40 &&
|
||||
data[i+1] <= 0xfe &&
|
||||
data[i+1] != 0xf7 {
|
||||
i += 2
|
||||
continue
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package str
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// StructToMap 利用反射将结构体转化为map
|
||||
func StructToMap(obj interface{}) map[string]interface{} {
|
||||
obj1 := reflect.TypeOf(obj)
|
||||
obj2 := reflect.ValueOf(obj)
|
||||
|
||||
var data = make(map[string]interface{})
|
||||
for i := 0; i < obj1.NumField(); i++ {
|
||||
data[obj1.Field(i).Name] = obj2.Field(i).Interface()
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// 连接字符串
|
||||
func Join(strs ...string) string {
|
||||
var builder strings.Builder
|
||||
if len(strs) == 0 {
|
||||
return ""
|
||||
}
|
||||
for _, str := range strs {
|
||||
builder.WriteString(str)
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package str
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestJoin(t *testing.T) {
|
||||
t.Run("字符串拼接", func(t *testing.T) {
|
||||
if got := Join("abc", " ", "def"); got != "abc def" {
|
||||
t.Errorf("Join() = %v, want %v", got, "abc def")
|
||||
}
|
||||
})
|
||||
t.Run("字符串拼接单个字符", func(t *testing.T) {
|
||||
if got := Join("abc"); got != "abc" {
|
||||
t.Errorf("Join() = %v, want %v", got, "abc")
|
||||
}
|
||||
})
|
||||
t.Run("中文字符串拼接", func(t *testing.T) {
|
||||
if got := Join("中文字符串拼接", " ", "你好"); got != "中文字符串拼接 你好" {
|
||||
t.Errorf("Join() = %v, want %v", got, "中文字符串拼接 你好")
|
||||
}
|
||||
})
|
||||
t.Run("中文字符串拼接单个字符", func(t *testing.T) {
|
||||
if got := Join("中文字符串拼接"); got != "中文字符串拼接" {
|
||||
t.Errorf("Join() = %v, want %v", got, "中文字符串拼接")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package sys
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CmdOutString(name string, arg ...string) (string, error) {
|
||||
bs, err := CmdOutBytes(name, arg...)
|
||||
if err != nil {
|
||||
return "", errors.New(fmt.Sprintf("CmdOutBytes get error : %v", err))
|
||||
}
|
||||
|
||||
return string(bs), nil
|
||||
}
|
||||
|
||||
func CmdOutBytes(name string, arg ...string) ([]byte, error) {
|
||||
cmd := exec.Command(name, arg...)
|
||||
return cmd.CombinedOutput()
|
||||
}
|
||||
|
||||
func CmdOutTrim(name string, arg ...string) (string, error) {
|
||||
out, err := CmdOutString(name, arg...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(out)), nil
|
||||
}
|
||||
|
||||
func CmdRun(name string, arg ...string) error {
|
||||
cmd := exec.Command(name, arg...)
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
// CmdRunT Command run with timeout
|
||||
func CmdRunT(timeout time.Duration, name string, arg ...string) (output string, err error, istimeout bool) {
|
||||
cmd := exec.Command(name, arg...)
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||
var b bytes.Buffer
|
||||
cmd.Stdout = &b
|
||||
cmd.Stderr = &b
|
||||
|
||||
cmd.Start()
|
||||
err, istimeout = WrapTimeout(cmd, timeout)
|
||||
output = b.String()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func WrapTimeout(cmd *exec.Cmd, timeout time.Duration) (error, bool) {
|
||||
var err error
|
||||
done := make(chan error)
|
||||
go func() {
|
||||
done <- cmd.Wait()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(timeout):
|
||||
go func() {
|
||||
<-done // allow goroutine to exit
|
||||
}()
|
||||
|
||||
// IMPORTANT: cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} is necessary before cmd.Start()
|
||||
// err = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
|
||||
err = cmd.Process.Kill()
|
||||
return fmt.Errorf("cmd kill process %w", err), true
|
||||
case err = <-done:
|
||||
return err, false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package sys
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CmdOutString(name string, arg ...string) (string, error) {
|
||||
bs, err := CmdOutBytes(name, arg...)
|
||||
if err != nil {
|
||||
return "", errors.New(fmt.Sprintf("CmdOutBytes get error : %v", err))
|
||||
}
|
||||
|
||||
return string(bs), nil
|
||||
}
|
||||
|
||||
func CmdOutBytes(name string, arg ...string) ([]byte, error) {
|
||||
cmd := exec.Command(name, arg...)
|
||||
return cmd.CombinedOutput()
|
||||
}
|
||||
|
||||
func CmdOutTrim(name string, arg ...string) (string, error) {
|
||||
out, err := CmdOutString(name, arg...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(out)), nil
|
||||
}
|
||||
|
||||
func CmdRun(name string, arg ...string) error {
|
||||
cmd := exec.Command(name, arg...)
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
// CmdRunT Command run with timeout
|
||||
func CmdRunT(timeout time.Duration, name string, arg ...string) (output string, err error, istimeout bool) {
|
||||
cmd := exec.Command(name, arg...)
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||
var b bytes.Buffer
|
||||
cmd.Stdout = &b
|
||||
cmd.Stderr = &b
|
||||
|
||||
cmd.Start()
|
||||
err, istimeout = WrapTimeout(cmd, timeout)
|
||||
output = b.String()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func WrapTimeout(cmd *exec.Cmd, timeout time.Duration) (error, bool) {
|
||||
var err error
|
||||
done := make(chan error)
|
||||
go func() {
|
||||
done <- cmd.Wait()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(timeout):
|
||||
go func() {
|
||||
<-done // allow goroutine to exit
|
||||
}()
|
||||
|
||||
// IMPORTANT: cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} is necessary before cmd.Start()
|
||||
// err = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
|
||||
err = cmd.Process.Kill()
|
||||
return fmt.Errorf("cmd kill process %w", err), true
|
||||
case err = <-done:
|
||||
return err, false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package sys
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CmdOutString(name string, arg ...string) (string, error) {
|
||||
bs, err := CmdOutBytes(name, arg...)
|
||||
if err != nil {
|
||||
return "", errors.New(fmt.Sprintf("CmdOutBytes get error : %v", err))
|
||||
}
|
||||
|
||||
return string(bs), nil
|
||||
}
|
||||
|
||||
func CmdOutBytes(name string, arg ...string) ([]byte, error) {
|
||||
cmd := exec.Command(name, arg...)
|
||||
return cmd.CombinedOutput()
|
||||
}
|
||||
|
||||
func CmdOutTrim(name string, arg ...string) (string, error) {
|
||||
out, err := CmdOutString(name, arg...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(out)), nil
|
||||
}
|
||||
|
||||
func CmdRun(name string, arg ...string) error {
|
||||
cmd := exec.Command(name, arg...)
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
// CmdRunT Command run with timeout
|
||||
func CmdRunT(timeout time.Duration, name string, arg ...string) (output string, err error, istimeout bool) {
|
||||
cmd := exec.Command(name, arg...)
|
||||
// cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
HideWindow: true,
|
||||
CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
|
||||
}
|
||||
var b bytes.Buffer
|
||||
cmd.Stdout = &b
|
||||
cmd.Stderr = &b
|
||||
|
||||
cmd.Start()
|
||||
err, istimeout = WrapTimeout(cmd, timeout)
|
||||
output = b.String()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func WrapTimeout(cmd *exec.Cmd, timeout time.Duration) (error, bool) {
|
||||
var err error
|
||||
done := make(chan error)
|
||||
go func() {
|
||||
done <- cmd.Wait()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(timeout):
|
||||
go func() {
|
||||
<-done // allow goroutine to exit
|
||||
}()
|
||||
|
||||
// IMPORTANT: cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} is necessary before cmd.Start()
|
||||
// err = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
|
||||
err = cmd.Process.Kill()
|
||||
return fmt.Errorf("cmd kill process %w", err), true
|
||||
case err = <-done:
|
||||
return err, false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package sys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func KillProcessByCmdline(cmdline string) error {
|
||||
cmdline = strings.TrimSpace(cmdline)
|
||||
if cmdline == "" {
|
||||
return fmt.Errorf("cmdline is blank")
|
||||
}
|
||||
|
||||
pids := PidsByCmdline(cmdline)
|
||||
for i := 0; i < len(pids); i++ {
|
||||
out, err := CmdOutTrim("kill", "-9", strconv.Itoa(pids[i]))
|
||||
if err != nil {
|
||||
return fmt.Errorf("kill -9 %d fail: %v, output: %s", pids[i], err, out)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package sys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func IntranetIP() (ips []string, err error) {
|
||||
ips = make([]string, 0)
|
||||
|
||||
ifaces, e := net.Interfaces()
|
||||
if e != nil {
|
||||
return ips, e
|
||||
}
|
||||
|
||||
for _, iface := range ifaces {
|
||||
if iface.Flags&net.FlagUp == 0 {
|
||||
continue // interface down
|
||||
}
|
||||
|
||||
if iface.Flags&net.FlagLoopback != 0 {
|
||||
continue // loopback interface
|
||||
}
|
||||
|
||||
// ignore docker and warden bridge
|
||||
if strings.HasPrefix(iface.Name, "docker") || strings.HasPrefix(iface.Name, "w-") {
|
||||
continue
|
||||
}
|
||||
|
||||
addrs, e := iface.Addrs()
|
||||
if e != nil {
|
||||
return ips, e
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
|
||||
if ip == nil || ip.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
|
||||
ip = ip.To4()
|
||||
if ip == nil {
|
||||
continue // not an ipv4 address
|
||||
}
|
||||
|
||||
ipStr := ip.String()
|
||||
if IsIntranet(ipStr) {
|
||||
ips = append(ips, ipStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
func IsIntranet(ipStr string) bool {
|
||||
if strings.HasPrefix(ipStr, "10.") {
|
||||
return true
|
||||
}
|
||||
|
||||
// for didi
|
||||
if strings.HasPrefix(ipStr, "100.") {
|
||||
return true
|
||||
}
|
||||
|
||||
if strings.HasPrefix(ipStr, "192.168.") {
|
||||
return true
|
||||
}
|
||||
|
||||
if strings.HasPrefix(ipStr, "172.") {
|
||||
// 172.16.0.0-172.31.255.255
|
||||
arr := strings.Split(ipStr, ".")
|
||||
if len(arr) != 4 {
|
||||
return false
|
||||
}
|
||||
|
||||
second, err := strconv.ParseInt(arr[1], 10, 64)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if second >= 16 && second <= 31 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// ${sn}-${hostname}-${ip}
|
||||
func LocalHostIdent() string {
|
||||
sn, _ := CmdOutTrim("/bin/bash", "-c", "dmidecode -s system-serial-number")
|
||||
if sn != "" {
|
||||
arr := strings.Fields(sn)
|
||||
sn = arr[len(arr)-1]
|
||||
} else {
|
||||
sn = "nil"
|
||||
}
|
||||
|
||||
name, _ := CmdOutTrim("hostname")
|
||||
|
||||
ips, _ := IntranetIP()
|
||||
ip := ""
|
||||
if ips != nil && len(ips) > 0 {
|
||||
ip = ips[0]
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s-%s-%s", sn, name, ip)
|
||||
}
|
||||
|
||||
func GetOutboundIpaddr() string {
|
||||
conn, err := net.Dial("udp4", "1.2.3.4:56")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
localAddr := conn.LocalAddr().String()
|
||||
|
||||
if ip, _, err := net.SplitHostPort(localAddr); err != nil {
|
||||
return ""
|
||||
} else {
|
||||
return ip
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package sys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"pet-house.com/core/helper/dir"
|
||||
)
|
||||
|
||||
func PidsByCmdline(cmdline string) []int {
|
||||
ret := []int{}
|
||||
|
||||
var dirs []string
|
||||
dirs, err := dir.DirsUnder("/proc")
|
||||
if err != nil {
|
||||
return ret
|
||||
}
|
||||
|
||||
count := len(dirs)
|
||||
for i := 0; i < count; i++ {
|
||||
pid, err := strconv.Atoi(dirs[i])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
cmdlineFile := fmt.Sprintf("/proc/%d/cmdline", pid)
|
||||
if !dir.IsExist(cmdlineFile) {
|
||||
continue
|
||||
}
|
||||
|
||||
cmdlineBytes, err := dir.ReadBytes(cmdlineFile)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
cmdlineBytesLen := len(cmdlineBytes)
|
||||
if cmdlineBytesLen == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
noNut := make([]byte, 0, cmdlineBytesLen)
|
||||
for j := 0; j < cmdlineBytesLen; j++ {
|
||||
if cmdlineBytes[j] != 0 {
|
||||
noNut = append(noNut, cmdlineBytes[j])
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(string(noNut), cmdline) {
|
||||
ret = append(ret, pid)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
Reference in New Issue
Block a user