1
0
mirror of https://github.com/alice-lg/alice-lg.git synced 2024-05-11 05:55:03 +00:00
alice-lg-alice-lg/pkg/store/sources_store.go

231 lines
5.0 KiB
Go
Raw Normal View History

2021-11-19 19:08:59 +01:00
package store
import (
2021-12-06 10:03:17 +01:00
"context"
2021-11-19 22:00:09 +01:00
"log"
2021-11-19 19:08:59 +01:00
"sync"
"time"
"github.com/alice-lg/alice-lg/pkg/config"
"github.com/alice-lg/alice-lg/pkg/sources"
)
// Store State Constants
const (
StateInit = iota
StateReady
2021-11-19 22:00:09 +01:00
StateBusy
2021-11-19 19:08:59 +01:00
StateError
)
2021-11-19 22:00:09 +01:00
// State is an enum of the above States
type State int
2021-11-19 19:08:59 +01:00
2021-11-19 22:00:09 +01:00
// String() converts a state into a string
func (s State) String() string {
switch s {
2021-11-19 19:08:59 +01:00
case StateInit:
return "INIT"
case StateReady:
return "READY"
2021-11-19 22:00:09 +01:00
case StateBusy:
return "BUSY"
2021-11-19 19:08:59 +01:00
case StateError:
return "ERROR"
}
return "INVALID"
}
2021-11-19 22:00:09 +01:00
// Status defines a status the store can be in
type Status struct {
RefreshInterval time.Duration
LastRefresh time.Time
LastRefreshDuration time.Duration
LastError interface{}
State State
2021-12-03 18:17:41 +01:00
Initialized bool
2021-11-19 22:00:09 +01:00
lastRefreshStart time.Time
}
2021-11-19 19:08:59 +01:00
// SourcesStore provides methods for retrieving
// the current status of a source.
type SourcesStore struct {
2021-11-19 22:00:09 +01:00
refreshInterval time.Duration
status map[string]*Status
sources map[string]*config.SourceConfig
2021-11-19 19:08:59 +01:00
sync.Mutex
}
// NewSourcesStore initializes a new source store
2021-11-19 22:00:09 +01:00
func NewSourcesStore(
cfg *config.Config,
refreshInterval time.Duration,
) *SourcesStore {
status := make(map[string]*Status)
sources := make(map[string]*config.SourceConfig)
// Add sources from config
for _, src := range cfg.Sources {
sourceID := src.ID
sources[sourceID] = src
status[sourceID] = &Status{
RefreshInterval: refreshInterval,
}
2021-11-19 19:08:59 +01:00
}
2021-11-19 22:00:09 +01:00
return &SourcesStore{
status: status,
sources: sources,
refreshInterval: refreshInterval,
}
2021-11-19 19:08:59 +01:00
}
// GetStatus will retrieve the status of a source
func (s *SourcesStore) GetStatus(sourceID string) (*Status, error) {
s.Lock()
defer s.Unlock()
return s.getStatus(sourceID)
}
// Internal getStatus
func (s *SourcesStore) getStatus(sourceID string) (*Status, error) {
status, ok := s.status[sourceID]
if !ok {
return nil, sources.ErrSourceNotFound
}
2021-11-19 22:00:09 +01:00
return status, nil
2021-11-19 19:08:59 +01:00
}
2021-12-03 18:17:41 +01:00
// IsInitialized will retrieve the status of the source
// and check if a successful refresh happend at least
// once.
func (s *SourcesStore) IsInitialized(sourceID string) (bool, error) {
s.Lock()
defer s.Unlock()
status, err := s.getStatus(sourceID)
if err != nil {
return false, err
}
return status.Initialized, nil
}
2021-11-19 22:21:18 +01:00
// NextRefresh calculates the next refresh time
2021-12-06 10:03:17 +01:00
func (s *SourcesStore) NextRefresh(ctx context.Context) time.Time {
2021-11-19 22:21:18 +01:00
status, err := s.GetStatus(sourceID)
if err != nil {
log.Println("get status error:", err)
2021-12-03 18:17:41 +01:00
return time.Time{}
2021-11-19 22:21:18 +01:00
}
nextRefresh := status.LastRefresh.Add(
s.refreshInterval)
return nextRefresh
}
2021-11-19 22:00:09 +01:00
// ShouldRefresh checks if the source needs a
2021-11-19 19:08:59 +01:00
// new refresh according to the provided refreshInterval.
2021-11-19 22:00:09 +01:00
func (s *SourcesStore) ShouldRefresh(
2021-11-19 19:08:59 +01:00
sourceID string,
) bool {
2021-11-19 22:00:09 +01:00
status, err := s.GetStatus(sourceID)
if err != nil {
log.Println("get status error:", err)
return false
2021-11-19 19:08:59 +01:00
}
2021-11-19 22:00:09 +01:00
if status.State == StateBusy {
2021-11-19 19:08:59 +01:00
return false // Source is busy
}
2021-11-19 22:00:09 +01:00
nextRefresh := status.LastRefresh.Add(
s.refreshInterval)
2021-11-19 19:08:59 +01:00
if time.Now().UTC().Before(nextRefresh) {
return false // Too soon
}
return true // Go for it
}
// GetInstance retrieves a source instance by ID
func (s *SourcesStore) GetInstance(sourceID string) sources.Source {
s.Lock()
defer s.Unlock()
return s.sources[sourceID].GetInstance()
}
// GetName retrieves a source name by ID
func (s *SourcesStore) GetName(sourceID string) string {
s.Lock()
defer s.Unlock()
return s.sources[sourceID].Name
}
2021-12-02 16:11:15 +01:00
// Get retrieves the source
func (s *SourcesStore) Get(sourceID string) *config.SourceConfig {
s.Lock()
defer s.Unlock()
return s.sources[sourceID]
}
2021-11-19 19:08:59 +01:00
// GetSourceIDs returns a list of registered source ids.
func (s *SourcesStore) GetSourceIDs() []string {
s.Lock()
defer s.Unlock()
ids := make([]string, 0, len(s.sources))
for id := range s.sources {
ids = append(ids, id)
}
return ids
}
// LockSource indicates the start of a refresh
func (s *SourcesStore) LockSource(sourceID string) error {
s.Lock()
defer s.Unlock()
status, err := s.getStatus(sourceID)
if err != nil {
return err
}
2021-11-19 22:00:09 +01:00
if status.State == StateBusy {
2021-11-19 19:08:59 +01:00
return sources.ErrSourceBusy
}
2021-11-19 22:00:09 +01:00
status.State = StateBusy
status.lastRefreshStart = time.Now()
2021-11-19 19:08:59 +01:00
return nil
}
2021-11-19 22:00:09 +01:00
// RefreshSuccess indicates a successfull update
// of the store's content.
func (s *SourcesStore) RefreshSuccess(sourceID string) error {
2021-11-19 19:08:59 +01:00
s.Lock()
defer s.Unlock()
2021-11-19 22:00:09 +01:00
status, err := s.getStatus(sourceID)
2021-11-19 19:08:59 +01:00
if err != nil {
return err
}
status.State = StateReady
2021-11-19 22:00:09 +01:00
status.LastRefresh = time.Now().UTC()
status.LastRefreshDuration = time.Now().Sub(
status.lastRefreshStart)
2021-11-19 19:08:59 +01:00
status.LastError = nil
2021-12-03 18:17:41 +01:00
status.Initialized = true // We now have data
2021-11-19 22:00:09 +01:00
return nil
2021-11-19 19:08:59 +01:00
}
2021-11-19 22:00:09 +01:00
// RefreshError indicates that the refresh has failed
func (s *SourcesStore) RefreshError(
sourceID string,
err interface{},
) {
2021-11-19 19:08:59 +01:00
s.Lock()
defer s.Unlock()
2021-11-19 22:00:09 +01:00
status, err := s.getStatus(sourceID)
2021-11-19 19:08:59 +01:00
if err != nil {
2021-11-19 22:00:09 +01:00
log.Println("error getting source status:", err)
return
2021-11-19 19:08:59 +01:00
}
status.State = StateError
2021-11-19 22:00:09 +01:00
status.LastRefresh = time.Now().UTC()
status.LastRefreshDuration = time.Now().Sub(
status.lastRefreshStart)
status.LastError = err
return
2021-11-19 19:08:59 +01:00
}