db.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. package main
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "log"
  6. "os"
  7. "strconv"
  8. "strings"
  9. "time"
  10. _ "github.com/mattn/go-sqlite3"
  11. )
  12. // Make sure the go-sqlite3 is here. Keep the db related things together.
  13. type DBData struct {
  14. DB *sql.DB
  15. User string
  16. LockValue string
  17. }
  18. func (db *DBData) Open(filename string) {
  19. var err error
  20. db.DB, err = sql.Open("sqlite3", filename)
  21. if err != nil {
  22. log.Panicln("Error Opening Sqlite3:", err)
  23. }
  24. // Create the tables (if needed)
  25. db.Create()
  26. }
  27. func (db *DBData) Close() {
  28. db.DB.Close()
  29. }
  30. const LOCK_USERNAME = ""
  31. const LOCK_SETTING = "LOCK"
  32. const LOCK_CLEAR = "0"
  33. func (db *DBData) Create() {
  34. _, err := db.DB.Exec(
  35. "CREATE TABLE IF NOT EXISTS settings(username TEXT, setting TEXT, value TEXT, PRIMARY KEY(username, setting));")
  36. if err != nil {
  37. log.Panicln(err)
  38. }
  39. _, err = db.DB.Exec(
  40. "CREATE TABLE IF NOT EXISTS scores ( username TEXT, `when` INTEGER, date INTEGER, hand INTEGER, won INTEGER, score INTEGER, PRIMARY KEY(username, date, hand));")
  41. if err != nil {
  42. log.Panicln(err)
  43. }
  44. _, err = db.DB.Exec(
  45. "CREATE TABLE IF NOT EXISTS monthly ( month INTEGER, username TEXT, days INTEGER, hands_won INTEGER, score INTEGER, PRIMARY KEY(month, username) );")
  46. if err != nil {
  47. log.Panicln(err)
  48. }
  49. // Make sure our settings LOCK value exists
  50. db.DB.Exec(
  51. "INSERT INTO settings(username, setting, value) VALUES(?,?,?);",
  52. LOCK_USERNAME, LOCK_SETTING, LOCK_CLEAR)
  53. // An error here is OK. It means the setting already exists.
  54. /*
  55. if err != nil {
  56. log.Printf("LOCK %#v\n", err)
  57. }
  58. */
  59. }
  60. func (db *DBData) Lock(timeout int) bool {
  61. var now time.Time = time.Now()
  62. var value string = fmt.Sprintf("%d,%d", os.Getpid(), now.Unix())
  63. RetryLock:
  64. _, err := db.DB.Exec("UPDATE settings SET value=? WHERE username=? AND setting=? AND value=?;",
  65. value, LOCK_USERNAME, LOCK_SETTING, LOCK_CLEAR)
  66. if err != nil {
  67. log.Printf("Lock(%s) : %s\n", value, err)
  68. }
  69. row := db.DB.QueryRow("SELECT value FROM settings WHERE username=? AND setting=?;",
  70. LOCK_USERNAME, LOCK_SETTING)
  71. var result string
  72. err = row.Scan(&result)
  73. if err != nil {
  74. log.Println("Lock Scan", err)
  75. }
  76. // I need to do further checking here -- to make sure the lock isn't stale.
  77. if result == value {
  78. // Success! We've got the lock!
  79. log.Printf("Lock [%s]\n", value)
  80. db.LockValue = value
  81. return true
  82. }
  83. // We failed. There's already a lock present. Check if it is stale.
  84. var lockSet string
  85. var pos int
  86. var howOld time.Duration
  87. pos = strings.Index(result, ",")
  88. if pos != -1 {
  89. lockSet = result[pos+1:]
  90. var unixtime int64
  91. unixtime, err = strconv.ParseInt(lockSet, 10, 64)
  92. if err == nil {
  93. var lockTime time.Time = time.Unix(unixtime, 0)
  94. howOld = now.Sub(lockTime)
  95. log.Printf("Lock %s [%0.2f seconds old]\n", result, howOld.Seconds())
  96. if howOld.Seconds() > 60 {
  97. // Lock expired
  98. log.Printf("Lock %s [%0.2f seconds old] -- Expiring\n", result, howOld.Seconds())
  99. db.DB.Exec("UPDATE settings SET value=? WHERE username=? AND setting=? AND value=?;",
  100. LOCK_CLEAR, LOCK_USERNAME, LOCK_SETTING, result)
  101. goto RetryLock
  102. }
  103. }
  104. } else {
  105. log.Printf("Can't find , in [%s]\n", result)
  106. }
  107. time.Sleep(time.Duration(50) * time.Millisecond)
  108. howOld = time.Until(now) // now.Sub(time.Now())
  109. if int(-howOld.Seconds()) > timeout {
  110. return false
  111. }
  112. goto RetryLock
  113. }
  114. func (db *DBData) Unlock() bool {
  115. if db.LockValue == "" {
  116. // Nothing to unlock -- we didn't get the lock.
  117. return true
  118. }
  119. _, err := db.DB.Exec("UPDATE settings SET value=? WHERE username=? AND setting=? AND value=?;",
  120. LOCK_CLEAR, LOCK_USERNAME, LOCK_SETTING, db.LockValue)
  121. if err != nil {
  122. log.Printf("Unlock(%s) : %s\n", db.LockValue, err)
  123. }
  124. row := db.DB.QueryRow("SELECT value FROM settings WHERE username=? AND setting=?;",
  125. LOCK_USERNAME, LOCK_SETTING)
  126. var result string
  127. err = row.Scan(&result)
  128. if err != nil {
  129. log.Println("Unlock Scan", err)
  130. }
  131. if result != LOCK_CLEAR {
  132. log.Printf("Unlock Failed (LockValue %s) Result %s (should be %s)\n", db.LockValue, result, LOCK_CLEAR)
  133. } else {
  134. log.Println("Unlocked.")
  135. }
  136. return result == LOCK_CLEAR
  137. }
  138. func (db *DBData) GetSetting(setting string, ifMissing string) string {
  139. row := db.DB.QueryRow("SELECT value FROM settings WHERE username=? AND setting=?;",
  140. db.User, setting)
  141. var value string
  142. // log.Printf("row: %#v\n", row)
  143. err := row.Scan(&value)
  144. if err != nil {
  145. return ifMissing
  146. }
  147. return value
  148. }
  149. func (db *DBData) SetSetting(setting string, value string) {
  150. _, err := db.DB.Exec("REPLACE INTO settings(username, setting, value) VALUES(?,?,?);",
  151. db.User, setting, value)
  152. if err != nil {
  153. log.Panicln("Query SetSetting", err)
  154. }
  155. // log.Printf("SetSetting %s %s = %s\n", db.User, setting, value)
  156. }
  157. func (db *DBData) SaveScore(when int64, date int64, hand int, won int, score int) {
  158. _, err := db.DB.Exec("INSERT INTO scores(username, `when`, date, hand, won, score) VALUES(?,?,?,?,?,?);",
  159. db.User, when, date, hand, won, score)
  160. if err != nil {
  161. log.Panicln("SaveScore", err)
  162. }
  163. }
  164. func (db *DBData) HandsPlayedOnDay(day int64) int {
  165. row := db.DB.QueryRow("SELECT COUNT(*) FROM scores WHERE username=? AND date=?;")
  166. var value int
  167. err := row.Scan(&value)
  168. if err != nil {
  169. return 0
  170. }
  171. return value
  172. }
  173. /*
  174. WhenPlayed = GetPlayed (as far as I can tell...)
  175. */
  176. func (db *DBData) WhenPlayed() map[int64]int {
  177. var result map[int64]int = make(map[int64]int)
  178. rows, err := db.DB.Query("SELECT date, COUNT(hand) FROM scores WHERE username=? GROUP BY date;",
  179. db.User)
  180. if err != nil {
  181. log.Println("GetPlayed", err)
  182. return result
  183. }
  184. defer rows.Close()
  185. for rows.Next() {
  186. var date int64
  187. var hands int
  188. if err := rows.Scan(&date, &hands); err != nil {
  189. log.Println("GetPlayed Scan", err)
  190. return result
  191. }
  192. result[date] = hands
  193. }
  194. if err = rows.Err(); err != nil {
  195. log.Println("GetPlayed rows.Err", err)
  196. }
  197. return result
  198. }
  199. type MonthUser struct {
  200. Date int64
  201. Username string
  202. }
  203. type MonthStats struct {
  204. Days int
  205. Hands_Won int
  206. Score int
  207. }
  208. func (db *DBData) ExpireScores(month_first_t int64) {
  209. // step 1: acquire lock
  210. l := db.Lock(5)
  211. if l {
  212. // log.Println("Locked")
  213. defer db.Unlock()
  214. } else {
  215. log.Println("Lock failed")
  216. return
  217. }
  218. // var Monthly map[MonthUser]MonthStats = make(map[MonthUser]MonthStats)
  219. }
  220. type ScoresDetails struct {
  221. User string
  222. Date int64
  223. Hand int
  224. Won int
  225. Score int
  226. }
  227. func (db *DBData) GetScoresOnDay(date int64) []ScoresDetails {
  228. var result []ScoresDetails
  229. rows, err := db.DB.Query("SELECT username, date, hand, won, score FROM SCORES WHERE date=? ORDER BY username, hand;",
  230. date)
  231. if err != nil {
  232. log.Println("GetScoresOnDay", date, err)
  233. return result
  234. }
  235. defer rows.Close()
  236. for rows.Next() {
  237. var sd ScoresDetails
  238. if err := rows.Scan(&sd.User, &sd.Date, &sd.Hand, &sd.Won, &sd.Score); err != nil {
  239. log.Println("GetScoresOnDay Scan", err)
  240. return result
  241. }
  242. result = append(result, sd)
  243. }
  244. if err = rows.Err(); err != nil {
  245. log.Println("GetScoresOnDay rows.Err", err)
  246. }
  247. return result
  248. }
  249. type ScoresData struct {
  250. Date int64
  251. User string
  252. Score int
  253. Won int
  254. }
  255. func (db *DBData) GetScores(limit int) []ScoresData {
  256. var result []ScoresData
  257. rows, err := db.DB.Query("SELECT date, username, SUM(score), SUM(won) FROM SCORES GROUP BY date, username ORDER BY SUM(score) DESC LIMIT ?;",
  258. limit)
  259. if err != nil {
  260. log.Println("GetScores", err)
  261. return result
  262. }
  263. defer rows.Close()
  264. for rows.Next() {
  265. var sd ScoresData
  266. if err := rows.Scan(&sd.Date, &sd.User, &sd.Score, &sd.Won); err != nil {
  267. log.Println("GetScores Scan", err)
  268. return result
  269. }
  270. result = append(result, sd)
  271. }
  272. if err = rows.Err(); err != nil {
  273. log.Println("GetScores rows.Err", err)
  274. }
  275. return result
  276. }
  277. type MonthlyData struct {
  278. Date int64
  279. User string
  280. Days int
  281. Hands_Won int
  282. Score int
  283. }
  284. func (db *DBData) GetMonthlyScores(limit int) []MonthlyData {
  285. var result []MonthlyData
  286. rows, err := db.DB.Query("SELECT month, username, days, hands_won, score FROM monthly ORDER BY score DESC LIMIT ?;",
  287. limit)
  288. if err != nil {
  289. log.Println("GetMonthlyScores", err)
  290. return result
  291. }
  292. defer rows.Close()
  293. for rows.Next() {
  294. var md MonthlyData
  295. if err := rows.Scan(&md.Date, &md.User, &md.Days, &md.Hands_Won, &md.Score); err != nil {
  296. log.Println("GetMonthlyScores Scan", err)
  297. return result
  298. }
  299. result = append(result, md)
  300. }
  301. if err = rows.Err(); err != nil {
  302. log.Println("GetMonthlyScores rows.Err", err)
  303. }
  304. return result
  305. }