package nextcloud import ( "bytes" "context" "crypto/rand" "encoding/hex" "fmt" "io" ) const defaultUploadChunkSize = 10 * 1024 * 1024 // UploadStreaming uploads large files via Nextcloud chunked DAV assembly. func (c *Client) UploadStreaming(ctx context.Context, userID, targetPath string, content io.Reader, contentType string, totalSize int64) error { uploadID, err := newChunkUploadID() if err != nil { return err } buf := make([]byte, defaultUploadChunkSize) var uploaded int64 chunkIndex := 0 for { n, readErr := io.ReadFull(content, buf) if n == 0 && readErr == io.EOF { break } if n > 0 { chunkIndex++ if err := c.UploadChunk(ctx, userID, uploadID, chunkIndexName(chunkIndex), bytes.NewReader(buf[:n]), contentType); err != nil { _ = c.AbortChunkUpload(ctx, userID, uploadID) return err } uploaded += int64(n) } if readErr == io.EOF || readErr == io.ErrUnexpectedEOF { break } if readErr != nil { _ = c.AbortChunkUpload(ctx, userID, uploadID) return readErr } } finalSize := uploaded if totalSize > 0 { finalSize = totalSize } if err := c.AssembleChunks(ctx, userID, uploadID, targetPath, finalSize); err != nil { _ = c.AbortChunkUpload(ctx, userID, uploadID) return err } return nil } func newChunkUploadID() (string, error) { b := make([]byte, 16) if _, err := rand.Read(b); err != nil { return "", fmt.Errorf("chunk upload id: %w", err) } return hex.EncodeToString(b), nil } func chunkIndexName(index int) string { return fmt.Sprintf("%d", index) }