This repository was archived by the owner on Aug 15, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 605
Expand file tree
/
Copy pathcache.go
More file actions
146 lines (124 loc) · 3.28 KB
/
Copy pathcache.go
File metadata and controls
146 lines (124 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package api
import (
"errors"
"github.com/koding/cache"
)
// ErrSessionNotFound is returned by Storage.Get
// when requested session was not found.
var ErrSessionNotFound = errors.New("session not found")
// Storage is an interface for external session storage.
type Storage interface {
// Get gets a session.
//
// It returns ErrSessionNotFound if requested
// session was not cached.
Get(*User) (*Session, error)
// Set sets a session.
//
// It overwrites any session that may exist
// already.
Set(*Session) error
// Delete deletes a session.
//
// If requested session does not exist,
// the method is a nop.
Delete(*Session) error
}
// SessionCache is a wrapper for AuthFunc that caches
// sessions and invalidates them when requested.
type SessionCache struct {
// AuthFunc is a mean to obtain session information.
//
// It is only called when a session was requested
// for a user/team pair that is not cached yet.
// Or when we were explicitly asked to request
// new session with Refresh set to true.
AuthFunc AuthFunc
// Storage is an external storage for storing session.
//
// If nil, a default, in-memory map is going to be used instead.
Storage Storage
}
// NewCache gives new SessionCache value.
func NewCache(fn AuthFunc) *SessionCache {
return &SessionCache{
AuthFunc: fn,
Storage: newDefaultStorage(),
}
}
// Auth is a method, which method selector can be used
// as a AuthFunc value, like:
//
// cache := api.NewSessionCache(authFn)
//
// t := &api.Transport{
// AuthFunc: cache.Auth,
// }
//
func (s *SessionCache) Auth(opts *AuthOptions) (*Session, error) {
if !opts.Refresh {
session, err := s.Storage.Get(opts.User)
switch err {
case ErrSessionNotFound:
// continue
case nil:
return session, nil
default:
return nil, err
}
}
session, err := s.AuthFunc(opts)
// TODO(rjeczalik): for now we ignore storage errors,
// maybe we should handle them (fallback to memory?).
//
// - if storage failed to delete invalidated session,
// then the worst case any concurrent requests could
// try to use it again at most once.
//
// - if set failed, we are going to request session again
// for the next request
//
// System-wise Kloud uses in-memory cache while KD and Klient
// use BoltDB-backed cache. Since the latter two take exclusive
// lock of the database file, the only reason storage can
// fail are filesystem errors - there is no recovery from
// that, and falling back to memory makes sense only for
// Klient.
if opts.Refresh {
_ = s.Storage.Delete(session)
}
if err == nil {
_ = s.Storage.Set(session)
}
return session, err
}
type defaultStorage struct {
cache cache.Cache
}
var _ Storage = (*defaultStorage)(nil)
func newDefaultStorage() *defaultStorage {
return &defaultStorage{
cache: cache.NewLRU(2000),
}
}
func (ds *defaultStorage) Get(u *User) (*Session, error) {
s, err := ds.cache.Get(u.String())
if err == cache.ErrNotFound {
return nil, ErrSessionNotFound
}
if err != nil {
return nil, err
}
return s.(*Session), nil
}
func (ds *defaultStorage) Set(s *Session) error {
return ds.cache.Set(s.User.String(), s)
}
func (ds *defaultStorage) Delete(s *Session) error {
switch err := ds.cache.Delete(s.User.String()); err {
case cache.ErrNotFound:
return nil
default:
return err
}
}