mirror of https://github.com/dirtbags/moth.git
commit
e286f265b9
|
@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Handle cases where non-legacy puzzles don't have an `author` attribute
|
- Handle cases where non-legacy puzzles don't have an `author` attribute
|
||||||
- Handle YAML-formatted file and script lists as expected
|
- Handle YAML-formatted file and script lists as expected
|
||||||
- YAML-formatted example puzzle actually works as expected
|
- YAML-formatted example puzzle actually works as expected
|
||||||
|
- points.log will now always be sorted chronologically
|
||||||
|
|
||||||
## [3.4.3] - 2019-11-20
|
## [3.4.3] - 2019-11-20
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -37,6 +37,7 @@ type Instance struct {
|
||||||
nextAttempt map[string]time.Time
|
nextAttempt map[string]time.Time
|
||||||
nextAttemptMutex *sync.RWMutex
|
nextAttemptMutex *sync.RWMutex
|
||||||
mux *http.ServeMux
|
mux *http.ServeMux
|
||||||
|
PointsMux *sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Instance) Initialize() error {
|
func (ctx *Instance) Initialize() error {
|
||||||
|
@ -54,6 +55,7 @@ func (ctx *Instance) Initialize() error {
|
||||||
ctx.nextAttempt = map[string]time.Time{}
|
ctx.nextAttempt = map[string]time.Time{}
|
||||||
ctx.nextAttemptMutex = new(sync.RWMutex)
|
ctx.nextAttemptMutex = new(sync.RWMutex)
|
||||||
ctx.mux = http.NewServeMux()
|
ctx.mux = http.NewServeMux()
|
||||||
|
ctx.PointsMux = new(sync.RWMutex)
|
||||||
|
|
||||||
ctx.BindHandlers()
|
ctx.BindHandlers()
|
||||||
ctx.MaybeInitialize()
|
ctx.MaybeInitialize()
|
||||||
|
@ -83,7 +85,11 @@ func (ctx *Instance) MaybeInitialize() {
|
||||||
// Remove any extant control and state files
|
// Remove any extant control and state files
|
||||||
os.Remove(ctx.StatePath("until"))
|
os.Remove(ctx.StatePath("until"))
|
||||||
os.Remove(ctx.StatePath("disabled"))
|
os.Remove(ctx.StatePath("disabled"))
|
||||||
|
|
||||||
|
ctx.PointsMux.Lock()
|
||||||
os.Remove(ctx.StatePath("points.log"))
|
os.Remove(ctx.StatePath("points.log"))
|
||||||
|
ctx.PointsMux.Unlock()
|
||||||
|
|
||||||
os.RemoveAll(ctx.StatePath("points.tmp"))
|
os.RemoveAll(ctx.StatePath("points.tmp"))
|
||||||
os.RemoveAll(ctx.StatePath("points.new"))
|
os.RemoveAll(ctx.StatePath("points.new"))
|
||||||
os.RemoveAll(ctx.StatePath("teams"))
|
os.RemoveAll(ctx.StatePath("teams"))
|
||||||
|
@ -156,6 +162,10 @@ func (ctx *Instance) PointsLog(teamId string) []*Award {
|
||||||
var ret []*Award
|
var ret []*Award
|
||||||
|
|
||||||
fn := ctx.StatePath("points.log")
|
fn := ctx.StatePath("points.log")
|
||||||
|
|
||||||
|
ctx.PointsMux.RLock()
|
||||||
|
defer ctx.PointsMux.RUnlock()
|
||||||
|
|
||||||
f, err := os.Open(fn)
|
f, err := os.Open(fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Unable to open %s: %s", fn, err)
|
log.Printf("Unable to open %s: %s", fn, err)
|
||||||
|
|
|
@ -4,9 +4,11 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -95,7 +97,7 @@ func (ctx *Instance) generatePointsLog(teamId string) []byte {
|
||||||
log.Printf("Marshalling points.js: %v", err)
|
log.Printf("Marshalling points.js: %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(teamId) == 0 {
|
if len(teamId) == 0 {
|
||||||
ctx.jPointsLog = jpl
|
ctx.jPointsLog = jpl
|
||||||
}
|
}
|
||||||
|
@ -203,6 +205,9 @@ func (ctx *Instance) readTeams() {
|
||||||
// collectPoints gathers up files in points.new/ and appends their contents to points.log,
|
// collectPoints gathers up files in points.new/ and appends their contents to points.log,
|
||||||
// removing each points.new/ file as it goes.
|
// removing each points.new/ file as it goes.
|
||||||
func (ctx *Instance) collectPoints() {
|
func (ctx *Instance) collectPoints() {
|
||||||
|
ctx.PointsMux.Lock()
|
||||||
|
defer ctx.PointsMux.Unlock()
|
||||||
|
|
||||||
logf, err := os.OpenFile(ctx.StatePath("points.log"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
logf, err := os.OpenFile(ctx.StatePath("points.log"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Can't append to points log: %s", err)
|
log.Printf("Can't append to points log: %s", err)
|
||||||
|
@ -248,6 +253,46 @@ func (ctx *Instance) collectPoints() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that points.log is sorted chronologically
|
||||||
|
func (ctx *Instance) sortPoints() {
|
||||||
|
var points []*Award
|
||||||
|
|
||||||
|
ctx.PointsMux.Lock()
|
||||||
|
defer ctx.PointsMux.Unlock()
|
||||||
|
|
||||||
|
logf, err := os.OpenFile(ctx.StatePath("points.log"), os.O_CREATE|os.O_RDWR, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Can't sort points.log: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer logf.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(logf)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
cur, err := ParseAward(line)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Encountered malformed award line, not sorting %s: %s", line, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
points = append(points, cur)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only sort and write to file if we need to
|
||||||
|
if ! sort.SliceIsSorted(points, func( i, j int) bool { return points[i].When.Before(points[j].When) }) {
|
||||||
|
|
||||||
|
sort.SliceStable(points, func(i, j int) bool { return points[i].When.Before(points[j].When) })
|
||||||
|
|
||||||
|
logf.Seek(0, io.SeekStart)
|
||||||
|
|
||||||
|
for i := range points {
|
||||||
|
point := points[i]
|
||||||
|
fmt.Fprintf(logf, "%s\n", point.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ctx *Instance) isEnabled() bool {
|
func (ctx *Instance) isEnabled() bool {
|
||||||
// Skip if we've been disabled
|
// Skip if we've been disabled
|
||||||
if _, err := os.Stat(ctx.StatePath("disabled")); err == nil {
|
if _, err := os.Stat(ctx.StatePath("disabled")); err == nil {
|
||||||
|
@ -293,6 +338,7 @@ func (ctx *Instance) Maintenance(maintenanceInterval time.Duration) {
|
||||||
ctx.tidy()
|
ctx.tidy()
|
||||||
ctx.readTeams()
|
ctx.readTeams()
|
||||||
ctx.collectPoints()
|
ctx.collectPoints()
|
||||||
|
ctx.sortPoints()
|
||||||
ctx.generatePuzzleList()
|
ctx.generatePuzzleList()
|
||||||
ctx.generatePointsLog("")
|
ctx.generatePointsLog("")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue