@@ -20,15 +20,18 @@ import (
2020 "compress/gzip"
2121 "fmt"
2222 "io"
23+ "mime/multipart"
2324 "net/http"
2425 "os"
2526 "path"
2627 "path/filepath"
2728 "strings"
2829
2930 "github.com/schollz/progressbar/v3"
31+ "golang.org/x/sync/errgroup"
3032
3133 "github.com/livekit/livekit-cli/v2/pkg/util"
34+ "github.com/livekit/protocol/livekit"
3235 "github.com/livekit/protocol/logger"
3336
3437 "github.com/moby/patternmatcher"
5154 }
5255)
5356
54- func UploadTarball (directory string , presignedUrl string , excludeFiles []string , projectType ProjectType ) error {
57+ func UploadTarball (
58+ directory string ,
59+ presignedUrl string ,
60+ presignedPostRequest * livekit.PresignedPostRequest ,
61+ excludeFiles []string ,
62+ projectType ProjectType ,
63+ ) error {
5564 excludeFiles = append (excludeFiles , defaultExcludePatterns ... )
5665
5766 loadExcludeFiles := func (filename string ) (bool , string , error ) {
@@ -274,25 +283,79 @@ func UploadTarball(directory string, presignedUrl string, excludeFiles []string,
274283 }),
275284 )
276285
277- req , err := http .NewRequest ("PUT" , presignedUrl , io .TeeReader (& buffer , uploadProgress ))
286+ if presignedPostRequest != nil {
287+ if err := multipartUpload (presignedPostRequest .Url , presignedPostRequest .Values , & buffer , uploadProgress ); err != nil {
288+ return fmt .Errorf ("multipart upload failed: %w" , err )
289+ }
290+ } else {
291+ if err := upload (presignedUrl , & buffer , uploadProgress ); err != nil {
292+ return fmt .Errorf ("upload failed: %w" , err )
293+ }
294+ }
295+
296+ fmt .Println ()
297+ return nil
298+ }
299+
300+ func upload (presignedUrl string , buffer * bytes.Buffer , uploadProgress * progressbar.ProgressBar ) error {
301+ req , err := http .NewRequest ("PUT" , presignedUrl , io .TeeReader (buffer , uploadProgress ))
278302 if err != nil {
279303 return fmt .Errorf ("failed to create request: %w" , err )
280304 }
281305 req .Header .Set ("Content-Type" , "application/gzip" )
282306 req .ContentLength = int64 (buffer .Len ())
283-
284- client := & http.Client {}
285- resp , err := client .Do (req )
307+ resp , err := http .DefaultClient .Do (req )
286308 if err != nil {
287309 return fmt .Errorf ("failed to upload tarball: %w" , err )
288310 }
289311 defer resp .Body .Close ()
290-
291312 if resp .StatusCode != http .StatusOK {
292313 body , _ := io .ReadAll (resp .Body )
293314 return fmt .Errorf ("failed to upload tarball: %d: %s" , resp .StatusCode , body )
294315 }
295-
296- fmt .Println ()
297316 return nil
298317}
318+
319+ func multipartUpload (presignedURL string , fields map [string ]string , buf * bytes.Buffer , uploadProgress * progressbar.ProgressBar ) error {
320+ pr , pw := io .Pipe ()
321+ w := multipart .NewWriter (pw )
322+ var eg errgroup.Group
323+ eg .Go (func () error {
324+ defer pw .Close ()
325+ defer w .Close ()
326+ for k , v := range fields {
327+ if err := w .WriteField (k , v ); err != nil {
328+ pw .CloseWithError (err )
329+ return err
330+ }
331+ }
332+ part , err := w .CreateFormFile ("file" , "upload.tar.gz" )
333+ if err != nil {
334+ pw .CloseWithError (err )
335+ return err
336+ }
337+ if _ , err := io .Copy (part , io .TeeReader (buf , uploadProgress )); err != nil {
338+ pw .CloseWithError (err )
339+ return err
340+ }
341+ return nil
342+ })
343+ eg .Go (func () error {
344+ req , err := http .NewRequest ("POST" , presignedURL , pr )
345+ if err != nil {
346+ return err
347+ }
348+ req .Header .Set ("Content-Type" , w .FormDataContentType ())
349+ resp , err := http .DefaultClient .Do (req )
350+ if err != nil {
351+ return err
352+ }
353+ defer resp .Body .Close ()
354+ if resp .StatusCode != http .StatusOK && resp .StatusCode != http .StatusCreated {
355+ respBody , _ := io .ReadAll (resp .Body )
356+ return fmt .Errorf ("failed to upload tarball: %d: %s" , resp .StatusCode , respBody )
357+ }
358+ return nil
359+ })
360+ return eg .Wait ()
361+ }
0 commit comments