github.com/Files-com/files-sdk-go/v3@v3.1.81/file/upload.go (about) 1 package file 2 3 import ( 4 "context" 5 "io" 6 "os" 7 "os/user" 8 "path/filepath" 9 "time" 10 11 files_sdk "github.com/Files-com/files-sdk-go/v3" 12 "github.com/Files-com/files-sdk-go/v3/file/manager" 13 "github.com/Files-com/files-sdk-go/v3/file/status" 14 lib "github.com/Files-com/files-sdk-go/v3/lib" 15 "github.com/Files-com/files-sdk-go/v3/lib/direction" 16 ) 17 18 type UploadOption func(uploadIO) (uploadIO, error) 19 20 func UploadWithContext(ctx context.Context) UploadOption { 21 return func(params uploadIO) (uploadIO, error) { 22 params.passedInContext = ctx 23 return params, nil 24 } 25 } 26 27 func UploadWithReader(reader io.Reader) UploadOption { 28 return func(params uploadIO) (uploadIO, error) { 29 if lenReader, ok := reader.(Len); ok && params.Size == nil { 30 params.Size = lib.Int64(int64(lenReader.Len())) 31 } 32 params.reader = reader 33 return params, nil 34 } 35 } 36 37 func UploadWithReaderAt(readerAt io.ReaderAt) UploadOption { 38 return func(params uploadIO) (uploadIO, error) { 39 if lenReader, ok := readerAt.(Len); ok && params.Size == nil { 40 params.Size = lib.Int64(int64(lenReader.Len())) 41 } 42 params.readerAt = readerAt 43 return params, nil 44 } 45 } 46 47 func UploadWithFile(sourcePath string) UploadOption { 48 return func(params uploadIO) (uploadIO, error) { 49 file, err := os.Open(sourcePath) 50 if err != nil { 51 return params, err 52 } 53 info, err := file.Stat() 54 if err != nil { 55 return params, err 56 } 57 58 params, err = UploadWithReaderAt(file)(params) 59 if err != nil { 60 return params, err 61 } 62 return UploadWithSize(info.Size())(params) 63 } 64 } 65 66 func UploadWithDestinationPath(destinationPath string) UploadOption { 67 return func(params uploadIO) (uploadIO, error) { 68 params.Path = destinationPath 69 return params, nil 70 } 71 } 72 73 func UploadWithProvidedMtime(providedMtime time.Time) UploadOption { 74 return func(params uploadIO) (uploadIO, error) { 75 params.ProvidedMtime = providedMtime 76 return params, nil 77 } 78 } 79 80 func UploadWithManager(manager lib.ConcurrencyManagerWithSubWorker) UploadOption { 81 return func(params uploadIO) (uploadIO, error) { 82 params.Manager = manager 83 return params, nil 84 } 85 } 86 87 func UploadWithSize(size int64) UploadOption { 88 return func(params uploadIO) (uploadIO, error) { 89 params.Size = &size 90 return params, nil 91 } 92 } 93 94 func UploadWithProgress(progress Progress) UploadOption { 95 return func(params uploadIO) (uploadIO, error) { 96 params.Progress = progress 97 return params, nil 98 } 99 } 100 101 // UploadRewindAllProgressOnFailure on upload failure rewind all successfully parts 102 func UploadRewindAllProgressOnFailure() UploadOption { 103 return func(params uploadIO) (uploadIO, error) { 104 params.RewindAllProgressOnFailure = true 105 return params, nil 106 } 107 } 108 109 func UploadWithResume(resume UploadResumable) UploadOption { 110 return func(params uploadIO) (uploadIO, error) { 111 if params.Path == "" { 112 params.Path = resume.FileUploadPart.Path 113 } 114 params.Parts = resume.Parts 115 params.FileUploadPart = resume.FileUploadPart 116 return params, nil 117 } 118 } 119 120 func (c *Client) Upload(opts ...UploadOption) error { 121 _, err := c.UploadWithResume(opts...) 122 123 return err 124 } 125 126 func (c *Client) UploadWithResume(opts ...UploadOption) (UploadResumable, error) { 127 uploadIo := uploadIO{ 128 Client: c, 129 Manager: manager.Default().FilePartsManager, 130 passedInContext: context.Background(), 131 ByteOffset: ByteOffset{PartSizes: lib.PartSizes}, 132 } 133 134 for _, opt := range opts { 135 var err error 136 uploadIo, err = opt(uploadIo) 137 if err != nil { 138 return UploadResumable{}, err 139 } 140 } 141 return (&uploadIo).Run(uploadIo.passedInContext) 142 } 143 144 // UploadFile Deprecated use c.Upload(UploadWithFile(sourcePath), UploadWithDestinationPath(destinationPath)) 145 func (c *Client) UploadFile(sourcePath string, destinationPath string, opts ...UploadOption) error { 146 return c.Upload(append(opts, UploadWithFile(sourcePath), UploadWithDestinationPath(destinationPath))...) 147 } 148 149 func (c *Client) UploadRetry(job Job, opts ...files_sdk.RequestResponseOption) *Job { 150 newJob := job.ClearStatuses() 151 return c.Uploader( 152 UploaderParams{ 153 Sync: newJob.Sync, 154 LocalPath: newJob.LocalPath, 155 RemotePath: newJob.RemotePath, 156 EventsReporter: newJob.EventsReporter, 157 Manager: newJob.Manager, 158 RetryPolicy: newJob.RetryPolicy.(RetryPolicy), 159 Ignore: newJob.Params.(UploaderParams).Ignore, 160 }, 161 opts..., 162 ) 163 } 164 165 type UploaderParams struct { 166 // Ignore gitignore formatted pattern 167 Ignore []string 168 // Include gitignore formatted pattern 169 Include []string 170 // Sync compare destination and only upload if different or non-existent. 171 Sync bool 172 // LocalPaths files or directories to upload. 173 LocalPaths []string 174 // LocalPath a file or directory to recursively upload. 175 LocalPath string 176 // RemotePath destination path for files.com, formatted `/` path separator. 177 RemotePath string 178 // DryRun see what files would be uploaded. 179 DryRun bool 180 // RetryPolicy config for retrying errored uploads. 181 RetryPolicy 182 // EventsReporter log file events 183 EventsReporter 184 // Manager limit concurrency 185 *manager.Manager 186 *Job 187 config files_sdk.Config 188 PreserveTimes bool 189 } 190 191 func expand(path string) (string, error) { 192 if len(path) == 0 || path[0] != '~' { 193 return path, nil 194 } 195 usr, err := user.Current() 196 if err != nil { 197 return "", err 198 } 199 return filepath.Join(usr.HomeDir, path[1:]), nil 200 } 201 202 func (c *Client) Uploader(params UploaderParams, opts ...files_sdk.RequestResponseOption) *Job { 203 job := (&Job{}).Init() 204 params.config = c.Config 205 SetJobParams(job, direction.UploadType, params, c.Logger, (&FS{}).Init(c.Config, true)) 206 job.Config = params.config 207 job.CodeStart = func() { 208 params.Job = job 209 job.Params = params 210 params.RemotePath = lib.Path{Path: params.RemotePath}.PruneStartingSlash().String() 211 file := &UploadStatus{file: files_sdk.File{}, remotePath: params.RemotePath, localPath: params.LocalPath, status: status.Queued, job: job} 212 expandedPath, err := expand(params.LocalPath) 213 if err != nil { 214 job.Add(file) 215 job.UpdateStatus(status.Errored, file, err) 216 return 217 } 218 absolutePath, err := filepath.Abs(expandedPath) 219 if err != nil { 220 job.Add(file) 221 job.UpdateStatus(status.Errored, file, err) 222 return 223 } 224 if (lib.Path{Path: params.LocalPath}).EndingSlash() { 225 params.LocalPath = absolutePath + string(os.PathSeparator) 226 } else { 227 params.LocalPath = absolutePath 228 } 229 230 uploader(files_sdk.ContextOption(opts), c, params).CodeStart() 231 } 232 233 return job 234 }