From 2a7b46437fdb5c2fa8796796b4fa152c50d702a3 Mon Sep 17 00:00:00 2001 From: Aaron Liu Date: Thu, 5 Jun 2025 16:51:48 +0800 Subject: [PATCH] fix(onedrive): cannot list folder with more than 500 direct children (#2446) --- pkg/filemanager/driver/onedrive/api.go | 70 +++++++++++++++--------- pkg/filemanager/driver/onedrive/types.go | 5 +- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/pkg/filemanager/driver/onedrive/api.go b/pkg/filemanager/driver/onedrive/api.go index 4b73b05..89ff0fb 100644 --- a/pkg/filemanager/driver/onedrive/api.go +++ b/pkg/filemanager/driver/onedrive/api.go @@ -4,16 +4,17 @@ import ( "context" "encoding/json" "fmt" - "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/chunk" - "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/chunk/backoff" - "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs" - "github.com/cloudreve/Cloudreve/v4/pkg/request" "io" "net/http" "net/url" "path" "strings" "time" + + "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/chunk" + "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/chunk/backoff" + "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs" + "github.com/cloudreve/Cloudreve/v4/pkg/request" ) const ( @@ -76,31 +77,50 @@ func (client *client) ListChildren(ctx context.Context, path string) ([]FileInfo requestURL = client.getRequestURL("root:/" + dst + ":/children") } - res, err := client.requestWithStr(ctx, "GET", requestURL+"?$top=999999999", "", 200) - if err != nil { - retried := 0 - if v, ok := ctx.Value(RetryCtx{}).(int); ok { - retried = v + // Add pagination parameter + requestURL += "?$top=5000" + + var allFiles []FileInfo + + for { + res, err := client.requestWithStr(ctx, "GET", requestURL, "", 200) + if err != nil { + retried := 0 + if v, ok := ctx.Value(RetryCtx{}).(int); ok { + retried = v + } + if retried < ListRetry { + retried++ + client.l.Debug("Failed to list path %q: %s, will retry in 5 seconds.", path, err) + time.Sleep(time.Duration(5) * time.Second) + return client.ListChildren(context.WithValue(ctx, RetryCtx{}, retried), path) + } + return nil, err } - if retried < ListRetry { - retried++ - client.l.Debug("Failed to list path %q: %s, will retry in 5 seconds.", path, err) - time.Sleep(time.Duration(5) * time.Second) - return client.ListChildren(context.WithValue(ctx, RetryCtx{}, retried), path) + + var ( + decodeErr error + fileInfo ListResponse + ) + decodeErr = json.Unmarshal([]byte(res), &fileInfo) + if decodeErr != nil { + return nil, decodeErr } - return nil, err + + // Append current page results + allFiles = append(allFiles, fileInfo.Value...) + + // Check if there's a next page + if fileInfo.NextLink == "" { + break + } + + // Use the next link for the next iteration + client.l.Debug("Load next page, next link: %s", fileInfo.NextLink) + requestURL = fileInfo.NextLink } - var ( - decodeErr error - fileInfo ListResponse - ) - decodeErr = json.Unmarshal([]byte(res), &fileInfo) - if decodeErr != nil { - return nil, decodeErr - } - - return fileInfo.Value, nil + return allFiles, nil } // Meta 根据资源ID或文件路径获取文件元信息 diff --git a/pkg/filemanager/driver/onedrive/types.go b/pkg/filemanager/driver/onedrive/types.go index f430d3e..101ff05 100644 --- a/pkg/filemanager/driver/onedrive/types.go +++ b/pkg/filemanager/driver/onedrive/types.go @@ -94,8 +94,9 @@ type ThumbResponse struct { // ListResponse 列取子项目响应 type ListResponse struct { - Value []FileInfo `json:"value"` - Context string `json:"@odata.context"` + Value []FileInfo `json:"value"` + Context string `json:"@odata.context"` + NextLink string `json:"@odata.nextLink,omitempty"` } // oauthEndpoint OAuth接口地址