~edwargix/tallyard

81a358ed267bd6f54408f622c7b1964f681b0488 — David Florness 4 years ago f6ac62b
Save election data in separate file
4 files changed, 67 insertions(+), 35 deletions(-)

M cmd/tallyard/main.go
M election/map.go
M election/voter.go
M matrix/data.go
M cmd/tallyard/main.go => cmd/tallyard/main.go +11 -19
@@ 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)

M election/map.go => election/map.go +44 -2
@@ 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) {

M election/voter.go => election/voter.go +3 -3
@@ 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
}


M matrix/data.go => matrix/data.go +9 -11
@@ 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