Follow the leader with help from a server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

sql_service.go 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. // NGnius 2020-02-11
  2. package main
  3. import (
  4. "database/sql"
  5. "fmt"
  6. "time"
  7. _ "github.com/lib/pq" // postgres
  8. _ "github.com/mattn/go-sqlite3" // sqlite
  9. )
  10. const (
  11. sqlServerDefault = "sqlite3"
  12. sqlConnectionDefault = "test.sqlite"
  13. )
  14. var (
  15. // command line arguments
  16. sqlServer string
  17. sqlConnection string
  18. buildTables bool
  19. populateTables bool
  20. autocreate bool
  21. // internal variables
  22. db *sql.DB
  23. queryType int
  24. queryStrings [][]string
  25. )
  26. func sqlInit() error {
  27. var dbOpenErr error
  28. if sqlServer == "postgres" {
  29. queryType = 1
  30. } else { // sqlite3
  31. queryType = 0
  32. }
  33. queryStrings = [][]string{
  34. []string{ // sqlite
  35. "SELECT * FROM Boards WHERE name=? LIMIT 1;",
  36. "SELECT * FROM Players WHERE name=? LIMTI 1;",
  37. "INSERT INTO Entries(score, player, board, time) VALUES (?, ?, ?, ?);",
  38. "INSERT INTO Keys(token, player, time) VALUES (?, ?, ?);",
  39. "SELECT * FROM Keys WHERE token=? AND player=? AND time=?",
  40. "SELECT * FROM Keys WHERE token=? LIMIT 1;",
  41. "SELECT * FROM Keys WHERE player=? LIMIT 1;",
  42. "SELECT * FROM Boards WHERE id=?",
  43. "INSERT OR REPLACE INTO Boards(id, name, description) VALUES (?, ?, ?);",
  44. "SELECT * FROM Entries WHERE board=?",
  45. "SELECT * FROM Entries WHERE board=? and rank >= ? and rank <= ? ORDER BY rank ASC;",
  46. "SELECT * FROM Players WHERE id=? LIMIT 1;",
  47. "INSERT OR REPLACE INTO Players(id, name) VALUES (?, ?);",
  48. "SELECT * FROM Entries WHERE player=?",
  49. "SELECT * FROM Entries WHERE player=? ORDER BY time DESC LIMIT ?;",
  50. "SELECT * FROM Entries WHERE id=? LIMIT 1;",
  51. "INSERT OR REPLACE INTO Entries(id, rank, score, player, board, time, metadata) VALUES (?, ?, ?, ?, ?, ?, ?);",
  52. "SELECT * FROM Keys WHERE id=? LIMIT 1;",
  53. "INSERT OR REPLACE INTO Keys(id, token, player, time, metadata) VALUES (?, ?, ?, ?, ?);",
  54. "CREATE TABLE IF NOT EXISTS Players (id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
  55. "CREATE TABLE IF NOT EXISTS Boards (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL);",
  56. "CREATE TABLE IF NOT EXISTS Entries (id INTEGER PRIMARY KEY, rank INTEGER NOT NULL DEFAULT -1, score INTEGER NOT NULL, player INTEGER NOT NULL, board INTEGER NOT NULL, time INTEGER NOT NULL, metadata BLOB NOT NULL DEFAULT x'FF', FOREIGN KEY(player) REFERENCES Players(id), FOREIGN KEY(board) REFERENCES Boards(id));",
  57. "CREATE TABLE IF NOT EXISTS Keys (id INTEGER PRIMARY KEY, token TEXT NOT NULL, player INTEGER NOT NULL, time INTEGER NOT NULL, metadata BLOB NOT NULL DEFAULT x'FF', FOREIGN KEY(player) REFERENCES Players(id));",
  58. },
  59. []string{ // postgres
  60. "SELECT * FROM Boards WHERE name=$1 LIMIT 1;",
  61. "SELECT * FROM Players WHERE name=$1 LIMTI 1;",
  62. "INSERT INTO Entries(score, player, board, time) VALUES ($1, $2, $3, $4);",
  63. "INSERT INTO Keys(token, player, time) VALUES ($1, $2, $3);",
  64. "SELECT * FROM Keys WHERE token=$1 AND player=$2 AND time=$3",
  65. "SELECT * FROM Keys WHERE token=$1 LIMIT 1;",
  66. "SELECT * FROM Keys WHERE player=$1 LIMIT 1;",
  67. "SELECT * FROM Boards WHERE id=$1",
  68. "INSERT INTO Boards(id, name, description) VALUES ($1, $2, $3) ON CONFLICT(id) DO UPDATE SET name=$2, description=$3;",
  69. "SELECT * FROM Entries WHERE board=$1",
  70. "SELECT * FROM Entries WHERE board=$1 and rank >= $2 and rank <= $3 ORDER BY rank ASC;",
  71. "SELECT * FROM Players WHERE id=$1 LIMIT 1;",
  72. "INSERT INTO Players(id, name) VALUES ($1, $2) ON CONFLICT(id) DO UPDATE SET name=$2;",
  73. "SELECT * FROM Entries WHERE player=$1",
  74. "SELECT * FROM Entries WHERE player=$1 ORDER BY time DESC LIMIT $2;",
  75. "SELECT * FROM Entries WHERE id=$1 LIMIT 1;",
  76. "INSERT INTO Entries(id, rank, score, player, board, time, metadata) VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT(id) DO UPDATE SET rank=$2, score=$3, player=$4, board=$5, time=$6, metadata=$7;",
  77. "SELECT * FROM Keys WHERE id=$1 LIMIT 1;",
  78. "INSERT INTO Keys(id, token, player, time, metadata) VALUES ($1, $2, $3, $4, $5) ON CONFLICT(id) DO UPDATE SET token=$2, player=$3, time=$4, metadata=$5;",
  79. "CREATE TABLE IF NOT EXISTS Players (id BIGSERIAL PRIMARY KEY, name TEXT NOT NULL);",
  80. "CREATE TABLE IF NOT EXISTS Boards (id BIGSERIAL PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL);",
  81. "CREATE TABLE IF NOT EXISTS Entries (id BIGSERIAL PRIMARY KEY, rank INTEGER NOT NULL DEFAULT -1, score BIGINT NOT NULL, player BIGSERIAL NOT NULL, board BIGSERIAL NOT NULL, time INTEGER NOT NULL, metadata BYTEA NOT NULL DEFAULT E'\\\\xFF', FOREIGN KEY(player) REFERENCES Players(id), FOREIGN KEY(board) REFERENCES Boards(id));",
  82. "CREATE TABLE IF NOT EXISTS Keys (id BIGSERIAL PRIMARY KEY, token TEXT NOT NULL, player BIGSERIAL NOT NULL, time BIGSERIAL NOT NULL, metadata BYTEA NOT NULL DEFAULT E'\\\\xFF', FOREIGN KEY(player) REFERENCES Players(id));",
  83. },
  84. }
  85. fmt.Printf("SQL Server %s is query type %d\n", sqlServer, queryType)
  86. //fmt.Println(len(queryStrings[queryType]))
  87. db, dbOpenErr = sql.Open(sqlServer, sqlConnection)
  88. if dbOpenErr != nil {
  89. return dbOpenErr
  90. }
  91. if buildTables {
  92. fmt.Println("Building tables in database...")
  93. sqlBuildTables()
  94. }
  95. if populateTables {
  96. fmt.Println("Populating tables in database...")
  97. sqlPopulateTables()
  98. }
  99. return nil
  100. }
  101. func sqlClose() error {
  102. if db != nil {
  103. err := db.Close()
  104. if err != nil {
  105. return err
  106. }
  107. db = nil
  108. }
  109. return nil
  110. }
  111. func boardByName(name string) (*Board, error) {
  112. b := &Board{}
  113. return b, db.QueryRow(queryStrings[queryType][0], name).Scan(b.Intake()...)
  114. }
  115. func playerByName(name string) (*Player, error) {
  116. p := &Player{}
  117. return p, db.QueryRow(queryStrings[queryType][1], name).Scan(p.Intake()...)
  118. }
  119. func newEntrySql(score, player, board int64) error {
  120. tx, _ := db.Begin()
  121. stmt, _ := tx.Prepare(queryStrings[queryType][2])
  122. _, err := stmt.Exec(score, player, board, time.Now().Unix())
  123. if err != nil {
  124. tx.Rollback()
  125. return err
  126. }
  127. tx.Commit()
  128. return nil
  129. }
  130. func newKeySql(player int64, name string) (*Key, error) {
  131. tx, _ := db.Begin()
  132. if autocreate {
  133. sqlPlayer := &Player{ID: player, Name: name}
  134. if (sqlPlayer.Load() != nil) {
  135. playerErr := sqlPlayer.Commit()
  136. if playerErr != nil {
  137. return nil, playerErr
  138. }
  139. }
  140. }
  141. newKey := &Key{Token: "new", Player: player, Time: time.Now().Unix()}
  142. stmt, _ := tx.Prepare(queryStrings[queryType][3])
  143. _, err := stmt.Exec(newKey.Token, newKey.Player, newKey.Time)
  144. if err != nil {
  145. tx.Rollback()
  146. return nil, err
  147. }
  148. tx.Commit()
  149. db.QueryRow(queryStrings[queryType][4], newKey.Token, newKey.Player, newKey.Time).Scan(newKey.Intake()...)
  150. tokenErr := newKey.GenerateToken()
  151. if tokenErr != nil {
  152. return nil, tokenErr
  153. }
  154. newKey.Metadata = []byte{0xFE} // enable key with not extra permissions
  155. return newKey, newKey.Commit()
  156. }
  157. func keyByToken(token string) (*Key, error) {
  158. k := &Key{}
  159. return k, db.QueryRow(queryStrings[queryType][5], token).Scan(k.Intake()...)
  160. }
  161. func keyByPlayer(player int64) (*Key, error) {
  162. k := &Key{}
  163. return k, db.QueryRow(queryStrings[queryType][6], player).Scan(k.Intake()...)
  164. }
  165. // internal operations
  166. func sqlBuildTables() {
  167. transaction, txErr := db.Begin()
  168. if txErr != nil {
  169. return
  170. }
  171. // test table
  172. //transaction.Exec("CREATE TABLE IF NOT EXISTS Test (Sometext VARCHAR, Somenumber);")
  173. //transaction.Exec("INSERT INTO Test (Sometext, Somenumber) VALUES (?,?);", "Hello sqlite", 123)
  174. // build real tables
  175. transaction.Exec(queryStrings[queryType][19])
  176. transaction.Exec(queryStrings[queryType][20])
  177. transaction.Exec(queryStrings[queryType][21])
  178. transaction.Exec(queryStrings[queryType][22])
  179. transaction.Commit()
  180. }
  181. func sqlPopulateTables() {
  182. boards := []*Board{
  183. &Board{ID: 1, Name: "main-test", Description: "Overall best (test data)"},
  184. &Board{ID: 2, Name: "coolest-test", Description: "Coolest score (test data)"},
  185. &Board{ID: 3, Name: "fastest-test", Description: "Fastest time (test data)"},
  186. }
  187. for _, b := range boards {
  188. err := b.Commit()
  189. if err != nil {
  190. fmt.Printf("Error creating board %d: %s\n", b.ID, err)
  191. }
  192. }
  193. players := []*Player{
  194. &Player{ID: 1, Name: "NGnius (test)"},
  195. &Player{ID: 2, Name: "Also NGnius (test)"},
  196. &Player{ID: 3, Name: ".xX||eDgY TeeNaGeR||Xx. (test)"},
  197. &Player{ID: 4, Name: "New username who dis? (test)"},
  198. &Player{ID: 5, Name: "Extremely Ridiculously Long Name to break things (test)"},
  199. &Player{ID: 6, Name: "P|P3 |o|z (test)"},
  200. &Player{ID: 7, Name: "Waldo (test)"},
  201. &Player{ID: 8, Name: "Zettagram.com (test)"},
  202. &Player{ID: 9, Name: "The Doctor (test)"},
  203. &Player{ID: 10, Name: "Marvin the Paranoid Android (test)"},
  204. &Player{ID: 11, Name: "IDK HOW (test)"},
  205. &Player{ID: 12, Name: "If you can read this your API may be wrong (test)"},
  206. &Player{ID: 13, Name: "Unlucky 7 (test)"},
  207. }
  208. for _, p := range players {
  209. err := p.Commit()
  210. if err != nil {
  211. fmt.Printf("Error creating player %d: %s\n", p.ID, err)
  212. }
  213. }
  214. now := time.Now().Unix()
  215. metadata := []byte{0x00, 0x00, 0x00, 0x00}
  216. entries := []*Entry{
  217. &Entry{ID: 1, Rank: 1, Score: 1000, Player: players[0].ID, Board: boards[0].ID, Time: now, Metadata: metadata},
  218. &Entry{ID: 2, Rank: 2, Score: 900, Player: players[1].ID, Board: boards[0].ID, Time: now, Metadata: metadata},
  219. &Entry{ID: 3, Rank: 3, Score: 400, Player: players[2].ID, Board: boards[0].ID, Time: now, Metadata: metadata},
  220. &Entry{ID: 4, Rank: 4, Score: 350, Player: players[3].ID, Board: boards[0].ID, Time: now, Metadata: metadata},
  221. &Entry{ID: 5, Rank: 5, Score: 350, Player: players[4].ID, Board: boards[0].ID, Time: now, Metadata: metadata},
  222. &Entry{ID: 6, Rank: 6, Score: 250, Player: players[5].ID, Board: boards[0].ID, Time: now, Metadata: metadata},
  223. &Entry{ID: 7, Rank: 7, Score: 200, Player: players[6].ID, Board: boards[0].ID, Time: now, Metadata: metadata},
  224. &Entry{ID: 8, Rank: 8, Score: 175, Player: players[7].ID, Board: boards[0].ID, Time: now, Metadata: metadata},
  225. &Entry{ID: 9, Rank: 9, Score: 150, Player: players[8].ID, Board: boards[0].ID, Time: now, Metadata: metadata},
  226. &Entry{ID: 10, Rank: 10, Score: 140, Player: players[9].ID, Board: boards[0].ID, Time: now, Metadata: metadata},
  227. &Entry{ID: 11, Rank: 11, Score: 10, Player: players[10].ID, Board: boards[0].ID, Time: now, Metadata: metadata},
  228. &Entry{ID: 12, Rank: 12, Score: 60, Player: players[11].ID, Board: boards[0].ID, Time: now, Metadata: metadata},
  229. &Entry{ID: 13, Rank: 13, Score: 13, Player: players[12].ID, Board: boards[0].ID, Time: now},
  230. }
  231. for _, e := range entries {
  232. err := e.Commit()
  233. if err != nil {
  234. fmt.Printf("Error creating entry %d: %s\n", e.ID, err)
  235. }
  236. }
  237. metadata = []byte{0x7E}
  238. keys := []*Key{
  239. &Key{ID: 1, Token: "", Player: players[0].ID, Time: now, Metadata: metadata},
  240. &Key{ID: 2, Token: "", Player: players[1].ID, Time: now, Metadata: metadata},
  241. }
  242. for _, k := range keys {
  243. genErr := k.GenerateToken()
  244. if genErr != nil {
  245. fmt.Printf("Error generating token for key %d, %s\n", k.ID, genErr)
  246. }
  247. //fmt.Printf("Key %d token: %s\n", k.ID, k.Token)
  248. err := k.Commit()
  249. if err != nil {
  250. fmt.Printf("Error creating key %d, %s\n", k.ID, err)
  251. }
  252. // bitwise op test
  253. //fmt.Printf("Key &d is superuser:%t, enabled:%t\n", k.ID, k.IsSuperuser(), k.IsEnabled())
  254. }
  255. }