()
| 37 | var progressMutex sync.Mutex |
| 38 | |
| 39 | func (hs *HttpServer) initStorageRouter() { |
| 40 | g := hs.ginEngine.Group("/storage") |
| 41 | |
| 42 | g.POST("/upload", func(c *gin.Context) { |
| 43 | // check file size |
| 44 | c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxUploadSize) |
| 45 | if err := c.Request.ParseMultipartForm(maxMemorySize); err != nil { |
| 46 | c.JSON(http.StatusBadRequest, gin.H{ |
| 47 | "error": "file size exceeds max upload size", |
| 48 | "detail": err.Error(), |
| 49 | "max limit": maxUploadSize, |
| 50 | "file size": c.Request.ContentLength, |
| 51 | }) |
| 52 | return |
| 53 | } |
| 54 | |
| 55 | // get file from form |
| 56 | file, header, err := c.Request.FormFile("file") |
| 57 | if err != nil { |
| 58 | c.JSON(http.StatusBadRequest, gin.H{"error": "file not found"}) |
| 59 | return |
| 60 | } |
| 61 | defer file.Close() |
| 62 | |
| 63 | // generate UUID and file path |
| 64 | fileUUID := uuid.New().String() |
| 65 | fileDir := filepath.Join(ExeDirPath, uploadDir, fileUUID) |
| 66 | if err := os.MkdirAll(fileDir, os.ModePerm); err != nil { |
| 67 | c.JSON(http.StatusInternalServerError, gin.H{"error": "create storage directory failed"}) |
| 68 | return |
| 69 | } |
| 70 | |
| 71 | // create target file |
| 72 | filename := header.Filename |
| 73 | filePath := filepath.Join(fileDir, filename) |
| 74 | out, err := os.Create(filePath) |
| 75 | if err != nil { |
| 76 | c.JSON(http.StatusInternalServerError, gin.H{"error": "create file failed"}) |
| 77 | return |
| 78 | } |
| 79 | defer out.Close() |
| 80 | |
| 81 | // create md5 calculator and progress tracker |
| 82 | md5Hash := md5.New() |
| 83 | progressKey := fileUUID // use UUID as progress key |
| 84 | totalSize := header.Size |
| 85 | |
| 86 | // create multi-writer: write to file, calculate md5, and update progress |
| 87 | multiWriter := io.MultiWriter(out, md5Hash) |
| 88 | progressWriter := &ProgressWriter{ |
| 89 | Writer: multiWriter, |
| 90 | Progress: &progressMap, |
| 91 | Key: progressKey, |
| 92 | Mutex: &progressMutex, |
| 93 | Total: totalSize, |
| 94 | } |
| 95 | |
| 96 | // copy file content |
no test coverage detected