瀏覽代碼

Updating the database code.

Locking was an issue.  I don't have a good filelock.
So, I use sqlite to handle my locking.
Steve Thielemann 3 年之前
父節點
當前提交
bcc1e97ec4
共有 3 個文件被更改,包括 247 次插入5 次删除
  1. 240 4
      db.go
  2. 4 1
      playcards.go
  3. 3 0
      space-ace.go

+ 240 - 4
db.go

@@ -3,6 +3,8 @@ package main
 import (
 	"database/sql"
 	"log"
+	"os"
+	"strconv"
 
 	_ "github.com/mattn/go-sqlite3"
 )
@@ -30,6 +32,10 @@ func (db *DBData) Close() {
 	db.DB.Close()
 }
 
+const LOCK_USERNAME = ""
+const LOCK_SETTING = "LOCK"
+const LOCK_CLEAR = "0"
+
 func (db *DBData) Create() {
 	_, err := db.DB.Exec(
 		"CREATE TABLE IF NOT EXISTS settings(username TEXT, setting TEXT, value TEXT, PRIMARY KEY(username, setting));")
@@ -37,20 +43,64 @@ func (db *DBData) Create() {
 		log.Panicln(err)
 	}
 	_, err = db.DB.Exec(
-		"CREATE TABLE IF NOT EXISTS scores ( \"username\" TEXT, \"when\" INTEGER, \"date\" INTEGER, \"hand\" INTEGER, \"won\" INTEGER, \"score\" INTEGER, PRIMARY KEY(\"username\", \"date\", \"hand\"));")
+		"CREATE TABLE IF NOT EXISTS scores ( username TEXT, `when` INTEGER, date INTEGER, hand INTEGER, won INTEGER, score INTEGER, PRIMARY KEY(username, date, hand));")
 	if err != nil {
 		log.Panicln(err)
 	}
 	_, err = db.DB.Exec(
-		"CREATE TABLE IF NOT EXISTS \"monthly\" ( \"month\"	INTEGER, \"username\" TEXT, \"days\" INTEGER, \"hands_won\" INTEGER, \"score\" INTEGER, PRIMARY KEY(\"month\",\"username\") );")
+		"CREATE TABLE IF NOT EXISTS monthly ( month	INTEGER, username TEXT, days INTEGER, hands_won INTEGER, score INTEGER, PRIMARY KEY(month, username) );")
 	if err != nil {
 		log.Panicln(err)
 	}
+	// Make sure our settings LOCK value exists
+	db.DB.Exec(
+		"INSERT INTO settings(username, setting, value) VALUES(?,?,?);",
+		LOCK_USERNAME, LOCK_SETTING, LOCK_CLEAR)
+	// An error here is OK.  It means the setting already exists.
+	/*
+		if err != nil {
+			log.Printf("LOCK %#v\n", err)
+		}
+	*/
+}
+
+func (db *DBData) Lock(value string) string {
+	_, err := db.DB.Exec("UPDATE settings SET value=? WHERE username=? AND setting=? AND value=?;",
+		value, LOCK_USERNAME, LOCK_SETTING, LOCK_CLEAR)
+	if err != nil {
+		log.Printf("Lock(%s) : %s\n", value, err)
+	}
+	row := db.DB.QueryRow("SELECT value FROM settings WHERE username=? AND setting=?;",
+		LOCK_USERNAME, LOCK_SETTING)
+	var result string
+	err = row.Scan(&result)
+	if err != nil {
+		log.Println("Lock Scan", err)
+	}
+	log.Printf("Lock(%s) = %s\n", value, result)
+	return result
+}
 
+func (db *DBData) Unlock(value string) bool {
+	_, err := db.DB.Exec("UPDATE settings SET value=? WHERE username=? AND setting=? AND value=?;",
+		LOCK_CLEAR, LOCK_USERNAME, LOCK_SETTING, value)
+	if err != nil {
+		log.Printf("Unlock(%s) : %s\n", value, err)
+	}
+	row := db.DB.QueryRow("SELECT value FROM settings WHERE username=? AND setting=?;",
+		LOCK_USERNAME, LOCK_SETTING)
+	var result string
+	err = row.Scan(&result)
+	if err != nil {
+		log.Println("Unlock Scan", err)
+	}
+	log.Printf("Unlock(%s) = %s\n", value, result)
+	return result == LOCK_CLEAR
 }
 
 func (db *DBData) GetSetting(setting string, ifMissing string) string {
-	row := db.DB.QueryRow("SELECT value FROM settings WHERE username=? AND setting=?;", db.User, setting)
+	row := db.DB.QueryRow("SELECT value FROM settings WHERE username=? AND setting=?;",
+		db.User, setting)
 	var value string
 	// log.Printf("row: %#v\n", row)
 	err := row.Scan(&value)
@@ -61,9 +111,195 @@ func (db *DBData) GetSetting(setting string, ifMissing string) string {
 }
 
 func (db *DBData) SetSetting(setting string, value string) {
-	_, err := db.DB.Exec("REPLACE INTO settings(username, setting, value) VALUES(?,?,?);", db.User, setting, value)
+	_, err := db.DB.Exec("REPLACE INTO settings(username, setting, value) VALUES(?,?,?);",
+		db.User, setting, value)
 	if err != nil {
 		log.Panicln("Query SetSetting", err)
 	}
 	// log.Printf("SetSetting %s %s = %s\n", db.User, setting, value)
 }
+
+func (db *DBData) SaveScore(when int64, date int64, hand int, won int, score int) {
+	_, err := db.DB.Exec("INSERT INTO scores(username, `when`, date, hand, won, score) VALUES(?,?,?,?,?,?);",
+		db.User, when, date, hand, won, score)
+	if err != nil {
+		log.Panicln("SaveScore", err)
+	}
+}
+
+func (db *DBData) HandsPlayedOnDay(day int64) int {
+	row := db.DB.QueryRow("SELECT COUNT(*) FROM scores WHERE username=? AND date=?;")
+	var value int
+	err := row.Scan(&value)
+	if err != nil {
+		return 0
+	}
+	return value
+}
+
+/*
+WhenPlayed = GetPlayed  (as far as I can tell...)
+*/
+func (db *DBData) WhenPlayed() map[int64]int {
+	var result map[int64]int = make(map[int64]int)
+
+	rows, err := db.DB.Query("SELECT date, COUNT(hand) FROM scores WHERE username=? GROUP BY date;",
+		db.User)
+	if err != nil {
+		log.Println("GetPlayed", err)
+		return result
+	}
+	defer rows.Close()
+
+	for rows.Next() {
+		var date int64
+		var hands int
+
+		if err := rows.Scan(&date, &hands); err != nil {
+			log.Println("GetPlayed Scan", err)
+			return result
+		}
+
+		result[date] = hands
+	}
+
+	if err = rows.Err(); err != nil {
+		log.Println("GetPlayed rows.Err", err)
+	}
+
+	return result
+}
+
+type MonthUser struct {
+	Date     int64
+	Username string
+}
+
+type MonthStats struct {
+	Days      int
+	Hands_Won int
+	Score     int
+}
+
+func (db *DBData) ExpireScores(month_first_t int64) {
+	// step 1: acquire lock
+	// ... step 0: find working lock strategy in go.  :(
+	// lockfile := lockedfile.Create("db.lock")
+	// defer lockfile.Close()
+	var pid string = strconv.Itoa(os.Getpid())
+
+	l := db.Lock(pid)
+
+	if l == pid {
+		log.Printf("Lock worked!\n")
+		defer db.Unlock(pid)
+	} else {
+		log.Printf("Lock failed [%s]\n", l)
+	}
+
+	// var Monthly map[MonthUser]MonthStats = make(map[MonthUser]MonthStats)
+
+}
+
+type ScoresDetails struct {
+	User  string
+	Date  int64
+	Hand  int
+	Won   int
+	Score int
+}
+
+func (db *DBData) GetScoresOnDay(date int64) []ScoresDetails {
+	var result []ScoresDetails
+	rows, err := db.DB.Query("SELECT username, date, hand, won, score FROM SCORES WHERE date=? ORDER BY username, hand;",
+		date)
+	if err != nil {
+		log.Println("GetScoresOnDay", date, err)
+		return result
+	}
+	defer rows.Close()
+
+	for rows.Next() {
+		var sd ScoresDetails
+
+		if err := rows.Scan(&sd.User, &sd.Date, &sd.Hand, &sd.Won, &sd.Score); err != nil {
+			log.Println("GetScoresOnDay Scan", err)
+			return result
+		}
+		result = append(result, sd)
+	}
+
+	if err = rows.Err(); err != nil {
+		log.Println("GetScoresOnDay rows.Err", err)
+	}
+	return result
+}
+
+type ScoresData struct {
+	Date  int64
+	User  string
+	Score int
+	Won   int
+}
+
+func (db *DBData) GetScores(limit int) []ScoresData {
+	var result []ScoresData
+
+	rows, err := db.DB.Query("SELECT date, username, SUM(score), SUM(won) FROM SCORES GROUP BY date, username ORDER BY SUM(score) DESC LIMIT ?;",
+		limit)
+	if err != nil {
+		log.Println("GetScores", err)
+		return result
+	}
+	defer rows.Close()
+
+	for rows.Next() {
+		var sd ScoresData
+
+		if err := rows.Scan(&sd.Date, &sd.User, &sd.Score, &sd.Won); err != nil {
+			log.Println("GetScores Scan", err)
+			return result
+		}
+		result = append(result, sd)
+	}
+
+	if err = rows.Err(); err != nil {
+		log.Println("GetScores rows.Err", err)
+	}
+	return result
+}
+
+type MonthlyData struct {
+	Date      int64
+	User      string
+	Days      int
+	Hands_Won int
+	Score     int
+}
+
+func (db *DBData) GetMonthlyScores(limit int) []MonthlyData {
+	var result []MonthlyData
+
+	rows, err := db.DB.Query("SELECT month, username, days, hands_won, score FROM monthly ORDER BY score DESC LIMIT ?;",
+		limit)
+	if err != nil {
+		log.Println("GetMonthlyScores", err)
+		return result
+	}
+	defer rows.Close()
+
+	for rows.Next() {
+		var md MonthlyData
+
+		if err := rows.Scan(&md.Date, &md.User, &md.Days, &md.Hands_Won, &md.Score); err != nil {
+			log.Println("GetMonthlyScores Scan", err)
+			return result
+		}
+		result = append(result, md)
+	}
+
+	if err = rows.Err(); err != nil {
+		log.Println("GetMonthlyScores rows.Err", err)
+	}
+	return result
+}

+ 4 - 1
playcards.go

@@ -809,6 +809,7 @@ Next_Hand:
 								// if r == 'D' ?
 
 								if r == 'Q' {
+									// this seemed odd.  We quit the game ?
 									r = 'Q'
 								}
 
@@ -860,10 +861,12 @@ Next_Hand:
 					pc.Door.Write(c.Output() + door.Reset)
 				}
 			}
+		} else {
+			in_game = false
 		}
 	}
 
-	return 0
+	return r
 }
 
 func (pc *PlayCards) Redraw(Dealing bool) {

+ 3 - 0
space-ace.go

@@ -468,6 +468,7 @@ func Configure(d *door.Door, db *DBData) {
 			if c > 0 {
 				db.SetSetting("DeckColor", DeckColors[c-1])
 			}
+			d.Write(door.CRNL)
 			press_a_key(d)
 		case 'V':
 			// View settings
@@ -624,6 +625,8 @@ func main() {
 	// Check for maint run -- get FirstOfMonthDate, and see if
 	// records are older then it is.  (If so, yes -- run maint)!
 
+	db.ExpireScores(0)
+
 	if last_call != 0 {
 		d.Write("Welcome Back!" + door.CRNL)
 		delta := now.Sub(time.Unix(last_call, 0))