Administrator 1 سال پیش
کامیت
e62d3a9c80

+ 139 - 0
command_test.go

@@ -0,0 +1,139 @@
+package main
+
+//
+//func TestCommand(t *testing.T) {
+//	bytes := make([]byte, 0)
+//	bytes = append(bytes, 0x2a)
+//	command := "你好1"
+//	cmd := []byte(command)
+//	l := util.IntToBytes(int32(len(cmd)))
+//	bytes = append(bytes, l...)
+//	bytes = append(bytes, cmd...)
+//	bytes = append(bytes, util.Int16ToBytes(util.Crc16CCITT(cmd))...)
+//	fmt.Println(util.ToHexBytes(bytes))
+//}
+//func TestGetFiles(t *testing.T) {
+//	// 标准用法
+//	result, err := GetPathInfo("D:\\project\\my\\file-manger\\frontend\\node_modules")
+//	if err != nil {
+//		fmt.Printf("错误: %+v\n", err)
+//		return
+//	}
+//	fmt.Printf("找到 %d 目录\n", len(result.Dirs))
+//	fmt.Printf("找到 %d 文件\n", len(result.Files))
+//	time.Sleep(20 * time.Second)
+//	// 流式处理
+//	//paths, errs := StreamPathInfo("/bigdata")
+//	//for {
+//	//	select {
+//	//	case path, ok := <-paths:
+//	//		if !ok {
+//	//			return
+//	//		}
+//	//		fmt.Println(path)
+//	//	case err := <-errs:
+//	//		fmt.Println("错误:", err)
+//	//		return
+//	//	}
+//	//}
+//}
+//
+//type PathInfo struct {
+//	Dirs  []string // 目录路径(包含所有层级)
+//	Files []string // 文件路径
+//}
+//
+//var pathPool = sync.Pool{
+//	New: func() interface{} {
+//		return &PathInfo{
+//			Dirs:  make([]string, 0, 1024), // 预分配容量
+//			Files: make([]string, 0, 4096),
+//		}
+//	},
+//}
+//
+//func GetPathInfo(root string) (*PathInfo, error) {
+//	// 复用对象减少内存分配[9](@ref)
+//	info := pathPool.Get().(*PathInfo)
+//
+//	// 路径有效性校验[5,6](@ref)
+//	root = filepath.Clean(root)
+//	stat, err := os.Stat(root)
+//	if err != nil {
+//		if errors.Is(err, fs.ErrNotExist) {
+//			return nil, &os.PathError{Op: "stat", Path: root, Err: err} // 增强错误信息[8](@ref)
+//		}
+//		return nil, err
+//	}
+//
+//	// 文件直接返回[4](@ref)
+//	if !stat.IsDir() {
+//		info.Files = append(info.Files, root)
+//		return info, nil
+//	}
+//
+//	// 使用WalkDir优化遍历性能[4,9](@ref)
+//	err = filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
+//		if err != nil {
+//			// 处理遍历错误但继续执行[7](@ref)
+//			if errors.Is(err, fs.ErrPermission) {
+//				return nil // 跳过权限错误
+//			}
+//			return err
+//		}
+//
+//		// 排除根目录自身
+//		if path == root {
+//			return nil
+//		}
+//
+//		// 动态扩容检测[9](@ref)
+//		if len(info.Dirs)+len(info.Files) > 1e6 {
+//			return errors.New("超出内存安全阈值(1,000,000条路径)")
+//		}
+//		fmt.Println(path)
+//		if d.IsDir() {
+//			info.Dirs = append(info.Dirs, path)
+//		} else {
+//			info.Files = append(info.Files, path)
+//		}
+//		return nil
+//	})
+//
+//	if err != nil {
+//		return nil, &os.PathError{Op: "walk", Path: root, Err: err} // 错误包装[6](@ref)
+//	}
+//
+//	return info, nil
+//}
+//
+//// 流式处理版本(适用于超大数据集)
+//func StreamPathInfo(root string) (<-chan string, <-chan error) {
+//	paths := make(chan string, 1000)
+//	errs := make(chan error, 1)
+//
+//	go func() {
+//		defer close(paths)
+//		defer close(errs)
+//
+//		err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
+//			if err != nil {
+//				return err
+//			}
+//			if path != root {
+//				select {
+//				case paths <- path:
+//				default:
+//					return errors.New("消费者处理过慢")
+//				}
+//			}
+//			return nil
+//		})
+//
+//		if err != nil {
+//			errs <- &os.PathError{Op: "stream", Path: root, Err: err}
+//		}
+//	}()
+//
+//	return paths, errs
+//}

+ 46 - 0
config/Config.go

@@ -0,0 +1,46 @@
+package config
+
+import (
+	"log"
+	"os"
+
+	"gopkg.in/yaml.v3"
+)
+
+var Conf Config
+
+type Config struct {
+	Server Server `yaml:"server"`
+	Tcp    Tcp    `yaml:"Tcp"`
+	File   File   `yaml:"file"`
+}
+type Server struct {
+	Port int `yaml:"port"`
+}
+type Tcp struct {
+	Port int `yaml:"port"`
+}
+type File struct {
+	Upload Upload `yaml:"upload"`
+}
+type Upload struct {
+	Path string `yaml:"path"`
+}
+
+func ReadConfig() {
+	// 打开并读取配置文件
+	file, err := os.Open("file/config.yaml")
+	if err != nil {
+		log.Fatalf("无法打开文件: %v", err)
+	}
+	defer file.Close()
+
+	// 创建一个 Config 变量来存储 YAML 配置内容
+
+	// 解析 YAML 内容
+	decoder := yaml.NewDecoder(file)
+	err = decoder.Decode(&Conf)
+	if err != nil {
+		log.Fatalf("解析 YAML 文件失败: %v", err)
+	}
+}

+ 34 - 0
db/File.go

@@ -0,0 +1,34 @@
+package db
+
+import (
+	"file-manger-server/domain"
+	"fmt"
+)
+
+type FileDao struct{}
+
+func (dao FileDao) Insert(file domain.File) error {
+	_, err := Engin.Table("file").Insert(&file)
+	if err != nil {
+		fmt.Println(err)
+		return err
+	}
+	return nil
+}
+
+type FileUserDao struct {
+}
+
+func (dao FileUserDao) Get(TransactionId string) (domain.FileUser, error) {
+	var fileUser domain.FileUser
+	_, err := Engin.Table("file_user").Where("transaction_id = ?", TransactionId).Get(&fileUser)
+	return fileUser, err
+}
+
+func (dao FileUserDao) Insert(TransactionId string, userId int64) error {
+	_, err := Engin.Table("file_user").Insert(&domain.FileUser{
+		TransactionId: TransactionId,
+		UserId:        userId,
+	})
+	return err
+}

+ 39 - 0
db/SqlXorm.go

@@ -0,0 +1,39 @@
+package db
+
+import (
+	"file-manger-server/domain"
+	"log"
+	"os"
+	"xorm.io/xorm"
+
+	_ "github.com/glebarez/sqlite"
+)
+
+var Engin *xorm.Engine
+
+func Open() {
+	os.OpenFile("file/file.db", os.O_RDWR|os.O_CREATE, 0666)
+	// 连接SQLite数据库
+	engine, err := xorm.NewEngine("sqlite", "file/file.db")
+	if err != nil {
+		log.Fatalf("数据库连接失败: %v", err)
+	}
+	//defer engine.Close()
+	Engin = engine
+
+	// 同步结构体到数据库
+	if err := engine.Sync2(
+		new(domain.User),
+		new(domain.File),
+		new(domain.FileUser),
+	); err != nil {
+		log.Fatalf("同步失败: %v", err)
+	}
+}
+
+func Close() {
+	err := Engin.Close()
+	if err != nil {
+		return
+	}
+}

+ 26 - 0
domain/File.go

@@ -0,0 +1,26 @@
+package domain
+
+//设定文件结构
+
+type FileInfo struct {
+	FileName string      `json:"fileName"` //文件名
+	FileType string      `json:"fileType"` //文件夹或者文件
+	FilePath string      `json:"filePath"` //相对路径
+	FileSize int64       `json:"fileSize"` //文件大小
+	FileTime FileTime    `json:"fileTime"` //文件时间
+	Content  []byte      `json:"content"`  //文件内容
+	Other    interface{} `json:"other"`    //其他信息
+}
+
+type FileTime struct {
+	CreateTime string `json:"createTime"`
+	ModifyTime string `json:"modifyTime"`
+	AccessTime string `json:"accessTime"`
+}
+
+type FileType int
+
+const (
+	FileTypeFolder FileType = iota //文件夹
+	FileTypeFile                   //文件
+)

+ 82 - 0
domain/User.go

@@ -0,0 +1,82 @@
+package domain
+
+//=============| 用户与权限 |================
+
+type User struct {
+	Id         int64  `json:"id" xorm:"pk autoincr 'id'"`                // 用户Id,主键,自增长
+	Name       string `json:"name" xorm:"'name' notnull"`                // 用户名,非空
+	Username   string `json:"username" xorm:"'username' unique notnull"` // 用户账号,唯一,非空
+	Password   string `json:"password" xorm:"'password' notnull"`        // 用户密码,非空
+	Email      string `json:"email" xorm:"'email' notnull"`              // 用户邮箱,非空
+	Phone      string `json:"phone" xorm:"'phone' notnull"`              // 用户手机,非空
+	Status     int64  `json:"status" xorm:"'status' notnull"`            // 用户状态,非空
+	CreateTime int64  `json:"createTime" xorm:"created"`                 // 创建时间,自动填充
+	UpdateTime int64  `json:"updateTime" xorm:"updated"`                 // 更新时间,自动填充
+	Role       string `json:"role" xorm:"'role' notnull"`                // 用户角色,非空
+}
+
+//type UserRole struct {
+//	Id         int64  `json:"id" xorm:"pk autoincr 'id'"`      // 用户角色Id,主键,自增长
+//	UserId     int64  `json:"userId" xorm:"'user_id' notnull"` // 用户Id,非空
+//	RoleId     int64  `json:"roleId" xorm:"'role_id' notnull"` // 角色Id,非空
+//	CreateTime int64  `json:"createTime" xorm:"created"`       // 创建时间,自动填充
+//	UpdateTime int64  `json:"updateTime" xorm:"updated"`       // 更新时间,自动填充
+//	Role       string `json:"role" xorm:"'role' notnull"`      // 角色,非空
+//}
+//
+//type Role struct {
+//	Id         int64  `json:"id" xorm:"pk autoincr 'id'"` // 角色Id,主键,自增长
+//	Name       string `json:"name" xorm:"'name' notnull"` // 角色名称,非空
+//	CreateTime int64  `json:"createTime" xorm:"created"`  // 创建时间,自动填充
+//	UpdateTime int64  `json:"updateTime" xorm:"updated"`  // 更新时间,自动填充
+//}
+//
+//type RoleMenu struct {
+//	Id         int64  `json:"id" xorm:"pk autoincr 'id'"`      // 角色菜单Id,主键,自增长
+//	RoleId     int64  `json:"roleId" xorm:"'role_id' notnull"` // 角色Id,非空
+//	MenuId     int64  `json:"menuId" xorm:"'menu_id' notnull"` // 菜单Id,非空
+//	CreateTime int64  `json:"createTime" xorm:"created"`       // 创建时间,自动填充
+//	UpdateTime int64  `json:"updateTime" xorm:"updated"`       // 更新时间,自动填充
+//	Menu       string `json:"menu" xorm:"'menu' notnull"`      // 菜单,非空
+//}
+//
+//type Menu struct {
+//	Id         int64  `json:"id" xorm:"pk autoincr 'id'"` // 菜单Id,主键,自增长
+//	Name       string `json:"name" xorm:"'name' notnull"` // 菜单名称,非空
+//	Url        string `json:"url" xorm:"'url' notnull"`   // 菜单URL,非空
+//	CreateTime int64  `json:"createTime" xorm:"created"`  // 创建时间,自动填充
+//	UpdateTime int64  `json:"updateTime" xorm:"updated"`  // 更新时间,自动填充
+//}
+
+//=============| 文件管理 |================
+
+type FileUser struct {
+	TransactionId string `json:"transactionId" xorm:"pk 'transaction_id'"`
+	UserId        int64  `json:"id" xorm:"pk autoincr 'id'"`
+}
+
+type File struct {
+	Id            int64      `json:"id" xorm:"pk autoincr 'id'"`                    // 文件Id,主键,自增长
+	Name          string     `json:"name" xorm:"'name' notnull"`                    // 文件名,非空
+	Url           string     `json:"url" xorm:"'url' notnull"`                      // 文件URL,非空
+	Size          int64      `json:"size" xorm:"'size' notnull"`                    // 文件大小,非空
+	Type          string     `json:"type" xorm:"'type' notnull"`                    // 文件类型,非空
+	MD5           string     `json:"md5" xorm:"'md5' notnull"`                      // 文件MD5,非空
+	TransactionId string     `json:"transactionId" xorm:"'transaction_id' notnull"` // 事务Id,非空
+	Extension     string     `json:"extension" xorm:"'extension' notnull"`          // 文件扩展名,非空
+	Access        FileAccess `json:"access" `                                       // 文件访问权限,非空  xorm:"'access' notnull"
+	CreateUser    int64      `json:"createUser" xorm:"'create_user' notnull"`       // 创建用户Id,非空
+	CreateTime    int64      `json:"createTime" xorm:"create_time"`                 // 创建时间,自动填充
+	UpdateTime    int64      `json:"updateTime" xorm:"update_time"`                 // 更新时间,自动填充
+	AccessTime    int64      `json:"accessTime" xorm:"access_time"`                 // 更新时间,自动填充
+}
+
+type FileAccess struct {
+	Id                 int64  `json:"id" xorm:"pk autoincr 'id'"`                        // 文件访问记录Id,主键,自增长
+	FileId             int64  `json:"fileId" xorm:"'file_id' notnull"`                   // 文件Id,非空
+	CreateId           int64  `json:"createId" xorm:"'create_id' notnull"`               // 创建人,非空
+	AccessReadUserId   string `json:"accessReadUserId" xorm:"'access_read_user_id'"`     // 可读用户Id
+	AccessWriteUserId  string `json:"accessWriteUserId" xorm:"'access_write_user_id'"`   // 可写用户Id
+	AccessDeleteUserId string `json:"accessDeleteUserId" xorm:"'access_delete_user_id'"` // 可删用户Id
+	CreateTime         int64  `json:"createTime" xorm:"created"`                         // 创建时间,自动填充
+}

+ 7 - 0
file/config.yaml

@@ -0,0 +1,7 @@
+server:
+  port: 8080
+tcp:
+  port: 8080
+file:
+  upload:
+    path: ./upload

BIN
file/file.db


+ 53 - 0
go.mod

@@ -0,0 +1,53 @@
+module file-manger-server
+
+go 1.23.4
+
+require (
+	github.com/glebarez/sqlite v1.11.0
+	gopkg.in/yaml.v3 v3.0.1
+	xorm.io/xorm v1.3.9
+)
+
+require (
+	github.com/bytedance/sonic v1.11.6 // indirect
+	github.com/bytedance/sonic/loader v0.1.1 // indirect
+	github.com/cloudwego/base64x v0.1.4 // indirect
+	github.com/cloudwego/iasm v0.2.0 // indirect
+	github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
+	github.com/dustin/go-humanize v1.0.1 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+	github.com/gin-contrib/sse v0.1.0 // indirect
+	github.com/gin-gonic/gin v1.10.0 // indirect
+	github.com/glebarez/go-sqlite v1.21.2 // indirect
+	github.com/go-playground/locales v0.14.1 // indirect
+	github.com/go-playground/universal-translator v0.18.1 // indirect
+	github.com/go-playground/validator/v10 v10.20.0 // indirect
+	github.com/goccy/go-json v0.10.2 // indirect
+	github.com/golang/snappy v0.0.4 // indirect
+	github.com/google/uuid v1.3.0 // indirect
+	github.com/jinzhu/inflection v1.0.0 // indirect
+	github.com/jinzhu/now v1.1.5 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.7 // indirect
+	github.com/leodido/go-urn v1.4.0 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
+	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
+	github.com/syndtr/goleveldb v1.0.0 // indirect
+	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
+	github.com/ugorji/go/codec v1.2.12 // indirect
+	golang.org/x/arch v0.8.0 // indirect
+	golang.org/x/crypto v0.23.0 // indirect
+	golang.org/x/net v0.25.0 // indirect
+	golang.org/x/sys v0.20.0 // indirect
+	golang.org/x/text v0.15.0 // indirect
+	google.golang.org/protobuf v1.34.1 // indirect
+	gorm.io/gorm v1.25.7 // indirect
+	modernc.org/libc v1.22.5 // indirect
+	modernc.org/mathutil v1.5.0 // indirect
+	modernc.org/memory v1.5.0 // indirect
+	modernc.org/sqlite v1.23.1 // indirect
+	xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 // indirect
+)

+ 334 - 0
main.go

@@ -0,0 +1,334 @@
+package main
+
+import (
+	"encoding/binary"
+	"errors"
+	"file-manger-server/server"
+	"fmt"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"strings"
+	"sync"
+)
+
+func main() {
+	//config.ReadConfig()
+	//db.Open()
+	////server.Run()
+	////service.RunGin()
+	//TestHandlerReceiveFile()
+	TestFiles()
+}
+func TestHandlerReceiveFile() {
+	bytes := []byte{
+		0x00,
+	}
+	for i := 0; i < 32; i++ {
+		bytes = append(bytes, byte(i+3))
+	}
+	var fileName = "test.txt"
+	//文件名长度
+	bytes = binary.BigEndian.AppendUint32(bytes, uint32(len(fileName)))
+	//文件名
+	bytes = append(bytes, []byte(fileName)...)
+	//文件大小
+	bytes = binary.BigEndian.AppendUint64(bytes, uint64(10))
+	var path = "./file/" + fileName
+	bytes = binary.BigEndian.AppendUint32(bytes, uint32(len(path)))
+	//文件路径
+	bytes = append(bytes, []byte(path)...)
+	//分片大小
+	bytes = binary.BigEndian.AppendUint32(bytes, uint32(0))
+	//创建时间
+	bytes = binary.BigEndian.AppendUint64(bytes, uint64(999))
+	//修改时间
+	bytes = binary.BigEndian.AppendUint64(bytes, uint64(9999))
+	//最后访问时间
+	bytes = binary.BigEndian.AppendUint64(bytes, uint64(99999))
+	bytes = append(bytes, []byte("1234567890中文")...)
+	server.HandlerReceiveFile(nil, bytes)
+}
+func TestBigFileSend() {
+	//var str = "\tif err != nil {\n\t\treturn errors.New(\"FileUser transactionId is not found\")\n\t}\n\tif fileUser.UserId == 0 {\n\t\treturn errors.New(\"FileUser userId is not found\")\n\t}"
+	//var data = []byte(str + str + str + str + str + str + "\t//config.ReadConfig()\n\t//db.Open()\n\t////server.Run()\n\t// server")
+	////切片1
+	//{
+	//	bytes := []byte{
+	//		0x00,
+	//	}
+	//	for i := 0; i < 32; i++ {
+	//		bytes = append(bytes, byte(i+3))
+	//	}
+	//	var fileName = "test.txt"
+	//	//文件名长度
+	//	bytes = binary.BigEndian.AppendUint32(bytes, uint32(len(fileName)))
+	//	//文件名
+	//	bytes = append(bytes, []byte(fileName)...)
+	//	//文件大小
+	//	bytes = binary.BigEndian.AppendUint64(bytes, uint64(1024*2+8))
+	//	var path = "file/" + fileName
+	//	bytes = binary.BigEndian.AppendUint32(bytes, uint32(len(path)))
+	//	//文件路径
+	//	bytes = append(bytes, []byte(path)...)
+	//	//分片大小
+	//	bytes = binary.BigEndian.AppendUint32(bytes, uint32(2))
+	//	//创建时间
+	//	bytes = binary.BigEndian.AppendUint64(bytes, uint64(999))
+	//	//修改时间
+	//	bytes = binary.BigEndian.AppendUint64(bytes, uint64(9999))
+	//	//最后访问时间
+	//	bytes = binary.BigEndian.AppendUint64(bytes, uint64(99999))
+	//	server.HandlerReceiveFile(nil, bytes)
+	//}
+	//{
+	//	//切片2
+	//	bytes := []byte{
+	//		0x01,
+	//	}
+	//	for i := 0; i < 32; i++ {
+	//		bytes = append(bytes, byte(i+3))
+	//	}
+	//	var fileName = "test.txt"
+	//	//切片id
+	//	bytes = binary.BigEndian.AppendUint32(bytes, uint32(0))
+	//	var path = "file/" + fileName
+	//	bytes = binary.BigEndian.AppendUint32(bytes, uint32(len(path)))
+	//	//文件路径
+	//	bytes = append(bytes, []byte(path)...)
+	//	fmt.Println("=================================")
+	//	fmt.Println("data len : ", len(data))
+	//	fmt.Println("=================================")
+	//	bytes = append(bytes, data...)
+	//	server.HandlerReceiveFile(nil, bytes)
+	//}
+	//
+	//{
+	//	//切片4
+	//	bytes := []byte{
+	//		0x01,
+	//	}
+	//	for i := 0; i < 32; i++ {
+	//		bytes = append(bytes, byte(i+3))
+	//	}
+	//	var fileName = "test.txt"
+	//	//切片id
+	//	bytes = binary.BigEndian.AppendUint32(bytes, uint32(2))
+	//	var path = "file/" + fileName
+	//	bytes = binary.BigEndian.AppendUint32(bytes, uint32(len(path)))
+	//	//文件路径
+	//	bytes = append(bytes, []byte(path)...)
+	//	var end = "\n| end |"
+	//	bytes = append(bytes, []byte(end)...)
+	//
+	//	fmt.Println("=================================")
+	//	fmt.Println("end len : ", len(end))
+	//	fmt.Println("=================================")
+	//	server.HandlerReceiveFile(nil, bytes)
+	//}
+	//{
+	//	//切片2
+	//	bytes := []byte{
+	//		0x01,
+	//	}
+	//	for i := 0; i < 32; i++ {
+	//		bytes = append(bytes, byte(i+3))
+	//	}
+	//	var fileName = "test.txt"
+	//	//切片id
+	//	bytes = binary.BigEndian.AppendUint32(bytes, uint32(1))
+	//	var path = "file/" + fileName
+	//	bytes = binary.BigEndian.AppendUint32(bytes, uint32(len(path)))
+	//	//文件路径
+	//	bytes = append(bytes, []byte(path)...)
+	//	fmt.Println("=================================")
+	//	fmt.Println("data len : ", len(data))
+	//	fmt.Println("=================================")
+	//	bytes = append(bytes, data...)
+	//	server.HandlerReceiveFile(nil, bytes)
+	//}
+	{
+		bytes := []byte{
+			0x00,
+		}
+		for i := 0; i < 32; i++ {
+			bytes = append(bytes, byte(i+3))
+		}
+		var fileName = "testtxt"
+		//文件名长度
+		bytes = binary.BigEndian.AppendUint32(bytes, uint32(len(fileName)))
+		//文件名
+		bytes = append(bytes, []byte(fileName)...)
+		//文件大小
+		bytes = binary.BigEndian.AppendUint64(bytes, uint64(0xFFFFFFFFFFFFFFFF))
+		var path = "file/" + fileName
+		bytes = binary.BigEndian.AppendUint32(bytes, uint32(len(path)))
+		//文件路径
+		bytes = append(bytes, []byte(path)...)
+		//分片大小
+		bytes = binary.BigEndian.AppendUint32(bytes, uint32(0))
+		//创建时间
+		bytes = binary.BigEndian.AppendUint64(bytes, uint64(1999))
+		//修改时间
+		bytes = binary.BigEndian.AppendUint64(bytes, uint64(19999))
+		//最后访问时间
+		bytes = binary.BigEndian.AppendUint64(bytes, uint64(199999))
+		server.HandlerReceiveFile(nil, bytes)
+	}
+
+}
+
+func TestFiles() {
+	info, err := GetPathInfo("D:\\")
+	if err != nil {
+		panic(err)
+	}
+	heavy, err := GoHeavy(info)
+	if err != nil {
+		panic(err)
+	}
+	fmt.Println(heavy.Dirs)
+
+}
+
+type PathInfo struct {
+	Dirs  []string // 目录路径(包含所有层级)
+	Files []string // 文件路径
+}
+
+var pathPool = sync.Pool{
+	New: func() interface{} {
+		return &PathInfo{
+			Dirs:  make([]string, 0, 1024), // 预分配容量
+			Files: make([]string, 0, 4096),
+		}
+	},
+}
+
+func GoHeavy(info *PathInfo) (PathInfo, error) {
+	m := make(map[string]bool)
+	for i := range info.Files {
+		path := info.Files[i]
+		lastIndex := strings.LastIndex(path, "/")
+
+		if lastIndex == -1 {
+			lastIndex = strings.LastIndex(path, "\\")
+		}
+		if lastIndex == -1 {
+			continue
+		}
+		//if _, ok := m[path[:lastIndex]]; !ok {
+		//	fmt.Println(path[:lastIndex])
+		//}
+		m[path[:lastIndex]] = true
+	}
+	var dirs = make([]string, 0, len(m))
+	fmt.Println(len(info.Dirs))
+	for i := range info.Dirs {
+		path := info.Dirs[i]
+		if !m[path] {
+			fmt.Println(info.Dirs[i])
+			dirs = append(dirs, info.Dirs[i])
+		}
+	}
+	info.Dirs = dirs
+	return *info, nil
+}
+
+func GetPathInfo(root string) (*PathInfo, error) {
+	//获取文件名
+	index := strings.LastIndex(root, "/")
+	if index == -1 {
+		index = strings.LastIndex(root, "\\")
+	}
+	//RootFileName := ""
+	//if index == -1 {
+	//	RootFileName = root
+	//} else {
+	//	RootFileName = root[:index+1]
+	//}
+
+	// 复用对象减少内存分配[9](@ref)
+	info := pathPool.Get().(*PathInfo)
+
+	// 路径有效性校验[5,6](@ref)
+	root = filepath.Clean(root)
+	stat, err := os.Stat(root)
+	if err != nil {
+		if errors.Is(err, fs.ErrNotExist) {
+			return nil, &os.PathError{Op: "stat", Path: root, Err: err} // 增强错误信息[8](@ref)
+		}
+		return nil, err
+	}
+
+	// 文件直接返回[4](@ref)
+	if !stat.IsDir() {
+		info.Files = append(info.Files, root)
+		return info, nil
+	}
+
+	// 使用WalkDir优化遍历性能[4,9](@ref)
+	err = filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
+		if err != nil {
+			// 处理遍历错误但继续执行[7](@ref)
+			if errors.Is(err, fs.ErrPermission) {
+				return nil // 跳过权限错误
+			}
+			return err
+		}
+
+		// 排除根目录自身
+		if path == root {
+			return nil
+		}
+
+		// 动态扩容检测[9](@ref)
+		if len(info.Dirs)+len(info.Files) > 1e8 {
+			return errors.New("超出内存安全阈值(1,000,000条路径)")
+		}
+		//fmt.Println(path[len(RootFileName):])
+		if d.IsDir() {
+			info.Dirs = append(info.Dirs, path)
+		} else {
+			info.Files = append(info.Files, path)
+		}
+		return nil
+	})
+
+	if err != nil {
+		return nil, &os.PathError{Op: "walk", Path: root, Err: err} // 错误包装[6](@ref)
+	}
+
+	return info, nil
+}
+
+// 流式处理版本(适用于超大数据集)
+func StreamPathInfo(root string) (<-chan string, <-chan error) {
+	paths := make(chan string, 1000)
+	errs := make(chan error, 1)
+
+	go func() {
+		defer close(paths)
+		defer close(errs)
+
+		err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
+			if err != nil {
+				return err
+			}
+			if path != root {
+				select {
+				case paths <- path:
+				default:
+					return errors.New("消费者处理过慢")
+				}
+			}
+			return nil
+		})
+
+		if err != nil {
+			errs <- &os.PathError{Op: "stream", Path: root, Err: err}
+		}
+	}()
+
+	return paths, errs
+}

+ 228 - 0
server/Handler.go

@@ -0,0 +1,228 @@
+package server
+
+import (
+	"encoding/binary"
+	"errors"
+	"file-manger-server/config"
+	"file-manger-server/db"
+	"file-manger-server/domain"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+)
+
+type ReturnCommand interface {
+	Return() []byte
+}
+
+func HandlerReceiveFile(info *ConnInfo, msg []byte) {
+	var commandId = msg[0]
+
+	//事务id解析
+	var transactionId = msg[1:33]
+	fmt.Println(ToHexBytes(transactionId))
+	var tranId = ToHexBytes(transactionId)
+	if commandId == 0 {
+		InfoTransaction(info, msg, tranId)
+	} else if commandId == 1 {
+
+		err := InfoTransactionSplit(info, msg, tranId)
+		fmt.Println(err)
+	}
+	//1. 接收基本元数据(事务id(32),len文件名(4+?),文件大小(8),相对路径(4+?),分片数量(按特定大小进行分片)(4),创建时间(8),修改时间(8),访问时间(8)=> 返回事务id,如果重复则返回错误 76+?
+	//2. 接收包含事务id的分片内容
+}
+
+// InfoTransaction 获取的事务数据内容
+func InfoTransaction(info *ConnInfo, msg []byte, transactionId string) error {
+
+	fileUser, err := db.FileUserDao{}.Get(transactionId)
+	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}
+
+	var fileNameLength = binary.BigEndian.Uint32(msg[33:37])
+	var filename = string(msg[37 : 37+fileNameLength])
+	var fileSize = int64(binary.BigEndian.Uint64(msg[37+fileNameLength : 45+fileNameLength]))
+	var pathLength = binary.BigEndian.Uint32(msg[45+fileNameLength : 49+fileNameLength])
+	var path = string(msg[49+fileNameLength : 49+fileNameLength+pathLength])
+	path = fmt.Sprint(config.Conf.File.Upload.Path, "/", fileUser.UserId, "/", transactionId, "/", path)
+
+	var splitCount = binary.BigEndian.Uint32(msg[49+fileNameLength+pathLength : 53+fileNameLength+pathLength])
+
+	var createTime = binary.BigEndian.Uint64(msg[53+fileNameLength+pathLength : 61+fileNameLength+pathLength])
+	var modifyTime = binary.BigEndian.Uint64(msg[61+fileNameLength+pathLength : 69+fileNameLength+pathLength])
+	var accessTime = binary.BigEndian.Uint64(msg[69+fileNameLength+pathLength : 77+fileNameLength+pathLength])
+
+	Type := ""
+	if fileSize == -1 {
+		Type = "folder"
+	} else {
+		Type = "file"
+	}
+	ExtensionName := ""
+	index := strings.Index(filename, ".")
+	if index != -1 {
+		ExtensionName = filename[index+1:]
+	}
+
+	file := domain.File{
+		Name:          filename,
+		Url:           path,
+		Size:          fileSize,
+		Type:          Type,
+		MD5:           "",
+		TransactionId: transactionId,
+		Extension:     ExtensionName,
+		Access:        domain.FileAccess{},
+		CreateUser:    0,
+		CreateTime:    int64(createTime),
+		UpdateTime:    int64(modifyTime),
+	}
+	//添加元素
+	db.FileDao{}.Insert(file)
+	//递归创建前面的文件夹
+	lastIndex := strings.LastIndex(path, "/")
+	if lastIndex != -1 {
+		err := os.MkdirAll(path[:lastIndex], 0755)
+		if err != nil {
+			return err
+		}
+	}
+	if splitCount == 0 {
+		if fileSize >= 0 {
+			//打开文件
+			openFile, err := os.Create(path)
+			if err != nil {
+				fmt.Println("err:", err)
+			}
+			defer openFile.Close()
+			var content = msg[77+fileNameLength+pathLength:]
+			openFile.Write(content)
+		} else {
+			err := os.Mkdir(path, 0755)
+			if err != nil {
+				fmt.Println(err)
+			}
+		}
+	} else {
+		// 创建一个空文件
+		file, err := os.Create(path)
+		if err != nil {
+			fmt.Println("Error creating file:", err)
+			return err
+		}
+		defer file.Close() // 确保在函数结束时关闭文件
+		fmt.Println("file size :", fileSize)
+		err = file.Truncate(fileSize)
+
+		if err != nil {
+			fmt.Println("Error setting file size:", err)
+			return err
+		}
+	}
+	// 返回状态信息
+	//info.conn.Write()
+	fmt.Println(fmt.Sprintf("事务id:%d\n文件名:%s\n文件大小:%d\n相对路径:%s\n分片数量:%d\n创建时间:%d\n修改时间:%d\n访问时间:%d", transactionId, filename, fileSize, path, splitCount, createTime, modifyTime, accessTime))
+	return nil
+}
+
+// InfoTransactionSplit 获取的事务数据内容
+func InfoTransactionSplit(info *ConnInfo, msg []byte, transactionId string) error {
+	fileUser, err := db.FileUserDao{}.Get(transactionId)
+	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}
+
+	var splitNum = binary.BigEndian.Uint32(msg[33:37])
+	var pathLength = binary.BigEndian.Uint32(msg[37:41])
+	var path = string(msg[41 : 41+pathLength])
+	path = fmt.Sprint(config.Conf.File.Upload.Path, "/", fileUser.UserId, "/", transactionId, "/", path)
+	var content = msg[41+pathLength:]
+	err = insertDataAtPosition(path, int64(splitNum*1024), content)
+	return err
+	// 返回状态信息
+	//info.conn.Write()
+	//fmt.Println(fmt.Sprintf("事务id:%d\n文件名:%s\n文件大小:%d\n相对路径:%s\n分片数量:%d\n创建时间:%d\n修改时间:%d\n访问时间:%d", transactionId, filename, fileSize, path, splitCount, createTime, modifyTime, accessTime))
+}
+
+var sign = 0
+
+func insertDataAtPosition(filePath string, position int64, data []byte) error {
+	// 1. 打开文件
+	file, err := os.OpenFile(filePath, os.O_RDWR, 0644)
+	if err != nil {
+		return fmt.Errorf("error opening file: %v", err)
+	}
+	defer file.Close()
+
+	// 2. 获取文件元数据
+	fileInfo, err := file.Stat()
+	if err != nil {
+		return fmt.Errorf("error getting file info: %v", err)
+	}
+	fileSize := fileInfo.Size()
+
+	// 3. 校验插入位置
+	if position > fileSize {
+		return fmt.Errorf("position exceeds file size")
+	}
+
+	// 4. 计算需要移动的数据量
+	//originalDataLength := fileSize - position
+	insertLength := int64(len(data))
+
+	// 5. 分块移动原始数据(从后往前处理)
+	//var offset int64 = position
+
+	//for offset > 0 {
+	// 定位读取位置
+	readPos := position
+
+	// 读取块数据
+	buffer := make([]byte, insertLength)
+	_, err = file.ReadAt(buffer, readPos)
+	if err != nil && err != io.EOF {
+		return fmt.Errorf("read block error: %v", err)
+	}
+	sign += 1
+	fmt.Println("buffer len :", len(buffer), "  sign => ", sign)
+	// 写入新位置
+	_, err = file.WriteAt(buffer, readPos)
+	if err != nil {
+		return fmt.Errorf("write block error: %v", err)
+	}
+	fmt.Println("writePos ind :", readPos+int64(len(buffer)))
+	//}
+
+	// 6. 写入新数据
+	_, err = file.WriteAt(data, position)
+	if err != nil {
+		return fmt.Errorf("write data error: %v", err)
+	}
+
+	// 7. 扩展文件大小(如果需要)
+	//newSize := fileSize + insertLength
+	//if newSize > fileSize {
+	//	if err := file.Truncate(newSize); err != nil {
+	//		return fmt.Errorf("truncate error: %v", err)
+	//	}
+	//}
+
+	return nil
+}
+
+func ToHexBytes(bytes []byte) string {
+	var hexBytes string
+	for b := range bytes {
+		hexBytes = fmt.Sprint(hexBytes, fmt.Sprintf("%02X", bytes[b]))
+	}
+	return strings.TrimSpace(hexBytes)
+}

+ 38 - 0
server/Handler_test.go

@@ -0,0 +1,38 @@
+package server
+
+import (
+	"encoding/binary"
+	"file-manger-server/db"
+	"testing"
+)
+
+func TestHandlerReceiveFile(t *testing.T) {
+	db.Open()
+	bytes := []byte{
+		0x01,
+	}
+	for i := 0; i < 32; i++ {
+		bytes = append(bytes, byte(i))
+	}
+	var fileName = "test.txt"
+	//文件名长度
+	bytes = binary.BigEndian.AppendUint32(bytes, uint32(len(fileName)))
+	//文件名
+	bytes = append(bytes, []byte(fileName)...)
+	//文件大小
+	bytes = binary.BigEndian.AppendUint64(bytes, uint64(10))
+	var path = "./file/" + fileName
+	bytes = binary.BigEndian.AppendUint32(bytes, uint32(len(path)))
+	//文件路径
+	bytes = append(bytes, []byte(path)...)
+	//分片大小
+	bytes = binary.BigEndian.AppendUint32(bytes, uint32(9))
+	//创建时间
+	bytes = binary.BigEndian.AppendUint64(bytes, uint64(999))
+	//修改时间
+	bytes = binary.BigEndian.AppendUint64(bytes, uint64(9999))
+	//最后访问时间
+	bytes = binary.BigEndian.AppendUint64(bytes, uint64(99999))
+	bytes = append(bytes, []byte("1234567890")...)
+	HandlerReceiveFile(nil, bytes)
+}

+ 291 - 0
server/TCPServer.go

@@ -0,0 +1,291 @@
+package server
+
+import (
+	"bufio"
+	"context"
+	"encoding/binary"
+	"errors"
+	"file-manger-server/util"
+	"fmt"
+	"io"
+	"log"
+	"net"
+	"os"
+	"os/signal"
+	"sync"
+	"sync/atomic"
+	"syscall"
+	"time"
+)
+
+// ConnPool 改进后的连接池结构
+type ConnPool struct {
+	connections  sync.Map           // 使用sync.Map替代原生map
+	maxConns     int32              // 最大连接数
+	currentConns atomic.Int32       // 当前连接数(原子操作)
+	ctx          context.Context    // 上下文
+	cancel       context.CancelFunc // 用于取消上下文
+}
+
+type ConnInfo struct {
+	conn         net.Conn      // 原始连接
+	lastActive   atomic.Int64  // 最后活跃时间(原子操作)
+	heartbeatTTL time.Duration // 心跳TTL
+	closed       atomic.Bool   // 关闭状态标记
+	bufReader    *bufio.Reader // 带缓冲的读取器
+}
+
+const (
+	MaxConnections    = 1000             // 最大连接数
+	HeartbeatInterval = 30 * time.Second // 心跳间隔
+	ReadTimeout       = 2 * time.Minute  // 读取超时时间
+)
+
+func NewConnPool(maxConns int) *ConnPool {
+	ctx, cancel := context.WithCancel(context.Background())
+	return &ConnPool{
+		maxConns: int32(maxConns),
+		ctx:      ctx,
+		cancel:   cancel,
+	}
+}
+
+// Add 添加连接到池(带数量检查)
+func (p *ConnPool) Add(conn net.Conn) error {
+	if p.currentConns.Load() >= p.maxConns {
+		return errors.New("connection limit reached")
+	}
+
+	ci := &ConnInfo{
+		conn:         conn,
+		heartbeatTTL: HeartbeatInterval * 3,
+		bufReader:    bufio.NewReaderSize(conn, 4096),
+	}
+	ci.lastActive.Store(time.Now().UnixNano())
+
+	p.connections.Store(conn, ci)
+	p.currentConns.Add(1)
+	return nil
+}
+
+// Remove 移除连接
+func (p *ConnPool) Remove(conn net.Conn) {
+	if ci, loaded := p.connections.LoadAndDelete(conn); loaded {
+		ci.(*ConnInfo).Close()
+		p.currentConns.Add(-1)
+	}
+}
+
+// Close 关闭连接
+func (ci *ConnInfo) Close() {
+	if ci.closed.CompareAndSwap(false, true) {
+		ci.conn.Close()
+	}
+}
+
+// StartCleaner 启动自动清理协程
+func (p *ConnPool) StartCleaner() {
+	go func() {
+		ticker := time.NewTicker(1 * time.Minute)
+		defer ticker.Stop()
+
+		for {
+			select {
+			case <-ticker.C:
+				p.cleanup()
+			case <-p.ctx.Done():
+				return
+			}
+		}
+	}()
+}
+
+// 清理失效连接
+func (p *ConnPool) cleanup() {
+	p.connections.Range(func(key, value any) bool {
+		ci := value.(*ConnInfo)
+		if time.Since(time.Unix(0, ci.lastActive.Load())) > ci.heartbeatTTL {
+			p.Remove(ci.conn)
+		}
+		return true
+	})
+}
+
+// Shutdown 优雅关闭
+func (p *ConnPool) Shutdown() {
+	p.cancel()
+	p.connections.Range(func(key, value any) bool {
+		ci := value.(*ConnInfo)
+		ci.Close()
+		p.connections.Delete(key)
+		return true
+	})
+}
+
+func Run() {
+	pool := NewConnPool(MaxConnections)
+	pool.StartCleaner()
+
+	listener, err := net.Listen("tcp", ":8080")
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// 信号处理
+	sigCh := make(chan os.Signal, 1)
+	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
+
+	go func() {
+		<-sigCh
+		log.Println("Shutting down server...")
+		listener.Close()
+		pool.Shutdown()
+	}()
+
+	for {
+		conn, err := listener.Accept()
+		if err != nil {
+			if errors.Is(err, net.ErrClosed) {
+				break // 正常关闭
+			}
+			log.Printf("Accept error: %v", err)
+			continue
+		}
+
+		if err := pool.Add(conn); err != nil {
+			conn.Close()
+			log.Printf("Reject connection: %v", err)
+			continue
+		}
+
+		go handleConnection(pool, conn)
+	}
+}
+
+func handleConnection(pool *ConnPool, conn net.Conn) {
+	defer func() {
+		if r := recover(); r != nil {
+			log.Printf("Connection panic: %v", r)
+		}
+		pool.Remove(conn)
+	}()
+
+	// 获取连接信息
+	ci, ok := pool.connections.Load(conn)
+	if !ok {
+		return
+	}
+	connInfo := ci.(*ConnInfo)
+
+	// 心跳检测
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	go heartbeat(ctx, connInfo)
+
+	// 消息处理循环
+	for {
+		// 设置读取超时
+		connInfo.conn.SetReadDeadline(time.Now().Add(ReadTimeout))
+
+		// 使用长度前缀协议处理粘包
+		message, err := readMessage(connInfo.bufReader)
+		if err != nil {
+			if !errors.Is(err, io.EOF) {
+				log.Printf("Read error: %v", err)
+			}
+			return
+		}
+
+		// 更新活跃时间
+		connInfo.lastActive.Store(time.Now().UnixNano())
+
+		// 处理业务逻辑
+		if err := processMessage(connInfo, message); err != nil {
+			log.Printf("Process message error: %v", err)
+			return
+		}
+	}
+}
+
+// 自定义错误类型
+var (
+	ErrInvalidStartByte = errors.New("invalid start byte")
+	ErrChecksumMismatch = errors.New("checksum mismatch")
+	ErrMessageTooLarge  = errors.New("message exceeds size limit")
+)
+
+func readMessage(r *bufio.Reader) ([]byte, error) {
+
+	// 读取起始字节 (0x2a)
+	startByte, err := r.ReadByte()
+	if err != nil {
+		return nil, fmt.Errorf("read start byte failed: %w", err)
+	}
+	if startByte != 0x2a {
+		return nil, fmt.Errorf("%w: received 0x%02x", ErrInvalidStartByte, startByte)
+	}
+
+	// 读取长度字段 (4字节大端序)
+	lengthBuf := make([]byte, 4)
+	if _, err := io.ReadFull(r, lengthBuf); err != nil {
+		return nil, fmt.Errorf("read length failed: %w", err)
+	}
+	dataLength := binary.BigEndian.Uint32(lengthBuf)
+
+	// 验证数据长度 (10MB限制)
+	if dataLength > 10*1024*1024 {
+		return nil, fmt.Errorf("%w: %d bytes", ErrMessageTooLarge, dataLength)
+	}
+
+	// 读取数据体
+	dataBody := make([]byte, dataLength)
+	if _, err := io.ReadFull(r, dataBody); err != nil {
+		return nil, fmt.Errorf("read data body failed: %w", err)
+	}
+
+	// 读取校验和 (2字节大端序)
+	checksumBuf := make([]byte, 2)
+	if _, err := io.ReadFull(r, checksumBuf); err != nil {
+		return nil, fmt.Errorf("read checksum failed: %w", err)
+	}
+	receivedChecksum := binary.BigEndian.Uint16(checksumBuf)
+
+	// 计算校验和 (CRC16-CCITT)
+	calculatedChecksum := util.Crc16CCITT(dataBody)
+	if calculatedChecksum != receivedChecksum {
+		return nil, fmt.Errorf("%w: expected %04X, got %04X",
+			ErrChecksumMismatch, calculatedChecksum, receivedChecksum)
+	}
+	return dataBody, nil
+}
+
+// 心跳检测
+func heartbeat(ctx context.Context, ci *ConnInfo) {
+	ticker := time.NewTicker(HeartbeatInterval)
+	defer ticker.Stop()
+
+	for {
+		select {
+		case <-ticker.C:
+			if ci.closed.Load() {
+				return
+			}
+
+			// 发送心跳包
+			if _, err := ci.conn.Write([]byte("PING")); err != nil {
+				ci.Close()
+				return
+			}
+		case <-ctx.Done():
+			return
+		}
+	}
+}
+
+// 示例消息处理
+func processMessage(info *ConnInfo, msg []byte) error {
+	// 实现业务逻辑
+	fmt.Printf("Processing message: %s\n", util.ToHexBytes(msg))
+	info.conn.Write(msg)
+	return nil
+}

+ 52 - 0
service/Gin.go

@@ -0,0 +1,52 @@
+package service
+
+import (
+	"file-manger-server/config"
+	"file-manger-server/db"
+	"file-manger-server/domain"
+	"file-manger-server/service/router"
+	"file-manger-server/util"
+	"fmt"
+	"github.com/gin-gonic/gin"
+)
+
+var engine *gin.Engine
+
+func RunGin() {
+	//判断 管理员是否存在
+	user := domain.User{}
+	db.Engin.Table("user").Where("username = ?", "admin").Get(&user)
+	if user.Id == 0 {
+		user.Name = "管理员"
+		user.Username = "admin"
+		user.Password = "123123"
+		db.Engin.Table("user").Insert(&user)
+	}
+
+	engine = gin.Default()
+	//engine.LoadHTMLGlob("service/template/*/*.*")
+	engine.Static("/static", "service/static")
+	baseRouter()
+	var port = config.Conf.Server.Port
+	if port == 0 {
+		port = 8080
+	}
+	engine.Run(fmt.Sprint(":", port))
+}
+
+func baseRouter() {
+	authRouter("/auth")
+	fileRouter("/file")
+	//权限校验
+	engine.Use(util.ValidateToken())
+}
+
+func authRouter(rootPath string) {
+	group := engine.RouterGroup.Group(rootPath)
+	group.POST("/login", router.Login)
+}
+
+func fileRouter(rootPath string) {
+	group := engine.RouterGroup.Group(rootPath)
+	group.POST("/uploadInfo", router.UploadInfo)
+}

+ 24 - 0
service/router/Base.go

@@ -0,0 +1,24 @@
+package router
+
+import "github.com/gin-gonic/gin"
+
+func CreateResult() gin.H {
+	return gin.H{
+		"code": 200,
+		"msg":  "success",
+	}
+}
+func CreateResultData(Data any) gin.H {
+	return gin.H{
+		"code": 200,
+		"msg":  "success",
+		"data": Data,
+	}
+}
+
+func CreateResultError(errCode int, errMsg string) gin.H {
+	return gin.H{
+		"code": errCode,
+		"msg":  errMsg,
+	}
+}

+ 45 - 0
service/router/FileRouter.go

@@ -0,0 +1,45 @@
+package router
+
+import (
+	"crypto/rand"
+	"file-manger-server/db"
+	"file-manger-server/domain"
+	"file-manger-server/util"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"strings"
+)
+
+func UploadInfo(c *gin.Context) {
+	//获取用户数据信息
+	claims, err := util.ValidateTokenToMyClaims(c.GetHeader("auth-sign"))
+	if err != nil {
+		c.JSON(200, CreateResultError(400, "token错误"))
+		return
+	}
+	var user domain.User
+	db.Engin.Table("user").Where("id =? ", claims.Id).Get(&user)
+	tid := ToHexBytes(random32Bytes())
+	db.FileUserDao{}.Insert(tid, user.Id)
+	c.JSON(200, CreateResultData(gin.H{
+		"transactionId": tid,
+	}))
+}
+func ToHexBytes(bytes []byte) string {
+	var hexBytes string
+	for b := range bytes {
+		hexBytes = fmt.Sprint(hexBytes, fmt.Sprintf("%02X", bytes[b]))
+	}
+	return strings.TrimSpace(hexBytes)
+}
+func random32Bytes() []byte {
+	randomBytes := make([]byte, 32)
+	_, err := rand.Read(randomBytes)
+	if err != nil {
+		panic(err) // 处理错误(如随机源不可用)
+	}
+
+	// 直接使用 randomBytes(原始二进制)
+	//fmt.Printf("Raw Bytes: %v\n", randomBytes)
+	return randomBytes
+}

+ 46 - 0
service/router/UserRouter.go

@@ -0,0 +1,46 @@
+package router
+
+import (
+	"file-manger-server/service/service"
+	"file-manger-server/util"
+	"github.com/gin-gonic/gin"
+)
+
+//func GetAll(c *service.Context) {
+//	var dao domain.UserDao
+//	dao.GetAll(entity.User{})
+//}
+
+type loginData struct {
+	Username string `json:"username"`
+	Password string `json:"password"`
+}
+
+type loginVo struct {
+	Token  string `json:"token"`
+	Expire int64  `json:"expire"`
+}
+
+func Login(c *gin.Context) {
+	var data loginData
+	err := c.BindJSON(&data)
+	if err != nil {
+		c.JSON(200, CreateResultError(400, "参数错误"))
+	}
+	user, err := service.Login(data.Username, data.Password)
+	if err != nil {
+		c.JSON(200, CreateResultError(400, err.Error()))
+		return
+	}
+	token, expire, err := util.GenerateToken(user.Id, user.Role)
+	if err != nil {
+		c.JSON(200, CreateResultError(400, err.Error()))
+		return
+	}
+	vo := loginVo{
+		Token:  token,
+		Expire: expire,
+	}
+
+	c.JSON(200, CreateResultData(vo))
+}

+ 33 - 0
service/service/FileRouter.go

@@ -0,0 +1,33 @@
+package service
+
+import (
+	"file-manger-server/db"
+	"file-manger-server/domain"
+)
+
+type FileDao struct{}
+
+func Insert(file domain.File) error {
+	_, err := db.Engin.Table("file").Insert(&file)
+	return err
+}
+func BatchInsert(files []domain.File) error {
+	table := db.Engin.Table("file")
+	err := table.Begin()
+	defer func() {
+		if err != nil {
+			err := table.Rollback()
+			if err != nil {
+				return
+			}
+		} else {
+			err := table.Commit()
+			if err != nil {
+				table.Rollback()
+				return
+			}
+		}
+	}()
+	_, err = table.Insert(&files)
+	return err
+}

+ 20 - 0
service/service/LoginDao.go

@@ -0,0 +1,20 @@
+package service
+
+import (
+	"errors"
+	"file-manger-server/db"
+	"file-manger-server/domain"
+)
+
+func Login(username, password string) (domain.User, error) {
+	var user domain.User
+	_, err := db.Engin.Table("user").Where("username=? and password=?", username, password).Get(&user)
+	if err != nil {
+		return user, err
+	}
+	if user.Id != 0 {
+		return user, nil
+	} else {
+		return user, errors.New("用户名或密码错误")
+	}
+}

+ 23 - 0
service/service/UserDao.go

@@ -0,0 +1,23 @@
+package service
+
+import (
+	"errors"
+	"file-manger-server/db"
+	"file-manger-server/domain"
+)
+
+type UserDao struct{}
+
+func (dao UserDao) GetAll(user domain.User) ([]domain.User, int64, error) {
+	var users []domain.User
+	count, err := db.Engin.Table("user").FindAndCount(&users, &user)
+	return users, count, err
+}
+func (dao UserDao) GetById(id int64) (domain.User, error) {
+	var user domain.User
+	res, err := db.Engin.Table("user").Where("id=?", id).Get(&user)
+	if !res {
+		return user, errors.New("用户不存在")
+	}
+	return user, err
+}

+ 16 - 0
test/test.http

@@ -0,0 +1,16 @@
+POST http://localhost:8080/auth/login
+Content-Type: application/json
+
+{
+  "username": "admin",
+  "password": "123123"
+}
+
+###
+POST http://localhost:8080/file/uploadInfo
+Content-Type: application/json
+auth-sign: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJZCI6MSwiUm9sZSI6IjEiLCJleHAiOjE3NDAzNzg1MjEsImlzcyI6Im15RmlsZU1hbmdlciJ9.PoMJbdSvIrpLGkJ7NwiZvYngfbko-d1yzfEj8ev3bTg
+
+{}
+
+###

+ 68 - 0
upload/1/030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122/file/test.txt

@@ -0,0 +1,68 @@
+	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}	//config.ReadConfig()
+	//db.Open()
+	////server.Run()
+	// server	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}	if err != nil {
+		return errors.New("FileUser transactionId is not found")
+	}
+	if fileUser.UserId == 0 {
+		return errors.New("FileUser userId is not found")
+	}	//config.ReadConfig()
+	//db.Open()
+	////server.Run()
+	// server
+| end |

+ 45 - 0
util/Command.go

@@ -0,0 +1,45 @@
+package util
+
+import (
+	"encoding/binary"
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// IntToBytes 将一个 4 字节数字转换为 byte 数组
+func IntToBytes(n int32) []byte {
+	buf := make([]byte, 4)
+	binary.BigEndian.PutUint32(buf, uint32(n)) // 使用 BigEndian 或 LittleEndian
+	return buf
+}
+
+// Int16ToBytes 将一个 4 字节数字转换为 byte 数组
+func Int16ToBytes(n uint16) []byte {
+	buf := make([]byte, 2)
+	binary.BigEndian.PutUint16(buf, uint16(n)) // 使用 BigEndian 或 LittleEndian
+	return buf
+}
+func ToHexBytes(bytes []byte) string {
+	var hexBytes string
+	for b := range bytes {
+		hexBytes = fmt.Sprint(hexBytes, strconv.FormatInt(int64(bytes[b]), 16), " ")
+	}
+	return strings.TrimSpace(hexBytes)
+}
+
+// CRC16-CCITT 校验算法 (多项式0x1021)
+func Crc16CCITT(data []byte) uint16 {
+	crc := uint16(0xFFFF)
+	for _, b := range data {
+		crc ^= uint16(b) << 8
+		for i := 0; i < 8; i++ {
+			if crc&0x8000 != 0 {
+				crc = (crc << 1) ^ 0x1021
+			} else {
+				crc <<= 1
+			}
+		}
+	}
+	return crc
+}

+ 110 - 0
util/TokenUtil.go

@@ -0,0 +1,110 @@
+package util
+
+import (
+	"errors"
+	"fmt"
+	"github.com/dgrijalva/jwt-go"
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+)
+
+var secretKey = []byte("my-file-manger") // 用于签名和验证的密钥
+const Issuer = "myFileManger"
+
+type MyClaims struct {
+	Id   int64
+	Role string
+	jwt.StandardClaims
+}
+
+// GenerateToken 创建一个JWT Token
+func GenerateToken(id int64, role string) (string, int64, error) {
+	// 设置token的过期时间
+	expirationTime := time.Now().Add(72 * time.Hour)
+
+	myClaims := &MyClaims{
+		Id:   id,
+		Role: role,
+		StandardClaims: jwt.StandardClaims{
+			ExpiresAt: expirationTime.Unix(),
+			Issuer:    Issuer,
+		},
+	}
+	// 创建token
+	token := jwt.NewWithClaims(jwt.SigningMethodHS256, myClaims)
+	// 签名并返回token字符串
+	signedString, err := token.SignedString(secretKey)
+
+	return signedString, expirationTime.UnixMilli(), err
+}
+
+// ValidateToken 中间件:验证JWT Token
+func ValidateToken() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		// 获取请求中的token
+		tokenString, err := c.Cookie("token")
+		if err != nil {
+			c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "Authorization token is missing"})
+			c.Abort()
+			return
+		}
+		fmt.Println(tokenString)
+		if tokenString == "" {
+			c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "Authorization token is missing"})
+			c.Abort()
+			return
+		}
+
+		// 解析token
+		token, _ := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
+			return secretKey, nil
+		})
+		if token == nil || !token.Valid {
+			c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "Invalid token"})
+			c.Abort()
+			return
+		}
+		_, ok := token.Claims.(*MyClaims)
+		if !ok {
+			c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "Invalid token"})
+			c.Abort()
+			return
+		}
+
+		c.Next() // Token验证通过,继续执行后续处理
+	}
+}
+func ValidateTokenToMyClaims(tokenString string) (*MyClaims, error) {
+	token, _ := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
+		return secretKey, nil
+	})
+	if token == nil || !token.Valid {
+
+		return nil, errors.New("Invalid token")
+	}
+	mc, ok := token.Claims.(*MyClaims)
+	if !ok {
+		return nil, errors.New("Invalid token")
+	}
+	return mc, nil
+}
+
+func ParseJWTWithValidation(tokenString string) (*MyClaims, error) {
+	// 解析Token
+	token, err := jwt.ParseWithClaims(tokenString, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
+		// 使用密钥来验证token
+		return secretKey, nil
+	})
+	if err != nil {
+		return nil, fmt.Errorf("error parsing token: %v", err)
+	}
+
+	// 断言token为有效类型
+	if claims, ok := token.Claims.(*MyClaims); ok && token.Valid {
+		return claims, nil
+	} else {
+		return nil, fmt.Errorf("invalid token")
+	}
+}

+ 1 - 0
util/saveFile.go

@@ -0,0 +1 @@
+package util