map_service.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. package map_service
  2. import (
  3. "archive/zip"
  4. "context"
  5. "encoding/json"
  6. "fmt"
  7. "github.com/cloudwego/hertz/pkg/app"
  8. "github.com/cloudwego/hertz/pkg/protocol/consts"
  9. uuid "github.com/satori/go.uuid"
  10. "io"
  11. "net/http"
  12. "os"
  13. "path/filepath"
  14. "pji_desktop_http/biz/dal/mysql"
  15. "pji_desktop_http/biz/model"
  16. "pji_desktop_http/common/config"
  17. "pji_desktop_http/common/config/c_log"
  18. "pji_desktop_http/common/entity"
  19. "pji_desktop_http/common/util"
  20. "strconv"
  21. "strings"
  22. )
  23. // CheckMapBufConsistency 检查请求id对应的mapBuf文件夹的一致性
  24. // @router /map/checkmapbuf [POST]
  25. func CheckMapBufConsistency(ctx context.Context, c *app.RequestContext) {
  26. var req []string
  27. err := c.BindAndValidate(&req)
  28. if err != nil {
  29. c.String(consts.StatusBadRequest, err.Error())
  30. return
  31. }
  32. fmt.Println(req)
  33. if len(req) == 0 { // 请求数据为空
  34. c.JSON(consts.StatusBadRequest, entity.HttpResult{Status: false, Code: "", Message: "请求数据为空。"})
  35. } else if len(req) == 1 { // 只有一条数据则直接返回
  36. c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "mapBuf文件夹数据一致。"})
  37. } else {
  38. var firstValue int
  39. for i, id := range req {
  40. // 根据id获取对应的oss文件列表
  41. fileList, err := util.GetExactedMapFileById(id)
  42. // 过滤特定后缀的文件列表
  43. fileList = util.FilterBySuffixes(fileList, config.MapBufFiltersuffixes...)
  44. //fmt.Println("Filtered Strings:", fileList)
  45. if err != nil {
  46. c.String(consts.StatusBadRequest, err.Error())
  47. return
  48. }
  49. // 获取文件列表的总大小
  50. totalSize := calculateTotalFileSize(fileList)
  51. fmt.Println("Total Size:", totalSize)
  52. // 判断不同文件列表(mapBuf)中文件的总大小是否一致
  53. if i == 0 {
  54. firstValue = totalSize
  55. } else {
  56. if totalSize != firstValue {
  57. c.JSON(consts.StatusOK, entity.HttpResult{Status: false, Code: "", Message: "mapBuf文件夹数据不一致。"})
  58. return
  59. }
  60. }
  61. }
  62. c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "mapBuf文件夹数据一致。"})
  63. }
  64. }
  65. // DownloadOSSFile 根据objectKey下载指定的oss文件
  66. // @router /map/downloadossfile [GET]
  67. func DownloadOSSFile(ctx context.Context, c *app.RequestContext) {
  68. objectKey := c.Query("objectKey")
  69. // 从OSS下载文件
  70. reader, err := config.OssBucket.GetObject(objectKey)
  71. if err != nil {
  72. c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
  73. return
  74. }
  75. defer reader.Close()
  76. // 设置响应头
  77. c.Response.Header.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filepath.Base(objectKey)))
  78. c.Response.Header.Set("Content-Type", "binary/octet-stream")
  79. // 将文件流式传输回客户端
  80. data, err := io.ReadAll(reader)
  81. if err != nil {
  82. panic(err)
  83. }
  84. if _, err := c.Write(data); err != nil {
  85. c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
  86. return
  87. }
  88. }
  89. // DownloadMapZipFile 根据请求id从oss拉取并打包下载建图所需要的文件
  90. // @router /map/download/map/zip [GET]
  91. func DownloadMapZipFile(ctx context.Context, c *app.RequestContext) {
  92. id := c.Query("id")
  93. fmt.Println("id", id)
  94. ids := strings.Split(id, ",")
  95. fmt.Println("ids", ids)
  96. // 根据id生成用于地图更新的压缩包
  97. filePath, tmpDir, err := generateMapZipById(ids)
  98. if err != nil {
  99. c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
  100. }
  101. fmt.Println("filePath", filePath)
  102. // 检查文件是否存在
  103. if _, err := os.Stat(filePath); os.IsNotExist(err) {
  104. c.JSON(http.StatusNotFound, map[string]string{"error": "File not found"})
  105. return
  106. }
  107. // 打开文件
  108. f, err := os.Open(filePath)
  109. if err != nil {
  110. c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to open file"})
  111. return
  112. }
  113. defer f.Close()
  114. // 设置响应头
  115. c.Response.Header.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filepath.Base(filePath)))
  116. c.Response.Header.Set("Content-Type", "binary/octet-stream")
  117. // 将文件流式传输回客户端
  118. data, err := io.ReadAll(f)
  119. if err != nil {
  120. panic(err)
  121. }
  122. if _, err := c.Write(data); err != nil {
  123. c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
  124. return
  125. }
  126. defer os.RemoveAll(tmpDir)
  127. }
  128. // DownloadMapBagFile 根据请求id从oss拉取并下载解析后的map.bag文件
  129. // @router /map/downloadmapbagfile [GET]
  130. func DownloadMapBagFile(ctx context.Context, c *app.RequestContext) {
  131. id := c.Query("id")
  132. fmt.Println("id: ", id)
  133. // 根据id获取对应的oss文件列表
  134. fileList, err := util.GetExactedMapFileById(id)
  135. // 过滤特定后缀的文件列表
  136. fileList = util.FilterBySuffixes(fileList, config.MapBagFiltersuffixes...)
  137. //fmt.Println("fileList", fileList)
  138. objectKey := fileList[0]
  139. // 从OSS下载文件
  140. reader, err := config.OssBucket.GetObject(objectKey)
  141. if err != nil {
  142. c.JSON(consts.StatusInternalServerError, entity.HttpResult{Status: false, Code: "", Message: "解析地图Bag下载失败。"})
  143. return
  144. }
  145. defer reader.Close()
  146. // 设置响应头
  147. c.Response.Header.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filepath.Base(objectKey)))
  148. c.Response.Header.Set("Content-Type", "binary/octet-stream")
  149. // 将文件流式传输回客户端
  150. data, err := io.ReadAll(reader)
  151. if err != nil {
  152. panic(err)
  153. }
  154. if _, err := c.Write(data); err != nil {
  155. c.JSON(consts.StatusInternalServerError, entity.HttpResult{Status: false, Code: "", Message: "解析地图Bag下载失败。"})
  156. return
  157. }
  158. c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "解析地图Bag下载成功。"})
  159. }
  160. // 根据id生成用于地图更新的压缩包
  161. func generateMapZipById(ids []string) (file string, tmpDir string, err error) {
  162. // 根据id获取对应的oss文件列表
  163. allFileList, err := util.GetExactedMapFileByIds(ids)
  164. fmt.Println("allFileList", allFileList)
  165. // 过滤特定后缀的文件列表
  166. mapBufFileList := util.FilterBySuffixes(allFileList, config.MapBufFiltersuffixes...)
  167. //fmt.Println("Filtered Strings:", fileList)
  168. if err != nil {
  169. return
  170. }
  171. // 创建临时文件夹
  172. tmpDir, err = os.MkdirTemp("", "temp-download-*")
  173. fmt.Println("tmpDir:", tmpDir)
  174. if err != nil {
  175. fmt.Println("Error creating temporary directory:", err)
  176. return "", "", err
  177. }
  178. c_log.GlobalLogger.Info("创建下载-临时文件夹:", tmpDir)
  179. // 创建根文件夹(文件打包的根目录)
  180. baseDir := filepath.Join(tmpDir, "data")
  181. if err := os.Mkdir(baseDir, 0755); err != nil {
  182. fmt.Println("Error creating subdirectory:", err)
  183. return "", "", err
  184. }
  185. c_log.GlobalLogger.Info("创建文件打包根目录:", baseDir)
  186. // 根目录创建子文件夹 bag_folder
  187. bagFolderDir := filepath.Join(baseDir, "bag_folder")
  188. if err := os.Mkdir(bagFolderDir, 0755); err != nil {
  189. fmt.Println("Error creating subdirectory:", err)
  190. return "", "", err
  191. }
  192. c_log.GlobalLogger.Info("根目录下创建bag_folder子文件夹:", bagFolderDir)
  193. // 根目录创建子文件夹 origin_map_folder
  194. originMapFolderDir := filepath.Join(baseDir, "origin_map_folder")
  195. if err := os.Mkdir(originMapFolderDir, 0755); err != nil {
  196. fmt.Println("Error creating subdirectory:", err)
  197. return "", "", err
  198. }
  199. c_log.GlobalLogger.Info("根目录下创建origin_map_folder子文件夹:", originMapFolderDir)
  200. // 子文件夹 bag_folder 创建子文件夹 mapBuf
  201. mapBufDir := filepath.Join(bagFolderDir, "mapBuf")
  202. if err := os.Mkdir(mapBufDir, 0755); err != nil {
  203. fmt.Println("Error creating subdirectory:", err)
  204. return "", "", err
  205. }
  206. c_log.GlobalLogger.Info("bag_folder创建mapBuf子文件夹 :", mapBufDir)
  207. // 从oss下载build_map.bag文件到 bag_folder 文件夹
  208. // 过滤特定后缀的文件列表
  209. buildMapBagFileList := util.FilterBySuffixes(allFileList, config.BuildMapBagFiltersuffixes...)
  210. fmt.Println("buildMapBagFileList", buildMapBagFileList)
  211. //buildMapBagFile := buildMapBagFileList[0]
  212. //err = config.OssBucket.GetObjectToFile(buildMapBagFile, filepath.Join(bagFolderDir, filepath.Base(buildMapBagFile)))
  213. for i, file := range buildMapBagFileList {
  214. fileName := "build_map" + "-" + strconv.Itoa(i) + ".bag"
  215. err = config.OssBucket.GetObjectToFile(file, filepath.Join(bagFolderDir, fileName))
  216. if err != nil {
  217. fmt.Println("Error downloading build map file:", err)
  218. return "", "", err
  219. }
  220. }
  221. if err != nil {
  222. fmt.Println("Error downloading Bag file:", err)
  223. return "", "", err
  224. }
  225. c_log.GlobalLogger.Info("下载文件到bag_folder文件夹 - 成功")
  226. // 从oss下载文件到 mapBuf 文件夹
  227. for _, file := range mapBufFileList {
  228. err = config.OssBucket.GetObjectToFile(file, filepath.Join(mapBufDir, filepath.Base(file)))
  229. if err != nil {
  230. fmt.Println("Error downloading mapBuf file:", err)
  231. return "", "", err
  232. }
  233. }
  234. c_log.GlobalLogger.Info("下载文件到mapBuf子文件夹 - 成功")
  235. // 从oss下载bag文件到 origin_map_folder 文件夹
  236. // 过滤特定后缀的文件列表
  237. originMapFileList := util.FilterBySuffixes(allFileList, config.OriginMapFiltersuffixes...)
  238. for _, file := range originMapFileList {
  239. err = config.OssBucket.GetObjectToFile(file, filepath.Join(originMapFolderDir, filepath.Base(file)))
  240. if err != nil {
  241. fmt.Println("Error downloading origin_map file:", err)
  242. return "", "", err
  243. }
  244. }
  245. c_log.GlobalLogger.Info("下载文件到origin_map_folder文件夹 - 成功")
  246. // 创建压缩文件
  247. zipPath := filepath.Join(tmpDir, "mapFile-"+ids[0]+".zip")
  248. zipFile, err := os.Create(zipPath)
  249. if err != nil {
  250. fmt.Println("Error creating ZIP file:", err)
  251. return "", "", err
  252. }
  253. defer zipFile.Close()
  254. zipWriter := zip.NewWriter(zipFile)
  255. defer zipWriter.Close()
  256. // 压缩文件夹
  257. if err := util.AddDirToZip(baseDir, zipWriter); err != nil {
  258. fmt.Println("Error adding directory to ZIP:", err)
  259. return "", "", err
  260. }
  261. fmt.Println("ZIP file created successfully.")
  262. c_log.GlobalLogger.Info("创建压缩文件 - 成功")
  263. return zipPath, tmpDir, nil
  264. }
  265. // UploadMapFile 将地图更新相关文件上传到oss
  266. // @router /map/upload/map [GET]
  267. func UploadMapFile(ctx context.Context, c *app.RequestContext) {
  268. equipmentNo := c.Query("equipmentNo")
  269. fmt.Println("equipmentNo", equipmentNo)
  270. mapId := c.Query("mapId")
  271. fmt.Println("mapId", mapId)
  272. timeStamp := c.Query("timeStamp")
  273. fmt.Println("timeStamp", timeStamp)
  274. header, err := c.FormFile("file")
  275. if err != nil {
  276. c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))
  277. return
  278. }
  279. fileName := header.Filename
  280. fmt.Println("filename", fileName)
  281. ossObjectKey := config.UpdateMapOssBasePrefix + "/" + equipmentNo + "/" + mapId + "/" + timeStamp + "/" + fileName
  282. fmt.Println("ossObjectKey", ossObjectKey)
  283. f, _ := header.Open()
  284. defer f.Close()
  285. config.OssMutex.Lock()
  286. err = config.OssBucket.PutObject(ossObjectKey, f)
  287. config.OssMutex.Unlock()
  288. if err != nil {
  289. c_log.GlobalLogger.Error("程序异常退出。上传文件", fileName, "->", ossObjectKey, "出错:", err)
  290. c.JSON(consts.StatusOK, entity.HttpResult{Status: false, Code: "", Message: "上传文件失败", Details: ""})
  291. return
  292. }
  293. c_log.GlobalLogger.Info("上传文件", fileName, "->", ossObjectKey, "成功。")
  294. c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "上传文件成功", Details: ossObjectKey})
  295. }
  296. // AddMapUpdateRecord 添加仿真测试记录
  297. // @router /map/add/record [GET]
  298. func AddMapUpdateRecord(ctx context.Context, c *app.RequestContext) {
  299. var record model.MapUpdate
  300. err := c.BindAndValidate(&record)
  301. record.ID = uuid.NewV1().String()
  302. fmt.Println("record", record)
  303. if err != nil {
  304. c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))
  305. return
  306. }
  307. err = mysql.AddMapUpdateOneRecord(ctx, record)
  308. if err != nil {
  309. c.JSON(consts.StatusOK, entity.HttpResult{Status: false, Code: "", Message: "地图更新记录添加失败"})
  310. return
  311. }
  312. c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "地图更新记录添加成功"})
  313. }
  314. // QueryMapUpdateRecord 根据条件查询地图更新记录
  315. // @router /map/query/update/record [GET]
  316. func QueryMapUpdateRecord(ctx context.Context, c *app.RequestContext) {
  317. var record model.MapUpdate
  318. err := c.BindAndValidate(&record)
  319. fmt.Println("record", record)
  320. var pageFlag bool
  321. if c.Query("page") != "" && c.Query("pageSize") != "" {
  322. pageFlag = true
  323. } else {
  324. pageFlag = false
  325. }
  326. page, _ := strconv.Atoi(c.Query("page"))
  327. pageSize, _ := strconv.Atoi(c.Query("pageSize"))
  328. records, count, err := mysql.QueryMapUpdateRecords(ctx, &record, pageFlag, page, pageSize)
  329. if err != nil {
  330. c.JSON(consts.StatusOK, entity.Response{Status: false, Code: "", Message: "地图更新记录查询失败", Total: 0})
  331. return
  332. }
  333. output, err := json.Marshal(records)
  334. if err != nil {
  335. c.JSON(consts.StatusOK, entity.Response{Status: false, Code: "", Message: "地图更新记录查询失败", Total: 0})
  336. return
  337. }
  338. c.JSON(consts.StatusOK, entity.Response{Status: true, Code: "", Message: "地图更新查询成功", Data: string(output), Total: int(count)})
  339. }
  340. // 计算oss中文件列表的总大小
  341. func calculateTotalFileSize(fileList []string) int {
  342. var totalSize int
  343. for _, file := range fileList {
  344. size, err := util.GetOSSFileSize(config.OssBucket, file) // 获取oss中单个文件的大小
  345. if err != nil {
  346. return 0
  347. }
  348. totalSize += size
  349. }
  350. return totalSize
  351. }