~edwargix/tallyard

042450fd62421f65bf2644b2cc6e752a5f852f75 — David Florness 4 years ago 9dba2c2
Version the elections map
2 files changed, 60 insertions(+), 49 deletions(-)

M cmd/tallyard/main.go
M election/map.go
M cmd/tallyard/main.go => cmd/tallyard/main.go +1 -1
@@ 72,7 72,7 @@ func main() {
	}()
	client.Store = store

	elections, err := election.GetElections()
	elections, err := election.GetElectionsMap()
	if err != nil {
		panic(err)
	}

M election/map.go => election/map.go +59 -48
@@ 17,69 17,51 @@ import (

type ElectionsMap struct {
	sync.RWMutex
	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()
	// The version of the elections map.  If the version in the file doesn't
	// match the current version then we can give a clear error message
	// telling the user to update their file to the current version.  The
	// version in the file should only be different if there has been a
	// breaking change to the elections map format.
	Version int `json:"version"`

	// Maps election create event IDs to the corresponding election.
	M map[id.EventID]*Election `json:"elections"`

	// Maps room to a list of the room's elections, reverse sorted by
	// CreationTimestamp (i.e. newest to oldest).  Here for convenience.
	L map[id.RoomID][]*Election `json:"-"`
	// The latest time L was updated
	Ltime time.Time `json:"-"`

	// maps join event ID to voter. This is a convenience in scenarios when
	// we don't know the exact election
	Joins map[id.EventID]*Voter `json:"-"`
}

const electionsMapVersion = 1

var electionsFname = xdg.DataHome() + "/tallyard/elections.json"

func GetElections() (elections *ElectionsMap, err error) {
	elections = NewElectionsMap()
func GetElectionsMap() (em *ElectionsMap, err error) {
	em = &ElectionsMap{}
	if _, err = os.Stat(electionsFname); os.IsNotExist(err) {
		return elections, nil
		return newElectionsMap(), nil
	}
	jsonBytes, err := ioutil.ReadFile(electionsFname)
	if err != nil {
		return nil, fmt.Errorf("error reading data file %s: %s", electionsFname, err)
	}
	err = json.Unmarshal(jsonBytes, elections)
	err = json.Unmarshal(jsonBytes, em)
	if err != nil {
		return nil, fmt.Errorf("error unmarshalling data file: %s", err)
	}
	return
}

func NewElectionsMap() *ElectionsMap {
	em := &ElectionsMap{
		M:     make(map[id.EventID]*Election),
		L:     make(map[id.RoomID][]*Election, 0),
		Ltime: time.Now(),
		Joins: make(map[id.EventID]*Voter),
	}
	em.Save = func() {
		em.RLock()
		defer em.RUnlock()
		for _, el := range em.M {
			el.RLock()
			defer el.RUnlock()
		}
		jsonBytes, err := json.Marshal(em)
		if err != nil {
			log.Errorf("couldn't marshal elections: %s", err)
		}
		err = ioutil.WriteFile(electionsFname, jsonBytes, 0600)
		if err != nil {
			log.Errorf("couldn't save elections: %s", err)
		}
	}
	return em
}

func (em *ElectionsMap) MarshalJSON() ([]byte, error) {
	return json.Marshal(em.M)
}

func (em *ElectionsMap) UnmarshalJSON(b []byte) error {
	if err := json.Unmarshal(b, &em.M); err != nil {
		return err
	if em.Version != electionsMapVersion {
		return nil, fmt.Errorf("Your stored elections schema version (%d) is incompitable with the latest schema version (%d).",
			em.Version, electionsMapVersion)
	}
	em.L = make(map[id.RoomID][]*Election, 0)
	em.Ltime = time.Now()
	for createEventId, el := range em.M {
		em.insort(createEventId, el)
	}


@@ 90,7 72,36 @@ func (em *ElectionsMap) UnmarshalJSON(b []byte) error {
			em.Joins[joinEventId] = voter
		}
	}
	return nil
	return
}

func newElectionsMap() *ElectionsMap {
	return &ElectionsMap{
		Version: electionsMapVersion,
		M:       make(map[id.EventID]*Election),
		L:       make(map[id.RoomID][]*Election),
		Ltime:   time.Now(),
		Joins:   make(map[id.EventID]*Voter),
	}
}

func (em *ElectionsMap) Save() {
	em.RLock()
	defer em.RUnlock()
	for _, el := range em.M {
		el.RLock()
		defer el.RUnlock()
	}
	jsonBytes, err := json.Marshal(em)
	if err != nil {
		log.Errorf("couldn't marshal elections: %s", err)
		return
	}
	err = ioutil.WriteFile(electionsFname, jsonBytes, 0600)
	if err != nil {
		log.Errorf("couldn't save elections: %s", err)
		return
	}
}

func (em *ElectionsMap) Get(createEventID id.EventID) *Election {