@@ 1,7 1,9 @@
package main
import (
+ "encoding/json"
"fmt"
+ "io/ioutil"
"os"
"time"
@@ 28,9 30,7 @@ func main() {
log.Errorf("failed to open logging file; using default stderr: %s", err)
}
log.Info("tallyard starting...")
- defer func() {
- log.Info("tallyard exiting...")
- }()
+ defer log.Info("tallyard exiting...")
authInfo, err := GetAuthInfo()
if err != nil {
@@ 46,14 46,12 @@ func main() {
setDeviceName(client, authInfo.DeviceID)
// setup the elections store
- elections, err := election.GetElectionsMap(client.UserID)
+ elections, err := getElections(authInfo.UserID)
if err != nil {
panic(err)
}
client.Store = matrix.NewTallyardStore(elections)
- defer func() {
- elections.Save()
- }()
+ defer elections.Save()
syncer := client.Syncer.(*mautrix.DefaultSyncer)
syncer.OnEvent(debugEventHook)
@@ 207,3 205,43 @@ func setDeviceName(client *mautrix.Client, deviceID id.DeviceID) {
log.Warnf("couldn't set device display name: %s", err)
}
}
+
+var electionsFname = xdg.DataHome() + "/tallyard/elections.json"
+
+func getElections(userID id.UserID) (*election.ElectionsMap, error) {
+ if _, err := os.Stat(electionsFname); os.IsNotExist(err) {
+ return election.NewElectionsMap(userID, saveElections), nil
+ } else if err != nil {
+ return nil, fmt.Errorf("couldn't stat elections file: %s", err)
+ }
+
+ jsonBytes, err := ioutil.ReadFile(electionsFname)
+ if err != nil {
+ return nil, fmt.Errorf("couldn't read elections file: %s", err)
+ }
+
+ em, err := election.ReadElectionsMapFrom(jsonBytes, userID, saveElections)
+ if err != nil {
+ return nil, fmt.Errorf("couldn't read elections map: %s", err)
+ }
+
+ return em, nil
+}
+
+func saveElections(em *election.ElectionsMap) {
+ em.RLock()
+ defer em.RUnlock()
+ for _, el := range em.Elections {
+ 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)
+ }
+ log.Info("saved elections map")
+}
@@ 3,13 3,10 @@ package election
import (
"encoding/json"
"fmt"
- "io/ioutil"
- "os"
"sort"
"sync"
"time"
- "github.com/kyoh86/xdg"
log "github.com/sirupsen/logrus"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/id"
@@ 36,24 33,29 @@ type ElectionsMap struct {
// GUIs. Ltime represents the latest time L was updated.
L map[id.RoomID][]*Election `json:"-"`
Ltime time.Time `json:"-"`
+ // hook given by parent code to save elections (e.g. to disk)
+ save func(*ElectionsMap) `json:"-"`
}
const electionsMapVersion = 5
-var electionsFname = xdg.DataHome() + "/tallyard/elections.json"
-
-func GetElectionsMap(userID id.UserID) (*ElectionsMap, error) {
- if _, err := os.Stat(electionsFname); os.IsNotExist(err) {
- return newElectionsMap(userID), nil
+func NewElectionsMap(userID id.UserID, save func(*ElectionsMap)) *ElectionsMap {
+ return &ElectionsMap{
+ Version: electionsMapVersion,
+ Elections: make(map[id.EventID]*Election),
+ L: make(map[id.RoomID][]*Election),
+ Ltime: time.Now(),
+ Rooms: make(map[id.RoomID]*mautrix.Room),
+ UserID: userID,
+ save: save,
}
+}
+
+func ReadElectionsMapFrom(jsonBytes []byte, userID id.UserID, save func(*ElectionsMap)) (*ElectionsMap, error) {
em := &ElectionsMap{}
- jsonBytes, err := ioutil.ReadFile(electionsFname)
- if err != nil {
- return nil, fmt.Errorf("error reading data file %s: %s", electionsFname, err)
- }
- err = json.Unmarshal(jsonBytes, em)
+ err := json.Unmarshal(jsonBytes, em)
if err != nil {
- return nil, fmt.Errorf("error unmarshalling data file: %s", err)
+ return nil, fmt.Errorf("error unmarshalling elections: %s", err)
}
if em.Version != electionsMapVersion {
return nil, fmt.Errorf("Your stored elections schema version (%d) is incompitable with the latest schema version (%d).",
@@ 66,6 68,7 @@ func GetElectionsMap(userID id.UserID) (*ElectionsMap, error) {
// set runtime attributes for elections
em.L = make(map[id.RoomID][]*Election, 0)
em.Ltime = time.Now()
+ em.save = save
storedElections := em.Elections
em.Elections = make(map[id.EventID]*Election, len(storedElections))
for _, el := range storedElections {
@@ 92,33 95,8 @@ func (em *ElectionsMap) UnmarshalJSON(b []byte) error {
return nil
}
-func newElectionsMap(userID id.UserID) *ElectionsMap {
- return &ElectionsMap{
- Version: electionsMapVersion,
- Elections: make(map[id.EventID]*Election),
- L: make(map[id.RoomID][]*Election),
- Ltime: time.Now(),
- Rooms: make(map[id.RoomID]*mautrix.Room),
- UserID: userID,
- }
-}
-
func (em *ElectionsMap) Save() {
- em.RLock()
- defer em.RUnlock()
- for _, el := range em.Elections {
- 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)
- }
- log.Info("saved elections map")
+ em.save(em)
}
func (em *ElectionsMap) GetElection(createID id.EventID) *Election {