## Description Pulls in fix for a panic caused by concurrent map updates in the clues pkg ## Does this PR need a docs update or release note? - [ ] ✅ Yes, it's included - [ ] 🕐 Yes, but in a later PR - [x] ⛔ No ## Type of change <!--- Please check the type of change your PR introduces: ---> - [ ] 🌻 Feature - [x] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Test - [ ] 💻 CI/Deployment - [ ] 🧹 Tech Debt/Cleanup ## Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [x] ⚡ Unit test - [x] 💚 E2E
72 lines
2.0 KiB
Go
72 lines
2.0 KiB
Go
package uploadsession
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/alcionai/clues"
|
|
"gopkg.in/resty.v1"
|
|
|
|
"github.com/alcionai/corso/src/pkg/logger"
|
|
)
|
|
|
|
const (
|
|
contentRangeHeaderKey = "Content-Range"
|
|
// Format for Content-Range is "bytes <start>-<end>/<total>"
|
|
contentRangeHeaderValueFmt = "bytes %d-%d/%d"
|
|
contentLengthHeaderKey = "Content-Length"
|
|
)
|
|
|
|
// Writer implements an io.Writer for a M365
|
|
// UploadSession URL
|
|
type writer struct {
|
|
// Identifier
|
|
id string
|
|
// Upload URL for this item
|
|
url string
|
|
// Tracks how much data will be written
|
|
contentLength int64
|
|
// Last item offset that was written to
|
|
lastWrittenOffset int64
|
|
client *resty.Client
|
|
}
|
|
|
|
func NewWriter(id, url string, size int64) *writer {
|
|
return &writer{id: id, url: url, contentLength: size, client: resty.New()}
|
|
}
|
|
|
|
// Write will upload the provided data to M365. It sets the `Content-Length` and `Content-Range` headers based on
|
|
// https://docs.microsoft.com/en-us/graph/api/driveitem-createuploadsession
|
|
func (iw *writer) Write(p []byte) (int, error) {
|
|
rangeLength := len(p)
|
|
logger.Ctx(context.Background()).Debugf("WRITE for %s. Size:%d, Offset: %d, TotalSize: %d",
|
|
iw.id, rangeLength, iw.lastWrittenOffset, iw.contentLength)
|
|
|
|
endOffset := iw.lastWrittenOffset + int64(rangeLength)
|
|
|
|
// PUT the request - set headers `Content-Range`to describe total size and `Content-Length` to describe size of
|
|
// data in the current request
|
|
_, err := iw.client.R().
|
|
SetHeaders(map[string]string{
|
|
contentRangeHeaderKey: fmt.Sprintf(contentRangeHeaderValueFmt,
|
|
iw.lastWrittenOffset,
|
|
endOffset-1,
|
|
iw.contentLength),
|
|
contentLengthHeaderKey: fmt.Sprintf("%d", rangeLength),
|
|
}).
|
|
SetBody(bytes.NewReader(p)).Put(iw.url)
|
|
if err != nil {
|
|
return 0, clues.Wrap(err, "uploading item").With(
|
|
"upload_id", iw.id,
|
|
"upload_chunk_size", rangeLength,
|
|
"upload_offset", iw.lastWrittenOffset,
|
|
"upload_size", iw.contentLength)
|
|
}
|
|
|
|
// Update last offset
|
|
iw.lastWrittenOffset = endOffset
|
|
|
|
return rangeLength, nil
|
|
}
|