lxz 1 tuần trước cách đây
mục cha
commit
85863def13
17 tập tin đã thay đổi với 720 bổ sung360 xóa
  1. 2 0
      .idea/vcs.xml
  2. 11 47
      demo3.1/main.go
  3. 4 32
      demo3.4/main.go
  4. 0 52
      demo3.9/main.go
  5. BIN
      demo4/demo4.exe
  6. 0 123
      demo4/main.go
  7. BIN
      demo4/snp.efi
  8. 59 3
      demo5/main.go
  9. 10 0
      etcd/global.go
  10. 7 33
      etcd/lock/test.go
  11. 89 43
      etcd/test.go
  12. 111 0
      fileupload/client/test.go
  13. 179 0
      fileupload/main.go
  14. 2 1
      go.mod
  15. 4 2
      go.sum
  16. 93 24
      gorm/main.go
  17. 149 0
      ipgen/main.go

+ 2 - 0
.idea/vcs.xml

@@ -2,5 +2,7 @@
 <project version="4">
   <component name="VcsDirectoryMappings">
     <mapping directory="$PROJECT_DIR$" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/FtpServer" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/goForward" vcs="Git" />
   </component>
 </project>

+ 11 - 47
demo3.1/main.go

@@ -2,58 +2,22 @@ package main
 
 import (
 	"fmt"
-	"net"
-	"strconv"
-)
-
-// ipToInt 将IP地址转换为整数
-func ipToInt(ip net.IP) uint32 {
-	ip = ip.To4()
-	return uint32(ip[0])<<24 + uint32(ip[1])<<16 + uint32(ip[2])<<8 + uint32(ip[3])
-}
-
-// intToIP 将整数转换为IP地址
-func intToIP(n uint32) net.IP {
-	return net.IPv4(byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
-}
-
-// generateIPs 生成从startIP到endIP的所有IP地址
-func generateIPs(startIP, endIP string) ([]string, error) {
-	start := net.ParseIP(startIP)
-	end := net.ParseIP(endIP)
-	if start == nil || end == nil {
-		return nil, fmt.Errorf("invalid IP address")
-	}
-
-	startInt := ipToInt(start)
-	endInt := ipToInt(end)
-
-	if startInt > endInt {
-		return nil, fmt.Errorf("start IP must be less than or equal to end IP")
-	}
 
-	var ips []string
-	for ip := startInt; ip <= endInt; ip++ {
-		ips = append(ips, intToIP(ip).String())
-	}
-	return ips, nil
-}
+	"github.com/bwmarrin/snowflake"
+)
 
 func main() {
-	startIP := "10.10.1.200"
-	endIP := "10.10.2.50"
-	_, ipNet, err := net.ParseCIDR("10.10.1.1/22")
-	if err != nil {
-		panic(err)
-	}
-	fmt.Println(strconv.Itoa(int(ipNet.Mask[0])) + "." + strconv.Itoa(int(ipNet.Mask[1])) + "." + strconv.Itoa(int(ipNet.Mask[2])) + "." + strconv.Itoa(int(ipNet.Mask[3])))
-	ips, err := generateIPs(startIP, endIP)
+
+	// Create a new Node with a Node number of 1
+	node, err := snowflake.NewNode(1)
 	if err != nil {
-		fmt.Println("Error:", err)
+		fmt.Println(err)
 		return
 	}
 
-	for _, ip := range ips {
-		fmt.Println(ip)
-	}
+	// Generate a snowflake ID.
+	id := node.Generate()
+
+	json, _ := id.MarshalJSON()
+	fmt.Println(string(json))
 }

+ 4 - 32
demo3.4/main.go

@@ -1,37 +1,9 @@
 package main
 
-import (
-	"fmt"
-	"github.com/lucklucif/ipmigo"
-)
+import "fmt"
 
 func main() {
-	c, err := ipmigo.NewClient(ipmigo.Arguments{
-		Version:       ipmigo.V2_0,
-		Address:       "120.46.150.226:623",
-		Username:      "ADMIN",
-		Password:      "ADMIN",
-		CipherSuiteID: 3,
-	})
-	if err != nil {
-		fmt.Println(err)
-		return
-	}
-
-	if err := c.Open(); err != nil {
-		fmt.Println(err)
-		return
-	}
-	defer c.Close()
-	//err = c.Ping()
-	//if err != nil {
-	//	fmt.Println(err)
-	//	return
-	//}
-	//cmd := ipmigo.GetChassisStatusCommand{}
-	//if err := c.Execute(&cmd); err != nil {
-	//	fmt.Println(err)
-	//	return
-	//}
-	//fmt.Println("Power On Hours", cmd)
+	nums := []int{1, 2, 3, 4}
+	nums = append(nums[:1], nums[2:]...)
+	fmt.Println(nums)
 }

+ 0 - 52
demo3.9/main.go

@@ -1,52 +0,0 @@
-package main
-
-import (
-	"fmt"
-	"io"
-	"net/http"
-	"os"
-	"path/filepath"
-	"strings"
-
-	"github.com/gin-gonic/gin"
-)
-
-func main() {
-	router := gin.Default()
-
-	router.POST("/upload", func(c *gin.Context) {
-		file, header, err := c.Request.FormFile("file")
-		if err != nil {
-			c.String(http.StatusBadRequest, fmt.Sprintf("文件上传失败: %s", err.Error()))
-			return
-		}
-		defer file.Close()
-
-		// 指定保存目录
-		uploadDir := filepath.Join("./uploads", strings.Split(header.Filename, ".")[0])
-		err = os.MkdirAll(uploadDir, os.ModePerm)
-		if err != nil {
-			c.String(http.StatusInternalServerError, fmt.Sprintf("创建上传目录失败: %s", err.Error()))
-			return
-		}
-
-		// 指定保存文件路径
-		filePath := filepath.Join(uploadDir, header.Filename)
-		out, err := os.Create(filePath)
-		if err != nil {
-			c.String(http.StatusInternalServerError, fmt.Sprintf("保存文件失败: %s", err.Error()))
-			return
-		}
-		defer out.Close()
-
-		_, err = io.Copy(out, file)
-		if err != nil {
-			c.String(http.StatusInternalServerError, fmt.Sprintf("保存文件失败: %s", err.Error()))
-			return
-		}
-
-		c.String(http.StatusOK, fmt.Sprintf("文件 %s 上传成功", header.Filename))
-	})
-
-	router.Run(":8080")
-}

BIN
demo4/demo4.exe


+ 0 - 123
demo4/main.go

@@ -1,123 +0,0 @@
-package main
-
-import (
-	"errors"
-	"fmt"
-	"reflect"
-	"strings"
-)
-
-func main() {
-	type Address struct {
-		City  string
-		State string
-	}
-	type User struct {
-		Name    string
-		Age     int
-		Address *Address
-	}
-
-	var test = new(User)
-	test.Name = "ra"
-	fmt.Println(test)
-}
-
-// Struct2MgrStr 结构提转换为字符串
-func Struct2MgrStr(in interface{}, tag, connector string) (string, error) {
-	var out string
-	var val = reflect.ValueOf(in)
-	if val.Kind() == reflect.Array || val.Kind() == reflect.Slice && !val.IsZero() {
-		val = reflect.ValueOf(in.([]interface{})[0])
-	}
-
-	// 判断in是否为指针类型, 如果v为指针类型这将v替换为指针对应的值
-	if val.Kind() == reflect.Ptr {
-		val = val.Elem()
-	}
-
-	if val.Kind() != reflect.Struct && val.Kind() != reflect.Map {
-		return "", errors.New("输入格式异常,不是Struct/Map类型数据")
-	}
-
-	var tp = val.Type()
-	var args = make([]string, 0)
-
-	for i := 0; i < val.NumField(); i++ {
-		v := val.Field(i)
-		if v.IsZero() {
-			continue
-		}
-		if v.Kind() == reflect.Ptr {
-			v = v.Elem()
-		}
-		fi := tp.Field(i)
-		tagVal := fi.Tag.Get(tag)
-		if tagVal == "-" || tagVal == "" {
-			continue
-		}
-		if v.Kind() == reflect.String && v.String() == "" {
-			continue
-		}
-		args = append(args, fmt.Sprintf("%s%s%v", tagVal, connector, v.Interface()))
-	}
-	out = strings.Join(args, " ")
-	return out, nil
-}
-
-//package main
-//
-//import (
-//	"fmt"
-//	"github.com/robfig/cron/v3"
-//	"os"
-//	"time"
-//
-//	"go.uber.org/zap"
-//)
-//
-//func main() {
-//
-//	c := cron.New()
-//
-//	c.Start()
-//	// 初始化 logger
-//	logger := initLogger()
-//
-//	// 监听 SIGUSR1 信号
-//
-//	EntryID, err := c.AddFunc("*/1 * * * *", func() {
-//		logger.Info("cron running")
-//
-//		logger = initLogger()
-//	})
-//	fmt.Println(time.Now(), EntryID, err)
-//
-//	// 保持进程运行
-//	select {}
-//}
-//
-//func initLogger() *zap.Logger {
-//	// 获取当前日期
-//	currentTime := time.Now()
-//
-//	// 格式化日期作为文件名
-//	filename := "log/app_" + currentTime.Format("2006-01-02-15-04-05") + ".log"
-//
-//	_, err2 := os.Create(filename)
-//	if err2 != nil {
-//		panic(err2)
-//
-//	}
-//	// 配置日志输出路径
-//	config := zap.NewProductionConfig()
-//	config.OutputPaths = []string{filename, "stdout"}
-//
-//	// 创建 logger 实例
-//	logger, err := config.Build()
-//	if err != nil {
-//		panic(err)
-//	}
-//
-//	return logger
-//}

BIN
demo4/snp.efi


+ 59 - 3
demo5/main.go

@@ -2,17 +2,73 @@ package main
 
 import (
 	"encoding/hex"
+	"errors"
 	"github.com/tjfoc/gmsm/sm3"
+	"reflect"
 )
 
-var a *int
-
 func main() {
-	if true && false && false || false {
 
+	s := new(string)
+	if s == nil {
+		VarAssignment(s, "/home")
 	}
+	VarAssignment(s, "/")
+	println(*s)
 }
 
+// VarAssignment 变量赋值
+func VarAssignment(to, from any) error {
+	var oldTv, oldFv, tv, fv reflect.Value
+	tv = reflect.ValueOf(to)
+	fv = reflect.ValueOf(from)
+	if _, ok := to.(reflect.Value); ok {
+		tv = to.(reflect.Value)
+	}
+	if _, ok := from.(reflect.Value); ok {
+		fv = from.(reflect.Value)
+	}
+	if _, ok := to.(*reflect.Value); ok {
+		tv = *(to.(*reflect.Value))
+	}
+	if _, ok := from.(*reflect.Value); ok {
+		fv = *(from.(*reflect.Value))
+	}
+
+	oldTv = tv
+	oldFv = fv
+
+	if tv.IsNil() {
+		return errors.New("The target data cannot be nil\n")
+	}
+	// 判断目标变量类型是否为指针类型,非指针类型返回错误
+	if tv.Kind() == reflect.Ptr {
+		tv = tv.Elem()
+	} else {
+		return errors.New("The target variable must be of pointer type ")
+	}
+	if fv.Kind() == reflect.Ptr {
+		fv = fv.Elem()
+	}
+
+	// 判断目标变量类型和原变量类型是否一致
+	if oldTv.Type().Elem().Kind() != fv.Kind() {
+		return errors.New("Inconsistent data types ")
+	}
+
+	// 判断来源变量是否为空指针,如果为空指针则直接退出
+	if oldFv.IsZero() && oldFv.Kind() == reflect.Ptr {
+		return nil
+	}
+
+	// 判断目标变量是否为空,如果为空则创建内存空间
+	if oldTv.IsZero() {
+		val := reflect.New(oldTv.Type().Elem())
+		oldTv.Set(val)
+	}
+	oldTv.Elem().Set(fv)
+	return nil
+}
 func SM3SUM(in string) string {
 	sm3Sum := sm3.Sm3Sum([]byte(in))
 	return hex.EncodeToString(sm3Sum)

+ 10 - 0
etcd/global.go

@@ -0,0 +1,10 @@
+package main
+
+import (
+	"context"
+	clientv3 "go.etcd.io/etcd/client/v3"
+)
+
+var client *clientv3.Client
+
+var ctx = context.Background()

+ 7 - 33
etcd/lock/test.go

@@ -2,7 +2,6 @@ package main
 
 import (
 	"context"
-	"fmt"
 	clientv3 "go.etcd.io/etcd/client/v3"
 	"go.etcd.io/etcd/client/v3/concurrency"
 	"time"
@@ -18,40 +17,15 @@ func main() {
 	}
 	defer cli.Close()
 
-	for i := 0; i < 10; i++ {
+	grant, _ := cli.Grant(context.Background(), 15)
 
-		go func(i int) {
-			m, err := NewPciLock(cli)
-			if err != nil {
-				fmt.Printf("Error creating")
-			}
-			m.IsOwner()
-			err = m.Lock(context.Background())
-			if err != nil {
-				fmt.Printf("Failed to lock: %v\n", err)
-				return
-			}
-			if i == 1 {
-				time.Sleep(time.Second * 10)
-			}
-			fmt.Println(i)
-			err = m.Unlock(context.Background())
-			if err != nil {
-				fmt.Printf("Failed to Unlock: %v\n", err)
-				return
-			}
-		}(i)
-	}
-	time.Sleep(time.Second * 15)
-}
-
-func NewPciLock(etcd *clientv3.Client) (*concurrency.Mutex, error) {
-	session, err := concurrency.NewSession(etcd, concurrency.WithTTL(5))
+	session, err := concurrency.NewSession(cli, concurrency.WithLease(grant.ID))
 	if err != nil {
-		return nil, err
+		panic(err)
 	}
+	m := concurrency.NewLocker(session, "lock/test")
+	m.Lock()
+	defer m.Unlock()
+	time.Sleep(20 * time.Second)
 
-	m := concurrency.NewMutex(session, "hstack/server/pciLock")
-
-	return m, nil
 }

+ 89 - 43
etcd/test.go

@@ -1,10 +1,11 @@
 package main
 
 import (
-	"context"
 	"fmt"
 	"go.etcd.io/etcd/client/v3"
+	"go.etcd.io/etcd/client/v3/concurrency"
 	"log"
+	"strings"
 	"time"
 )
 
@@ -66,12 +67,74 @@ func main() {
 		panic(err)
 	}
 	defer cli.Close()
+	session, err := concurrency.NewSession(cli, concurrency.WithTTL(5))
+	if err != nil {
+		panic(err)
+	}
+	m := concurrency.NewMutex(session, "lock/test")
+	for i := 0; i < 10; i++ {
+		err = m.TryLock(ctx)
+		if err != nil {
+			fmt.Printf("Failed to lock: %v\n", err)
+			time.Sleep(1 * time.Second)
+			continue
+		}
+		fmt.Println("Locked")
+		time.Sleep(1 * time.Second)
+		m.Unlock(ctx)
+		fmt.Println("Unlocked")
+	}
+}
+
+// 保持租约
+func keepAlive(cli *clientv3.Client, leaseID clientv3.LeaseID) {
+	alive, err := cli.KeepAlive(ctx, leaseID)
+	if err != nil {
+		fmt.Printf("Failed to keep alive: %v\n", err)
+		return
+	}
+	//监听KeepAlive的响应
+	go func() {
+		for {
+			ka := <-alive
+			if ka == nil {
+				log.Println("租约已失效或KeepAlive通道已关闭")
+				return
+			}
+			log.Printf("续租成功: %v\n", ka)
+		}
+	}()
+}
+
+// 新增键值对
+func put(cli *clientv3.Client, key, value string) error {
+	_, err := cli.Put(ctx, key, value)
+	if err != nil {
+		log.Fatal(err)
+		return err
+	}
+	return nil
+}
+
+// 新增键值对,带有过期时间
+func putWithTTL(cli *clientv3.Client, key, value string, ttl int64) (int64, error) {
+	leaseResp, err := cli.Grant(ctx, ttl)
+	if err != nil {
+		log.Fatal(err)
+		return 0, err
+	}
+	_, err = cli.Put(ctx, key, value, clientv3.WithLease(leaseResp.ID))
+	if err != nil {
+		log.Fatal(err)
+		return 0, err
+	}
+	return int64(leaseResp.ID), nil
+}
 
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel()
+// 监听键值变化
+func watch(cli *clientv3.Client, key string) {
 
-	// 开始监听以 "/services/" 为前缀的键值变化
-	watchCh := cli.Watch(ctx, "/services/", clientv3.WithPrefix())
+	watchCh := cli.Watch(ctx, key, clientv3.WithPrefix())
 
 	go func() {
 
@@ -91,48 +154,31 @@ func main() {
 			}
 		}
 	}()
-	// 创建租约
-	leaseResp, err := cli.Grant(ctx, 15) // 租约时间为 15 秒
-	if err != nil {
-		fmt.Printf("Failed to grant lease: %v\n", err)
-		return
-	}
+}
 
-	// 使用租约创建服务实例的键
-	_, err = cli.Put(ctx, "/services/service1", "", clientv3.WithLease(leaseResp.ID))
+// 获取键的值
+func get(cli *clientv3.Client, key string) (string, error) {
+	resp, err := cli.Get(ctx, key)
 	if err != nil {
-		fmt.Printf("Failed to put service instance: %v\n", err)
-		return
+		log.Fatal(err)
+		return "", err
+	}
+	if resp.Count == 0 {
+		return "", fmt.Errorf("key %s not found", key)
 	}
+	return string(resp.Kvs[0].Value), nil
+}
 
-	alive, err := cli.KeepAlive(ctx, leaseResp.ID) // 续租(ttl/3)
+// 获取当前前缀下所有的键并截取前缀
+func getAndCutPrefix(cli *clientv3.Client, prefix string) ([]string, error) {
+	resp, err := cli.Get(ctx, prefix, clientv3.WithPrefix())
 	if err != nil {
-		fmt.Printf("Failed to keep alive: %v\n", err)
-		return
+		log.Fatal(err)
+		return nil, err
 	}
-	//监听KeepAlive的响应
-	go func() {
-		for {
-			ka := <-alive
-			if ka == nil {
-				log.Println("租约已失效或KeepAlive通道已关闭")
-				return
-			}
-			log.Printf("续租成功: %v\n", ka)
-		}
-	}()
-
-	fmt.Println("Watching for changes...")
-	get, _ := cli.Get(ctx, "/services/service1")
-	fmt.Println(get.Kvs)
-	// 处理监听结果
-	go func() {
-		time.Sleep(10 * time.Second)
-		// 注意: 程序退出时,应当撤销租约或删除键
-		_, err = cli.Revoke(context.TODO(), leaseResp.ID)
-		if err != nil {
-			log.Fatal(err)
-		}
-	}()
-	time.Sleep(15 * time.Second)
+	keys := make([]string, 0)
+	for _, kv := range resp.Kvs {
+		keys = append(keys, strings.TrimPrefix(string(kv.Key), prefix))
+	}
+	return keys, nil
 }

+ 111 - 0
fileupload/client/test.go

@@ -0,0 +1,111 @@
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"mime/multipart"
+	"net/http"
+	"os"
+)
+
+func main() {
+	filePath := "C:\\Users\\lx\\Downloads\\ubuntu-22.04.4-live-server-amd64.iso"
+	chunkSize := int64(1024 * 1024 * 100) // 100MB 分块大小
+	fileID := "unique-file-id"            // 文件唯一标识符
+
+	// 打开文件
+	file, err := os.Open(filePath)
+	if err != nil {
+		panic(err)
+	}
+	defer file.Close()
+
+	// 获取文件信息
+	fileInfo, err := file.Stat()
+	if err != nil {
+		panic(err)
+	}
+	fileSize := fileInfo.Size()
+
+	// 计算总块数
+	totalChunks := (fileSize + chunkSize - 1) / chunkSize
+
+	// 记录已上传的块(可以保存在文件或数据库中)
+	uploadedChunks := make(map[int64]bool)
+
+	// 遍历每个块并上传
+	for chunkIndex := int64(0); chunkIndex < totalChunks; chunkIndex++ {
+		if uploadedChunks[chunkIndex] {
+			// 如果该块已经上传,则跳过
+			continue
+		}
+
+		// 创建块的缓冲区
+		buffer := make([]byte, chunkSize)
+		readBytes, err := file.Read(buffer)
+		if err != nil && err != io.EOF {
+			panic(err)
+		}
+		if readBytes == 0 {
+			break
+		}
+
+		// 上传块
+		err = uploadChunk(buffer[:readBytes], chunkIndex, totalChunks, fileID, fileInfo.Name())
+		if err != nil {
+			fmt.Printf("Failed to upload chunk %d: %v\n", chunkIndex, err)
+			continue
+		}
+
+		// 记录已上传块
+		uploadedChunks[chunkIndex] = true
+	}
+}
+
+func uploadChunk(chunkData []byte, chunkIndex, totalChunks int64, fileID, filename string) error {
+	// 创建 multipart 请求体
+	body := new(bytes.Buffer)
+	writer := multipart.NewWriter(body)
+
+	// 添加文件块
+	part, err := writer.CreateFormFile("file", filename)
+	if err != nil {
+		return err
+	}
+	part.Write(chunkData)
+
+	// 添加其他字段
+	writer.WriteField("chunkIndex", fmt.Sprintf("%d", chunkIndex))
+	writer.WriteField("totalChunks", fmt.Sprintf("%d", totalChunks))
+	writer.WriteField("fileID", fileID)
+
+	// 关闭 multipart 编写器
+	err = writer.Close()
+	if err != nil {
+		return err
+	}
+
+	// 发送请求
+	req, err := http.NewRequest("POST", "http://localhost:8080/upload", body)
+	if err != nil {
+		return err
+	}
+	req.Header.Set("Content-Type", writer.FormDataContentType())
+
+	client := &http.Client{}
+	resp, err := client.Do(req)
+	if err != nil {
+		return err
+	}
+	defer resp.Body.Close()
+
+	// 读取响应
+	respBody, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return err
+	}
+
+	fmt.Printf("Response: %s\n", string(respBody))
+	return nil
+}

+ 179 - 0
fileupload/main.go

@@ -0,0 +1,179 @@
+package main
+
+import (
+	"fmt"
+	"io"
+	"net/http"
+	"os"
+	"path/filepath"
+	"strconv"
+	"sync"
+
+	"github.com/gin-gonic/gin"
+)
+
+const uploadPath = "C:\\Users\\lx\\GolandProjects\\demo\\fileupload\\uploads"
+const progressFilePath = "C:\\Users\\lx\\GolandProjects\\demo\\fileupload\\uploads\\progress"
+
+var mu sync.Mutex // 使用互斥锁来确保并发时的进度文件读写安全
+
+func main() {
+	router := gin.Default()
+
+	// 确保上传和进度记录目录存在
+	err := os.MkdirAll(uploadPath, os.ModePerm)
+	if err != nil {
+		panic(err)
+	}
+	err = os.MkdirAll(progressFilePath, os.ModePerm)
+	if err != nil {
+		panic(err)
+	}
+
+	// 定义分块上传接口,支持断点续传
+	router.POST("/upload", upload)
+
+	router.Run(":8080")
+}
+
+func upload(c *gin.Context) {
+	// 获取上传的文件块
+	file, header, err := c.Request.FormFile("file")
+	if err != nil {
+		c.String(http.StatusBadRequest, "Failed to get file: %s", err.Error())
+		return
+	}
+	defer file.Close()
+
+	// 获取文件块编号和总块数
+	chunkIndex := c.PostForm("chunkIndex")   // 当前块编号
+	totalChunks := c.PostForm("totalChunks") // 总块数
+	fileID := c.PostForm("fileID")           // 文件标识符
+
+	chunkIdx, err := strconv.Atoi(chunkIndex)
+	if err != nil {
+		c.String(http.StatusBadRequest, "Invalid chunk index")
+		return
+	}
+	totalChunksNum, err := strconv.Atoi(totalChunks)
+	if err != nil {
+		c.String(http.StatusBadRequest, "Invalid total chunks")
+		return
+	}
+
+	// 先检查该文件的进度文件,看看该块是否已经上传
+	if isChunkUploaded(fileID, chunkIdx) {
+		c.String(http.StatusOK, "Chunk %d already uploaded", chunkIdx)
+		return
+	}
+
+	// 构造临时文件路径
+	tempFilePath := filepath.Join(uploadPath, fmt.Sprintf("%s.tmp", fileID))
+
+	// 打开或创建临时文件
+	tempFile, err := os.OpenFile(tempFilePath, os.O_CREATE|os.O_WRONLY, os.ModePerm)
+	if err != nil {
+		c.String(http.StatusInternalServerError, "Failed to create temp file: %s", err.Error())
+		return
+	}
+	defer tempFile.Close()
+
+	// 计算文件块的偏移量
+	chunkSize := header.Size
+	offset := int64(chunkIdx) * chunkSize
+
+	// 定位文件指针到正确的偏移量并写入块数据
+	_, err = tempFile.Seek(offset, 0)
+	if err != nil {
+		c.String(http.StatusInternalServerError, "Failed to seek in temp file: %s", err.Error())
+		return
+	}
+
+	// 将块写入临时文件
+	_, err = io.Copy(tempFile, file)
+	if err != nil {
+		c.String(http.StatusInternalServerError, "Failed to write to temp file: %s", err.Error())
+		return
+	}
+
+	// 记录该块已上传
+	recordChunkProgress(fileID, chunkIdx)
+
+	// 当所有块上传完毕时,将临时文件重命名为最终的文件
+	if chunkIdx == totalChunksNum-1 {
+		tempFile.Close()
+		finalFilePath := filepath.Join(uploadPath, header.Filename)
+		err = os.Rename(tempFilePath, finalFilePath)
+		if err != nil {
+			c.String(http.StatusInternalServerError, "Failed to finalize file: %s", err.Error())
+			return
+		}
+
+		// 上传完成后删除进度记录文件
+		deleteProgressFile(fileID)
+
+		c.String(http.StatusOK, "Upload complete: %s", finalFilePath)
+	} else {
+		c.String(http.StatusOK, "Chunk %d of %d uploaded", chunkIdx+1, totalChunksNum)
+	}
+}
+
+// 检查该文件的某个块是否已经上传
+func isChunkUploaded(fileID string, chunkIndex int) bool {
+	progressFile := filepath.Join(progressFilePath, fileID+".progress")
+
+	mu.Lock()
+	defer mu.Unlock()
+
+	if _, err := os.Stat(progressFile); os.IsNotExist(err) {
+		return false
+	}
+
+	file, err := os.Open(progressFile)
+	if err != nil {
+		return false
+	}
+	defer file.Close()
+
+	// 读取进度文件中的内容
+	var uploadedChunk int
+	for {
+		_, err := fmt.Fscanf(file, "%d\n", &uploadedChunk)
+		if err != nil {
+			break
+		}
+		if uploadedChunk == chunkIndex {
+			return true
+		}
+	}
+
+	return false
+}
+
+// 记录某个文件的某块已经上传
+func recordChunkProgress(fileID string, chunkIndex int) {
+	progressFile := filepath.Join(progressFilePath, fileID+".progress")
+
+	mu.Lock()
+	defer mu.Unlock()
+
+	file, err := os.OpenFile(progressFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.ModePerm)
+	if err != nil {
+		fmt.Println("Failed to open progress file:", err)
+		return
+	}
+	defer file.Close()
+
+	_, err = fmt.Fprintf(file, "%d\n", chunkIndex)
+	if err != nil {
+		fmt.Println("Failed to write to progress file:", err)
+	}
+}
+
+// 删除进度文件(在文件上传完成后)
+func deleteProgressFile(fileID string) {
+	progressFile := filepath.Join(progressFilePath, fileID+".progress")
+	mu.Lock()
+	defer mu.Unlock()
+	os.Remove(progressFile)
+}

+ 2 - 1
go.mod

@@ -3,13 +3,13 @@ module demo
 go 1.22
 
 require (
+	github.com/bwmarrin/snowflake v0.3.0
 	github.com/dtm-labs/client v1.18.7
 	github.com/fsnotify/fsnotify v1.7.0
 	github.com/gin-gonic/gin v1.10.0
 	github.com/go-ping/ping v1.1.0
 	github.com/google/wire v0.6.0
 	github.com/lithammer/shortuuid/v3 v3.0.7
-	github.com/lucklucif/ipmigo v0.0.0-20220207161123-b2ae2e5288df
 	github.com/pin/tftp/v3 v3.1.0
 	github.com/spf13/viper v1.19.0
 	github.com/streadway/amqp v1.1.0
@@ -94,6 +94,7 @@ require (
 	github.com/sagikazarmark/crypt v0.19.0 // indirect
 	github.com/sagikazarmark/locafero v0.4.0 // indirect
 	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
+	github.com/sony/sonyflake v1.2.0 // indirect
 	github.com/sourcegraph/conc v0.3.0 // indirect
 	github.com/spf13/afero v1.11.0 // indirect
 	github.com/spf13/cast v1.6.0 // indirect

+ 4 - 2
go.sum

@@ -30,6 +30,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
+github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
 github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
 github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
 github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
@@ -263,8 +265,6 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
 github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
 github.com/lithammer/shortuuid/v3 v3.0.7 h1:trX0KTHy4Pbwo/6ia8fscyHoGA+mf1jWbPJVuvyJQQ8=
 github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts=
-github.com/lucklucif/ipmigo v0.0.0-20220207161123-b2ae2e5288df h1:CMRy+hqaA7Qyb5YLePQ9MaSa8RsFzhCyrUn5vuCRr1o=
-github.com/lucklucif/ipmigo v0.0.0-20220207161123-b2ae2e5288df/go.mod h1:LoolTif163tJ8JEFud3n1ow7MtfG2yelWQklvVrGNyA=
 github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
 github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -369,6 +369,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUt
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sony/sonyflake v1.2.0 h1:Pfr3A+ejSg+0SPqpoAmQgEtNDAhc2G1SUYk205qVMLQ=
+github.com/sony/sonyflake v1.2.0/go.mod h1:LORtCywH/cq10ZbyfhKrHYgAUGH7mOBa76enV9txy/Y=
 github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
 github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
 github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=

+ 93 - 24
gorm/main.go

@@ -4,6 +4,8 @@ import (
 	"fmt"
 	"gorm.io/driver/mysql"
 	"gorm.io/gorm"
+	"gorm.io/gorm/logger"
+	"time"
 )
 
 // 定义 User 模型
@@ -11,11 +13,24 @@ type User struct {
 	gorm.Model
 	Name  string
 	Email string
+	Test  Test
+}
+
+type Test struct {
+	gorm.Model
+	Name   string
+	UserID *uint
 }
 
 func main() {
 
-	user := User{Name: "John Doe", Email: "john.doe@example.com"}
+	user := User{
+		Name:  "John Doe",
+		Email: "john.doe@example.com",
+		Test: Test{
+			Name: "test",
+		},
+	}
 	Created(&user)
 	// 打印成功创建的消息
 	fmt.Printf("User created with ID: %d\n", user.ID)
@@ -23,35 +38,89 @@ func main() {
 }
 
 func Created(u *User) {
-	dsn := "root:lxz664278@tcp(106.54.33.152:33369)/gorm?charset=utf8mb4&parseTime=True&loc=Local"
-	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
+	dsn := "root:lxz664278@tcp(106.54.33.152:33369)/hstack?charset=utf8mb4&parseTime=True&loc=Local"
+	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
+		Logger: logger.Default.LogMode(logger.Info),
+	})
 	if err != nil {
 		panic("failed to connect database")
 	}
+	info, _ := GetNodePartInfo(&Node{Model: Model{ID: 2}}, *db)
+	fmt.Println(info)
+}
 
-	// 创建记录
-	result := db.Create(u)
+func GetNodePartInfo(node *Node, DBConn gorm.DB) (*Node, error) {
+	var result = new(Node)
 
-	if result.Error != nil {
-		fmt.Println("Error creating user:", result.Error)
-		return
+	tx := DBConn.Model(Node{}).Select([]string{
+		"id", "node_tag",
+		"max_v_cpu", "use_v_cpu",
+		"max_mem", "use_mem",
+		"max_gpu", "use_gpu",
+		"max_vpc", "use_vpc",
+		"stat"}).Where("id=?", node.ID).Find(result)
+	if tx.Error != nil {
+		return nil, tx.Error
 	}
-
-	// 更新记录
-	var t = &User{
-		Model: gorm.Model{
-			ID: u.ID,
-		},
-		Name:  "John Doe Updated",
-		Email: "",
+	if result.ID <= 0 {
+		result = nil
 	}
-	db.Updates(t)
+	return result, nil
+}
 
-	var user User
-	re := db.Model(&User{}).First(&user, u.ID)
-	if re.Error != nil {
-		fmt.Println("Error getting user:", re.Error)
-		return
-	}
-	fmt.Println("User:", user)
+// Node 节点信息
+type Node struct {
+	Model
+	NodeName               string `json:"node_name" gorm:"node_name" `                     // 节点名称
+	ZoneId                 int    `json:"zone_id" gorm:"zone_id" `                         // 所属资源区ID
+	ZoneName               string `json:"zone_name" gorm:"zone_name" `                     // 所属资源区名
+	BmcIP                  string `json:"bmc_ip" gorm:"bmc_ip" `                           // BMC IP
+	BmcUser                string `json:"bmc_user" gorm:"bmc_user" `                       // BMC 用户名
+	BmcPass                string `json:"bmc_pass" gorm:"bmc_pass" `                       // BMC 密码
+	MgrIp                  string `json:"mgr_ip" gorm:"mgr_ip" `                           // 管理IP
+	NodeIp                 string `json:"node_ip" gorm:"node_ip" `                         // 节点IP
+	ListenPort             int    `json:"listen_port" gorm:"listen_port" `                 // 监听端口
+	SSHPort                int    `json:"ssh_port" gorm:"ssh_port" `                       // SSH端口号
+	RootUser               string `json:"root_user" gorm:"root_user" `                     // root用户
+	RootPass               string `json:"root_pass" gorm:"root_pass" `                     // root密码
+	RootSecretKey          string `json:"root_secret_key" gorm:"root_secret_key" `         // Root账号密钥
+	SecretKeyPass          string `json:"secret_key_pass" gorm:"secret_key_pass" `         // 密钥密码
+	NodeMode               int    `json:"node_mode" gorm:"node_mode" `                     // 节点模式
+	NodeTag                string `json:"node_tag" gorm:"node_tag" `                       // 节点标记
+	MaxVCpu                int    `json:"max_v_cpu" gorm:"max_v_cpu" `                     // 最大可虚拟化CPU数量
+	UseVCpu                int    `json:"use_v_cpu" gorm:"use_v_cpu" `                     // 已使用虚拟化CPU数量
+	Cpu                    int    `json:"cpu" gorm:"cpu" `                                 // CPU数量
+	CpuType                int    `json:"cpu_type" gorm:"cpu_type" `                       // CPU类型 (x86_64:1;amd64:2;arm:3;other:4)
+	MaxMem                 int64  `json:"max_mem" gorm:"max_mem" `                         // 最大内存
+	UseMem                 int64  `json:"use_mem" gorm:"use_mem" `                         // 已使用内存
+	MaxGpu                 int    `json:"max_gpu" gorm:"max_gpu" `                         // 最大GPU数
+	UseGpu                 int    `json:"use_gpu" gorm:"use_gpu" `                         // 已使用GPU数
+	NodeWidget             int    `json:"node_widget" gorm:"node_widget" `                 // 节点权重
+	NodeLoadStat           int    `json:"node_load_stat" gorm:"node_load_stat" `           // 节点负载状态
+	MaxVPC                 int    `json:"max_vpc" gorm:"column:max_vpc;default:5" `        // 节点创建的最大VPC数量
+	UseVPC                 int    `json:"use_vpc" gorm:"column:use_vpc;default:0" `        // 节点已创建的VPC
+	RunStat                int    `json:"run_stat" gorm:"run_stat" `                       // 节点运行状态
+	AutoSyncNodeStat       int    `json:"auto_sync_node_stat" gorm:"auto_sync_node_stat" ` // 自动同步节点状态
+	PcieIdList             []int  `json:"pcie_id_list" gorm:"-" `                          // PCIE设备ID列表
+	HPCInitCommandIdList   []int  `json:"hpc_init_command_id_list" gorm:"-" `              // hpc命令ID数组
+	CloudInitCommandIdList []int  `json:"cloud_init_command_id_list" gorm:"-" `            // 云命令ID数组
+}
+type Model struct {
+	ID           int            `json:"id" gorm:"column:id;primarykey" `                                               // 主键ID
+	CreatedAt    *time.Time     `json:"created_at" gorm:"column:created_at;autoCreateTime:nano" swaggerignore:"true" ` // 创建时间
+	UpdatedAt    *time.Time     `json:"updated_at" gorm:"column:updated_at;autoUpdateTime:nano" swaggerignore:"true"`  // 更新时间
+	DeletedAt    gorm.DeletedAt `json:"deleted_at" gorm:"column:deleted_at;index" swaggerignore:"true"`                // 删除时间
+	CreateUser   string         `json:"create_user" gorm:"create_user" swaggerignore:"true"`                           // 创建用户
+	CreateUserId int            `json:"create_user_id" gorm:"create_user_id" swaggerignore:"true"`                     // 创建用户ID
+	UpdateUser   string         `json:"update_user" gorm:"update_user" swaggerignore:"true"`                           // 更新用户
+	UpdateUserId int            `json:"update_user_id" gorm:"update_user_id" swaggerignore:"true"`                     // 更新用户ID
+	DeleteUser   string         `json:"delete_user" gorm:"delete_user" swaggerignore:"true" `                          // 删除用户
+	DeleteUserId int            `json:"delete_user_id" gorm:"delete_user_id" swaggerignore:"true"`                     // 删除用户ID
+	Remark       string         `json:"remark" gorm:"remark" swaggerignore:"true"`                                     // 备注
+	Stat         int            `json:"stat" gorm:"stat" swaggerignore:"true"`                                         // 状态
+	ExpireAt     *time.Time     `json:"expire_at" gorm:"expire_at" swaggerignore:"true"`                               // 过期时间
+}
+
+func (Node) TableName() string {
+	return "node"
 }

+ 149 - 0
ipgen/main.go

@@ -0,0 +1,149 @@
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"net"
+	"strconv"
+	"strings"
+)
+
+func generateIP(startIP, endIP string) (string, error) {
+	start := net.ParseIP(startIP)
+	end := net.ParseIP(endIP)
+
+	if start == nil || end == nil {
+		return "", fmt.Errorf("invalid IP address")
+	}
+
+	ip := incrementIP(start)
+	if ip.Equal(end) {
+		return "", fmt.Errorf("invalid IP address")
+	}
+
+	return ip.String(), nil
+}
+
+func incrementIP(ip net.IP) net.IP {
+
+	ip = ip.To4()
+	if ip == nil {
+		return ip // Return if it's not a valid IPv4 address
+	}
+
+	for i := len(ip) - 1; i >= 0; i-- {
+		if ip[i] < 255 {
+			ip[i]++
+			return ip
+		}
+		ip[i] = 0 // Reset to 0 if it overflows
+	}
+	return ip // Return the incremented IP
+}
+
+// checkIPInRange 检查给定 IP 是否在指定的范围内
+func checkIPInRange(ipStr, startStr, endStr string) (bool, error) {
+	ip := net.ParseIP(ipStr)
+	start := net.ParseIP(startStr)
+	end := net.ParseIP(endStr)
+
+	if ip == nil || start == nil || end == nil {
+		return false, fmt.Errorf("invalid IP address")
+	}
+
+	return bytesCompare(ip, start) >= 0 && bytesCompare(ip, end) <= 0, nil
+}
+
+// bytesCompare 对 IP 进行字节比较
+func bytesCompare(a, b net.IP) int {
+	return bytes.Compare(a, b)
+}
+
+func ipToInt(ip net.IP) int64 {
+	// 将 IP 地址转换为整数
+	return int64(ip[0])<<24 + int64(ip[1])<<16 + int64(ip[2])<<8 + int64(ip[3])
+}
+
+func generateSequentialMAC(start [6]byte, count int) [][6]byte {
+	macAddresses := make([][6]byte, count)
+
+	for i := 0; i < count; i++ {
+		macAddresses[i] = start
+		// 递增MAC地址
+		for j := 5; j >= 0; j-- {
+			if start[j]++; start[j] != 0 {
+				break
+			}
+		}
+	}
+
+	return macAddresses
+}
+
+// parseMACString 将字符串格式的 MAC 地址转换为 [6]byte 类型
+func parseMACString(macStr string) ([6]byte, error) {
+	macParts := strings.Split(macStr, ":")
+	if len(macParts) != 6 {
+		return [6]byte{}, fmt.Errorf("invalid MAC address format: %s", macStr)
+	}
+
+	var mac [6]byte
+	for i, part := range macParts {
+		num, err := strconv.ParseUint(part, 16, 8)
+		if err != nil {
+			return [6]byte{}, fmt.Errorf("invalid MAC address format: %s", macStr)
+		}
+		mac[i] = byte(num)
+	}
+	return mac, nil
+}
+func formatMAC(mac [6]byte) string {
+	return fmt.Sprintf("%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])
+}
+
+func main() {
+	macStr := "23:E0:00:00:01:01"
+
+	// 转换为 [6]byte
+	startMAC, err := parseMACString(macStr)
+	if err != nil {
+		fmt.Println("Error:", err)
+		return
+	}
+	if isValidMACAddressInRange(startMAC, 0) {
+		fmt.Println("MAC地址在指定范围内")
+	} else {
+		fmt.Println("MAC地址不在指定范围内")
+	}
+}
+
+func NowIP() string {
+	return "192.168.1.13"
+}
+
+func GenerateIP(start, end string) string {
+	//startIp := net.ParseIP(start)
+	//endIp := net.ParseIP(end)
+	//
+	//ip := net.ParseIP(NowIP())
+	return ""
+}
+
+// isValidMACAddressInRange 检查 MAC 地址是否在指定范围内
+func isValidMACAddressInRange(mac [6]byte, networkType int) bool {
+	startMAC, err := parseMACString("23:E0:00:00:00:00")
+	if err != nil {
+		return false
+	}
+	endMAC, err := parseMACString("23:E0:00:00:00:FF")
+	if err != nil {
+		return false
+	}
+
+	for i := 0; i < 6; i++ {
+		if mac[i] < startMAC[i] || mac[i] > endMAC[i] {
+			return false
+		}
+	}
+	return true
+}