Skip to content

Commit 2076af9

Browse files
committed
Implemented caching of the webdav clients for OCM, with fallback to v1.0 access
1 parent 6af8c62 commit 2076af9

File tree

1 file changed

+59
-5
lines changed
  • pkg/ocm/storage/received

1 file changed

+59
-5
lines changed

pkg/ocm/storage/received/ocm.go

+59-5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
"net/url"
2727
"path/filepath"
2828
"strings"
29+
"sync"
30+
"time"
2931

3032
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
3133
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
@@ -49,9 +51,17 @@ func init() {
4951
registry.Register("ocmreceived", New)
5052
}
5153

54+
type cachedClient struct {
55+
client *gowebdav.Client
56+
share *ocmpb.ReceivedShare
57+
expiresAt time.Time
58+
}
59+
5260
type driver struct {
5361
c *config
5462
gateway gateway.GatewayAPIClient
63+
ccache map[string]*cachedClient
64+
mu sync.Mutex
5565
}
5666

5767
type config struct {
@@ -78,8 +88,9 @@ func New(ctx context.Context, m map[string]interface{}) (storage.FS, error) {
7888
d := &driver{
7989
c: &c,
8090
gateway: gateway,
91+
ccache: make(map[string]*cachedClient), // this is a cache of webdav clients
8192
}
82-
93+
go d.ccacheCleanupThread()
8394
return d, nil
8495
}
8596

@@ -106,7 +117,6 @@ func shareInfoFromReference(ref *provider.Reference) (*ocmpb.ShareId, string) {
106117
}
107118

108119
func (d *driver) getWebDAVFromShare(ctx context.Context, shareID *ocmpb.ShareId) (*ocmpb.ReceivedShare, string, string, error) {
109-
// TODO: we may want to cache the share
110120
res, err := d.gateway.GetReceivedOCMShare(ctx, &ocmpb.GetReceivedOCMShareRequest{
111121
Ref: &ocmpb.ShareReference{
112122
Spec: &ocmpb.ShareReference_Id{
@@ -143,13 +153,22 @@ func getWebDAVProtocol(protocols []*ocmpb.Protocol) (*ocmpb.WebDAVProtocol, bool
143153
}
144154

145155
func (d *driver) webdavClient(ctx context.Context, ref *provider.Reference) (*gowebdav.Client, *ocmpb.ReceivedShare, string, error) {
156+
log := appctx.GetLogger(ctx)
146157
id, rel := shareInfoFromReference(ref)
147158

159+
// check first if we have a cached webdav client
160+
d.mu.Lock()
161+
defer d.mu.Unlock()
162+
if entry, found := d.ccache[id.OpaqueId]; found {
163+
log.Info().Interface("share", entry.share).Str("rel", rel).Msg("Using cached client to access OCM share")
164+
return entry.client, entry.share, rel, nil
165+
}
166+
167+
// we don't, build a webdav client
148168
share, endpoint, secret, err := d.getWebDAVFromShare(ctx, id)
149169
if err != nil {
150170
return nil, nil, "", err
151171
}
152-
153172
endpoint, err = url.PathUnescape(endpoint)
154173
if err != nil {
155174
return nil, nil, "", err
@@ -158,9 +177,21 @@ func (d *driver) webdavClient(ctx context.Context, ref *provider.Reference) (*go
158177
// use the secret as bearer authentication according to OCM v1.1+
159178
c := gowebdav.NewClient(endpoint, "", "")
160179
c.SetHeader("Authorization", "Bearer "+secret)
180+
_, err = c.Stat(rel)
181+
if err != nil {
182+
// if we got an error, try to use OCM v1.0 basic auth
183+
log.Info().Str("endpoint", endpoint).Interface("share", share).Str("rel", rel).Str("secret", secret).Err(err).Msg("falling back to OCM v1.0 access")
184+
c.SetHeader("Authorization", "Basic "+secret+":")
185+
} else {
186+
log.Info().Str("endpoint", endpoint).Interface("share", share).Str("rel", rel).Str("secret", secret).Msg("using OCM v1.1 access")
187+
}
161188

162-
log := appctx.GetLogger(ctx)
163-
log.Info().Str("endpoint", endpoint).Interface("share", share).Str("rel", rel).Str("secret", secret).Msg("Accessing OCM share")
189+
// add to cache and return
190+
d.ccache[id.OpaqueId] = &cachedClient{
191+
client: c,
192+
expiresAt: time.Now().Add(1 * time.Hour),
193+
share: share,
194+
}
164195
return c, share, rel, nil
165196
}
166197

@@ -414,3 +445,26 @@ func (d *driver) CreateStorageSpace(ctx context.Context, req *provider.CreateSto
414445
func (d *driver) UpdateStorageSpace(ctx context.Context, req *provider.UpdateStorageSpaceRequest) (*provider.UpdateStorageSpaceResponse, error) {
415446
return nil, errtypes.NotSupported("operation not supported")
416447
}
448+
449+
// Cleanup function to remove expired cache entries
450+
func (d *driver) cleanupCache() {
451+
d.mu.Lock()
452+
defer d.mu.Unlock()
453+
454+
now := time.Now()
455+
for key, entry := range d.ccache {
456+
if now.After(entry.expiresAt) {
457+
delete(d.ccache, key)
458+
}
459+
}
460+
}
461+
462+
// Periodic cache cleanup goroutine
463+
func (d *driver) ccacheCleanupThread() {
464+
ticker := time.NewTicker(1 * time.Hour)
465+
defer ticker.Stop()
466+
467+
for range ticker.C {
468+
d.cleanupCache()
469+
}
470+
}

0 commit comments

Comments
 (0)