package state import ( "errors" "fmt" "time" "gitlab.com/whom/bingobot/internal/config" "gitlab.com/whom/bingobot/internal/logging" ) type VoteEvent map[string]string const ( VoteMissingKeyError = "vote data not found: " VoteCreatedKey = "created" VoteRequesterKey = "requester" VoteActionKey = "action" VoteResultKey = "result" VoteResultPass = "pass" VoteResultFail = "fail" VoteResultTie = "tie" VoteResultTimeout = "timeout" VoteBadResultError = "vote has invalid result: " VoteNotFinishedError = "vote has result but isnt finished" VoteMissingResultError = "vote finished but missing result" VoteStatusKey = "status" VoteStatusInProgress = "in_progress" VoteStatusFinalized = "finalized" VoteStatusTimeout = "timed_out" VoteBadStatusError = "vote has invalid status: " VeryOldVote = "1990-01-01T00:00:00Z" ) func (ve VoteEvent) Type() EventType { return Vote } func (ve VoteEvent) Time() time.Time { t, e := time.Parse(time.RFC3339, ve[VoteCreatedKey]) if e != nil { // we have a corrupted event // return old time so that this event gets // pruned from cache logging.Warn( "pruning corrupted vote event", "event", fmt.Sprintf("%+v", ve), ) tooOld, _ := time.Parse( time.RFC3339, VeryOldVote, ) return tooOld } return t } func (ve VoteEvent) Data() map[string]string { return map[string]string(ve) } func (ve VoteEvent) Validate() error { // make sure action, requester, and created are set for _, key := range []string{ VoteActionKey, VoteRequesterKey, VoteCreatedKey, VoteStatusKey, } { if _, found := ve[key]; !found { return errors.New(VoteMissingKeyError + key) } } status := ve[VoteStatusKey] if status != VoteStatusTimeout && status != VoteStatusInProgress && status != VoteStatusFinalized { return errors.New(VoteBadStatusError + status) } result, hasResult := ve[VoteResultKey] if hasResult && status == VoteStatusInProgress { return errors.New(VoteNotFinishedError) } if status != VoteStatusInProgress && !hasResult { return errors.New(VoteMissingResultError) } if hasResult && (result != VoteResultPass && result != VoteResultFail && result != VoteResultTie && result != VoteResultTimeout) { return errors.New(VoteBadResultError + result) } return nil } func (ve VoteEvent) Disposable() bool { // will be implemented with democracy module logging.Warn("unimplemented: VoteEvent::Disposable") return false } type UserEvent struct { uid string created time.Time } const ( UserEventUserKey = "user" UserEventCreatedKey = "created" UserEventBadUserError = "event has bad user" ) func (ue UserEvent) Time() time.Time { return ue.created } func (ue UserEvent) Data() map[string]string { return map[string]string{ UserEventUserKey: ue.uid, UserEventCreatedKey: ue.created.Format(time.RFC3339), } } func (ue UserEvent) Validate() error { // empty for now, we may do some validation later. return nil } func (ue UserEvent) Disposable() bool { // when I make a module for challenges, restorations, and UserActives // then I should implement this logging.Warn("unimplemented: UserEvent::Disposable") return false } type ChallengeEvent struct { UserEvent } func (ce ChallengeEvent) Type() EventType { return Challenge } func NewChallengeEvent(user string) ChallengeEvent { return ChallengeEvent{UserEvent{ uid: user, created: time.Now(), }} } type RestorationEvent struct { UserEvent } func (re RestorationEvent) Type() EventType { return Restoration } func NewRestorationEvent(user string) RestorationEvent { return RestorationEvent{UserEvent{ uid: user, created: time.Now(), }} } type UserActiveEvent struct { UserEvent } func (ua UserActiveEvent) Type() EventType { return UserActive } func (ua UserActiveEvent) Disposable() bool { return (time.Since(ua.created).Hours() / 24) >= float64(config.Get().UserEventLifespanDays) } func NewUserActiveEvent(user string) UserActiveEvent { return UserActiveEvent{UserEvent{ uid: user, created: time.Now(), }} } const ( TestEventDisposeKey = "dispose" TestEventIDKey = "id" ) type TestEvent struct { Dispose bool ID int } func (te TestEvent) Type() EventType { return Test } func (te TestEvent) Time() time.Time { return time.Now() } func (te TestEvent) Data() map[string]string { m := map[string]string{} if te.Dispose { m[TestEventDisposeKey] = "t" } m[TestEventIDKey] = fmt.Sprintf("%d", te.ID) return m } func (te TestEvent) Validate() error { return nil } func (te TestEvent) Disposable() bool { return te.Dispose }