1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00
kube-arangodb/integrations/authentication/v1/cache.go
2024-03-08 12:01:36 +01:00

144 lines
2.6 KiB
Go

//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package v1
import (
"io"
"os"
"path"
"sort"
"time"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
)
const MaxSize = 128
type cache struct {
parent *implementation
eol time.Time
signingToken []byte
validationTokens [][]byte
}
func (i *implementation) newCache(cfg Configuration) (*cache, error) {
files, err := os.ReadDir(i.cfg.Path)
if err != nil {
return nil, err
}
var keys []string
var tokens = make(map[string][]byte)
for _, file := range files {
if file.IsDir() {
continue
}
data, err := util.OpenWithRead(path.Join(i.cfg.Path, file.Name()), MaxSize)
if err != nil {
continue
}
if len(data) == 0 {
continue
}
buff := make([]byte, cfg.Create.MaxSize)
for id := range buff {
buff[id] = 0
}
copy(buff, data)
keys = append(keys, file.Name())
tokens[file.Name()] = buff
}
if len(keys) == 0 {
return nil, io.ErrUnexpectedEOF
}
sort.Strings(keys)
data := make([][]byte, len(keys))
for id := range data {
data[id] = tokens[keys[id]]
}
cache := cache{
parent: i,
eol: time.Now().Add(i.cfg.TTL),
signingToken: tokens[keys[0]],
validationTokens: data,
}
return &cache, nil
}
func (i *implementation) localGetCache() *cache {
if c := i.cache; c != nil && c.eol.After(time.Now()) {
return c
}
return nil
}
func (i *implementation) withCache() (*cache, error) {
if c := i.getCache(); c != nil {
return c, nil
}
return i.refreshCache()
}
func (i *implementation) getCache() *cache {
i.lock.RLock()
defer i.lock.RUnlock()
return i.localGetCache()
}
func (i *implementation) refreshCache() (*cache, error) {
i.lock.Lock()
defer i.lock.Unlock()
if c := i.localGetCache(); c != nil {
return c, nil
}
// Get was not successful, retry
if c, err := i.newCache(i.cfg); err != nil {
return nil, err
} else if c == nil {
return nil, errors.Errorf("cache returned is nil")
} else {
i.cache = c
return i.cache, nil
}
}