github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/fs/rc/cache.go (about) 1 // Utilities for accessing the Fs cache 2 3 package rc 4 5 import ( 6 "context" 7 "errors" 8 "fmt" 9 10 "github.com/rclone/rclone/fs" 11 "github.com/rclone/rclone/fs/cache" 12 "github.com/rclone/rclone/fs/config/configmap" 13 "github.com/rclone/rclone/fs/filter" 14 "github.com/rclone/rclone/fs/fspath" 15 ) 16 17 // getFsName gets an fs name from fsName either from the cache or direct 18 func getFsName(in Params, fsName string) (fsString string, err error) { 19 fsString, err = in.GetString(fsName) 20 if err != nil { 21 if !IsErrParamInvalid(err) { 22 return fsString, err 23 } 24 fsString, err = getConfigMap(in, fsName) 25 if err != nil { 26 return fsString, err 27 } 28 } 29 return fsString, err 30 } 31 32 // GetFsNamed gets an fs.Fs named fsName either from the cache or creates it afresh 33 func GetFsNamed(ctx context.Context, in Params, fsName string) (f fs.Fs, err error) { 34 fsString, err := getFsName(in, fsName) 35 if err != nil { 36 return nil, err 37 } 38 return cache.Get(ctx, fsString) 39 } 40 41 // GetFsNamedFileOK gets an fs.Fs named fsName either from the cache or creates it afresh 42 // 43 // If the fs.Fs points to a single file then it returns a new ctx with 44 // filters applied to make the listings return only that file. 45 func GetFsNamedFileOK(ctx context.Context, in Params, fsName string) (newCtx context.Context, f fs.Fs, err error) { 46 fsString, err := getFsName(in, fsName) 47 if err != nil { 48 return ctx, nil, err 49 } 50 f, err = cache.Get(ctx, fsString) 51 if err == nil { 52 return ctx, f, nil 53 } else if !errors.Is(err, fs.ErrorIsFile) { 54 return ctx, nil, err 55 } 56 // f points to the directory above the file so find the remote name 57 _, fileName, err := fspath.Split(fsString) 58 if err != nil { 59 return ctx, f, err 60 } 61 ctx, fi := filter.AddConfig(ctx) 62 if !fi.InActive() { 63 return ctx, f, fmt.Errorf("can't limit to single files when using filters: %q", fileName) 64 } 65 // Limit transfers to this file 66 err = fi.AddFile(fileName) 67 if err != nil { 68 return ctx, f, fmt.Errorf("failed to limit to single file: %w", err) 69 } 70 return ctx, f, nil 71 } 72 73 // getConfigMap gets the config as a map from in and converts it to a 74 // config string 75 // 76 // It uses the special parameters _name to name the remote and _root 77 // to make the root of the remote. 78 func getConfigMap(in Params, fsName string) (fsString string, err error) { 79 var m configmap.Simple 80 err = in.GetStruct(fsName, &m) 81 if err != nil { 82 return fsString, err 83 } 84 pop := func(key string) string { 85 value := m[key] 86 delete(m, key) 87 return value 88 } 89 Type := pop("type") 90 name := pop("_name") 91 root := pop("_root") 92 if name != "" { 93 fsString = name 94 } else if Type != "" { 95 fsString = ":" + Type 96 } else { 97 return fsString, errors.New(`couldn't find "type" or "_name" in JSON config definition`) 98 } 99 config := m.String() 100 if config != "" { 101 fsString += "," 102 fsString += config 103 } 104 fsString += ":" 105 fsString += root 106 return fsString, nil 107 } 108 109 // GetFs gets an fs.Fs named "fs" either from the cache or creates it afresh 110 func GetFs(ctx context.Context, in Params) (f fs.Fs, err error) { 111 return GetFsNamed(ctx, in, "fs") 112 } 113 114 // GetFsAndRemoteNamed gets the fsName parameter from in, makes a 115 // remote or fetches it from the cache then gets the remoteName 116 // parameter from in too. 117 func GetFsAndRemoteNamed(ctx context.Context, in Params, fsName, remoteName string) (f fs.Fs, remote string, err error) { 118 remote, err = in.GetString(remoteName) 119 if err != nil { 120 return 121 } 122 f, err = GetFsNamed(ctx, in, fsName) 123 return 124 125 } 126 127 // GetFsAndRemote gets the `fs` parameter from in, makes a remote or 128 // fetches it from the cache then gets the `remote` parameter from in 129 // too. 130 func GetFsAndRemote(ctx context.Context, in Params) (f fs.Fs, remote string, err error) { 131 return GetFsAndRemoteNamed(ctx, in, "fs", "remote") 132 } 133 134 func init() { 135 Add(Call{ 136 Path: "fscache/clear", 137 Fn: rcCacheClear, 138 Title: "Clear the Fs cache.", 139 AuthRequired: true, 140 Help: ` 141 This clears the fs cache. This is where remotes created from backends 142 are cached for a short while to make repeated rc calls more efficient. 143 144 If you change the parameters of a backend then you may want to call 145 this to clear an existing remote out of the cache before re-creating 146 it. 147 `, 148 }) 149 } 150 151 // Clear the fs cache 152 func rcCacheClear(ctx context.Context, in Params) (out Params, err error) { 153 cache.Clear() 154 return nil, nil 155 } 156 157 func init() { 158 Add(Call{ 159 Path: "fscache/entries", 160 Fn: rcCacheEntries, 161 Title: "Returns the number of entries in the fs cache.", 162 AuthRequired: true, 163 Help: ` 164 This returns the number of entries in the fs cache. 165 166 Returns 167 - entries - number of items in the cache 168 `, 169 }) 170 } 171 172 // Return the Entries the fs cache 173 func rcCacheEntries(ctx context.Context, in Params) (out Params, err error) { 174 return Params{ 175 "entries": cache.Entries(), 176 }, nil 177 }