1// Utilities for accessing the Fs cache
2
3package rc
4
5import (
6	"context"
7	"errors"
8
9	"github.com/rclone/rclone/fs"
10	"github.com/rclone/rclone/fs/cache"
11	"github.com/rclone/rclone/fs/config/configmap"
12)
13
14// GetFsNamed gets an fs.Fs named fsName either from the cache or creates it afresh
15func GetFsNamed(ctx context.Context, in Params, fsName string) (f fs.Fs, err error) {
16	fsString, err := in.GetString(fsName)
17	if err != nil {
18		if !IsErrParamInvalid(err) {
19			return nil, err
20		}
21		fsString, err = getConfigMap(in, fsName)
22		if err != nil {
23			return nil, err
24		}
25	}
26	return cache.Get(ctx, fsString)
27}
28
29// getConfigMap gets the config as a map from in and converts it to a
30// config string
31//
32// It uses the special parameters _name to name the remote and _root
33// to make the root of the remote.
34func getConfigMap(in Params, fsName string) (fsString string, err error) {
35	var m configmap.Simple
36	err = in.GetStruct(fsName, &m)
37	if err != nil {
38		return fsString, err
39	}
40	pop := func(key string) string {
41		value := m[key]
42		delete(m, key)
43		return value
44	}
45	Type := pop("type")
46	name := pop("_name")
47	root := pop("_root")
48	if name != "" {
49		fsString = name
50	} else if Type != "" {
51		fsString = ":" + Type
52	} else {
53		return fsString, errors.New(`couldn't find "type" or "_name" in JSON config definition`)
54	}
55	config := m.String()
56	if config != "" {
57		fsString += ","
58		fsString += config
59	}
60	fsString += ":"
61	fsString += root
62	return fsString, nil
63}
64
65// GetFs gets an fs.Fs named "fs" either from the cache or creates it afresh
66func GetFs(ctx context.Context, in Params) (f fs.Fs, err error) {
67	return GetFsNamed(ctx, in, "fs")
68}
69
70// GetFsAndRemoteNamed gets the fsName parameter from in, makes a
71// remote or fetches it from the cache then gets the remoteName
72// parameter from in too.
73func GetFsAndRemoteNamed(ctx context.Context, in Params, fsName, remoteName string) (f fs.Fs, remote string, err error) {
74	remote, err = in.GetString(remoteName)
75	if err != nil {
76		return
77	}
78	f, err = GetFsNamed(ctx, in, fsName)
79	return
80
81}
82
83// GetFsAndRemote gets the `fs` parameter from in, makes a remote or
84// fetches it from the cache then gets the `remote` parameter from in
85// too.
86func GetFsAndRemote(ctx context.Context, in Params) (f fs.Fs, remote string, err error) {
87	return GetFsAndRemoteNamed(ctx, in, "fs", "remote")
88}
89
90func init() {
91	Add(Call{
92		Path:         "fscache/clear",
93		Fn:           rcCacheClear,
94		Title:        "Clear the Fs cache.",
95		AuthRequired: true,
96		Help: `
97This clears the fs cache. This is where remotes created from backends
98are cached for a short while to make repeated rc calls more efficient.
99
100If you change the parameters of a backend then you may want to call
101this to clear an existing remote out of the cache before re-creating
102it.
103`,
104	})
105}
106
107// Clear the fs cache
108func rcCacheClear(ctx context.Context, in Params) (out Params, err error) {
109	cache.Clear()
110	return nil, nil
111}
112
113func init() {
114	Add(Call{
115		Path:         "fscache/entries",
116		Fn:           rcCacheEntries,
117		Title:        "Returns the number of entries in the fs cache.",
118		AuthRequired: true,
119		Help: `
120This returns the number of entries in the fs cache.
121
122Returns
123- entries - number of items in the cache
124`,
125	})
126}
127
128// Return the Entries the fs cache
129func rcCacheEntries(ctx context.Context, in Params) (out Params, err error) {
130	return Params{
131		"entries": cache.Entries(),
132	}, nil
133}
134