blob: c09697f11469fe22667f5c2226980ef6463a1824 [file] [log] [blame]
package autoroll_modes
import (
"fmt"
"sync"
"time"
"go.skia.org/infra/go/sklog"
"go.skia.org/infra/go/util"
)
const (
MODE_HISTORY_LENGTH = 25
MODE_RUNNING = "running"
MODE_STOPPED = "stopped"
MODE_DRY_RUN = "dry run"
)
var (
VALID_MODES = []string{
MODE_RUNNING,
MODE_STOPPED,
MODE_DRY_RUN,
}
)
// ModeChange is a struct used for describing a change in the AutoRoll mode.
type ModeChange struct {
Message string `json:"message"`
Mode string `json:"mode"`
Time time.Time `json:"time"`
User string `json:"user"`
}
// Copy returns a copy of the ModeChange.
func (c *ModeChange) Copy() *ModeChange {
return &ModeChange{
Message: c.Message,
Mode: c.Mode,
Time: c.Time,
User: c.User,
}
}
// ModeHistory is a struct used for storing and retrieving mode change history.
type ModeHistory struct {
db *db
history []*ModeChange
mtx sync.RWMutex
}
// NewModeHistory returns a ModeHistory instance.
func NewModeHistory(dbFile string) (*ModeHistory, error) {
d, err := openDB(dbFile)
if err != nil {
return nil, err
}
mh := &ModeHistory{
db: d,
}
if err := mh.refreshHistory(); err != nil {
return nil, err
}
return mh, nil
}
// Close closes the database held by the ModeHistory.
func (mh *ModeHistory) Close() error {
return mh.db.Close()
}
// Add inserts a new ModeChange.
func (mh *ModeHistory) Add(m, user, message string) error {
if !util.In(m, VALID_MODES) {
return fmt.Errorf("Invalid mode: %s", m)
}
modeChange := &ModeChange{
Message: message,
Mode: m,
Time: time.Now(),
User: user,
}
mh.mtx.Lock()
defer mh.mtx.Unlock()
if err := mh.db.SetMode(modeChange); err != nil {
return err
}
return mh.refreshHistory()
}
// CurrentMode returns the current mode, which is the most recently added
// ModeChange.
func (mh *ModeHistory) CurrentMode() *ModeChange {
mh.mtx.RLock()
defer mh.mtx.RUnlock()
if len(mh.history) > 0 {
return mh.history[0].Copy()
} else {
sklog.Errorf("Mode history is empty even after initialization!")
return &ModeChange{
Message: "Mode history is empty!",
Mode: MODE_STOPPED,
Time: time.Now(),
User: "autoroller",
}
}
}
// GetHistory returns a slice of the most recent ModeChanges, most recent first.
func (mh *ModeHistory) GetHistory() []*ModeChange {
mh.mtx.RLock()
defer mh.mtx.RUnlock()
rv := make([]*ModeChange, 0, len(mh.history))
for _, m := range mh.history {
elem := new(ModeChange)
*elem = *m
rv = append(rv, elem)
}
return rv
}
// refreshHistory refreshes the mode history from the database. Assumes that the
// caller holds a write lock.
func (mh *ModeHistory) refreshHistory() error {
history, err := mh.db.GetModeHistory(MODE_HISTORY_LENGTH)
if err != nil {
return err
}
// If there's no history, set the initial mode.
if len(history) == 0 {
if err := mh.db.SetMode(&ModeChange{
Message: "Setting initial mode.",
Mode: MODE_RUNNING,
Time: time.Now(),
User: "AutoRoll Bot",
}); err != nil {
return err
}
history, err = mh.db.GetModeHistory(MODE_HISTORY_LENGTH)
if err != nil {
return err
}
}
mh.history = history
return nil
}