11package handles
22
33import (
4+ "context"
45 "fmt"
56 stdpath "path"
67 "strings"
@@ -14,10 +15,12 @@ import (
1415 "github.com/OpenListTeam/OpenList/v4/internal/op"
1516 "github.com/OpenListTeam/OpenList/v4/internal/setting"
1617 "github.com/OpenListTeam/OpenList/v4/internal/sign"
18+ "github.com/OpenListTeam/OpenList/v4/pkg/generic"
1719 "github.com/OpenListTeam/OpenList/v4/pkg/utils"
1820 "github.com/OpenListTeam/OpenList/v4/server/common"
1921 "github.com/gin-gonic/gin"
2022 "github.com/pkg/errors"
23+ log "github.com/sirupsen/logrus"
2124)
2225
2326type ListReq struct {
@@ -435,6 +438,12 @@ type FsOtherReq struct {
435438 Password string `json:"password" form:"password"`
436439}
437440
441+ type RecurseListReq struct {
442+ Path string `json:"path" form:"path"`
443+ Refresh bool `json:"refresh" form:"refresh"`
444+ IntervalSec int `json:"interval_sec" form:"interval_sec"`
445+ }
446+
438447func FsOther (c * gin.Context ) {
439448 var req FsOtherReq
440449 if err := c .ShouldBind (& req ); err != nil {
@@ -467,3 +476,79 @@ func FsOther(c *gin.Context) {
467476 }
468477 common .SuccessResp (c , res )
469478}
479+
480+ func FsRecurseList (c * gin.Context ) {
481+ var req RecurseListReq
482+ if err := c .ShouldBind (& req ); err != nil {
483+ common .ErrorResp (c , err , 400 )
484+ return
485+ }
486+ user := c .Request .Context ().Value (conf .UserKey ).(* model.User )
487+ reqPath , err := user .JoinPath (req .Path )
488+ if err != nil {
489+ common .ErrorResp (c , err , 403 )
490+ return
491+ }
492+ meta , err := op .GetNearestMeta (reqPath )
493+ if err != nil {
494+ if ! errors .Is (errors .Cause (err ), errs .MetaNotFound ) {
495+ common .ErrorResp (c , err , 500 , true )
496+ return
497+ }
498+ }
499+ if ! common .CanAccess (user , meta , reqPath , "" ) {
500+ common .ErrorStrResp (c , "password is incorrect or you have no permission" , 403 )
501+ return
502+ }
503+ if ! user .CanWrite () && ! common .CanWrite (meta , reqPath ) && req .Refresh {
504+ common .ErrorStrResp (c , "Refresh without permission" , 403 )
505+ return
506+ }
507+
508+ go func () {
509+ ctx := context .Background ()
510+ ctx = context .WithValue (ctx , conf .UserKey , user )
511+ ctx = context .WithValue (ctx , conf .MetaKey , meta )
512+
513+ queue := generic .NewQueue [string ]()
514+ queue .Push (reqPath )
515+
516+ visited := make (map [string ]bool )
517+
518+ for queue .Len () > 0 {
519+ currentPath := queue .Pop ()
520+
521+ if visited [currentPath ] {
522+ continue
523+ }
524+ visited [currentPath ] = true
525+
526+ objs , err := fs .List (ctx , currentPath , & fs.ListArgs {
527+ Refresh : req .Refresh ,
528+ WithStorageDetails : false ,
529+ NoLog : true ,
530+ })
531+ if err != nil {
532+ log .Warnf ("FsRecurseList: failed to list %s: %+v" , currentPath , err )
533+ continue
534+ }
535+
536+ for _ , obj := range objs {
537+ if obj .IsDir () {
538+ subPath := stdpath .Join (currentPath , obj .GetName ())
539+ if ! visited [subPath ] {
540+ queue .Push (subPath )
541+ }
542+ }
543+ }
544+
545+ if req .IntervalSec > 0 && queue .Len () > 0 {
546+ time .Sleep (time .Duration (req .IntervalSec ) * time .Second )
547+ }
548+ }
549+
550+ log .Infof ("FsRecurseList: completed recursion for path %s" , reqPath )
551+ }()
552+
553+ common .SuccessResp (c )
554+ }
0 commit comments