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

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
}