Files
core/session/registry.go
2022-08-19 11:46:30 +03:00

194 lines
3.9 KiB
Go

package session
import (
"fmt"
"os"
"path/filepath"
"regexp"
"sync"
"github.com/datarhei/core/v16/log"
)
// Config is the configuration for creating a new registry
type Config struct {
// PersistDir is a path to the directory where the session
// history will be persisted. If it is an empty value, the
// history will not be persisted.
PersistDir string
// Logger is an instance of a logger. If it is nil, no logs
// will be written.
Logger log.Logger
}
type RegistryReader interface {
// Collectors returns an array of all registered IDs
Collectors() []string
// Collector returns the collector with the ID, or nil if the ID is not registered
Collector(id string) Collector
// Summary returns the summary from a collector with the ID, or an empty summary if the ID is not registered
Summary(id string) Summary
// Active returns the active sessions from a collector with the ID, or an empty list if the ID is not registered
Active(id string) []Session
}
// The Registry interface
type Registry interface {
// Register returns a new collector from conf and registers it under the id and error is nil. In case of error
// the returned collector is nil and the error is not nil.
Register(id string, conf CollectorConfig) (Collector, error)
// Unregister unregisters the collector with the ID, returns error if the ID is not registered
Unregister(id string) error
// UnregisterAll unregisters al registered collectors
UnregisterAll()
RegistryReader
}
type registry struct {
collector map[string]*collector
persistDir string
logger log.Logger
lock sync.Mutex
}
// New returns a new registry for collectors that implement the Registry interface. The error
// is non-nil if the PersistDir from the config can't be created.
func New(conf Config) (Registry, error) {
r := &registry{
collector: make(map[string]*collector),
persistDir: conf.PersistDir,
logger: conf.Logger,
}
if r.logger == nil {
r.logger = log.New("Session")
}
if len(r.persistDir) != 0 {
if err := os.MkdirAll(r.persistDir, 0700); err != nil {
return nil, err
}
}
return r, nil
}
func (r *registry) Register(id string, conf CollectorConfig) (Collector, error) {
if len(id) == 0 {
return nil, fmt.Errorf("invalid ID. empty IDs are not allowed")
}
re := regexp.MustCompile(`^[0-9A-Za-z]+$`)
if !re.MatchString(id) {
return nil, fmt.Errorf("invalid ID. only numbers and letters are allowed")
}
r.lock.Lock()
defer r.lock.Unlock()
_, ok := r.collector[id]
if ok {
return nil, fmt.Errorf("a collector with the ID '%s' already exists", id)
}
persistPath := ""
if len(r.persistDir) != 0 {
persistPath = filepath.Join(r.persistDir, id+".json")
}
m, err := newCollector(id, persistPath, r.logger, conf)
if err != nil {
return nil, err
}
m.start()
r.collector[id] = m
return m, nil
}
func (r *registry) Unregister(id string) error {
r.lock.Lock()
defer r.lock.Unlock()
m, ok := r.collector[id]
if !ok {
return fmt.Errorf("a collector with the ID '%s' doesn't exist", id)
}
m.Stop()
delete(r.collector, id)
return nil
}
func (r *registry) Collectors() []string {
collectors := []string{}
r.lock.Lock()
defer r.lock.Unlock()
for name := range r.collector {
collectors = append(collectors, name)
}
return collectors
}
func (r *registry) Collector(id string) Collector {
r.lock.Lock()
defer r.lock.Unlock()
m, ok := r.collector[id]
if !ok {
return nil
}
return m
}
func (r *registry) UnregisterAll() {
r.lock.Lock()
defer r.lock.Unlock()
for _, m := range r.collector {
m.Stop()
}
r.collector = make(map[string]*collector)
}
func (r *registry) Summary(id string) Summary {
r.lock.Lock()
defer r.lock.Unlock()
m, ok := r.collector[id]
if !ok {
return Summary{}
}
return m.Summary()
}
func (r *registry) Active(id string) []Session {
r.lock.Lock()
defer r.lock.Unlock()
m, ok := r.collector[id]
if !ok {
return []Session{}
}
return m.Active()
}