simulation_service.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. package simulation_service
  2. import (
  3. "archive/zip"
  4. "context"
  5. "fmt"
  6. "github.com/cloudwego/hertz/pkg/app"
  7. "github.com/cloudwego/hertz/pkg/protocol/consts"
  8. uuid "github.com/satori/go.uuid"
  9. "io"
  10. "net/http"
  11. "os"
  12. "path/filepath"
  13. "pji_desktop_http/biz/dal/mysql"
  14. "pji_desktop_http/biz/model"
  15. "pji_desktop_http/common/config"
  16. "pji_desktop_http/common/config/c_log"
  17. "pji_desktop_http/common/entity"
  18. "pji_desktop_http/common/util"
  19. )
  20. // DownloadSimulationZipFile 根据请求id从oss拉取并打包仿真测试所需要的文件
  21. // @router /simulation/download/zipfile [GET]
  22. func DownloadSimulationZipFile(ctx context.Context, c *app.RequestContext) {
  23. id := c.Query("id")
  24. fmt.Println(id)
  25. // 根据id生成用于地图更新的压缩包
  26. filePath, tmpDir, err := generateSimulationZipById(ctx, id)
  27. if err != nil {
  28. c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
  29. }
  30. fmt.Println("filePath", filePath)
  31. // 检查文件是否存在
  32. if _, err := os.Stat(filePath); os.IsNotExist(err) {
  33. c.JSON(http.StatusNotFound, map[string]string{"error": "File not found"})
  34. return
  35. }
  36. // 打开文件
  37. f, err := os.Open(filePath)
  38. if err != nil {
  39. c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to open file"})
  40. return
  41. }
  42. defer f.Close()
  43. // 设置响应头
  44. c.Response.Header.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filepath.Base(filePath)))
  45. c.Response.Header.Set("Content-Type", "binary/octet-stream")
  46. // 将文件流式传输回客户端
  47. data, err := io.ReadAll(f)
  48. if err != nil {
  49. panic(err)
  50. }
  51. if _, err := c.Write(data); err != nil {
  52. c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
  53. return
  54. }
  55. defer os.RemoveAll(tmpDir)
  56. }
  57. // 根据id生成用于仿真测试的压缩包
  58. func generateSimulationZipById(ctx context.Context, id string) (file string, tmpDir string, err error) {
  59. // 根据id获取对应的oss文件列表
  60. allFileList, err := util.GetExactedMapFileById(id)
  61. //fmt.Println("Filtered Strings:", fileList)
  62. if err != nil {
  63. return
  64. }
  65. // 创建临时文件夹
  66. tmpDir, err = os.MkdirTemp("", "temp-download-*")
  67. fmt.Println("tmpDir:", tmpDir)
  68. if err != nil {
  69. fmt.Println("Error creating temporary directory:", err)
  70. return "", "", err
  71. }
  72. c_log.GlobalLogger.Info("创建下载-临时文件夹:", tmpDir)
  73. // 创建根文件夹(文件打包的根目录)
  74. baseDir := filepath.Join(tmpDir, "data")
  75. if err := os.Mkdir(baseDir, 0755); err != nil {
  76. fmt.Println("Error creating subdirectory:", err)
  77. return "", "", err
  78. }
  79. c_log.GlobalLogger.Info("创建文件打包根目录:", baseDir)
  80. // 从oss下载data.zip, map.pgm, map.yaml文件到根目录
  81. // 过滤特定后缀的文件列表
  82. simulationFileList := util.FilterBySuffixes(allFileList, config.SimulationFiltersuffixes...)
  83. fmt.Println("simulationFileList", simulationFileList)
  84. // 从oss下载文件到 根目录
  85. for _, file := range simulationFileList {
  86. err = config.OssBucket.GetObjectToFile(file, filepath.Join(baseDir, filepath.Base(file)))
  87. if err != nil {
  88. fmt.Println("Error downloading file - data.zip, map.pgm, map.yaml, map.bag:", err)
  89. return "", "", err
  90. }
  91. }
  92. c_log.GlobalLogger.Info("下载data.zip, map.pgm, map.yaml, map.bag文件到根目录 - 成功")
  93. // 下载world文件&map.stl文件
  94. // 查询状态
  95. world, err := mysql.QueryWorld(ctx, id)
  96. if err != nil || world == nil { // 记录不存在
  97. c_log.GlobalLogger.Info("world记录不存在 - 跳过")
  98. } else { // 记录存在
  99. // 下载world文件
  100. worldURL := world.WorldURL
  101. err = config.OssBucket.GetObjectToFile(worldURL, filepath.Join(baseDir, filepath.Base(worldURL)))
  102. if err != nil {
  103. fmt.Println("Error downloading world file:", err)
  104. return "", "", err
  105. }
  106. c_log.GlobalLogger.Info("下载world文件到根目录 - 成功")
  107. // 下载map.stl文件
  108. stlURL := world.StlURL
  109. if stlURL != nil && *stlURL != "" {
  110. err = config.OssBucket.GetObjectToFile(*stlURL, filepath.Join(baseDir, filepath.Base(*stlURL)))
  111. if err != nil {
  112. fmt.Println("Error downloading stl file:", err)
  113. return "", "", err
  114. }
  115. c_log.GlobalLogger.Info("下载map.stl文件到根目录 - 成功")
  116. } else {
  117. c_log.GlobalLogger.Info("map.stl文件不存在 - 跳过")
  118. }
  119. }
  120. // 下载原始bag
  121. rosField, err := util.GetRosFileById(id)
  122. if err != nil {
  123. fmt.Println("Error querying origin map's bag file:", err)
  124. return "", "", err
  125. }
  126. err = config.OssBucket.GetObjectToFile(rosField, filepath.Join(baseDir, "origin_map.bag"))
  127. if err != nil {
  128. fmt.Println("Error downloading origin map's bag file:", err)
  129. return "", "", err
  130. }
  131. c_log.GlobalLogger.Info("下载origin_map.bag文件到根目录 - 成功")
  132. // 创建压缩文件
  133. zipPath := filepath.Join(tmpDir, "simulationFile-"+id+".zip")
  134. zipFile, err := os.Create(zipPath)
  135. if err != nil {
  136. fmt.Println("Error creating ZIP file:", err)
  137. return "", "", err
  138. }
  139. defer zipFile.Close()
  140. zipWriter := zip.NewWriter(zipFile)
  141. defer zipWriter.Close()
  142. // 压缩文件夹
  143. if err := util.AddDirToZip(baseDir, zipWriter); err != nil {
  144. fmt.Println("Error adding directory to ZIP:", err)
  145. return "", "", err
  146. }
  147. fmt.Println("ZIP file created successfully.")
  148. c_log.GlobalLogger.Info("创建压缩文件 - 成功")
  149. return zipPath, tmpDir, nil
  150. }
  151. // CheckDataFileStatus 检查data目录是否存在
  152. // @router /simulation/check/file/data/status [GET]
  153. func CheckDataFileStatus(ctx context.Context, c *app.RequestContext) {
  154. sceneID := c.Query("id")
  155. fmt.Println("id", sceneID)
  156. // 根据id获取对应的oss文件列表
  157. allFileList, err := util.GetExactedMapFileById(sceneID)
  158. if err != nil {
  159. return
  160. }
  161. // 过滤特定后缀的文件列表(data.zip)
  162. simulationFileList := util.FilterBySuffixes(allFileList, config.DataFiltersuffixes...)
  163. if len(simulationFileList) == 0 {
  164. c.JSON(consts.StatusOK, entity.HttpResult{Status: false, Code: "", Message: "data目录不存在"})
  165. return
  166. }
  167. c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "data目录存在"})
  168. }
  169. // UploadPdfFile 将result.pdf文件上传到oss
  170. // @router /simulation/upload/pdf [GET]
  171. func UploadPdfFile(ctx context.Context, c *app.RequestContext) {
  172. equipmentNo := c.Query("equipmentNo")
  173. fmt.Println("equipmentNo", equipmentNo)
  174. sceneNo := c.Query("sceneNo")
  175. fmt.Println("sceneNo", sceneNo)
  176. timeStamp := c.Query("timeStamp")
  177. fmt.Println("timeStamp", timeStamp)
  178. round := c.Query("round")
  179. fmt.Println("round", round)
  180. header, err := c.FormFile("file")
  181. if err != nil {
  182. c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))
  183. return
  184. }
  185. fileName := header.Filename
  186. fmt.Println("filename", fileName)
  187. ossObjectKey := config.SimulationOssBasePrefix + "/" + equipmentNo + "/" + sceneNo + "/" + timeStamp + "/" + round + "/" + fileName
  188. fmt.Println("ossObjectKey", ossObjectKey)
  189. f, _ := header.Open()
  190. defer f.Close()
  191. config.OssMutex.Lock()
  192. err = config.OssBucket.PutObject(ossObjectKey, f)
  193. config.OssMutex.Unlock()
  194. if err != nil {
  195. c_log.GlobalLogger.Error("程序异常退出。上传文件", fileName, "->", ossObjectKey, "出错:", err)
  196. c.JSON(consts.StatusOK, entity.HttpResult{Status: false, Code: "", Message: "上传文件失败", Details: ""})
  197. return
  198. }
  199. c_log.GlobalLogger.Info("上传文件", fileName, "->", ossObjectKey, "成功。")
  200. c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "上传文件成功", Details: ossObjectKey})
  201. }
  202. // UploadBagFile 将test-${i}.bag文件上传到oss
  203. // @router /simulation/upload/bag [GET]
  204. func UploadBagFile(ctx context.Context, c *app.RequestContext) {
  205. equipmentNo := c.Query("equipmentNo")
  206. fmt.Println("equipmentNo", equipmentNo)
  207. sceneNo := c.Query("sceneNo")
  208. fmt.Println("sceneNo", sceneNo)
  209. timeStamp := c.Query("timeStamp")
  210. fmt.Println("timeStamp", timeStamp)
  211. round := c.Query("round")
  212. fmt.Println("round", round)
  213. header, err := c.FormFile("file")
  214. if err != nil {
  215. c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))
  216. return
  217. }
  218. fileName := header.Filename
  219. fmt.Println("filename", fileName)
  220. ossObjectKey := config.SimulationOssBasePrefix + "/" + equipmentNo + "/" + sceneNo + "/" + timeStamp + "/" + round + "/" + fileName
  221. fmt.Println("ossObjectKey", ossObjectKey)
  222. f, _ := header.Open()
  223. defer f.Close()
  224. config.OssMutex.Lock()
  225. err = config.OssBucket.PutObject(ossObjectKey, f)
  226. config.OssMutex.Unlock()
  227. if err != nil {
  228. c_log.GlobalLogger.Error("程序异常退出。上传文件", fileName, "->", ossObjectKey, "出错:", err)
  229. c.JSON(consts.StatusOK, entity.HttpResult{Status: false, Code: "", Message: "上传文件失败", Details: ""})
  230. return
  231. }
  232. c_log.GlobalLogger.Info("上传文件", fileName, "->", ossObjectKey, "成功。")
  233. c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "上传文件成功", Details: ossObjectKey})
  234. }
  235. // UploadPgmFile 将map.pgm文件上传到oss
  236. // @router /simulation/upload/pgm [GET]
  237. func UploadPgmFile(ctx context.Context, c *app.RequestContext) {
  238. equipmentNo := c.Query("equipmentNo")
  239. fmt.Println("equipmentNo", equipmentNo)
  240. sceneNo := c.Query("sceneNo")
  241. fmt.Println("sceneNo", sceneNo)
  242. header, err := c.FormFile("file")
  243. if err != nil {
  244. c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))
  245. return
  246. }
  247. fileName := header.Filename
  248. fmt.Println("filename", fileName)
  249. ossObjectKey := config.SimulationOssBasePrefix + "/" + equipmentNo + "/" + sceneNo + "/" + fileName
  250. fmt.Println("ossObjectKey", ossObjectKey)
  251. f, _ := header.Open()
  252. defer f.Close()
  253. config.OssMutex.Lock()
  254. err = config.OssBucket.PutObject(ossObjectKey, f)
  255. config.OssMutex.Unlock()
  256. if err != nil {
  257. c_log.GlobalLogger.Error("程序异常退出。上传文件", fileName, "->", ossObjectKey, "出错:", err)
  258. c.JSON(consts.StatusOK, entity.HttpResult{Status: false, Code: "", Message: "上传文件失败", Details: ""})
  259. return
  260. }
  261. c_log.GlobalLogger.Info("上传文件", fileName, "->", ossObjectKey, "成功。")
  262. c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "上传文件成功", Details: ossObjectKey})
  263. }
  264. // AddSimulationRecord 添加仿真测试记录
  265. // @router /simulation/add/record [GET]
  266. func AddSimulationRecord(ctx context.Context, c *app.RequestContext) {
  267. var records []*model.SimulationTestRecord
  268. err := c.BindAndValidate(&records)
  269. for _, record := range records {
  270. record.ID = uuid.NewV1().String()
  271. }
  272. fmt.Println("records", records)
  273. if err != nil {
  274. c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))
  275. return
  276. }
  277. err = mysql.AddSimulationTestRecords(ctx, records)
  278. if err != nil {
  279. c.JSON(consts.StatusOK, entity.HttpResult{Status: false, Code: "", Message: "仿真测试记录添加失败"})
  280. return
  281. }
  282. c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "仿真测试记录添加成功"})
  283. }