@@ 7,6 7,7 @@ import (
"os"
"sort"
"sync"
+ "time"
log "github.com/sirupsen/logrus"
@@ 16,8 17,12 @@ import (
type ElectionsMap struct {
sync.RWMutex
- M map[id.EventID]*Election
- L []*Election // sorted list of elections by CreationTimestamp (newest to oldest)
+ M map[id.EventID]*Election
+
+ // by room, sorted list of elections by CreationTimestamp (newest to oldest)
+ L map[id.RoomID][]*Election
+ Ltime time.Time // last time list was update
+
Joins map[id.EventID]*Voter
Save func()
}
@@ 43,7 48,8 @@ func GetElections() (elections *ElectionsMap, err error) {
func NewElectionsMap() *ElectionsMap {
em := &ElectionsMap{
M: make(map[id.EventID]*Election),
- L: make([]*Election, 0),
+ L: make(map[id.RoomID][]*Election, 0),
+ Ltime: time.Now(),
Joins: make(map[id.EventID]*Voter),
}
em.Save = func() {
@@ 73,7 79,7 @@ func (em *ElectionsMap) UnmarshalJSON(b []byte) error {
if err := json.Unmarshal(b, &em.M); err != nil {
return err
}
- em.L = make([]*Election, 0)
+ em.L = make(map[id.RoomID][]*Election, 0)
for createEventId, el := range em.M {
em.insort(createEventId, el)
}
@@ 100,12 106,6 @@ func (em *ElectionsMap) GetOk(createEventID id.EventID) (*Election, bool) {
return el, ok
}
-func (em *ElectionsMap) GetI(i int) *Election {
- em.RLock()
- defer em.RUnlock()
- return em.L[i]
-}
-
func (em *ElectionsMap) SetIfNotExists(createEventID id.EventID, el *Election) {
em.Lock()
defer em.Save()
@@ 126,12 126,14 @@ func (em *ElectionsMap) set(createEventID id.EventID, el *Election) {
}
func (em *ElectionsMap) insort(createEventID id.EventID, el *Election) {
- i := sort.Search(len(em.L), func(i int) bool {
- return em.L[i].CreationTimestamp < el.CreationTimestamp
+ list := em.L[el.RoomID]
+ i := sort.Search(len(list), func(i int) bool {
+ return list[i].CreationTimestamp < el.CreationTimestamp
})
- newList := make([]*Election, len(em.L)+1)
- copy(newList[:i], em.L[:i])
+ newList := make([]*Election, len(list)+1)
+ copy(newList[:i], list[:i])
newList[i] = el
- copy(newList[i+1:], em.L[i:])
- em.L = newList
+ copy(newList[i+1:], list[i:])
+ em.L[el.RoomID] = newList
+ em.Ltime = time.Now()
}
@@ 70,15 70,17 @@ func RoomTUI(client *mautrix.Client, roomID id.RoomID, elections *election.Elect
app := tview.NewApplication()
list := tview.NewList().
AddItem("Create Election", "start a new election in this room", '+', nil)
- n := 0
+ var L []*election.Election
+ var Ltime time.Time = elections.Ltime.Add(-1 * time.Millisecond)
update := func() {
elections.RLock()
defer elections.RUnlock()
- if n == len(elections.L) {
+ if !Ltime.Before(elections.Ltime) {
return
}
- n = len(elections.L)
- for i, el := range elections.L {
+ L = elections.L[roomID]
+ Ltime = elections.Ltime
+ for i, el := range L {
title := el.Title
if title == "" {
title = "<no name>"
@@ 104,11 106,18 @@ func RoomTUI(client *mautrix.Client, roomID id.RoomID, elections *election.Elect
list.SetSelectedFunc(func(i int, _ string, _ string, _ rune) {
alive = false
app.Stop()
+ elections.RLock()
+ // don't do anything if the election under the cursor has
+ // changed
+ if Ltime.Before(elections.Ltime) && L[i] != elections.L[roomID][i] {
+ return
+ }
+ elections.RUnlock()
if i > 0 {
// user wants to join election
- el = elections.GetI(i - 1)
+ el = L[i - 1]
// don't need to lock because this goroutine controls LocalVoter
if el.LocalVoter != nil {
if el.LocalVoter.Ballot == nil {