From 81a358ed267bd6f54408f622c7b1964f681b0488 Mon Sep 17 00:00:00 2001 From: David Florness Date: Tue, 19 Jan 2021 19:15:35 -0500 Subject: [PATCH] Save election data in separate file --- cmd/tallyard/main.go | 30 +++++++++++------------------ election/map.go | 46 ++++++++++++++++++++++++++++++++++++++++++-- election/voter.go | 6 +++--- matrix/data.go | 20 +++++++++---------- 4 files changed, 67 insertions(+), 35 deletions(-) diff --git a/cmd/tallyard/main.go b/cmd/tallyard/main.go index e2bb8ea..4caaffa 100644 --- a/cmd/tallyard/main.go +++ b/cmd/tallyard/main.go @@ -52,12 +52,10 @@ func main() { panic(err) } - if data.Elections == nil { - data.Elections = election.NewElectionsMap() + elections, err := election.GetElections() + if err != nil { + panic(err) } - data.Elections.SetSave(func() { - data.Save() - }) syncer := client.Syncer.(*mautrix.DefaultSyncer) syncer.OnEvent(client.Store.(*mautrix.InMemoryStore).UpdateState) @@ -67,8 +65,7 @@ func main() { log.Debug("redacted") return } - election.OnCreateElectionMessage(evt, data.Elections) - data.Save() + election.OnCreateElectionMessage(evt, elections) }) syncer.OnEventType(election.JoinElectionMessage, func(source mautrix.EventSource, evt *event.Event) { DebugCB(source, evt) @@ -76,8 +73,7 @@ func main() { log.Debug("redacted") return } - election.OnJoinElectionMessage(client, evt, data.Elections) - data.Save() + election.OnJoinElectionMessage(client, evt, elections) }) syncer.OnEventType(election.StartElectionMessage, func(source mautrix.EventSource, evt *event.Event) { DebugCB(source, evt) @@ -85,8 +81,7 @@ func main() { log.Debug("redacted") return } - election.OnStartElectionMessage(client, evt, data.Elections) - data.Save() + election.OnStartElectionMessage(client, evt, elections) }) syncer.OnEventType(election.EvalMessage, func(source mautrix.EventSource, evt *event.Event) { DebugCB(source, evt) @@ -94,8 +89,7 @@ func main() { log.Debug("redacted") return } - election.OnEvalMessage(client, evt, data.Elections) - data.Save() + election.OnEvalMessage(client, evt, elections) }) syncer.OnEventType(election.SumMessage, func(source mautrix.EventSource, evt *event.Event) { DebugCB(source, evt) @@ -103,8 +97,7 @@ func main() { log.Debug("redacted") return } - election.OnSumMessage(client, evt, data.Elections) - data.Save() + election.OnSumMessage(client, evt, elections) }) syncer.OnEventType(election.ResultMessage, func(source mautrix.EventSource, evt *event.Event) { DebugCB(source, evt) @@ -112,8 +105,7 @@ func main() { log.Debug("redacted") return } - election.OnResultMessage(client, evt, data.Elections) - data.Save() + election.OnResultMessage(client, evt, elections) }) go func() { @@ -128,7 +120,7 @@ func main() { } }() - el := ui.TUI(client, data.Elections) + el := ui.TUI(client, elections) if el == nil || el.LocalVoter.Ballot == nil { // user likely hit C-c return @@ -136,8 +128,8 @@ func main() { el.Lock() el.LocalVoter.Poly = math.NewRandomPoly(uint(len(*el.FinalVoters)-1), 1024, *el.LocalVoter.Ballot) - el.Save() el.Unlock() + el.Save() // TODO we may not have all voters' info err = el.SendEvals(client) diff --git a/election/map.go b/election/map.go index 219bc99..6171a72 100644 --- a/election/map.go +++ b/election/map.go @@ -2,9 +2,15 @@ package election import ( "encoding/json" + "fmt" + "io/ioutil" + "os" "sort" "sync" + log "github.com/sirupsen/logrus" + + "github.com/kyoh86/xdg" "maunium.net/go/mautrix/id" ) @@ -16,12 +22,47 @@ type ElectionsMap struct { Save func() } +var electionsFname = xdg.DataHome() + "/tallyard/elections.json" + +func GetElections() (elections *ElectionsMap, err error) { + elections = NewElectionsMap() + if _, err = os.Stat(electionsFname); os.IsNotExist(err) { + return elections, 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) + if err != nil { + return nil, fmt.Errorf("error unmarshalling data file: %s", err) + } + return +} + func NewElectionsMap() *ElectionsMap { - return &ElectionsMap{ + em := &ElectionsMap{ M: make(map[id.EventID]*Election), L: make([]*Election, 0), 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) { @@ -38,6 +79,7 @@ func (em *ElectionsMap) UnmarshalJSON(b []byte) error { } em.Joins = make(map[id.EventID]*Voter) for _, el := range em.M { + el.Save = em.Save for joinEventId, voter := range el.Joins { em.Joins[joinEventId] = voter } @@ -78,13 +120,13 @@ func (em *ElectionsMap) GetI(i int) *Election { func (em *ElectionsMap) SetIfNotExists(createEventID id.EventID, el *Election) { em.Lock() + defer em.Save() defer em.Unlock() _, exists := em.M[createEventID] if exists { return } em.set(createEventID, el) - em.Save() } func (em *ElectionsMap) set(createEventID id.EventID, el *Election) { diff --git a/election/voter.go b/election/voter.go index f45ae25..5012cd5 100644 --- a/election/voter.go +++ b/election/voter.go @@ -83,6 +83,7 @@ func (el *Election) JoinElection(client *mautrix.Client) error { } el.Lock() + defer el.Save() defer el.Unlock() resp, err := client.SendMessageEvent(el.RoomID, JoinElectionMessage, JoinElectionContent{ @@ -109,13 +110,13 @@ func (el *Election) JoinElection(client *mautrix.Client) error { PrivKey: *privKey, } el.Joins[resp.EventID] = el.LocalVoter.Voter - el.Save() return nil } func (el *Election) StartElection(client *mautrix.Client) error { // TODO err from this function if we didn't create the election el.Lock() + defer el.Save() defer el.Unlock() userIdMap := make(map[id.UserID]*Voter) // one vote per userID @@ -152,7 +153,6 @@ func (el *Election) StartElection(client *mautrix.Client) error { // OnStartElectionMessage(client, startEvt, elections) el.StartEvt = startEvt el.FinalVoters = &voters - el.Save() return nil } @@ -182,6 +182,7 @@ func (el *Election) WaitForVoters(client *mautrix.Client) error { func (el *Election) SendEvals(client *mautrix.Client) error { // this assumes we have all needed voter data el.Lock() + defer el.Save() defer el.Unlock() content := EvalMessageContent{ JoinEventId: el.LocalVoter.JoinEvt.ID, @@ -205,7 +206,6 @@ func (el *Election) SendEvals(client *mautrix.Client) error { el.LocalVoter.Eval = nil return err } - el.Save() return nil } diff --git a/matrix/data.go b/matrix/data.go index 65f97b2..70c0cd8 100644 --- a/matrix/data.go +++ b/matrix/data.go @@ -10,25 +10,23 @@ import ( "github.com/kyoh86/xdg" "maunium.net/go/mautrix" "maunium.net/go/mautrix/id" - "tallyard.xyz/election" ) type Data struct { - AccessToken string `json:"access_token"` - DeviceID id.DeviceID `json:"device_id"` - Elections *election.ElectionsMap `json:"elections,omitempty"` - Homeserver string `json:"homeserver"` - UserID id.UserID `json:"user_id"` - Username string `json:"username"` + AccessToken string `json:"access_token"` + DeviceID id.DeviceID `json:"device_id"` + Homeserver string `json:"homeserver"` + UserID id.UserID `json:"user_id"` + Username string `json:"username"` } var dataFname = xdg.DataHome() + "/tallyard/data.json" func GetData() (data *Data, err error) { if _, err = os.Stat(dataFname); os.IsNotExist(err) { - data, err = InquireForData() + data, err = inquireForData() if err == nil { - data.Save() + data.save() } return data, err } @@ -57,7 +55,7 @@ func stripNewline(s string) string { return s } -func InquireForData() (data *Data, err error) { +func inquireForData() (data *Data, err error) { var ( password string reader = bufio.NewReader(os.Stdin) @@ -113,7 +111,7 @@ func InquireForData() (data *Data, err error) { return data, nil } -func (data *Data) Save() error { +func (data *Data) save() error { jsonBytes, err := json.Marshal(*data) if err != nil { return err -- 2.38.4