github.com/artpar/rclone@v1.67.3/backend/imagekit/util.go (about) 1 package imagekit 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 "strconv" 8 "time" 9 10 "github.com/artpar/rclone/backend/imagekit/client" 11 "github.com/artpar/rclone/fs" 12 "github.com/artpar/rclone/fs/fserrors" 13 "github.com/artpar/rclone/lib/pacer" 14 ) 15 16 func (f *Fs) getFiles(ctx context.Context, path string, includeVersions bool) (files []client.File, err error) { 17 18 files = make([]client.File, 0) 19 20 var hasMore = true 21 22 for hasMore { 23 err = f.pacer.Call(func() (bool, error) { 24 var data *[]client.File 25 var res *http.Response 26 res, data, err = f.ik.Files(ctx, client.FilesOrFolderParam{ 27 Skip: len(files), 28 Limit: 100, 29 Path: path, 30 }, includeVersions) 31 32 hasMore = !(len(*data) == 0 || len(*data) < 100) 33 34 if len(*data) > 0 { 35 files = append(files, *data...) 36 } 37 38 return f.shouldRetry(ctx, res, err) 39 }) 40 } 41 42 if err != nil { 43 return make([]client.File, 0), err 44 } 45 46 return files, nil 47 } 48 49 func (f *Fs) getFolders(ctx context.Context, path string) (folders []client.Folder, err error) { 50 51 folders = make([]client.Folder, 0) 52 53 var hasMore = true 54 55 for hasMore { 56 err = f.pacer.Call(func() (bool, error) { 57 var data *[]client.Folder 58 var res *http.Response 59 res, data, err = f.ik.Folders(ctx, client.FilesOrFolderParam{ 60 Skip: len(folders), 61 Limit: 100, 62 Path: path, 63 }) 64 65 hasMore = !(len(*data) == 0 || len(*data) < 100) 66 67 if len(*data) > 0 { 68 folders = append(folders, *data...) 69 } 70 71 return f.shouldRetry(ctx, res, err) 72 }) 73 } 74 75 if err != nil { 76 return make([]client.Folder, 0), err 77 } 78 79 return folders, nil 80 } 81 82 func (f *Fs) getFileByName(ctx context.Context, path string, name string) (file *client.File) { 83 84 err := f.pacer.Call(func() (bool, error) { 85 res, data, err := f.ik.Files(ctx, client.FilesOrFolderParam{ 86 Limit: 1, 87 Path: path, 88 SearchQuery: fmt.Sprintf(`type = "file" AND name = %s`, strconv.Quote(name)), 89 }, false) 90 91 if len(*data) == 0 { 92 file = nil 93 } else { 94 file = &(*data)[0] 95 } 96 97 return f.shouldRetry(ctx, res, err) 98 }) 99 100 if err != nil { 101 return nil 102 } 103 104 return file 105 } 106 107 func (f *Fs) getFolderByName(ctx context.Context, path string, name string) (folder *client.Folder, err error) { 108 err = f.pacer.Call(func() (bool, error) { 109 res, data, err := f.ik.Folders(ctx, client.FilesOrFolderParam{ 110 Limit: 1, 111 Path: path, 112 SearchQuery: fmt.Sprintf(`type = "folder" AND name = %s`, strconv.Quote(name)), 113 }) 114 115 if len(*data) == 0 { 116 folder = nil 117 } else { 118 folder = &(*data)[0] 119 } 120 121 return f.shouldRetry(ctx, res, err) 122 }) 123 124 if err != nil { 125 return nil, err 126 } 127 128 return folder, nil 129 } 130 131 // retryErrorCodes is a slice of error codes that we will retry 132 var retryErrorCodes = []int{ 133 401, // Unauthorized (e.g. "Token has expired") 134 408, // Request Timeout 135 429, // Rate exceeded. 136 500, // Get occasional 500 Internal Server Error 137 503, // Service Unavailable 138 504, // Gateway Time-out 139 } 140 141 func shouldRetryHTTP(resp *http.Response, retryErrorCodes []int) bool { 142 if resp == nil { 143 return false 144 } 145 for _, e := range retryErrorCodes { 146 if resp.StatusCode == e { 147 return true 148 } 149 } 150 return false 151 } 152 153 func (f *Fs) shouldRetry(ctx context.Context, resp *http.Response, err error) (bool, error) { 154 if fserrors.ContextError(ctx, &err) { 155 return false, err 156 } 157 158 if resp != nil && (resp.StatusCode == 429 || resp.StatusCode == 503) { 159 var retryAfter = 1 160 retryAfterString := resp.Header.Get("X-RateLimit-Reset") 161 if retryAfterString != "" { 162 var err error 163 retryAfter, err = strconv.Atoi(retryAfterString) 164 if err != nil { 165 fs.Errorf(f, "Malformed %s header %q: %v", "X-RateLimit-Reset", retryAfterString, err) 166 } 167 } 168 169 return true, pacer.RetryAfterError(err, time.Duration(retryAfter)*time.Millisecond) 170 } 171 172 return fserrors.ShouldRetry(err) || shouldRetryHTTP(resp, retryErrorCodes), err 173 } 174 175 // EncodePath encapsulates the logic for encoding a path 176 func (f *Fs) EncodePath(str string) string { 177 return f.opt.Enc.FromStandardPath(str) 178 } 179 180 // DecodePath encapsulates the logic for decoding a path 181 func (f *Fs) DecodePath(str string) string { 182 return f.opt.Enc.ToStandardPath(str) 183 } 184 185 // EncodeFileName encapsulates the logic for encoding a file name 186 func (f *Fs) EncodeFileName(str string) string { 187 return f.opt.Enc.FromStandardName(str) 188 } 189 190 // DecodeFileName encapsulates the logic for decoding a file name 191 func (f *Fs) DecodeFileName(str string) string { 192 return f.opt.Enc.ToStandardName(str) 193 }