mirror of
https://github.com/rclone/rclone.git
synced 2025-03-02 17:32:56 +01:00
This commit modernizes Go usage. This was done with: go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./... Then files needed to be `go fmt`ed and a few comments needed to be restored. The modernizations include replacing - if/else conditional assignment by a call to the built-in min or max functions added in go1.21 - sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21 - interface{} by the 'any' type added in go1.18 - append([]T(nil), s...) by slices.Clone(s) or slices.Concat(s), added in go1.21 - loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21 - []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19 - append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1), added in go1.21 - a 3-clause for i := 0; i < n; i++ {} loop by for i := range n {}, added in go1.22
190 lines
4.3 KiB
Go
190 lines
4.3 KiB
Go
package imagekit
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"slices"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/rclone/rclone/backend/imagekit/client"
|
|
"github.com/rclone/rclone/fs"
|
|
"github.com/rclone/rclone/fs/fserrors"
|
|
"github.com/rclone/rclone/lib/pacer"
|
|
)
|
|
|
|
func (f *Fs) getFiles(ctx context.Context, path string, includeVersions bool) (files []client.File, err error) {
|
|
|
|
files = make([]client.File, 0)
|
|
|
|
var hasMore = true
|
|
|
|
for hasMore {
|
|
err = f.pacer.Call(func() (bool, error) {
|
|
var data *[]client.File
|
|
var res *http.Response
|
|
res, data, err = f.ik.Files(ctx, client.FilesOrFolderParam{
|
|
Skip: len(files),
|
|
Limit: 100,
|
|
Path: path,
|
|
}, includeVersions)
|
|
|
|
hasMore = !(len(*data) == 0 || len(*data) < 100)
|
|
|
|
if len(*data) > 0 {
|
|
files = append(files, *data...)
|
|
}
|
|
|
|
return f.shouldRetry(ctx, res, err)
|
|
})
|
|
}
|
|
|
|
if err != nil {
|
|
return make([]client.File, 0), err
|
|
}
|
|
|
|
return files, nil
|
|
}
|
|
|
|
func (f *Fs) getFolders(ctx context.Context, path string) (folders []client.Folder, err error) {
|
|
|
|
folders = make([]client.Folder, 0)
|
|
|
|
var hasMore = true
|
|
|
|
for hasMore {
|
|
err = f.pacer.Call(func() (bool, error) {
|
|
var data *[]client.Folder
|
|
var res *http.Response
|
|
res, data, err = f.ik.Folders(ctx, client.FilesOrFolderParam{
|
|
Skip: len(folders),
|
|
Limit: 100,
|
|
Path: path,
|
|
})
|
|
|
|
hasMore = !(len(*data) == 0 || len(*data) < 100)
|
|
|
|
if len(*data) > 0 {
|
|
folders = append(folders, *data...)
|
|
}
|
|
|
|
return f.shouldRetry(ctx, res, err)
|
|
})
|
|
}
|
|
|
|
if err != nil {
|
|
return make([]client.Folder, 0), err
|
|
}
|
|
|
|
return folders, nil
|
|
}
|
|
|
|
func (f *Fs) getFileByName(ctx context.Context, path string, name string) (file *client.File) {
|
|
|
|
err := f.pacer.Call(func() (bool, error) {
|
|
res, data, err := f.ik.Files(ctx, client.FilesOrFolderParam{
|
|
Limit: 1,
|
|
Path: path,
|
|
SearchQuery: fmt.Sprintf(`type = "file" AND name = %s`, strconv.Quote(name)),
|
|
}, false)
|
|
|
|
if len(*data) == 0 {
|
|
file = nil
|
|
} else {
|
|
file = &(*data)[0]
|
|
}
|
|
|
|
return f.shouldRetry(ctx, res, err)
|
|
})
|
|
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
return file
|
|
}
|
|
|
|
func (f *Fs) getFolderByName(ctx context.Context, path string, name string) (folder *client.Folder, err error) {
|
|
err = f.pacer.Call(func() (bool, error) {
|
|
res, data, err := f.ik.Folders(ctx, client.FilesOrFolderParam{
|
|
Limit: 1,
|
|
Path: path,
|
|
SearchQuery: fmt.Sprintf(`type = "folder" AND name = %s`, strconv.Quote(name)),
|
|
})
|
|
|
|
if len(*data) == 0 {
|
|
folder = nil
|
|
} else {
|
|
folder = &(*data)[0]
|
|
}
|
|
|
|
return f.shouldRetry(ctx, res, err)
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return folder, nil
|
|
}
|
|
|
|
// retryErrorCodes is a slice of error codes that we will retry
|
|
var retryErrorCodes = []int{
|
|
401, // Unauthorized (e.g. "Token has expired")
|
|
408, // Request Timeout
|
|
429, // Rate exceeded.
|
|
500, // Get occasional 500 Internal Server Error
|
|
503, // Service Unavailable
|
|
504, // Gateway Time-out
|
|
}
|
|
|
|
func shouldRetryHTTP(resp *http.Response, retryErrorCodes []int) bool {
|
|
if resp == nil {
|
|
return false
|
|
}
|
|
return slices.Contains(retryErrorCodes, resp.StatusCode)
|
|
}
|
|
|
|
func (f *Fs) shouldRetry(ctx context.Context, resp *http.Response, err error) (bool, error) {
|
|
if fserrors.ContextError(ctx, &err) {
|
|
return false, err
|
|
}
|
|
|
|
if resp != nil && (resp.StatusCode == 429 || resp.StatusCode == 503) {
|
|
var retryAfter = 1
|
|
retryAfterString := resp.Header.Get("X-RateLimit-Reset")
|
|
if retryAfterString != "" {
|
|
var err error
|
|
retryAfter, err = strconv.Atoi(retryAfterString)
|
|
if err != nil {
|
|
fs.Errorf(f, "Malformed %s header %q: %v", "X-RateLimit-Reset", retryAfterString, err)
|
|
}
|
|
}
|
|
|
|
return true, pacer.RetryAfterError(err, time.Duration(retryAfter)*time.Millisecond)
|
|
}
|
|
|
|
return fserrors.ShouldRetry(err) || shouldRetryHTTP(resp, retryErrorCodes), err
|
|
}
|
|
|
|
// EncodePath encapsulates the logic for encoding a path
|
|
func (f *Fs) EncodePath(str string) string {
|
|
return f.opt.Enc.FromStandardPath(str)
|
|
}
|
|
|
|
// DecodePath encapsulates the logic for decoding a path
|
|
func (f *Fs) DecodePath(str string) string {
|
|
return f.opt.Enc.ToStandardPath(str)
|
|
}
|
|
|
|
// EncodeFileName encapsulates the logic for encoding a file name
|
|
func (f *Fs) EncodeFileName(str string) string {
|
|
return f.opt.Enc.FromStandardName(str)
|
|
}
|
|
|
|
// DecodeFileName encapsulates the logic for decoding a file name
|
|
func (f *Fs) DecodeFileName(str string) string {
|
|
return f.opt.Enc.ToStandardName(str)
|
|
}
|