Преглед изворни кода

feat: 添加checkmapbuf接口

HeWang пре 10 месеци
родитељ
комит
8c9d60136b

+ 147 - 0
biz/handler/map_service/map_service.go

@@ -0,0 +1,147 @@
+package map_service
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"github.com/cloudwego/hertz/pkg/app"
+	"github.com/cloudwego/hertz/pkg/protocol/consts"
+	"io/ioutil"
+	"net/http"
+	"pji_desktop_http/common/config"
+	"pji_desktop_http/common/entity"
+	"pji_desktop_http/common/util"
+	"strings"
+)
+
+// CheckMapBufConsistency .
+// @router /map/checkmapbuf [GET]
+func CheckMapBufConsistency(ctx context.Context, c *app.RequestContext) {
+	var err error
+	var req []string
+	err = c.BindAndValidate(&req)
+	if err != nil {
+		c.String(consts.StatusBadRequest, err.Error())
+		return
+	}
+
+	fmt.Println(req)
+
+	if len(req) == 0 { // 请求数据为空
+		c.JSON(consts.StatusBadRequest, entity.HttpResult{Status: false, Code: "", Message: "请求数据为空。"})
+	} else if len(req) == 1 { // 只有一条数据则直接返回
+		c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "mapBuf文件夹数据一致。"})
+	} else {
+		var firstValue int
+		for i, v := range req {
+			// 根据id获取对应的oss文件列表
+			fileList, err := getFileObjectBYId(v)
+			if err != nil {
+				c.String(consts.StatusBadRequest, err.Error())
+				return
+			}
+
+			// 过滤特定后缀的文件列表
+			suffixes := []string{
+				"map.pgm",
+				"map.yaml",
+				"map.json",
+				"forbid_area.json",
+			}
+			filteredFileList := filterBySuffixes(fileList, suffixes...)
+			fmt.Println("Filtered Strings:", filteredFileList)
+
+			// 获取文件列表的总大小
+			totalSize := calculateTotalFileSize(filteredFileList)
+			fmt.Println("Total Size:", totalSize)
+
+			// 判断不同文件列表(mapBuf)中文件的总大小是否一致
+			if i == 0 {
+				firstValue = totalSize
+			} else {
+				if totalSize != firstValue {
+					c.JSON(consts.StatusOK, entity.HttpResult{Status: false, Code: "", Message: "mapBuf文件夹数据不一致。"})
+					return
+				}
+			}
+		}
+
+		c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "mapBuf文件夹数据一致。"})
+	}
+}
+
+// 根据id获取对应的oss文件列表
+func getFileObjectBYId(id string) (fileList []string, err error) {
+	url := config.SenceOssDownUrl + id
+
+	// 构建请求
+	req, err := http.NewRequest("GET", url, nil)
+	if err != nil {
+		fmt.Println("Error creating request:", err)
+		return
+	}
+
+	// 添加认证头
+	req.Header.Set("Authorization", config.Token)
+
+	// 发送请求
+	client := &http.Client{}
+	resp, err := client.Do(req)
+	if err != nil {
+		fmt.Println("Error executing request:", err)
+		return
+	}
+
+	defer resp.Body.Close()
+	body, _ := ioutil.ReadAll(resp.Body)
+
+	// Json转换为map
+	var data map[string]interface{}
+	err = json.Unmarshal(body, &data)
+
+	// 提取响应体中的data字段
+	dataField, ok := data["data"].([]interface{})
+	if !ok {
+		fmt.Println("Error extracting data field")
+		return
+	}
+
+	// 转换字符串切片
+	for _, item := range dataField {
+		str, ok := item.(string)
+		if !ok {
+			fmt.Println("Error converting item to string")
+			return
+		}
+		fileList = append(fileList, str)
+	}
+
+	return fileList, err
+}
+
+// 从字符串切片中筛选出以特定后缀结尾的字符串
+func filterBySuffixes(strList []string, suffixes ...string) []string {
+	var filtered []string
+	for _, s := range strList {
+		for _, suffix := range suffixes {
+			if strings.HasSuffix(s, suffix) {
+				filtered = append(filtered, s)
+				break
+			}
+		}
+	}
+	return filtered
+}
+
+// 计算oss中文件列表的总大小
+func calculateTotalFileSize(fileList []string) int {
+	var totalSize int
+	for _, file := range fileList {
+		size, err := util.GetOSSFileSize(config.OssBucket, file) // 获取oss中单个文件的大小
+		if err != nil {
+			return 0
+		}
+		totalSize += size
+	}
+	return totalSize
+}

+ 35 - 0
biz/model/http_result.go

@@ -0,0 +1,35 @@
+package model
+
+import "encoding/json"
+
+var DefaultSuccessHttpResult = &HttpResult{Status: true, Code: "1000", Message: "请求成功。"}
+var DefaultFailHttpResult = &HttpResult{Status: true, Code: "2000", Message: "请求失败。"}
+
+type HttpResult struct {
+	Status  bool   `json:"status"`
+	Code    string `json:"code"`
+	Message string `json:"message"`
+	Details string `json:"details"`
+}
+
+type Response struct {
+	Code  int         `json:"code"`  // 错误码
+	Msg   string      `json:"msg"`   // 错误描述
+	Data  interface{} `json:"data"`  // 返回数据
+	Total interface{} `json:"total"` // 分页的total数量
+}
+
+// ToString 返回 JSON 格式的错误详情
+func (res *Response) ToString() string {
+	err := &struct {
+		Code int         `json:"code"`
+		Msg  string      `json:"msg"`
+		Data interface{} `json:"data"`
+	}{
+		Code: res.Code,
+		Msg:  res.Msg,
+		Data: res.Data,
+	}
+	raw, _ := json.Marshal(err)
+	return string(raw)
+}

+ 43 - 0
biz/model/scene.go

@@ -0,0 +1,43 @@
+package model
+
+type Scene struct {
+	Id                      string      `json:"id"`
+	CreateTime              string      `json:"createTime"`
+	ModifyTime              interface{} `json:"modifyTime"`
+	CreateUserId            string      `json:"createUserId"`
+	ModifyUserId            interface{} `json:"modifyUserId"`
+	CreateUserName          interface{} `json:"createUserName"`
+	ModifyUserName          interface{} `json:"modifyUserName"`
+	EquipmentNo             string      `json:"equipmentNo"`
+	TaskId                  interface{} `json:"taskId"`
+	EquipmentId             string      `json:"equipmentId"`
+	TriggerId               string      `json:"triggerId"`
+	DataName                string      `json:"dataName"`
+	DataSize                string      `json:"dataSize"`
+	DataState               string      `json:"dataState"`
+	DataStateName           string      `json:"dataStateName"`
+	TriggerName             string      `json:"triggerName"`
+	EquipmentType           string      `json:"equipmentType"`
+	EquipmentTypeName       string      `json:"equipmentTypeName"`
+	EquipmentName           string      `json:"equipmentName"`
+	TriggerType             string      `json:"triggerType"`
+	TriggerTypeName         string      `json:"triggerTypeName"`
+	DataFileId              string      `json:"dataFileId"`
+	RosFileId               string      `json:"rosFileId"`
+	CallbackTime            string      `json:"callbackTime"`
+	HandleStartTime         string      `json:"handleStartTime"`
+	HandleEndTime           string      `json:"handleEndTime"`
+	RelationId              interface{} `json:"relationId"`
+	BadCase                 string      `json:"badCase"`
+	BadCaseName             string      `json:"badCaseName"`
+	Labels                  interface{} `json:"labels"`
+	LabelNames              interface{} `json:"labelNames"`
+	SceneLabels             interface{} `json:"sceneLabels"`
+	SceneLabelNames         interface{} `json:"sceneLabelNames"`
+	BadCaseCreateTime       interface{} `json:"badCaseCreateTime"`
+	BadCaseCreateUserId     interface{} `json:"badCaseCreateUserId"`
+	BadCaseCreateUserName   interface{} `json:"badCaseCreateUserName"`
+	SceneCaseCreateUserName interface{} `json:"sceneCaseCreateUserName"`
+	SceneCaseCreateUserId   interface{} `json:"sceneCaseCreateUserId"`
+	SceneCaseCreateTime     interface{} `json:"sceneCaseCreateTime"`
+}

+ 54 - 0
common/config/c_db/c_sqlx_mysql.go

@@ -0,0 +1,54 @@
+package c_db
+
+import (
+	"cicv-data-closedloop/common/config/c_log"
+	_ "github.com/go-sql-driver/mysql"
+	"github.com/jmoiron/sqlx"
+	"os"
+)
+
+var MysqlDb *sqlx.DB
+
+// InitSqlxMysql 初始化mysql连接
+// - charset 字符集 utf8、utf8mb4
+func InitSqlxMysql(username string, password string, ip string, port string, dbname string, charset string) {
+	var err error
+	// 连接数据库
+	// - parseTime 是否将数据库中的时间类型字段解析为 Go 中的 time.Time 类型。
+	// - loc 时间解析时使用的本地位置信息。通常设置为 "Local"。
+	MysqlDb, err = sqlx.Open("mysql", username+":"+password+"@tcp("+ip+":"+port+")/"+dbname+"?charset="+charset+"&parseTime=True&loc=Local")
+	if err != nil {
+		c_log.GlobalLogger.Error("程序退出。mysql连接失败:", err)
+		os.Exit(-1)
+	}
+
+	// 配置连接池
+	MysqlDb.SetMaxOpenConns(10)   // 设置最大打开连接数为 10
+	MysqlDb.SetMaxIdleConns(5)    // 设置最大空闲连接数为 5
+	MysqlDb.SetConnMaxLifetime(0) // 设置连接的最大生存时间为 0(不限制)
+	c_log.GlobalLogger.Info("mysql连接成功。")
+}
+
+func DoTx(sqlTemplate string, params []any) error {
+	// 插入到数据库
+	tx, err := MysqlDb.Beginx()
+	if err != nil {
+		c_log.GlobalLogger.Error("开启事务失败:", err)
+		return err
+	}
+	// 2 在事务中执行操作
+	_, err = tx.Exec(sqlTemplate, params...)
+	if err != nil {
+		c_log.GlobalLogger.Error("执行操作失败,回滚事务:", err)
+		tx.Rollback()
+		return err
+	}
+
+	// 如果所有操作成功,则提交事务
+	err = tx.Commit()
+	if err != nil {
+		c_log.GlobalLogger.Error("提交事务失败:", err)
+		return err
+	}
+	return nil
+}

+ 25 - 0
common/config/c_db/c_sqlx_sqlfile.go

@@ -0,0 +1,25 @@
+package c_db
+
+import (
+	"cicv-data-closedloop/common/config/c_log"
+	"os"
+	"path/filepath"
+)
+
+var SqlFilesMap = map[string]string{}
+
+func InitSqlFilesMap(dir string) {
+	files, err := os.ReadDir(dir)
+	if err != nil {
+		c_log.GlobalLogger.Error("程序退出。加载sql文件错误:", err)
+		os.Exit(-1)
+	}
+
+	for _, file := range files {
+		if !file.IsDir() && filepath.Ext(file.Name()) == ".sql" {
+			filePath := filepath.Join(dir, file.Name())
+			SqlFilesMap[file.Name()] = filePath
+		}
+	}
+	c_log.GlobalLogger.Info("sql文件加载成功:", SqlFilesMap)
+}

+ 39 - 0
common/config/c_log/log_config.go

@@ -0,0 +1,39 @@
+package c_log
+
+import (
+	"fmt"
+	"github.com/sirupsen/logrus"
+	"os"
+	"path/filepath"
+	"pji_desktop_http/common/util"
+	"runtime"
+	"time"
+)
+
+var GlobalLogger *logrus.Logger
+
+// InitLog 初始化日志配置
+func InitLog(logDir string, prefix string) {
+	time.Sleep(time.Duration(1) * time.Second)
+	// 创建、追加、读写,777,所有权限
+	logPath := logDir + prefix + "-" + time.Now().Format("2006-01-02-15-04-05") + ".log"
+	err := util.CreateParentDir(logPath)
+	if err != nil {
+		os.Exit(-1)
+	}
+	f, err := os.OpenFile(logPath, os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
+	if err != nil {
+		os.Exit(-1)
+	}
+	GlobalLogger = logrus.New()
+	GlobalLogger.SetOutput(f)
+	GlobalLogger.SetReportCaller(true) // 开启行号显示
+	GlobalLogger.SetFormatter(&logrus.JSONFormatter{
+		CallerPrettyfier: func(frame *runtime.Frame) (string, string) {
+			fileName := filepath.Base(frame.File)
+			return "", fmt.Sprintf("%s:%d", fileName, frame.Line)
+		},
+	})
+	GlobalLogger.Info("初始化GlobalLogger - 成功")
+
+}

+ 47 - 0
common/config/c_oss.go

@@ -0,0 +1,47 @@
+package config
+
+import (
+	"github.com/aliyun/aliyun-oss-go-sdk/oss"
+	"os"
+	"pji_desktop_http/common/config/c_log"
+	"sync"
+)
+
+type OssConnectInfoStruct struct {
+	Endpoint        string `json:"endpoint"`
+	AccessKeyId     string `json:"accessKeyId"`
+	AccessKeySecret string `json:"accessKeySecret"`
+	BucketName      string `json:"bucketName"`
+}
+
+var (
+	OssClient *oss.Client
+	OssBucket *oss.Bucket
+	OssMutex  sync.Mutex
+)
+
+func InitOssConfig() {
+	var err error
+	c_log.GlobalLogger.Info("初始化OSS客户端对象 - 开始。")
+
+	// 1 OSS 配置
+	var ossConnectInfo OssConnectInfoStruct
+	ossConnectInfo.Endpoint = "http://pji-bucket1.oss.icvdc.com"
+	ossConnectInfo.BucketName = "pji-bucket1"
+	ossConnectInfo.AccessKeyId = "n8glvFGS25MrLY7j"
+	ossConnectInfo.AccessKeySecret = "xZ2Fozoarpfw0z28FUhtg8cu0yDc5d"
+
+	OssClient, err = oss.New(ossConnectInfo.Endpoint, ossConnectInfo.AccessKeyId, ossConnectInfo.AccessKeySecret, oss.UseCname(true))
+	if err != nil {
+		c_log.GlobalLogger.Error("无法创建阿里云client:", err)
+		os.Exit(-1)
+	}
+	// 超时时间设置
+	//OssClient.Config.Timeout = 3600
+	OssBucket, err = OssClient.Bucket(ossConnectInfo.BucketName)
+	if err != nil {
+		c_log.GlobalLogger.Error("无法创建阿里云bucket:", err)
+		os.Exit(-1)
+	}
+	c_log.GlobalLogger.Info("初始化OSS客户端对象 - 成功。")
+}

+ 8 - 0
common/config/c_pji.go

@@ -0,0 +1,8 @@
+package config
+
+var (
+	SenceOssDownUrl string = "http://36.110.106.156:11121/open/scene/oss/down/"
+	SenceInfoUrl    string = "http://36.110.106.156:11121/open/scene/"
+
+	Token string = "4773hd92ysj54paflw2jem3onyhywxt2"
+)

+ 53 - 0
common/domain/d_service.go

@@ -0,0 +1,53 @@
+package domain
+
+import (
+	"cicv-data-closedloop/common/config/c_log"
+	"cicv-data-closedloop/common/entity"
+	"cicv-data-closedloop/common/util"
+	"os"
+	"strings"
+	"time"
+)
+
+func MoveFromDataToCopy(faultTime string, bagDataDir string, sourceBag string, bagCopyDir string) {
+	dir := GetCopyDir(bagCopyDir, faultTime)
+	util.CreateDir(dir)
+	targetBag := strings.Replace(sourceBag, bagDataDir, dir, 1)
+	err := os.Rename(sourceBag, targetBag)
+	if err != nil {
+		return
+	}
+	c_log.GlobalLogger.Infof("移动bag包 【%v】->【%v】", sourceBag, targetBag)
+
+}
+
+func GetCopyDir(bagDataDir string, faultTime string) string {
+	return bagDataDir + faultTime + "/"
+}
+
+// 如果 Copy目录下的包不够,则补充一些
+func SupplyCopyBags(bagDataDir string, bagCopyDir string, currentTimeWindow entity.TimeWindow) {
+	// 如果bag包没有达到length,补充几个
+	copyBags, _ := util.ListAbsolutePathWithSuffixAndSort(GetCopyDir(bagCopyDir, currentTimeWindow.FaultTime), ".bag")
+	copyBagsLength := len(copyBags)
+	if copyBagsLength >= currentTimeWindow.Length {
+		return
+	}
+	// 等待差距时间
+	gap := currentTimeWindow.Length - copyBagsLength
+	time.Sleep(time.Duration(gap) * time.Second)
+	// 获取data目录下的包列表
+	dataBags, _ := util.ListAbsolutePathWithSuffixAndSort(bagDataDir, ".bag")
+	c_log.GlobalLogger.Info("故障 ", currentTimeWindow.FaultTime, "需要从data目录找回 ", gap, " 个 bag 包")
+	for _, bag := range dataBags {
+		bagTime := util.GetBagTime(bag)
+		// 必须在区间内
+		if util.TimeCustom1GreaterEqualThanTimeCustom2(bagTime, currentTimeWindow.FaultTime) {
+			MoveFromDataToCopy(currentTimeWindow.FaultTime, bagDataDir, bag, bagCopyDir)
+			gap = gap - 1
+			if gap == 0 {
+				break
+			}
+		}
+	}
+}

+ 12 - 0
common/entity/callback.go

@@ -0,0 +1,12 @@
+package entity
+
+type CallBack struct {
+	DataName    string   `json:"dataName"`
+	DataSize    string   `json:"dataSize"`
+	EquipmentNo string   `json:"equipmentNo"`
+	SecretKey   string   `json:"secretKey"`
+	RosBagPath  string   `json:"rosBagPath"`
+	FilePath    string   `json:"filePath"`
+	TaskId      string   `json:"taskId"`
+	TriggerId   []string `json:"triggerId"`
+}

+ 35 - 0
common/entity/http_result.go

@@ -0,0 +1,35 @@
+package entity
+
+import "encoding/json"
+
+var DefaultSuccessHttpResult = &HttpResult{Status: true, Code: "1000", Message: "请求成功。"}
+var DefaultFailHttpResult = &HttpResult{Status: true, Code: "2000", Message: "请求失败。"}
+
+type HttpResult struct {
+	Status  bool   `json:"status"`
+	Code    string `json:"code"`
+	Message string `json:"message"`
+	Details string `json:"details"`
+}
+
+type Response struct {
+	Code  int         `json:"code"`  // 错误码
+	Msg   string      `json:"msg"`   // 错误描述
+	Data  interface{} `json:"data"`  // 返回数据
+	Total interface{} `json:"total"` // 分页的total数量
+}
+
+// ToString 返回 JSON 格式的错误详情
+func (res *Response) ToString() string {
+	err := &struct {
+		Code int         `json:"code"`
+		Msg  string      `json:"msg"`
+		Data interface{} `json:"data"`
+	}{
+		Code: res.Code,
+		Msg:  res.Msg,
+		Data: res.Data,
+	}
+	raw, _ := json.Marshal(err)
+	return string(raw)
+}

+ 96 - 0
common/entity/time_window.go

@@ -0,0 +1,96 @@
+package entity
+
+import (
+	"encoding/json"
+	"sync"
+	"time"
+)
+
+var (
+	TimeWindowProducerQueue      []TimeWindow
+	TimeWindowProducerQueueMutex sync.RWMutex
+
+	TimeWindowConsumerQueue      []TimeWindow
+	TimeWindowConsumerQueueMutex sync.RWMutex
+	Subscriber0Time              = time.Date(2023, time.November, 23, 10, 30, 0, 0, time.UTC)
+	Subscriber0TimeMutex         sync.Mutex
+	Subscriber1Time              = time.Date(2023, time.November, 23, 10, 30, 0, 0, time.UTC)
+	Subscriber1TimeMutex         sync.Mutex
+	Subscriber2Time              = time.Date(2023, time.November, 23, 10, 30, 0, 0, time.UTC)
+	Subscriber2TimeMutex         sync.Mutex
+	Subscriber3Time              = time.Date(2023, time.November, 23, 10, 30, 0, 0, time.UTC)
+	Subscriber3TimeMutex         sync.Mutex
+	Subscriber4Time              = time.Date(2023, time.November, 23, 10, 30, 0, 0, time.UTC)
+	Subscriber4TimeMutex         sync.Mutex
+	Subscriber5Time              = time.Date(2023, time.November, 23, 10, 30, 0, 0, time.UTC)
+	Subscriber5TimeMutex         sync.Mutex
+
+	TcpSendTime      = time.Date(2023, time.November, 23, 10, 30, 0, 0, time.UTC)
+	TcpSendTimeMutex sync.Mutex
+)
+
+type TimeWindow struct {
+	FaultTime       string   `json:"FaultTime"`
+	TimeWindowBegin string   `json:"TimeWindowBegin"`
+	TimeWindowEnd   string   `json:"TimeWindowEnd"`
+	Labels          []string `json:"Labels"`
+	TriggerIds      []string `json:"TriggerIds"`
+	Length          int      `json:"Length"`
+	CanUpload       string   `json:"CanUpload"`
+	MasterTopics    []string `json:"MasterTopics"`
+	SlaveTopics     []string `json:"SlaveTopics"`
+}
+
+func RefreshTcpSendTime() {
+	TcpSendTimeMutex.Lock()
+	TcpSendTime = time.Now()
+	TcpSendTimeMutex.Unlock()
+}
+
+func AddTimeWindowToTimeWindowProducerQueue(window TimeWindow) {
+	TimeWindowProducerQueueMutex.RLock()
+	{
+		TimeWindowProducerQueue = append(TimeWindowProducerQueue, window)
+	}
+	TimeWindowProducerQueueMutex.RUnlock()
+}
+
+func AddTimeWindowToTimeWindowConsumerQueue(window TimeWindow) {
+	TimeWindowConsumerQueueMutex.RLock()
+	{
+		TimeWindowConsumerQueue = append(TimeWindowConsumerQueue, window)
+	}
+	TimeWindowConsumerQueueMutex.RUnlock()
+}
+
+func RemoveHeadOfTimeWindowProducerQueue() {
+	TimeWindowProducerQueueMutex.RLock()
+	{
+		TimeWindowProducerQueue = TimeWindowProducerQueue[1:]
+	}
+	TimeWindowProducerQueueMutex.RUnlock()
+}
+
+func RemoveHeadOfTimeWindowConsumerQueue() {
+	TimeWindowConsumerQueueMutex.RLock()
+	{
+		TimeWindowConsumerQueue = TimeWindowConsumerQueue[1:]
+	}
+	TimeWindowConsumerQueueMutex.RUnlock()
+}
+
+// GetLastTimeWindow 获取最后一个时间窗口
+func GetLastTimeWindow() *TimeWindow {
+	var lastTimeWindow *TimeWindow // 获取最后一个时间窗口
+	if len(TimeWindowProducerQueue) > 0 {
+		lastTimeWindow = &TimeWindowProducerQueue[len(TimeWindowProducerQueue)-1]
+	}
+	return lastTimeWindow
+}
+func TimeWindowToJson(msg TimeWindow) (string, error) {
+	jsonData, err := json.Marshal(msg)
+	if err != nil {
+		return "", err
+	}
+	return string(jsonData), nil
+}

+ 39 - 0
common/gin/handler/h_hello.go

@@ -0,0 +1,39 @@
+package handler
+
+import (
+	"cicv-data-closedloop/common/config/c_db"
+	"cicv-data-closedloop/common/config/c_log"
+	"cicv-data-closedloop/common/entity"
+	"github.com/gin-gonic/gin"
+	"net/http"
+)
+
+type testStruct struct {
+	Id   int    `db:"id"`
+	Name string `db:"name"`
+}
+
+// Hello 测试接口
+// @Tags 此标记的所有接口均用于测试
+// @Summary 测试
+// @Description 该接口用于测试使用
+// @Param param query int true "Id"     参数 :@Param 参数名 位置(query 或者 path或者 body) 类型 是否必需 注释
+// @Produce json
+// @Success 200 {object} entity.HttpResult
+// @Router /test/hello [get]
+func Hello(c *gin.Context) {
+	// 获取请求参数
+	param := c.Query("param")
+	c_log.GlobalLogger.Info("接受到请求参数:", param)
+	var tests []testStruct
+	// 查询数据库
+	var testSql string
+	if err := c_db.MysqlDb.Select(&tests, testSql); err != nil {
+		c_log.GlobalLogger.Error("数据库查询报错:", err)
+		c.JSON(http.StatusInternalServerError, entity.DefaultFailHttpResult)
+		return
+	}
+	c_log.GlobalLogger.Info("数据库查询成功:", tests)
+
+	c.JSON(http.StatusOK, entity.DefaultSuccessHttpResult)
+}

+ 29 - 0
common/gin/handler/h_validate_request.go

@@ -0,0 +1,29 @@
+package handler
+
+import (
+	"cicv-data-closedloop/common/config/c_log"
+	"cicv-data-closedloop/common/entity"
+	"github.com/gin-gonic/gin"
+	"net/http"
+)
+
+var token = "U9yKpD6kZZDDe4LFKK6myAxBUT1XRrDM"
+
+func ValidateHeaders() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		acceptToken := c.GetHeader("Authorization")
+		if acceptToken == "" {
+			c_log.GlobalLogger.Errorf("未添加请求头 Authorization:%v", acceptToken)
+			c.JSON(http.StatusOK, entity.HttpResult{Status: false, Code: "1001", Message: "未添加请求头 Authorization。"})
+			c.Abort()
+			return
+		}
+		if acceptToken != token {
+			c_log.GlobalLogger.Errorf("请求头 Authorization 校验失败:%v --> %v", acceptToken[0], token)
+			c.JSON(http.StatusOK, entity.HttpResult{Status: false, Code: "1002", Message: "请求头 Authorization 校验失败。"})
+			c.Abort()
+			return
+		}
+		c.Next()
+	}
+}

+ 24 - 0
common/gin/middleware/m_cors.go

@@ -0,0 +1,24 @@
+package middleware
+
+import (
+	"github.com/gin-gonic/gin"
+	"net/http"
+)
+
+func Cors() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		method := c.Request.Method
+		origin := c.Request.Header.Get("Origin")
+		if origin != "" {
+			c.Header("Access-Control-Allow-Origin", "*") // 可将将 * 替换为指定的域名
+			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
+			c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
+			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
+			c.Header("Access-Control-Allow-Credentials", "true")
+		}
+		if method == "OPTIONS" {
+			c.AbortWithStatus(http.StatusNoContent)
+		}
+		c.Next()
+	}
+}

+ 23 - 0
common/gin/middleware/m_log_request.go

@@ -0,0 +1,23 @@
+package middleware
+
+import (
+	"github.com/gin-gonic/gin"
+)
+
+/*
+`::1` 是 IPv6 地址中的本地主机地址,相当于 IPv4 中的 `127.0.0.1`,即本地回环地址。在 IPv6 地址中,`::1` 表示本地主机,通常用于代表本地计算机与本地服务进行通信,例如访问本地运行的服务器或服务。
+在Gin框架中,`c.ClientIP()` 方法会尝试解析客户端的真实IP地址。然而,对于本地回环地址 `::1` 或者 `127.0.0.1`,这个方法可能会返回本地回环地址而不是实际的公共 IP 地址。在实际的网络部署中,您可能会看到类似 `::1` 或 `127.0.0.1` 的地址,特别是在开发和测试环境中。
+如果您希望获取请求的真实IP地址,而不是本地回环地址,可以考虑使用一些反向代理服务器或负载均衡器,它们通常会在请求头中添加一个字段来传递客户端的真实IP地址。在Gin中,您可以使用`c.Request.Header.Get("X-Real-IP")`或`c.Request.Header.Get("X-Forwarded-For")`来获取这些头部信息中的真实IP地址。请注意,使用这些方法时需要谨慎,确保信任传递的 IP 地址信息,以防止IP欺骗等安全问题。
+*/
+
+// LogRequest 中间件函数,用于打印请求方的IP地址和请求路径
+func LogRequest() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//clientIP := c.ClientIP()          // 获取请求方的IP地址
+		//requestPath := c.Request.URL.Path // 获取请求路径
+		//// 打印请求方的IP地址和请求路径
+		//c_log.GlobalLogger.Infof("客户端 %v 发送请求 %v", clientIP, requestPath)
+		// 继续处理后续请求
+		c.Next()
+	}
+}

+ 34 - 0
common/gin/middleware/m_validate_header.go

@@ -0,0 +1,34 @@
+package middleware
+
+import (
+	"cicv-data-closedloop/common/config/c_log"
+	"cicv-data-closedloop/common/entity"
+	"github.com/gin-gonic/gin"
+	"net/http"
+	"strings"
+)
+
+func ValidateHeaders(whiteList []string, webToken string) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		// 校验不在白名单中的路由
+		if isNotWhite(c.Request.URL.Path, whiteList) {
+			acceptToken := c.GetHeader("Authorization")
+			if acceptToken == "" || acceptToken != webToken {
+				c_log.GlobalLogger.Errorf("请求头 Authorization 校验失败:%v --> %v", acceptToken, webToken)
+				c.JSON(http.StatusOK, entity.HttpResult{Status: false, Code: "1001", Message: "请求头 Authorization 校验失败。"})
+				c.Abort()
+				return
+			}
+		}
+		c.Next()
+	}
+}
+
+func isNotWhite(path string, whiteList []string) bool {
+	for _, whitePath := range whiteList {
+		if strings.HasPrefix(path, whitePath) {
+			return false
+		}
+	}
+	return true
+}

+ 52 - 0
common/gin/middleware/m_whitelist.go

@@ -0,0 +1,52 @@
+package middleware
+
+import (
+	"github.com/gin-gonic/gin"
+	"net/http"
+)
+
+var (
+	whitelistIP = map[string]bool{
+		"192.168.1.100": true,
+		"10.0.0.1":      true,
+		// 添加更多的白名单IP地址
+	}
+	whitelistRoutes = map[string]bool{
+		"/yuexin-pay/swagger": true,
+		// 添加更多的白名单路由
+	}
+)
+
+// WhitelistMiddleware 白名单中间件
+func WhitelistMiddleware() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		// 检查IP地址
+		clientIP := c.ClientIP()
+		if !isIPInWhitelist(clientIP) {
+			c.JSON(http.StatusForbidden, gin.H{"error": "IP地址不在白名单中"})
+			c.Abort()
+			return
+		}
+
+		// 检查路由
+		if !isRouteInWhitelist(c.FullPath()) {
+			c.JSON(http.StatusForbidden, gin.H{"error": "路由不在白名单中"})
+			c.Abort()
+			return
+		}
+
+		c.Next()
+	}
+}
+
+// isIPInWhitelist 检查IP地址是否在白名单中
+func isIPInWhitelist(ip string) bool {
+	_, ok := whitelistIP[ip]
+	return ok
+}
+
+// isRouteInWhitelist 检查路由是否在白名单中
+func isRouteInWhitelist(route string) bool {
+	_, ok := whitelistRoutes[route]
+	return ok
+}

+ 33 - 0
common/handler/h_validate_request_header/validate_request_header.go

@@ -0,0 +1,33 @@
+package h_validate_request_header
+
+import (
+	"cicv-data-closedloop/common/config/c_log"
+	"cicv-data-closedloop/common/entity"
+	"encoding/json"
+	"fmt"
+	"net/http"
+)
+
+var token = "1e8YmQMYwTTbfUYMZczkj1x17AeXjbdU"
+
+// HeaderValidationMiddleware Middleware function to add header validation
+func HeaderValidationMiddleware(next http.Handler) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		acceptToken := r.Header["Authorization"]
+		if _, ok := r.Header["Authorization"]; !ok {
+			c_log.GlobalLogger.Errorf("未添加请求头 Authorization:%v", acceptToken)
+			result, _ := json.Marshal(entity.HttpResult{Status: false, Code: "1000", Message: "未添加请求头 Authorization。"})
+			_, _ = fmt.Fprintf(w, string(result))
+			return
+		}
+		if acceptToken[0] != token {
+			c_log.GlobalLogger.Errorf("请求头 Authorization 校验失败:%v --> %v", acceptToken[0], token)
+			result, _ := json.Marshal(entity.HttpResult{Status: false, Code: "1001", Message: "请求头 Authorization 校验失败。"})
+			_, _ = fmt.Fprintf(w, string(result))
+			return
+		}
+
+		// 如果通过校验,继续处理下一个处理程序
+		next.ServeHTTP(w, r)
+	})
+}

+ 127 - 0
common/util/u_exec.go

@@ -0,0 +1,127 @@
+package util
+
+import (
+	"os"
+	"os/exec"
+	"strconv"
+	"strings"
+)
+
+// GetSubProcessPid 只用于一个子进程
+func GetSubProcessPid(pid int) (int, error) {
+	pgrepCmd := exec.Command("pgrep", "-P", strconv.Itoa(pid))
+	output, err := pgrepCmd.CombinedOutput()
+	if err != nil {
+		return 0, err
+	}
+	replace := strings.Replace(string(output), "\n", "", 1)
+	subProcessPid, err := strconv.Atoi(replace)
+	if err != nil {
+		return 0, err
+	}
+	return subProcessPid, nil
+}
+
+func ExecuteWithPath(path string, name string, arg ...string) (*exec.Cmd, error) {
+	// 创建一个Cmd对象,表示要执行的命令
+	cmd := exec.Command(name, arg...)
+	// 指定目录
+	cmd.Dir = path
+	err := cmd.Start()
+	if err != nil {
+		return nil, err
+	} else {
+		// 执行命令并等待它完成d
+		return cmd, nil
+	}
+}
+
+func ExecuteWithDirAsync(dir string, name string, arg ...string) (*exec.Cmd, error) {
+	// 创建一个Cmd对象,表示要执行的命令
+	cmd := exec.Command(name, arg...)
+	// 指定目录
+	cmd.Dir = dir
+	err := cmd.Start()
+	if err != nil {
+		return nil, err
+	}
+	return cmd, nil
+}
+
+func ExecuteWithEnvAndDirAsync(envs []string, dir string, name string, arg ...string) (*exec.Cmd, error) {
+	cmd := exec.Command(name, arg...)
+	cmd.Dir = dir
+	for _, env := range envs {
+		cmd.Env = append(cmd.Env, env)
+	}
+	if err := cmd.Start(); err != nil {
+		return nil, err
+	}
+	return cmd, nil
+}
+
+// KillProcessByPid 必须使用该golang原生方法,通过直接执行kill命令行不通。
+func KillProcessByPid(pid int) error {
+	process, err := os.FindProcess(pid)
+	if err != nil {
+		return err
+	}
+	err = process.Kill()
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func Execute(name string, arg ...string) (*exec.Cmd, string, error) {
+	cmd := exec.Command(name, arg...)
+	combinedOutput, err := cmd.CombinedOutput()
+	if err != nil {
+		return nil, "", err
+	}
+	return cmd, string(combinedOutput), nil
+}
+
+func ExecuteSync(name string, arg ...string) (*exec.Cmd, string, error) {
+	cmd := exec.Command(name, arg...)
+	combinedOutput, err := cmd.CombinedOutput()
+	if err != nil {
+		return nil, "", err
+	}
+	return cmd, string(combinedOutput), nil
+}
+
+func ExecuteWithDirSync(dir string, name string, arg ...string) (*exec.Cmd, string, error) {
+	cmd := exec.Command(name, arg...)
+	cmd.Dir = dir
+	combinedOutput, err := cmd.CombinedOutput()
+	if err != nil {
+		return nil, "", err
+	}
+	return cmd, string(combinedOutput), nil
+}
+
+func ExecuteWithEnvSync(envs []string, name string, arg ...string) (*exec.Cmd, string, error) {
+	cmd := exec.Command(name, arg...)
+	for _, env := range envs {
+		cmd.Env = append(cmd.Env, env)
+	}
+	combinedOutput, err := cmd.CombinedOutput()
+	if err != nil {
+		return nil, "", err
+	}
+	return cmd, string(combinedOutput), nil
+}
+
+func ExecuteWithEnvAndDir(envs []string, dir string, name string, arg ...string) (*exec.Cmd, string, error) {
+	cmd := exec.Command(name, arg...)
+	cmd.Dir = dir
+	for _, env := range envs {
+		cmd.Env = append(cmd.Env, env)
+	}
+	combinedOutput, err := cmd.CombinedOutput()
+	if err != nil {
+		return nil, string(combinedOutput), err
+	}
+	return cmd, string(combinedOutput), nil
+}

+ 137 - 0
common/util/u_http.go

@@ -0,0 +1,137 @@
+package util
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+	"net/url"
+)
+
+func HttpGet(url string) (string, error) {
+	// 创建一个HTTP客户端
+	client := &http.Client{}
+
+	// 创建一个GET请求
+	req, err := http.NewRequest("GET", url, nil)
+	if err != nil {
+		return "", err
+	}
+
+	// 发送请求并获取响应
+	resp, err := client.Do(req)
+	if err != nil {
+		return "", err
+	}
+	defer func(Body io.ReadCloser) {
+		err := Body.Close()
+		if err != nil {
+
+		}
+	}(resp.Body)
+
+	// 读取响应的内容
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return "", err
+	}
+	return string(body), nil
+}
+func HttpPostJsonResponseString(url string, params map[string]string) (string, error) {
+	jsonData, err := json.Marshal(params)
+	if err != nil {
+		return "", err
+	}
+	resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
+	if err != nil {
+		return "", err
+	}
+	defer func(Body io.ReadCloser) {
+		err := Body.Close()
+		if err != nil {
+		}
+	}(resp.Body)
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return "", err
+	}
+	return string(body), nil
+}
+
+func HttpPostJsonWithHeaders(baseUrl string, headers map[string]string, params map[string]string) (string, error) {
+	// 将参数转换为 JSON 字符串
+	jsonData, err := json.Marshal(params)
+	if err != nil {
+		fmt.Println("Error encoding JSON:", err)
+		return "", err
+	}
+
+	// 创建请求
+	req, err := http.NewRequest("POST", baseUrl, bytes.NewBuffer(jsonData))
+	if err != nil {
+		fmt.Println("Error creating request:", err)
+		return "", err
+	}
+
+	// 设置请求头
+	for key, value := range headers {
+		req.Header.Set(key, value)
+	}
+
+	// 发送请求
+	client := &http.Client{}
+	resp, err := client.Do(req)
+	if err != nil {
+		fmt.Println("Error sending request:", err)
+		return "", err
+	}
+	defer resp.Body.Close()
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return "", err
+	}
+	return string(body), nil
+}
+
+func HttpGetStringAddHeadersResponseString(baseUrl string, headers map[string]string, params map[string]string) (string, error) {
+
+	// 将参数编码到URL中
+	u, _ := url.Parse(baseUrl)
+	q := u.Query()
+	for key, value := range params {
+		q.Add(key, value)
+	}
+	u.RawQuery = q.Encode()
+
+	// 创建请求
+	req, err := http.NewRequest("GET", u.String(), nil)
+	if err != nil {
+		return "", err
+	}
+
+	// 设置请求头
+	for key, value := range headers {
+		req.Header.Set(key, value)
+	}
+
+	// 发送请求
+	client := &http.Client{}
+	resp, err := client.Do(req)
+	if err != nil {
+		return "", err
+	}
+
+	// 读取响应体
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return "", err
+	}
+	err = resp.Body.Close()
+	if err != nil {
+		return "", err
+	}
+	result := string(body)
+	//log.GlobalLogger.Info("发送http请求,请求路径=", baseUrl, ",请求头=", headers, "请求参数=", params, "请求结果=", result)
+	return result, nil
+}

+ 262 - 0
common/util/u_io.go

@@ -0,0 +1,262 @@
+package util
+
+import (
+	"fmt"
+	"io"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+)
+
+func GetFileSize(filePath string) (int, error) {
+	fileInfo, err := os.Stat(filePath)
+	if err != nil {
+		return 0, err
+	}
+	return int(fileInfo.Size()), nil
+}
+
+func CheckSoFilesInDirectory(dirPath string) (bool, []string) {
+	hasSoFile := false
+	soFilePaths := make([]string, 0)
+	if _, err := os.Stat(dirPath); os.IsNotExist(err) {
+		fmt.Println("Directory does not exist:", dirPath)
+		return false, soFilePaths
+	}
+
+	err := filepath.Walk(dirPath, func(path string, info fs.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+
+		if info.IsDir() {
+			return nil
+		}
+
+		if filepath.Ext(path) == ".so" {
+			hasSoFile = true
+			soFilePaths = append(soFilePaths, path)
+		}
+		return nil
+	})
+
+	if err != nil {
+		fmt.Println("Error walking the directory:", err)
+		os.Exit(1)
+	}
+
+	return hasSoFile, soFilePaths
+}
+
+func GetFirstLevelSubdirectories(dirPath string) []string {
+	dirEntries, _ := os.ReadDir(dirPath)
+	subdirectories := make([]string, 0)
+	for _, entry := range dirEntries {
+		if entry.IsDir() {
+			subdirectories = append(subdirectories, entry.Name())
+		}
+	}
+	return subdirectories
+}
+
+func GetFileNameWithoutExtension(absPath string) string {
+	file := filepath.Base(absPath)
+	ext := filepath.Ext(file)
+	return strings.TrimSuffix(file, ext)
+}
+
+func GetSoFilePaths(dir string) []string {
+	var paths []string
+	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+		if err == nil && !info.IsDir() && filepath.Ext(path) == ".so" {
+			absPath, _ := filepath.Abs(path)
+			paths = append(paths, absPath)
+		}
+		return nil
+	})
+	if err != nil {
+		fmt.Println("Error:", err)
+		return nil
+	}
+	return paths
+}
+
+// CreateDir 创建目录
+func CreateDir(directory string) {
+	if _, err := os.Stat(directory); os.IsNotExist(err) {
+		_ = os.MkdirAll(directory, os.ModePerm)
+	}
+}
+
+// CreateParentDir 存在不创建,不存在则创建父目录
+func CreateParentDir(filePath string) error {
+	if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
+		return err
+	}
+	return nil
+}
+
+// RemoveDir 递归删除目录及其下的所有文件和子目录
+func RemoveDir(dirPath string) error {
+	// 打开目录
+	dir, err := os.Open(dirPath)
+	if err != nil {
+		return err
+	}
+	defer dir.Close()
+	// 读取目录下的文件和子目录
+	fileInfos, err := dir.Readdir(-1)
+	if err != nil {
+		return err
+	}
+	// 遍历文件和子目录
+	for _, fileInfo := range fileInfos {
+		path := filepath.Join(dirPath, fileInfo.Name())
+
+		if fileInfo.IsDir() {
+			// 如果是子目录,递归调用removeDir删除子目录及其下的文件和子目录
+			if err = RemoveDir(path); err != nil {
+				return err
+			}
+		} else {
+			// 如果是文件,直接删除文件
+			if err = os.Remove(path); err != nil {
+				return err
+			}
+		}
+	}
+	// 删除目录本身
+	if err = os.Remove(dirPath); err != nil {
+		return err
+	}
+	return nil
+}
+
+// RemoveSubFiles 递归删除目录及其下的所有文件和子目录
+func RemoveSubFiles(dirPath string) error {
+	// 打开目录
+	dir, err := os.Open(dirPath)
+	if err != nil {
+		return err
+	}
+	defer dir.Close()
+	// 读取目录下的文件和子目录
+	fileInfos, err := dir.Readdir(-1)
+	if err != nil {
+		return err
+	}
+	// 遍历文件和子目录
+	for _, fileInfo := range fileInfos {
+		path := filepath.Join(dirPath, fileInfo.Name())
+
+		if fileInfo.IsDir() {
+			// 如果是子目录,递归调用removeDir删除子目录及其下的文件和子目录
+			if err = RemoveDir(path); err != nil {
+				return err
+			}
+		} else {
+			// 如果是文件,直接删除文件
+			if err = os.Remove(path); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+func WriteFile(sourceContent string, targetFilePath string) error {
+	if err := CreateFile(targetFilePath); err != nil {
+		return err
+	}
+	if err := os.WriteFile(targetFilePath, []byte(sourceContent), 0644); err != nil {
+		return err
+	}
+	return nil
+}
+
+// CreateFile 存在则覆盖,不存在则创建文件
+func CreateFile(filePath string) error {
+	if err := CreateParentDir(filePath); err != nil {
+		return err
+	}
+	// 创建文件,如果文件已存在则覆盖
+	file, err := os.Create(filePath)
+	if err != nil {
+		return err
+	}
+	defer func(file *os.File) {
+		err := file.Close()
+		if err != nil {
+
+		}
+	}(file)
+	return nil
+}
+func ReadFile(filePath string) (string, error) {
+	// 1 打开文件
+	file, err := os.Open(filePath)
+	if err != nil {
+		return "", err
+	}
+	defer file.Close()
+
+	// 2 读取文件内容
+	content, err := io.ReadAll(file)
+	if err != nil {
+		return "", err
+	}
+	return string(content), err
+}
+
+func ListAbsolutePathWithSuffixAndSort(dir string, suffix string) ([]string, error) {
+	var result []string
+	if !strings.HasSuffix(dir, "/") {
+		dir = dir + "/"
+	}
+	files, err := os.ReadDir(dir)
+	if err != nil {
+		return nil, err
+	}
+	for _, file := range files {
+		if strings.HasSuffix(file.Name(), suffix) {
+			result = append(result, dir+file.Name())
+		}
+	}
+	// 根据文件名进行升序排序
+	sort.Slice(result, func(i, j int) bool {
+		return filepath.Base(result[i]) < filepath.Base(result[j])
+	})
+	return result, nil
+}
+
+func DeleteFile(path string) error {
+	// 检查文件是否存在
+	if _, err := os.Stat(path); err == nil {
+		// 文件存在,执行删除操作
+		err = os.Remove(path)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// WriteStringToFile 将字符串写入指定的文件路径
+func WriteStringToFile(content string, filePath string) {
+	// 方法一:使用os包
+	file, err := os.Create(filePath)
+	if err != nil {
+		fmt.Println("创建文件失败:", err)
+		return
+	}
+	defer file.Close()
+
+	_, err = file.WriteString(content)
+	if err != nil {
+		fmt.Println("写入文件失败:", err)
+		return
+	}
+	fmt.Println("字符串成功写入文件(os包)")
+}

+ 39 - 0
common/util/u_json.go

@@ -0,0 +1,39 @@
+package util
+
+import "encoding/json"
+
+// 将map转为JSON字符串的函数
+func MapToJsonString(inputMap map[string]interface{}) (string, error) {
+	// 使用json.Marshal将map转为JSON格式的字节切片
+	jsonBytes, err := json.Marshal(inputMap)
+	if err != nil {
+		return "", err
+	}
+
+	// 将字节切片转为字符串
+	jsonString := string(jsonBytes)
+	return jsonString, nil
+}
+
+// 将map转为JSON字符串的函数
+func MapToReadableJsonString(inputMap map[string]string) string {
+	// 使用json.Marshal将map转为JSON格式的字节切片
+	jsonBytes, err := json.Marshal(inputMap)
+	if err != nil {
+		return ""
+	}
+
+	// 将字节切片转为字符串
+	jsonString := string(jsonBytes)
+	return jsonString
+}
+
+func JsonStringToMap(source string) (map[string]interface{}, error) {
+	var dataMap map[string]interface{}
+	err := json.Unmarshal([]byte(source), &dataMap)
+	if err != nil {
+		return nil, err
+	} else {
+		return dataMap, nil
+	}
+}

+ 10 - 0
common/util/u_map.go

@@ -0,0 +1,10 @@
+package util
+
+import (
+	"sync"
+)
+
+func ContainsKey(m *sync.Map, key string) bool {
+	_, found := m.Load(key)
+	return found
+}

+ 48 - 0
common/util/u_oss.go

@@ -0,0 +1,48 @@
+package util
+
+import (
+	"github.com/aliyun/aliyun-oss-go-sdk/oss"
+	"os"
+	"strconv"
+)
+
+// LimitUpload 限速上传
+// limitBit 默认单位为bit/s。比如 41943040 为 5 MB/s。
+func LimitUpload(bucket *oss.Bucket, limitBit int64, ossObjectKey string, localFilePath string) error {
+	fd, err := os.Open(localFilePath)
+	if err != nil {
+		return err
+	}
+	defer fd.Close()
+	if err = bucket.PutObject(ossObjectKey, fd, oss.TrafficLimitHeader(limitBit)); err != nil {
+		return err
+	}
+	return nil
+}
+
+// LimitDownload 限速下载
+// limitBit 默认单位为bit/s。比如 41943040 为 5 MB/s。
+func LimitDownload(bucket *oss.Bucket, limitBit int64, ossObjectKey string, localFilePath string) error {
+	if err := CreateParentDir(localFilePath); err != nil {
+		return err
+	}
+	if err := bucket.GetObjectToFile(ossObjectKey, localFilePath, oss.TrafficLimitHeader(limitBit)); err != nil {
+		return err
+	}
+	return nil
+}
+
+func GetOSSFileSize(bucket *oss.Bucket, objectName string) (int, error) {
+	// 获取文件的元信息
+	attrs, err := bucket.GetObjectDetailedMeta(objectName)
+	if err != nil {
+		return 0, err
+	}
+
+	// 从元信息中获取文件大小
+	size, err := strconv.Atoi(attrs.Get("Content-Length"))
+	if err != nil {
+		return 0, err
+	}
+	return size, nil
+}

+ 164 - 0
common/util/u_resource.go

@@ -0,0 +1,164 @@
+package util
+
+import (
+	"github.com/shirou/gopsutil/cpu"
+	"github.com/shirou/gopsutil/disk"
+	"github.com/shirou/gopsutil/mem"
+	"github.com/shirou/gopsutil/process"
+	"os/exec"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type ProcessInfo struct {
+	Pid      int32   `json:"pid"`
+	Name     string  `json:"name"`
+	CpuUsage float64 `json:"cpuUsage"`
+	MemUsage float32 `json:"memUsage"`
+}
+
+func GetTop10CpuAndMem() ([]ProcessInfo, []ProcessInfo) {
+	// 获取所有进程的CPU占用率
+	processes, err := process.Processes()
+	if err != nil {
+		//fmt.Println("Error:", err)
+		return nil, nil
+	}
+
+	// 创建一个用于存储进程CPU占用率的映射
+	cpuPercent := make(map[int32]float64)
+	memPercent := make(map[int32]float32)
+
+	// 获取每个进程的CPU占用率
+	for _, p := range processes {
+		pid := p.Pid
+		cpuPercent[pid], err = p.CPUPercent()
+		memPercent[pid], err = p.MemoryPercent()
+	}
+
+	// 根据CPU占用率对进程进行排序
+	sortedPidsCpu := make([]int32, 0, len(cpuPercent))
+	sortedPidsMem := make([]int32, 0, len(cpuPercent))
+	for pid := range cpuPercent {
+		sortedPidsCpu = append(sortedPidsCpu, pid)
+	}
+
+	sort.Slice(sortedPidsCpu, func(i, j int) bool {
+		return cpuPercent[sortedPidsCpu[i]] > cpuPercent[sortedPidsCpu[j]]
+	})
+
+	// 输出前10个CPU占用率最高的进程名称
+	var top10Cpu []ProcessInfo
+
+	for i, pid := range sortedPidsCpu {
+		if i >= 10 {
+			break
+		}
+		p, err := process.NewProcess(pid)
+		if err != nil {
+			continue
+		}
+		name, _ := p.Name()
+		top10Cpu = append(top10Cpu, ProcessInfo{
+			Pid:      pid,
+			Name:     name,
+			CpuUsage: cpuPercent[pid],
+			MemUsage: memPercent[pid],
+		})
+	}
+
+	// --------------------- 内存
+	var top10Mem []ProcessInfo
+
+	for pid := range memPercent {
+		sortedPidsMem = append(sortedPidsMem, pid)
+	}
+
+	sort.Slice(sortedPidsMem, func(i, j int) bool {
+		return memPercent[sortedPidsMem[i]] > memPercent[sortedPidsMem[j]]
+	})
+
+	for i, pid := range sortedPidsMem {
+		if i >= 10 {
+			break
+		}
+		p, err := process.NewProcess(pid)
+		if err != nil {
+			continue
+		}
+		name, _ := p.Name()
+		top10Mem = append(top10Mem, ProcessInfo{
+			Pid:      pid,
+			Name:     name,
+			CpuUsage: cpuPercent[pid],
+			MemUsage: memPercent[pid],
+		})
+	}
+	return top10Cpu, top10Mem
+}
+
+// cpu总占用率
+func GetCpuPercent() float64 {
+	percent, _ := cpu.Percent(time.Second, false)
+	return percent[0]
+}
+
+// 内存总占用率
+func GetMemoryPercent() float64 {
+	memory, _ := mem.VirtualMemory()
+	return memory.UsedPercent
+}
+
+// 磁盘总占用率
+func GetDiskPercent() float64 {
+	parts, _ := disk.Partitions(true)
+	diskInfo, _ := disk.Usage(parts[0].Mountpoint)
+	return diskInfo.UsedPercent
+}
+
+// GetDiskUsed 解析 df 命令的输出
+// df -B1 /dev/vdb
+// Filesystem        1B-blocks        Used    Available Use% Mounted on
+// /dev/vdb       527371075584 16390344704 484120408064   4% /mnt/disk001
+func GetDiskUsed(filesystem string) (uint64, error) {
+	cmd := exec.Command("df", "-B1", filesystem)
+	output, err := cmd.CombinedOutput()
+	if err != nil {
+		return 0, err
+	}
+	lines := strings.Split(string(output), "\n")
+	fields := strings.Fields(lines[1])
+	parseUint, err := strconv.ParseUint(fields[2], 10, 64)
+	if err != nil {
+		return 0, err
+	}
+	return parseUint, nil
+}
+
+// GetDiskUsagePercent 获取磁盘使用率
+func GetDiskUsagePercent() (float64, error) {
+	// 执行 df 命令获取磁盘使用情况
+	cmd := exec.Command("df", "--total")
+	output, err := cmd.Output()
+	if err != nil {
+		return 0.0, err
+	}
+
+	// 解析 df 命令输出,计算磁盘占比
+	lines := strings.Split(string(output), "\n")
+	for _, line := range lines[1:] {
+		fields := strings.Fields(line)
+		if len(fields) >= 6 && fields[0] == "total" {
+			//filesystem := fields[0]
+			total, _ := strconv.ParseFloat(strings.TrimSuffix(fields[1], "G"), 64)
+			used, _ := strconv.ParseFloat(strings.TrimSuffix(fields[2], "G"), 64)
+			usedPercent := (used / total) * 100
+
+			//fmt.Printf("文件系统 %s 已使用 %.2f%%\n", filesystem, usedPercent)
+			return usedPercent, err
+		}
+	}
+	return 0.0, nil
+}

+ 28 - 0
common/util/u_slice.go

@@ -0,0 +1,28 @@
+package util
+
+// AppendIfNotExists 向切片中追加元素,如果元素已存在则不添加
+func AppendIfNotExists(slice []string, element string) []string {
+	for _, item := range slice {
+		if item == element {
+			return slice // 元素已存在,直接返回原切片
+		}
+	}
+	return append(slice, element) // 元素不存在,追加到切片末尾
+}
+func MergeSlice(slice1 []string, slice2 []string) []string {
+
+	// 遍历第二个切片中的元素,并去重追加到结果切片1中
+	for _, element := range slice2 {
+		found := false
+		for _, item := range slice1 {
+			if element == item {
+				found = true
+				break
+			}
+		}
+		if !found {
+			slice1 = append(slice1, element)
+		}
+	}
+	return slice1
+}

+ 23 - 0
common/util/u_string.go

@@ -0,0 +1,23 @@
+package util
+
+import (
+	"fmt"
+	"github.com/google/uuid"
+	"strconv"
+)
+
+func ToString(value interface{}) string {
+	return fmt.Sprintf("%v", value)
+}
+
+func NewUUID() string {
+	return uuid.New().String()[:8]
+}
+func NewShortUUID() string {
+	return uuid.New().String()[:8]
+}
+
+func StringToInt(str string) int {
+	intVal, _ := strconv.Atoi(str)
+	return intVal
+}

+ 76 - 0
common/util/u_time.go

@@ -0,0 +1,76 @@
+package util
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func GetNowTimeCustom() string {
+	currentTime := time.Now()
+	formattedTime := currentTime.Format("2006-01-02-15-04-05")
+	return formattedTime
+}
+
+func BagTimeInInterval(bagTime string, begin string, end string) bool {
+	compare1 := TimeCustom1GreaterEqualThanTimeCustom2(bagTime, begin)
+	compare2 := TimeCustom1LessEqualThanTimeCustom2(bagTime, end)
+	return compare1 && compare2
+}
+
+func TimeCustom1GreaterEqualThanTimeCustom2(timeCustom1 string, timeCustom2 string) bool {
+	timeInt1, _ := strconv.Atoi(strings.Replace(timeCustom1, "-", "", -1))
+	timeInt2, _ := strconv.Atoi(strings.Replace(timeCustom2, "-", "", -1))
+	return timeInt1 >= timeInt2
+}
+func GetBagTime(bagName string) string {
+	s1 := strings.Split(bagName, "_")[0]
+	s1Split := strings.Split(s1, "/")
+	s2 := s1Split[len(s1Split)-1]
+	return s2
+}
+func TimeCustomChange(originalTimeStr string, number int) string {
+	var newTimeStr string
+	layout := "2006-01-02-15-04-05"
+	originalTime, err := time.Parse(layout, originalTimeStr)
+	if err != nil {
+		return newTimeStr
+	}
+	newTime := originalTime.Add(time.Duration(number) * time.Second)
+	return newTime.Format(layout)
+}
+func CalculateDifferenceOfTimeCustom(timeCustom1 string, timeCustom2 string) int {
+	timeInt1, _ := strconv.Atoi(strings.Replace(timeCustom1, "-", "", -1))
+	timeInt2, _ := strconv.Atoi(strings.Replace(timeCustom2, "-", "", -1))
+	return timeInt2 - timeInt1 + 1
+
+}
+func TimeCustom1GreaterTimeCustom2(timeCustom1 string, timeCustom2 string) bool {
+	timeInt1, _ := strconv.Atoi(strings.Replace(timeCustom1, "-", "", -1))
+	timeInt2, _ := strconv.Atoi(strings.Replace(timeCustom2, "-", "", -1))
+	return timeInt1 > timeInt2
+}
+
+func TimeCustom1LessEqualThanTimeCustom2(timeCustom1 string, timeCustom2 string) bool {
+	timeInt1, _ := strconv.Atoi(strings.Replace(timeCustom1, "-", "", -1))
+	timeInt2, _ := strconv.Atoi(strings.Replace(timeCustom2, "-", "", -1))
+	return timeInt1 <= timeInt2
+}
+
+func GetTimeString(sourceTime time.Time) string {
+	var defaultTime = time.Date(2006, time.January, 2, 15, 4, 5, 0, time.Local)
+	if sourceTime.Equal(defaultTime) {
+		return ""
+	}
+	return sourceTime.Format("2006-01-02 15:04:05")
+}
+
+func AnyToTime(value any) (time.Time, error) {
+	switch v := value.(type) {
+	case time.Time:
+		return v, nil
+	default:
+		return time.Time{}, fmt.Errorf("unsupported type: %T", value)
+	}
+}

+ 37 - 7
go.mod

@@ -3,32 +3,62 @@ module pji_desktop_http
 go 1.22.5
 
 require (
+	github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
 	github.com/cloudwego/hertz v0.9.2
+	github.com/gin-gonic/gin v1.10.0
+	github.com/go-sql-driver/mysql v1.8.1
+	github.com/google/uuid v1.6.0
+	github.com/jmoiron/sqlx v1.4.0
+	github.com/shirou/gopsutil v3.21.11+incompatible
+	github.com/sirupsen/logrus v1.9.3
 	google.golang.org/protobuf v1.34.2
 	gorm.io/driver/mysql v1.5.7
 	gorm.io/gorm v1.25.11
 )
 
 require (
+	filippo.io/edwards25519 v1.1.0 // indirect
 	github.com/bytedance/go-tagexpr/v2 v2.9.2 // indirect
 	github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 // indirect
-	github.com/bytedance/sonic v1.8.1 // indirect
-	github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
+	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/cloudwego/netpoll v0.6.0 // indirect
 	github.com/fsnotify/fsnotify v1.5.4 // indirect
-	github.com/go-sql-driver/mysql v1.7.0 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+	github.com/gin-contrib/sse v0.1.0 // indirect
+	github.com/go-ole/go-ole v1.2.6 // 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/protobuf v1.5.0 // indirect
 	github.com/henrylee2cn/ameda v1.4.10 // indirect
 	github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.5 // indirect
-	github.com/klauspost/cpuid/v2 v2.0.9 // 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/nyaruka/phonenumbers v1.0.55 // indirect
+	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
 	github.com/tidwall/gjson v1.14.4 // indirect
 	github.com/tidwall/match v1.1.1 // indirect
 	github.com/tidwall/pretty v1.2.0 // indirect
+	github.com/tklauser/go-sysconf v0.3.14 // indirect
+	github.com/tklauser/numcpus v0.8.0 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
-	golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
-	golang.org/x/sys v0.5.0 // indirect
-	golang.org/x/text v0.14.0 // indirect
+	github.com/ugorji/go/codec v1.2.12 // indirect
+	github.com/yusufpapurcu/wmi v1.2.4 // 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
+	golang.org/x/time v0.5.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
 )

+ 91 - 9
go.sum

@@ -1,3 +1,7 @@
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
+github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
 github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I=
 github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM=
 github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 h1:PtwsQyQJGxf8iaPptPNaduEIu9BnrNms+pcRdHAxZaM=
@@ -5,13 +9,19 @@ github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7/go.mod h1:2ZlV9BaU
 github.com/bytedance/mockey v1.2.1 h1:g84ngI88hz1DR4wZTL3yOuqlEcq67MretBfQUdXwrmw=
 github.com/bytedance/mockey v1.2.1/go.mod h1:+Jm/fzWZAuhEDrPXVjDf/jLM2BlLXJkwk94zf2JZ3X4=
 github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
-github.com/bytedance/sonic v1.8.1 h1:NqAHCaGaTzro0xMmnTCLUyRlbEP6r8MCA1cJUrH3Pu4=
 github.com/bytedance/sonic v1.8.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
+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=
+github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
 github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
-github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
 github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
+github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
+github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
 github.com/cloudwego/hertz v0.9.2 h1:VbqddZ5RuvcgxzfxvXcmTiRisGYoo0+WnHGeDJKhjqI=
 github.com/cloudwego/hertz v0.9.2/go.mod h1:cs8dH6unM4oaJ5k9m6pqbgLBPqakGWMG0+cthsxitsg=
+github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
+github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
 github.com/cloudwego/netpoll v0.6.0 h1:JRMkrA1o8k/4quxzg6Q1XM+zIhwZsyoWlq6ef+ht31U=
 github.com/cloudwego/netpoll v0.6.0/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -19,13 +29,35 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
-github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
+github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
+github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
+github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
+github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
+github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
+github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/henrylee2cn/ameda v1.4.8/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4=
@@ -37,14 +69,39 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
+github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
+github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
+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/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
+github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
+github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg=
 github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
+github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
@@ -52,13 +109,17 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
 github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@@ -66,22 +127,41 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
 github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
 github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
 github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
+github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
+github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
+github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
 github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
+github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
+github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
+github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
 golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
-golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
 golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
+golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -89,6 +169,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
 google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -99,4 +180,5 @@ gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkD
 gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
 gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
 gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
+nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

+ 4 - 0
main.go

@@ -5,10 +5,14 @@ package main
 import (
 	"github.com/cloudwego/hertz/pkg/app/server"
 	"pji_desktop_http/biz/dal"
+	"pji_desktop_http/common/config"
+	"pji_desktop_http/common/config/c_log"
 )
 
 func main() {
 	dal.Init()
+	c_log.InitLog("logs/", "desktop_http")
+	config.InitOssConfig()
 	h := server.Default()
 	register(h)
 	h.Spin()

+ 4 - 1
router.go

@@ -5,6 +5,7 @@ package main
 import (
 	"github.com/cloudwego/hertz/pkg/app/server"
 	handler "pji_desktop_http/biz/handler"
+	"pji_desktop_http/biz/handler/map_service"
 	"pji_desktop_http/biz/handler/user_service"
 )
 
@@ -12,6 +13,8 @@ import (
 func customizedRegister(r *server.Hertz) {
 	r.GET("/ping", handler.Ping)
 
-	// your code ...
 	r.GET("/test/queryuser", user_service.TestQueryUser)
+
+	r.POST("/map/checkmapbuf", map_service.CheckMapBufConsistency)
+
 }