|
@@ -1,21 +1,25 @@
|
|
package map_service
|
|
package map_service
|
|
|
|
|
|
import (
|
|
import (
|
|
|
|
+ "archive/zip"
|
|
"context"
|
|
"context"
|
|
"encoding/json"
|
|
"encoding/json"
|
|
"fmt"
|
|
"fmt"
|
|
"github.com/cloudwego/hertz/pkg/app"
|
|
"github.com/cloudwego/hertz/pkg/app"
|
|
"github.com/cloudwego/hertz/pkg/protocol/consts"
|
|
"github.com/cloudwego/hertz/pkg/protocol/consts"
|
|
|
|
+ "io"
|
|
"io/ioutil"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http"
|
|
|
|
+ "os"
|
|
|
|
+ "path/filepath"
|
|
"pji_desktop_http/common/config"
|
|
"pji_desktop_http/common/config"
|
|
"pji_desktop_http/common/entity"
|
|
"pji_desktop_http/common/entity"
|
|
"pji_desktop_http/common/util"
|
|
"pji_desktop_http/common/util"
|
|
"strings"
|
|
"strings"
|
|
)
|
|
)
|
|
|
|
|
|
-// CheckMapBufConsistency .
|
|
|
|
-// @router /map/checkmapbuf [GET]
|
|
|
|
|
|
+// CheckMapBufConsistency 检查请求id对应的mapBuf文件夹的一致性
|
|
|
|
+// @router /map/checkmapbuf [POST]
|
|
func CheckMapBufConsistency(ctx context.Context, c *app.RequestContext) {
|
|
func CheckMapBufConsistency(ctx context.Context, c *app.RequestContext) {
|
|
var err error
|
|
var err error
|
|
var req []string
|
|
var req []string
|
|
@@ -33,26 +37,20 @@ func CheckMapBufConsistency(ctx context.Context, c *app.RequestContext) {
|
|
c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "mapBuf文件夹数据一致。"})
|
|
c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "mapBuf文件夹数据一致。"})
|
|
} else {
|
|
} else {
|
|
var firstValue int
|
|
var firstValue int
|
|
- for i, v := range req {
|
|
|
|
|
|
+ for i, id := range req {
|
|
// 根据id获取对应的oss文件列表
|
|
// 根据id获取对应的oss文件列表
|
|
- fileList, err := getFileObjectBYId(v)
|
|
|
|
|
|
+ fileList, err := getExactedMapFileById(id)
|
|
|
|
+ // 过滤特定后缀的文件列表
|
|
|
|
+ fileList = filterBySuffixes(fileList, config.Filtersuffixes...)
|
|
|
|
+ //fmt.Println("Filtered Strings:", fileList)
|
|
|
|
+
|
|
if err != nil {
|
|
if err != nil {
|
|
c.String(consts.StatusBadRequest, err.Error())
|
|
c.String(consts.StatusBadRequest, err.Error())
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
- // 过滤特定后缀的文件列表
|
|
|
|
- suffixes := []string{
|
|
|
|
- "map.pgm",
|
|
|
|
- "map.yaml",
|
|
|
|
- "map.json",
|
|
|
|
- "forbid_area.json",
|
|
|
|
- }
|
|
|
|
- filteredFileList := filterBySuffixes(fileList, suffixes...)
|
|
|
|
- fmt.Println("Filtered Strings:", filteredFileList)
|
|
|
|
-
|
|
|
|
// 获取文件列表的总大小
|
|
// 获取文件列表的总大小
|
|
- totalSize := calculateTotalFileSize(filteredFileList)
|
|
|
|
|
|
+ totalSize := calculateTotalFileSize(fileList)
|
|
fmt.Println("Total Size:", totalSize)
|
|
fmt.Println("Total Size:", totalSize)
|
|
|
|
|
|
// 判断不同文件列表(mapBuf)中文件的总大小是否一致
|
|
// 判断不同文件列表(mapBuf)中文件的总大小是否一致
|
|
@@ -70,15 +68,124 @@ func CheckMapBufConsistency(ctx context.Context, c *app.RequestContext) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-// 根据id获取对应的oss文件列表
|
|
|
|
-func getFileObjectBYId(id string) (fileList []string, err error) {
|
|
|
|
|
|
+// DownloadOSSFile 根据objectKey下载指定的oss文件
|
|
|
|
+// @router /map/downloadossfile [GET]
|
|
|
|
+func DownloadOSSFile(ctx context.Context, c *app.RequestContext) {
|
|
|
|
+ objectKey := "pjibot/pjibot-P1YNYD1M229000129/data_merge/2024-07-10-09-08-58_obstacledetection_30.bag"
|
|
|
|
+ // 从OSS下载文件
|
|
|
|
+ reader, err := config.OssBucket.GetObject(objectKey)
|
|
|
|
+
|
|
|
|
+ if err != nil {
|
|
|
|
+ c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ defer reader.Close()
|
|
|
|
+
|
|
|
|
+ // 设置响应头
|
|
|
|
+ c.Response.Header.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filepath.Base(objectKey)))
|
|
|
|
+ c.Response.Header.Set("Content-Type", "binary/octet-stream")
|
|
|
|
+
|
|
|
|
+ // 将文件流式传输回客户端
|
|
|
|
+ data, err := io.ReadAll(reader)
|
|
|
|
+ if err != nil {
|
|
|
|
+ panic(err)
|
|
|
|
+ }
|
|
|
|
+ if _, err := c.Write(data); err != nil {
|
|
|
|
+ c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// DownLoadZipFile 根据请求id从oss拉取并打包下载建图所需要的文件
|
|
|
|
+// @router /map/downloadmapzipfile [GET]
|
|
|
|
+func DownLoadMapZipFile(ctx context.Context, c *app.RequestContext) {
|
|
|
|
+ id := c.Query("id")
|
|
|
|
+ fmt.Println(id)
|
|
|
|
+
|
|
|
|
+ // 根据id生成用于地图更新的压缩包
|
|
|
|
+ filePath, tmpDir, err := generateZipById(id)
|
|
|
|
+ if err != nil {
|
|
|
|
+ c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
|
|
+ }
|
|
|
|
+ fmt.Println("filePath", filePath)
|
|
|
|
+
|
|
|
|
+ // 检查文件是否存在
|
|
|
|
+ if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
|
|
|
+ c.JSON(http.StatusNotFound, map[string]string{"error": "File not found"})
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 打开文件
|
|
|
|
+ f, err := os.Open(filePath)
|
|
|
|
+ if err != nil {
|
|
|
|
+ c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to open file"})
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ defer f.Close()
|
|
|
|
+
|
|
|
|
+ // 设置响应头
|
|
|
|
+ c.Response.Header.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filepath.Base(filePath)))
|
|
|
|
+ c.Response.Header.Set("Content-Type", "binary/octet-stream")
|
|
|
|
+
|
|
|
|
+ // 将文件流式传输回客户端
|
|
|
|
+ data, err := io.ReadAll(f)
|
|
|
|
+ if err != nil {
|
|
|
|
+ panic(err)
|
|
|
|
+ }
|
|
|
|
+ if _, err := c.Write(data); err != nil {
|
|
|
|
+ c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ defer os.RemoveAll(tmpDir)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// DownLoadMapBagFile 根据请求id从oss拉取并下载解析后的map.bag文件
|
|
|
|
+// @router /map/downloadmapbagfile [GET]
|
|
|
|
+func DownLoadMapBagFile(ctx context.Context, c *app.RequestContext) {
|
|
|
|
+ id := c.Query("id")
|
|
|
|
+ fmt.Println("id: ", id)
|
|
|
|
+
|
|
|
|
+ // 根据id获取对应的oss文件列表
|
|
|
|
+ fileList, err := getExactedMapFileById(id)
|
|
|
|
+ // 过滤特定后缀的文件列表
|
|
|
|
+ fileList = filterBySuffixes(fileList, "map.bag")
|
|
|
|
+ //fmt.Println("fileList", fileList)
|
|
|
|
+
|
|
|
|
+ objectKey := fileList[0]
|
|
|
|
+ // 从OSS下载文件
|
|
|
|
+ reader, err := config.OssBucket.GetObject(objectKey)
|
|
|
|
+
|
|
|
|
+ if err != nil {
|
|
|
|
+ c.JSON(consts.StatusInternalServerError, entity.HttpResult{Status: false, Code: "", Message: "解析地图Bag下载失败。"})
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ defer reader.Close()
|
|
|
|
+
|
|
|
|
+ // 设置响应头
|
|
|
|
+ c.Response.Header.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filepath.Base(objectKey)))
|
|
|
|
+ c.Response.Header.Set("Content-Type", "binary/octet-stream")
|
|
|
|
+
|
|
|
|
+ // 将文件流式传输回客户端
|
|
|
|
+ data, err := io.ReadAll(reader)
|
|
|
|
+ if err != nil {
|
|
|
|
+ panic(err)
|
|
|
|
+ }
|
|
|
|
+ if _, err := c.Write(data); err != nil {
|
|
|
|
+ c.JSON(consts.StatusInternalServerError, entity.HttpResult{Status: false, Code: "", Message: "解析地图Bag下载失败。"})
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "解析地图Bag下载成功。"})
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 根据id获取解析后的地图文件列表
|
|
|
|
+func getExactedMapFileById(id string) (fileList []string, err error) {
|
|
url := config.SenceOssDownUrl + id
|
|
url := config.SenceOssDownUrl + id
|
|
|
|
|
|
// 构建请求
|
|
// 构建请求
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
if err != nil {
|
|
if err != nil {
|
|
fmt.Println("Error creating request:", err)
|
|
fmt.Println("Error creating request:", err)
|
|
- return
|
|
|
|
|
|
+ return nil, err
|
|
}
|
|
}
|
|
|
|
|
|
// 添加认证头
|
|
// 添加认证头
|
|
@@ -89,7 +196,7 @@ func getFileObjectBYId(id string) (fileList []string, err error) {
|
|
resp, err := client.Do(req)
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
if err != nil {
|
|
fmt.Println("Error executing request:", err)
|
|
fmt.Println("Error executing request:", err)
|
|
- return
|
|
|
|
|
|
+ return nil, err
|
|
}
|
|
}
|
|
|
|
|
|
defer resp.Body.Close()
|
|
defer resp.Body.Close()
|
|
@@ -103,7 +210,7 @@ func getFileObjectBYId(id string) (fileList []string, err error) {
|
|
dataField, ok := data["data"].([]interface{})
|
|
dataField, ok := data["data"].([]interface{})
|
|
if !ok {
|
|
if !ok {
|
|
fmt.Println("Error extracting data field")
|
|
fmt.Println("Error extracting data field")
|
|
- return
|
|
|
|
|
|
+ return nil, err
|
|
}
|
|
}
|
|
|
|
|
|
// 转换字符串切片
|
|
// 转换字符串切片
|
|
@@ -111,12 +218,134 @@ func getFileObjectBYId(id string) (fileList []string, err error) {
|
|
str, ok := item.(string)
|
|
str, ok := item.(string)
|
|
if !ok {
|
|
if !ok {
|
|
fmt.Println("Error converting item to string")
|
|
fmt.Println("Error converting item to string")
|
|
- return
|
|
|
|
|
|
+ return nil, err
|
|
}
|
|
}
|
|
fileList = append(fileList, str)
|
|
fileList = append(fileList, str)
|
|
}
|
|
}
|
|
|
|
|
|
- return fileList, err
|
|
|
|
|
|
+ return fileList, nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 根据id获取对应的原始bag文件
|
|
|
|
+func getRosFileById(id string) (file string, err error) {
|
|
|
|
+ url := config.SenceInfoUrl + id
|
|
|
|
+
|
|
|
|
+ // 构建请求
|
|
|
|
+ req, err := http.NewRequest("GET", url, nil)
|
|
|
|
+ if err != nil {
|
|
|
|
+ fmt.Println("Error creating request:", err)
|
|
|
|
+ return "", err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 添加认证头
|
|
|
|
+ req.Header.Set("Authorization", config.Token)
|
|
|
|
+
|
|
|
|
+ // 发送请求
|
|
|
|
+ client := &http.Client{}
|
|
|
|
+ resp, err := client.Do(req)
|
|
|
|
+ if err != nil {
|
|
|
|
+ fmt.Println("Error executing request:", err)
|
|
|
|
+ return "", err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ defer resp.Body.Close()
|
|
|
|
+ body, _ := ioutil.ReadAll(resp.Body)
|
|
|
|
+
|
|
|
|
+ // Json转换为map
|
|
|
|
+ var data map[string]interface{}
|
|
|
|
+ err = json.Unmarshal(body, &data)
|
|
|
|
+
|
|
|
|
+ //fmt.Println("data:", data)
|
|
|
|
+ // 提取响应体中的data字段
|
|
|
|
+ dataField, ok := data["data"].(map[string]interface{})
|
|
|
|
+ if !ok {
|
|
|
|
+ fmt.Println("Error extracting data field")
|
|
|
|
+ return "", err
|
|
|
|
+ }
|
|
|
|
+ // 从 data字段中提取 rosField
|
|
|
|
+ rosField, ok := dataField["rosFileId"].(string)
|
|
|
|
+ if !ok {
|
|
|
|
+ fmt.Println("ID not found or not a string")
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ if !ok {
|
|
|
|
+ fmt.Println("Error extracting rosFileId field")
|
|
|
|
+ return "", err
|
|
|
|
+ }
|
|
|
|
+ //println("rosFileId:", rosField)
|
|
|
|
+
|
|
|
|
+ return rosField, nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 根据id生成用于地图更新的压缩包
|
|
|
|
+func generateZipById(id string) (file string, tmpDir string, err error) {
|
|
|
|
+ // 根据id获取对应的oss文件列表
|
|
|
|
+ fileList, err := getExactedMapFileById(id)
|
|
|
|
+ // 过滤特定后缀的文件列表
|
|
|
|
+ fileList = filterBySuffixes(fileList, config.Filtersuffixes...)
|
|
|
|
+ //fmt.Println("Filtered Strings:", fileList)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 创建临时文件夹
|
|
|
|
+ tmpDir, err = os.MkdirTemp("", "temp-download-*")
|
|
|
|
+ fmt.Println("tmpDir:", tmpDir)
|
|
|
|
+ if err != nil {
|
|
|
|
+ fmt.Println("Error creating temporary directory:", err)
|
|
|
|
+ return "", "", err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 创建根文件夹(文件打包的根目录)
|
|
|
|
+ baseDir := filepath.Join(tmpDir, "data")
|
|
|
|
+ if err := os.Mkdir(baseDir, 0755); err != nil {
|
|
|
|
+ fmt.Println("Error creating subdirectory:", err)
|
|
|
|
+ return "", "", err
|
|
|
|
+ }
|
|
|
|
+ // 创建子文件夹 mapBuf
|
|
|
|
+ subDir := filepath.Join(baseDir, "mapBuf")
|
|
|
|
+ if err := os.Mkdir(subDir, 0755); err != nil {
|
|
|
|
+ fmt.Println("Error creating subdirectory:", err)
|
|
|
|
+ return "", "", err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 从oss下载文件到 mapBuf文件夹
|
|
|
|
+ for _, file := range fileList {
|
|
|
|
+ err = config.OssBucket.GetObjectToFile(file, filepath.Join(subDir, filepath.Base(file)))
|
|
|
|
+ if err != nil {
|
|
|
|
+ fmt.Println("Error downloading mapBuf file:", err)
|
|
|
|
+ return "", "", err
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 从oss下载bag文件到 data文件夹
|
|
|
|
+ RosFileId, _ := getRosFileById(id)
|
|
|
|
+ err = config.OssBucket.GetObjectToFile(RosFileId, filepath.Join(baseDir, filepath.Base(RosFileId)))
|
|
|
|
+ if err != nil {
|
|
|
|
+ fmt.Println("Error downloading Bag file:", err)
|
|
|
|
+ return "", "", err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 创建压缩文件
|
|
|
|
+ zipPath := filepath.Join(tmpDir, "mapFile-"+id+".zip")
|
|
|
|
+ zipFile, err := os.Create(zipPath)
|
|
|
|
+ if err != nil {
|
|
|
|
+ fmt.Println("Error creating ZIP file:", err)
|
|
|
|
+ return "", "", err
|
|
|
|
+ }
|
|
|
|
+ defer zipFile.Close()
|
|
|
|
+
|
|
|
|
+ zipWriter := zip.NewWriter(zipFile)
|
|
|
|
+ defer zipWriter.Close()
|
|
|
|
+
|
|
|
|
+ // 压缩文件夹
|
|
|
|
+ if err := addDirToZip(baseDir, zipWriter); err != nil {
|
|
|
|
+ fmt.Println("Error adding directory to ZIP:", err)
|
|
|
|
+ return "", "", err
|
|
|
|
+ }
|
|
|
|
+ fmt.Println("ZIP file created successfully.")
|
|
|
|
+
|
|
|
|
+ return zipPath, tmpDir, nil
|
|
}
|
|
}
|
|
|
|
|
|
// 从字符串切片中筛选出以特定后缀结尾的字符串
|
|
// 从字符串切片中筛选出以特定后缀结尾的字符串
|
|
@@ -124,7 +353,11 @@ func filterBySuffixes(strList []string, suffixes ...string) []string {
|
|
var filtered []string
|
|
var filtered []string
|
|
for _, s := range strList {
|
|
for _, s := range strList {
|
|
for _, suffix := range suffixes {
|
|
for _, suffix := range suffixes {
|
|
- if strings.HasSuffix(s, suffix) {
|
|
|
|
|
|
+ //if strings.HasSuffix(s, suffix) {
|
|
|
|
+ // filtered = append(filtered, s)
|
|
|
|
+ // break
|
|
|
|
+ //}
|
|
|
|
+ if filepath.Base(s) == suffix {
|
|
filtered = append(filtered, s)
|
|
filtered = append(filtered, s)
|
|
break
|
|
break
|
|
}
|
|
}
|
|
@@ -145,3 +378,44 @@ func calculateTotalFileSize(fileList []string) int {
|
|
}
|
|
}
|
|
return totalSize
|
|
return totalSize
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+// 压缩文件夹
|
|
|
|
+func addDirToZip(dirPath string, zipWriter *zip.Writer) error {
|
|
|
|
+ filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if info.IsDir() {
|
|
|
|
+ return nil
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ file, err := os.Open(path)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ defer file.Close()
|
|
|
|
+
|
|
|
|
+ header, err := zip.FileInfoHeader(info)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Adjust the header name to reflect the relative path in the ZIP file
|
|
|
|
+ header.Name = strings.TrimPrefix(path, dirPath)
|
|
|
|
+ header.Name = filepath.ToSlash(header.Name)
|
|
|
|
+
|
|
|
|
+ writer, err := zipWriter.CreateHeader(header)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if _, err := io.Copy(writer, file); err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return nil
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ return nil
|
|
|
|
+}
|