Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic Multipart reader/writer implementaion #53

Merged
merged 19 commits into from
Mar 11, 2024
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/jfrog/gofrog
go 1.20

require (
github.com/cespare/xxhash v1.1.0
github.com/jfrog/archiver/v3 v3.6.0
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.8.4
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
Expand All @@ -23,6 +27,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
Expand Down
93 changes: 93 additions & 0 deletions http/multipart/multipart.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package multipart
sverdlov93 marked this conversation as resolved.
Show resolved Hide resolved

import (
"errors"
"fmt"
"github.com/cespare/xxhash"
ioutils "github.com/jfrog/gofrog/io"
"hash"
"io"
"mime/multipart"
"os"
)

type FileWriterFunc func(fileName string) (io.Writer, error)

func ReadFilesFromStream(multipartReader *multipart.Reader, fileWriterFunc FileWriterFunc) error {
for {
// Read the next file streamed from client
fileReader, err := multipartReader.NextPart()
omerzi marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
if err == io.EOF {
break
}
return fmt.Errorf("failed to read file: %w", err)
}
fileName := fileReader.FileName()
fileWriter, err := fileWriterFunc(fileName)
if err != nil {
return err
}

if _, err = io.Copy(fileWriter, fileReader); err != nil {
return fmt.Errorf("failed writing '%s' file: %w", fileName, err)
}
}
return nil
}

func WriteFilesToStream(writer io.Writer, filesList []string) error {
sverdlov93 marked this conversation as resolved.
Show resolved Hide resolved
multipartWriter := multipart.NewWriter(writer)
for _, filePath := range filesList {
fileReader, err := os.Open(filePath)
if err != nil {
return fmt.Errorf("failed to open file: %w", err)
}
defer ioutils.Close(fileReader, &err)
sverdlov93 marked this conversation as resolved.
Show resolved Hide resolved
fileWriter, err := multipartWriter.CreateFormFile("fieldname", filePath)
sverdlov93 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return fmt.Errorf("failed to CreateFormFile: %w", err)
}
_, err = io.Copy(fileWriter, fileReader)
if err != nil {
return err
}
}
return nil
}

func getFileWriter(fileName string) (fileWriter io.Writer, err error) {

Check failure on line 59 in http/multipart/multipart.go

View workflow job for this annotation

GitHub Actions / Static-Check

func `getFileWriter` is unused (unused)

Check failure on line 59 in http/multipart/multipart.go

View workflow job for this annotation

GitHub Actions / Static-Check

func `getFileWriter` is unused (unused)
lockfileMock := map[string]string{
"SDFDSFSDFSDFDSF": "file1",
"XXSDFDSFSDFSDFDSF": "file2",
}
realFileName := lockfileMock[fileName]
fileWriter, err = os.Create(realFileName)
if err != nil {
return nil, fmt.Errorf("create file: %w", err)
}
// Currently we are using the file name as the hash
fileHash := fileName
return io.MultiWriter(fileWriter, NewHashWrapper(fileHash)), nil
}

type HashWrapper struct {
hash hash.Hash64
actualChecksum string
}

func NewHashWrapper(actualChecksum string) *HashWrapper {
return &HashWrapper{hash: xxhash.New(), actualChecksum: actualChecksum}
}

func (hw *HashWrapper) Write(p []byte) (n int, err error) {
n, err = hw.hash.Write(p)
if fmt.Sprintf("%x", hw.hash.Sum(nil)) != hw.actualChecksum {
err = errors.New("checksum mismatch")
}
return
}

func myMain(filepath string) {

Check failure on line 91 in http/multipart/multipart.go

View workflow job for this annotation

GitHub Actions / Static-Check

`myMain` - `filepath` is unused (unparam)

Check failure on line 91 in http/multipart/multipart.go

View workflow job for this annotation

GitHub Actions / Static-Check

`myMain` - `filepath` is unused (unparam)
ReadFilesFromStream(nil, getFileWriter)

Check failure on line 92 in http/multipart/multipart.go

View workflow job for this annotation

GitHub Actions / Static-Check

Error return value is not checked (errcheck)

Check failure on line 92 in http/multipart/multipart.go

View workflow job for this annotation

GitHub Actions / Static-Check

Error return value is not checked (errcheck)
}
Loading