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
2021-11-19 19:08:59 +01:00

182 lines
4.1 KiB
Go

package store
import (
"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
StateUpdatingNeighbors
StateUpdatingRoutes
StateError
)
// Status defines a status the store can be in
type Status struct {
LastNeighborsRefresh time.Time
LastRoutesRefresh time.Time
LastError error
State int
}
// stateToString converts a state into a string
func stateToString(state int) string {
switch state {
case StateInit:
return "INIT"
case StateReady:
return "READY"
case StateUpdating:
return "UPDATING"
case StateError:
return "ERROR"
}
return "INVALID"
}
// SourcesStore provides methods for retrieving
// the current status of a source.
type SourcesStore struct {
status map[string]*Status
sources map[string]*config.SourceConfig
sync.Mutex
}
// NewSourcesStore initializes a new source store
func NewSourcesStore() *SourcesStore {
return &SourcesStore{
status: make(map[string]*Status),
sources: make(map[string]*config.SourceConfig),
}
}
// AddSource registers the source
func (s *SourcesStore) AddSource(src *config.SourceConfig) {
s.Lock()
defer s.Unlock()
sourceID := src.ID
sources[sourceID] = src
status[sourceID] = &Status{}
}
// 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
}
}
// ShouldRefreshNeighbors checks if the source needs a
// new refresh according to the provided refreshInterval.
func (s *SourcesStore) ShouldRefreshNeighbors(
sourceID string,
interval time.Duration,
) bool {
status = s.GetStatus(sourceID)
if status.State == StateUpdating {
return false // Source is busy
}
nextRefresh := status.LastNeighborsRefresh.Add(interval)
if time.Now().UTC().Before(nextRefresh) {
return false // Too soon
}
return true // Go for it
}
// ShouldRefreshRoutes checks if the source needs a
// new refresh according to the provided refreshInterval.
func (s *SourcesStore) ShouldRefreshRoutes(
sourceID string, interval time.Duration,
) bool {
status = s.GetStatus(sourceID)
if status.State == StateUpdating {
return false // Source is busy
}
nextRefresh := status.LastRoutesRefresh.Add(interval)
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
}
// 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
}
if status.State == StateUpdating {
return sources.ErrSourceBusy
}
status.State = StateUpdating
return nil
}
// NeighborsRefreshSuccess indicates a successfull refresh
func (s *SourcesStore) NeighborsRefreshSuccess(sourceID string) error {
s.Lock()
defer s.Unlock()
status, err := getStatus(sourceID)
if err != nil {
return err
}
status.State = StateReady
status.LastNeighborsRefresh = time.Now().UTC()
status.LastError = nil
}
// NeighborsRefreshError indicates that the refresh has failed
func (s *SourcesStore) NeighborsRefreshError(sourceID string, err error) error {
s.Lock()
defer s.Unlock()
status, err := getStatus(sourceID)
if err != nil {
return err
}
status.State = StateError
status.LastNeighborsRefresh = time.Now().UTC()
status.LastError = err.String()
}