@@ -26,6 +26,8 @@ import (
26
26
"net/url"
27
27
"path/filepath"
28
28
"strings"
29
+ "sync"
30
+ "time"
29
31
30
32
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
31
33
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
@@ -49,9 +51,17 @@ func init() {
49
51
registry .Register ("ocmreceived" , New )
50
52
}
51
53
54
+ type cachedClient struct {
55
+ client * gowebdav.Client
56
+ share * ocmpb.ReceivedShare
57
+ expiresAt time.Time
58
+ }
59
+
52
60
type driver struct {
53
61
c * config
54
62
gateway gateway.GatewayAPIClient
63
+ ccache map [string ]* cachedClient
64
+ mu sync.Mutex
55
65
}
56
66
57
67
type config struct {
@@ -78,8 +88,9 @@ func New(ctx context.Context, m map[string]interface{}) (storage.FS, error) {
78
88
d := & driver {
79
89
c : & c ,
80
90
gateway : gateway ,
91
+ ccache : make (map [string ]* cachedClient ), // this is a cache of webdav clients
81
92
}
82
-
93
+ go d . ccacheCleanupThread ()
83
94
return d , nil
84
95
}
85
96
@@ -106,7 +117,6 @@ func shareInfoFromReference(ref *provider.Reference) (*ocmpb.ShareId, string) {
106
117
}
107
118
108
119
func (d * driver ) getWebDAVFromShare (ctx context.Context , shareID * ocmpb.ShareId ) (* ocmpb.ReceivedShare , string , string , error ) {
109
- // TODO: we may want to cache the share
110
120
res , err := d .gateway .GetReceivedOCMShare (ctx , & ocmpb.GetReceivedOCMShareRequest {
111
121
Ref : & ocmpb.ShareReference {
112
122
Spec : & ocmpb.ShareReference_Id {
@@ -143,13 +153,22 @@ func getWebDAVProtocol(protocols []*ocmpb.Protocol) (*ocmpb.WebDAVProtocol, bool
143
153
}
144
154
145
155
func (d * driver ) webdavClient (ctx context.Context , ref * provider.Reference ) (* gowebdav.Client , * ocmpb.ReceivedShare , string , error ) {
156
+ log := appctx .GetLogger (ctx )
146
157
id , rel := shareInfoFromReference (ref )
147
158
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
148
168
share , endpoint , secret , err := d .getWebDAVFromShare (ctx , id )
149
169
if err != nil {
150
170
return nil , nil , "" , err
151
171
}
152
-
153
172
endpoint , err = url .PathUnescape (endpoint )
154
173
if err != nil {
155
174
return nil , nil , "" , err
@@ -158,9 +177,21 @@ func (d *driver) webdavClient(ctx context.Context, ref *provider.Reference) (*go
158
177
// use the secret as bearer authentication according to OCM v1.1+
159
178
c := gowebdav .NewClient (endpoint , "" , "" )
160
179
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
+ }
161
188
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
+ }
164
195
return c , share , rel , nil
165
196
}
166
197
@@ -414,3 +445,26 @@ func (d *driver) CreateStorageSpace(ctx context.Context, req *provider.CreateSto
414
445
func (d * driver ) UpdateStorageSpace (ctx context.Context , req * provider.UpdateStorageSpaceRequest ) (* provider.UpdateStorageSpaceResponse , error ) {
415
446
return nil , errtypes .NotSupported ("operation not supported" )
416
447
}
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