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
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
|
|
}
|