diff --git a/display/web/main.go b/display/web/main.go index badfabc..7bc84ac 100644 --- a/display/web/main.go +++ b/display/web/main.go @@ -222,10 +222,13 @@ func keyboardInputRoute(ctx echo.Context) error { } func uploadFileRoute(ctx echo.Context) error { + var err error + fullPath := ctx.Get("fullPath").(string) // Ensure parent directories exist if err := os.MkdirAll(filepath.Dir(fullPath), os.ModePerm); err != nil { + slog.Error("Failed to create storage path", "error", err, "path", fullPath) return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to prepare storage directory"}) } @@ -233,12 +236,30 @@ func uploadFileRoute(ctx echo.Context) error { return ctx.JSON(http.StatusConflict, shared.ErrorResponse{Description: "File already exists"}) } - data, err := io.ReadAll(ctx.Request().Body) + file, err := os.Create(fullPath) if err != nil { - return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Description: shared.BadRequestDescription}) + slog.Error("Failed to create file", "file", fullPath, "error", err) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to create file"}) + } + defer func() { + fileCloseErr := file.Close() + if fileCloseErr != nil { + slog.Error("Failed to close file", "file", fullPath, "error", fileCloseErr) + } + if err != nil { + os.Remove(fullPath) + } + }() + + _, err = io.Copy(file, ctx.Request().Body) + if err != nil { + slog.Error("Failed to write file", "file", fullPath, "error", err) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to write file"}) } - if err := os.WriteFile(fullPath, data, os.ModePerm); err != nil { + err = file.Sync() // ensure data is flushed to disk + if err != nil { + slog.Error("Failed to sync file to disk", "file", fullPath, "error", err) return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to save file"}) } @@ -253,14 +274,16 @@ func downloadFileRoute(ctx echo.Context) error { return ctx.JSON(http.StatusNotFound, shared.ErrorResponse{Description: "File not found"}) } - err := ctx.File(fullPath) - if err != nil { - slog.Error("Failed to serve file", "file", fullPath, "error", err) - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to serve file"}) - } + slog.Info("Serving file for download", "path", fullPath) - slog.Info("File downloaded successfully", "path", fullPath) - return nil + file, err := os.Open(fullPath) + if err != nil { + slog.Error("Failed to open file", "file", fullPath, "error", err) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to open file"}) + } + defer file.Close() + + return ctx.Stream(http.StatusOK, "application/octet-stream", file) } func openFileRoute(ctx echo.Context) error {