176 lines
4.3 KiB
Go
176 lines
4.3 KiB
Go
// NGnius 2020-01-30
|
|
|
|
package main // leadercraft-server
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"os/signal"
|
|
)
|
|
|
|
const (
|
|
// Version the current version
|
|
Version = "0.1"
|
|
// Name the program name
|
|
Name = "leadercraft-s"
|
|
)
|
|
|
|
var (
|
|
isClosing bool
|
|
printVersionAndExit bool
|
|
)
|
|
|
|
func init() {
|
|
initArgs()
|
|
}
|
|
|
|
func main() {
|
|
parseArgs()
|
|
sqlInitErr := sqlInit()
|
|
if sqlInitErr != nil {
|
|
fmt.Printf("Failed to initialise SQL connection: %s\n", sqlInitErr)
|
|
os.Exit(1)
|
|
}
|
|
// handle interrupt (terminate) signal
|
|
signalChan := make(chan os.Signal)
|
|
signal.Notify(signalChan, os.Interrupt)
|
|
go func() {
|
|
s := <-signalChan
|
|
fmt.Println("Received terminate signal " + s.String())
|
|
isClosing = true
|
|
sqlClose()
|
|
}()
|
|
// get new rankings
|
|
rows, err := db.Query("SELECT * FROM Entries WHERE rank=-1 ORDER BY time ASC;")
|
|
var players []int64
|
|
if err == nil {
|
|
// update rank for boards
|
|
var entries []*Entry
|
|
count := 0
|
|
for rows.Next() {
|
|
entries = append(entries, &Entry{})
|
|
scanErr := rows.Scan(entries[count].Intake()...)
|
|
if scanErr == nil {
|
|
//fmt.Printf("Updating rank for entry %d in board %d from player %d\n", entries[count].ID, entries[count].Board, entries[count].Player)
|
|
if entries[count].Board > 2 { // ignore special boards
|
|
players = append(players, entries[count].Player)
|
|
}
|
|
updateBoardEntries(entries[count])
|
|
count++
|
|
} else {
|
|
fmt.Println(scanErr)
|
|
}
|
|
}
|
|
// update special boards
|
|
for _, elem := range players {
|
|
p := &Player{ID: elem}
|
|
err := p.Load()
|
|
if err == nil {
|
|
//fmt.Printf("Updating high score for player %d\n", p.ID)
|
|
updateMainRank(p)
|
|
} else {
|
|
fmt.Println(err)
|
|
}
|
|
}
|
|
} else {
|
|
fmt.Println(err)
|
|
}
|
|
}
|
|
|
|
func initArgs() {
|
|
flag.BoolVar(&printVersionAndExit, "version", false, "Print version and exit")
|
|
flag.StringVar(&sqlConnection, "conn", sqlConnectionDefault, "Database connection string")
|
|
flag.StringVar(&sqlServer, "sql", sqlServerDefault, "SQL Database type")
|
|
}
|
|
|
|
func parseArgs() {
|
|
flag.Parse()
|
|
if printVersionAndExit {
|
|
fmt.Println(Name + " v" + Version)
|
|
os.Exit(0)
|
|
}
|
|
}
|
|
|
|
func updateBoardEntries(entry *Entry) {
|
|
// get nearest entry that's lower and steal it's rank
|
|
nearestEntry := &Entry{}
|
|
scanErr := db.QueryRow("SELECT * FROM Entries WHERE score < $1 AND rank!= -1 AND board=$2 ORDER BY score DESC LIMIT 1;", entry.Score, entry.Board).Scan(nearestEntry.Intake()...)
|
|
if scanErr == nil {
|
|
entry.Rank = nearestEntry.Rank
|
|
entry.Commit()
|
|
// update all ranks lower than itself
|
|
tx, _ := db.Begin()
|
|
stmt, _ := tx.Prepare("UPDATE Entries SET rank=rank+1 WHERE rank >=$1 AND id!=$2 AND board=$3;")
|
|
_, err := stmt.Exec(entry.Rank, entry.ID, entry.Board)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
fmt.Println(err)
|
|
} else {
|
|
tx.Commit()
|
|
}
|
|
} else {
|
|
// nothing to beat
|
|
scanErr = db.QueryRow("SELECT * FROM Entries WHERE score >= $1 AND rank!= -1 AND board=$2 ORDER BY score ASC LIMIT 1;", entry.Score, entry.Board).Scan(nearestEntry.Intake()...)
|
|
if scanErr == nil {
|
|
entry.Rank = nearestEntry.Rank + 1
|
|
entry.Commit()
|
|
} else {
|
|
// no other entries
|
|
entry.Rank = 1
|
|
entry.Commit()
|
|
}
|
|
}
|
|
}
|
|
|
|
func updateMainRank(p *Player) {
|
|
rows, err := db.Query("SELECT * FROM Entries WHERE player = $1 AND board > 2 ORDER BY score DESC LIMIT $2;", p.ID, 100)
|
|
var count int64 = 0
|
|
var sum int64 = 0
|
|
if err == nil {
|
|
for rows.Next() {
|
|
entry := &Entry{}
|
|
scanErr := rows.Scan(entry.Intake()...)
|
|
if scanErr == nil {
|
|
count++
|
|
sum += entry.Score
|
|
} else {
|
|
fmt.Println(scanErr)
|
|
return
|
|
}
|
|
}
|
|
if count > 0 && sum > 0 {
|
|
mainEntry := &Entry{
|
|
Player: p.ID,
|
|
Board: 1,
|
|
}
|
|
average := sum / count
|
|
//fmt.Printf("Average of %d/%d is %d\n", sum, count, average)
|
|
dne := db.QueryRow("SELECT * FROM Entries WHERE board=$1 AND player=$2", 1, p.ID).Scan(mainEntry.Intake()...)
|
|
if dne == nil {
|
|
tx, _ := db.Begin()
|
|
stmt, _ := tx.Prepare("UPDATE Entries SET rank=rank-1 WHERE rank >$1 AND id!=$2 AND board=$3;")
|
|
_, err := stmt.Exec(mainEntry.Rank, mainEntry.ID, 1)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
fmt.Println(err)
|
|
return // abort
|
|
} else {
|
|
tx.Commit()
|
|
}
|
|
mainEntry.Score = average
|
|
mainEntry.Rank = -1
|
|
mainEntry.Commit()
|
|
} else {
|
|
createErr := newEntrySql(average, p.ID, 1)
|
|
if createErr == nil {
|
|
fmt.Println(createErr)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
}
|