You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			440 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Go
		
	
		
		
			
		
	
	
			440 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Go
		
	
| 
											5 months ago
										 | package Common | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"bytes" | ||
|  | 	"crypto/md5" | ||
|  | 	"crypto/rand" | ||
|  | 	"encoding/binary" | ||
|  | 	"encoding/hex" | ||
|  | 	"encoding/json" | ||
|  | 	"errors" | ||
|  | 	"fmt" | ||
|  | 	"io" | ||
|  | 	"io/ioutil" | ||
|  | 	"net" | ||
|  | 	"net/http" | ||
|  | 	"net/url" | ||
|  | 	"os" | ||
|  | 	"path/filepath" | ||
|  | 	"strings" | ||
|  | 	"sync/atomic" | ||
|  | 	"time" | ||
|  | 
 | ||
|  | 	"fyne.io/fyne/v2" | ||
|  | 	"fyne.io/fyne/v2/widget" | ||
|  | 	"github.com/jlaffaye/ftp" | ||
|  | 	gcfg "gopkg.in/gcfg.v1" | ||
|  | 
 | ||
|  | 	log "github.com/sirupsen/logrus" | ||
|  | ) | ||
|  | 
 | ||
|  | type FLXConfig struct { | ||
|  | 	Kingbase struct { | ||
|  | 		IP       string //IP
 | ||
|  | 		Name     string //数据库名
 | ||
|  | 		Username string //用户名
 | ||
|  | 		Password string //密码
 | ||
|  | 	} | ||
|  | 	CheckInDoor struct { | ||
|  | 		PortName       string | ||
|  | 		DoorName       string | ||
|  | 		BaudRate       int | ||
|  | 		DataBits       int | ||
|  | 		StopBits       int | ||
|  | 		ParityMode     int | ||
|  | 		FtpServerIP    string | ||
|  | 		FtpServerPort  string | ||
|  | 		FtpUsername    string | ||
|  | 		FTPtpPassword  string | ||
|  | 		FtpPath        string | ||
|  | 		FtplocalDir    string | ||
|  | 		Windowsize     string | ||
|  | 		Windowposition string | ||
|  | 		IconType       string | ||
|  | 		ChromePath     string | ||
|  | 		BigPara        float32 | ||
|  | 	} | ||
|  | 	SeverData struct { | ||
|  | 		ServerIP           string | ||
|  | 		BackUpServerIP     string | ||
|  | 		FTPServiceIP       string | ||
|  | 		FTPServiceName     string | ||
|  | 		FTPServicePassWord string | ||
|  | 		HttpFileUrl        string | ||
|  | 	} | ||
|  | 	Other struct { | ||
|  | 		DShow            bool | ||
|  | 		CongressNameWrap bool | ||
|  | 		Dtype            int | ||
|  | 		ISServer         bool | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | func LoadConfig() FLXConfig { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("LoadConfig:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	var FLXCfig FLXConfig | ||
|  | 	err := gcfg.ReadFileInto(&FLXCfig, "Config.ini") | ||
|  | 
 | ||
|  | 	if err != nil { | ||
|  | 		fmt.Println("Failed to parse config file: %s", err) | ||
|  | 	} | ||
|  | 	return FLXCfig | ||
|  | } | ||
|  | 
 | ||
|  | var objectIdCounter uint32 = 0 | ||
|  | 
 | ||
|  | var machineId = readMachineId() | ||
|  | 
 | ||
|  | type ObjectId string | ||
|  | 
 | ||
|  | func readMachineId() []byte { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("readMachineId:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	var sum [3]byte | ||
|  | 	id := sum[:] | ||
|  | 	hostname, err1 := os.Hostname() | ||
|  | 	if err1 != nil { | ||
|  | 		_, err2 := io.ReadFull(rand.Reader, id) | ||
|  | 		if err2 != nil { | ||
|  | 			panic(fmt.Errorf("cannot get hostname: %v; %v", err1, err2)) | ||
|  | 		} | ||
|  | 		return id | ||
|  | 	} | ||
|  | 	hw := md5.New() | ||
|  | 	hw.Write([]byte(hostname)) | ||
|  | 	copy(id, hw.Sum(nil)) | ||
|  | 	fmt.Println("readMachineId:" + string(id)) | ||
|  | 	return id | ||
|  | } | ||
|  | 
 | ||
|  | // GUID returns a new unique ObjectId.
 | ||
|  | // 4byte 时间,
 | ||
|  | // 3byte 机器ID
 | ||
|  | // 2byte pid
 | ||
|  | // 3byte 自增ID
 | ||
|  | func GetGUID() ObjectId { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("GetGUID:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	var b [12]byte | ||
|  | 	// Timestamp, 4 bytes, big endian
 | ||
|  | 	binary.BigEndian.PutUint32(b[:], uint32(time.Now().Unix())) | ||
|  | 	// Machine, first 3 bytes of md5(hostname)
 | ||
|  | 	b[4] = machineId[0] | ||
|  | 	b[5] = machineId[1] | ||
|  | 	b[6] = machineId[2] | ||
|  | 	// Pid, 2 bytes, specs don't specify endianness, but we use big endian.
 | ||
|  | 	pid := os.Getpid() | ||
|  | 	b[7] = byte(pid >> 8) | ||
|  | 	b[8] = byte(pid) | ||
|  | 	// Increment, 3 bytes, big endian
 | ||
|  | 	i := atomic.AddUint32(&objectIdCounter, 1) | ||
|  | 	b[9] = byte(i >> 16) | ||
|  | 	b[10] = byte(i >> 8) | ||
|  | 	b[11] = byte(i) | ||
|  | 	return ObjectId(b[:]) | ||
|  | } | ||
|  | 
 | ||
|  | // Hex returns a hex representation of the ObjectId.
 | ||
|  | // 返回16进制对应的字符串
 | ||
|  | func (id ObjectId) Hex() string { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("Hex:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	return hex.EncodeToString([]byte(id)) | ||
|  | } | ||
|  | 
 | ||
|  | func NewTreeWithDatas(data map[string][]string) (t *widget.Tree) { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("NewTreeWithDatas:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	t = &widget.Tree{ | ||
|  | 		ChildUIDs: func(uid string) (c []string) { | ||
|  | 			c = data[uid] | ||
|  | 			return | ||
|  | 		}, | ||
|  | 		IsBranch: func(uid string) (b bool) { | ||
|  | 			_, b = data[uid] | ||
|  | 			return | ||
|  | 		}, | ||
|  | 		CreateNode: func(branch bool) fyne.CanvasObject { | ||
|  | 			return widget.NewLabel("Template Object") | ||
|  | 		}, | ||
|  | 		UpdateNode: func(uid string, branch bool, node fyne.CanvasObject) { | ||
|  | 
 | ||
|  | 			node.(*widget.Label).SetText(strings.Split(uid, "|")[1]) | ||
|  | 		}, | ||
|  | 	} | ||
|  | 	t.ExtendBaseWidget(t) | ||
|  | 	return | ||
|  | } | ||
|  | 
 | ||
|  | func ExternalIP() (net.IP, error) { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("ExternalIP:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	ifaces, err := net.Interfaces() | ||
|  | 	if err != nil { | ||
|  | 		return nil, err | ||
|  | 	} | ||
|  | 	for _, iface := range ifaces { | ||
|  | 		if iface.Flags&net.FlagUp == 0 { | ||
|  | 			continue // interface down
 | ||
|  | 		} | ||
|  | 		if iface.Flags&net.FlagLoopback != 0 { | ||
|  | 			continue // loopback interface
 | ||
|  | 		} | ||
|  | 		addrs, err := iface.Addrs() | ||
|  | 		if err != nil { | ||
|  | 			return nil, err | ||
|  | 		} | ||
|  | 		for _, addr := range addrs { | ||
|  | 			ip := getIpFromAddr(addr) | ||
|  | 			if ip == nil { | ||
|  | 				continue | ||
|  | 			} | ||
|  | 			return ip, nil | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return nil, errors.New("connected to the network?") | ||
|  | } | ||
|  | 
 | ||
|  | func getIpFromAddr(addr net.Addr) net.IP { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("getIpFromAddr:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	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() { | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 	ip = ip.To4() | ||
|  | 	if ip == nil { | ||
|  | 		return nil // not an ipv4 address
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return ip | ||
|  | } | ||
|  | 
 | ||
|  | func IsContain(items []string, item string) bool { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("IsContain:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	for _, eachItem := range items { | ||
|  | 		if eachItem == item { | ||
|  | 			return true | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return false | ||
|  | } | ||
|  | 
 | ||
|  | func Remove(items []string, item string) []string { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("Remove:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	var IndexN int | ||
|  | 	for id, eachItem := range items { | ||
|  | 		if eachItem == item { | ||
|  | 			IndexN = id | ||
|  | 		} | ||
|  | 	} | ||
|  | 	items = append(items[:IndexN], items[IndexN+1:]...) | ||
|  | 	return items | ||
|  | } | ||
|  | 
 | ||
|  | func DownloadDir(c *ftp.ServerConn, remoteDir, localDir string) error { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("DownloadDir:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	// 列出远程目录中的所有文件和子目录
 | ||
|  | 	entries, err := c.List(remoteDir) | ||
|  | 	if err != nil { | ||
|  | 		return err | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// 确保本地目录存在
 | ||
|  | 	err = os.MkdirAll(localDir, os.ModePerm) | ||
|  | 	if err != nil { | ||
|  | 		return err | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// 遍历目录内容
 | ||
|  | 	for _, entry := range entries { | ||
|  | 		remotePath := remoteDir + "/" + entry.Name | ||
|  | 		localPath := filepath.Join(localDir, entry.Name) | ||
|  | 
 | ||
|  | 		if entry.Type == ftp.EntryTypeFile { | ||
|  | 			// 如果是文件,下载它
 | ||
|  | 			err := downloadFile(c, remotePath, localPath) | ||
|  | 			if err != nil { | ||
|  | 				log.Printf("下载文件失败: %v\n", err) | ||
|  | 			} | ||
|  | 		} else if entry.Type == ftp.EntryTypeFolder { | ||
|  | 			// 如果是文件夹,递归下载该文件夹
 | ||
|  | 			err := DownloadDir(c, remotePath, localPath) | ||
|  | 			if err != nil { | ||
|  | 				log.Printf("下载文件夹失败: %v\n", err) | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return nil | ||
|  | } | ||
|  | 
 | ||
|  | func downloadFile(c *ftp.ServerConn, remotePath, localPath string) error { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("downloadFile:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	// 打开本地文件用于写入
 | ||
|  | 	file, err := os.Create(localPath) | ||
|  | 	if err != nil { | ||
|  | 		return err | ||
|  | 	} | ||
|  | 	defer file.Close() | ||
|  | 
 | ||
|  | 	// 从 FTP 服务器读取文件
 | ||
|  | 	reader, err := c.Retr(remotePath) | ||
|  | 	if err != nil { | ||
|  | 		return err | ||
|  | 	} | ||
|  | 	defer reader.Close() | ||
|  | 
 | ||
|  | 	// 将 FTP 文件内容复制到本地文件
 | ||
|  | 	_, err = io.Copy(file, reader) | ||
|  | 	if err != nil { | ||
|  | 		return err | ||
|  | 	} | ||
|  | 
 | ||
|  | 	fmt.Printf("已下载文件: %s\n", remotePath) | ||
|  | 	return nil | ||
|  | } | ||
|  | 
 | ||
|  | func SendPostRequest(sendurl string, data interface{}, contentType string) (string, int, error) { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("SendPostRequest:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	var reqBody *bytes.Buffer | ||
|  | 
 | ||
|  | 	// 根据 contentType 类型处理请求体
 | ||
|  | 	if contentType == "application/json" { | ||
|  | 		switch v := data.(type) { | ||
|  | 		case []byte: | ||
|  | 			reqBody = bytes.NewBuffer(v) | ||
|  | 		case string: | ||
|  | 			reqBody = bytes.NewBuffer([]byte(v)) | ||
|  | 		default: | ||
|  | 			return "", 0, fmt.Errorf("传入的 data 既不是字符串也不是字节切片") | ||
|  | 		} | ||
|  | 		// 如果是 JSON 数据,假设 data 是一个字符串类型
 | ||
|  | 		// reqBody = bytes.NewBuffer([]byte(data.(string)))
 | ||
|  | 	} else if contentType == "application/x-www-form-urlencoded" { | ||
|  | 		// 如果是表单数据
 | ||
|  | 		formData := url.Values{} | ||
|  | 		for key, value := range data.(map[string]string) { | ||
|  | 			formData.Add(key, value) | ||
|  | 		} | ||
|  | 		reqBody = bytes.NewBuffer([]byte(formData.Encode())) | ||
|  | 	} else { | ||
|  | 		return "", 0, fmt.Errorf("不支持的 Content-Type: %s", contentType) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// 发送 POST 请求
 | ||
|  | 	resp, err := http.Post(sendurl, contentType, reqBody) | ||
|  | 	if err != nil { | ||
|  | 		return "", 0, fmt.Errorf("请求失败: %v", err) | ||
|  | 	} | ||
|  | 	defer resp.Body.Close() | ||
|  | 
 | ||
|  | 	// 读取响应体
 | ||
|  | 	body, err := ioutil.ReadAll(resp.Body) | ||
|  | 	if err != nil { | ||
|  | 		return "", 0, fmt.Errorf("读取响应体失败: %v", err) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// 返回响应体和状态码
 | ||
|  | 	return string(body), resp.StatusCode, nil | ||
|  | } | ||
|  | 
 | ||
|  | type Response struct { | ||
|  | 	List    map[string]interface{} `json:"list"` | ||
|  | 	Message string                 `json:"message"` | ||
|  | 	Success bool                   `json:"success"` | ||
|  | } | ||
|  | 
 | ||
|  | func ParseResponseData(body string) map[string]interface{} { | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if r := recover(); r != nil { | ||
|  | 			log.Error("ParseResponseData:", r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	// 创建一个 Response 变量来存储解码后的数据
 | ||
|  | 	var response Response | ||
|  | 
 | ||
|  | 	// 解码 JSON 数据
 | ||
|  | 	err := json.Unmarshal([]byte(body), &response) | ||
|  | 	if err != nil { | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// 返回所需的字段值
 | ||
|  | 	return response.List | ||
|  | } |