Files

83 lines
1.8 KiB
Go

package config
import (
"context"
"errors"
"log/slog"
"sync"
"sync/atomic"
"charm.land/catwalk/pkg/catwalk"
"charm.land/catwalk/pkg/embedded"
)
type catwalkClient interface {
GetProviders(context.Context, string) ([]catwalk.Provider, error)
}
var _ syncer[[]catwalk.Provider] = (*catwalkSync)(nil)
type catwalkSync struct {
once sync.Once
result []catwalk.Provider
cache cache[[]catwalk.Provider]
client catwalkClient
autoupdate bool
init atomic.Bool
}
func (s *catwalkSync) Init(client catwalkClient, path string, autoupdate bool) {
s.client = client
s.cache = newCache[[]catwalk.Provider](path)
s.autoupdate = autoupdate
s.init.Store(true)
}
func (s *catwalkSync) Get(ctx context.Context) ([]catwalk.Provider, error) {
if !s.init.Load() {
panic("called Get before Init")
}
var throwErr error
s.once.Do(func() {
if !s.autoupdate {
slog.Info("Using embedded Catwalk providers")
s.result = embedded.GetAll()
return
}
cached, etag, cachedErr := s.cache.Get()
if len(cached) == 0 || cachedErr != nil {
// if cached file is empty, default to embedded providers
cached = embedded.GetAll()
}
slog.Info("Fetching providers from Catwalk")
result, err := s.client.GetProviders(ctx, etag)
if errors.Is(err, context.DeadlineExceeded) {
slog.Warn("Catwalk providers not updated in time")
s.result = cached
return
}
if errors.Is(err, catwalk.ErrNotModified) {
slog.Info("Catwalk providers not modified")
s.result = cached
return
}
if err != nil {
// On error, fall back to cached (which defaults to embedded if empty).
s.result = cached
return
}
if len(result) == 0 {
s.result = cached
throwErr = errors.New("empty providers list from catwalk")
return
}
s.result = result
throwErr = s.cache.Store(result)
})
return s.result, throwErr
}