persistence.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. package data
  2. import (
  3. "bytes"
  4. "database/sql"
  5. "encoding/gob"
  6. "sync"
  7. "time"
  8. // sqlite requires a blank import.
  9. _ "github.com/mattn/go-sqlite3"
  10. "github.com/owncast/owncast/config"
  11. "github.com/owncast/owncast/db"
  12. log "github.com/sirupsen/logrus"
  13. )
  14. // Datastore is the global key/value store for configuration values.
  15. type Datastore struct {
  16. DB *sql.DB
  17. cache map[string][]byte
  18. DbLock *sync.Mutex
  19. }
  20. func (ds *Datastore) warmCache() {
  21. log.Traceln("Warming config value cache")
  22. res, err := ds.DB.Query("SELECT key, value FROM datastore")
  23. if err != nil || res.Err() != nil {
  24. log.Errorln("error warming config cache", err, res.Err())
  25. }
  26. defer res.Close()
  27. for res.Next() {
  28. var rowKey string
  29. var rowValue []byte
  30. if err := res.Scan(&rowKey, &rowValue); err != nil {
  31. log.Errorln("error pre-caching config row", err)
  32. }
  33. ds.cache[rowKey] = rowValue
  34. }
  35. }
  36. // GetQueries will return the shared instance of the SQL query generator.
  37. func (ds *Datastore) GetQueries() *db.Queries {
  38. return db.New(ds.DB)
  39. }
  40. // Get will query the database for the key and return the entry.
  41. func (ds *Datastore) Get(key string) (ConfigEntry, error) {
  42. cachedValue, err := ds.GetCachedValue(key)
  43. if err == nil {
  44. return ConfigEntry{
  45. Key: key,
  46. Value: cachedValue,
  47. }, nil
  48. }
  49. var resultKey string
  50. var resultValue []byte
  51. row := ds.DB.QueryRow("SELECT key, value FROM datastore WHERE key = ? LIMIT 1", key)
  52. if err := row.Scan(&resultKey, &resultValue); err != nil {
  53. return ConfigEntry{}, err
  54. }
  55. result := ConfigEntry{
  56. Key: resultKey,
  57. Value: resultValue,
  58. }
  59. ds.SetCachedValue(resultKey, resultValue)
  60. return result, nil
  61. }
  62. // Save will save the ConfigEntry to the database.
  63. func (ds *Datastore) Save(e ConfigEntry) error {
  64. ds.DbLock.Lock()
  65. defer ds.DbLock.Unlock()
  66. var dataGob bytes.Buffer
  67. enc := gob.NewEncoder(&dataGob)
  68. if err := enc.Encode(e.Value); err != nil {
  69. return err
  70. }
  71. tx, err := ds.DB.Begin()
  72. if err != nil {
  73. return err
  74. }
  75. var stmt *sql.Stmt
  76. stmt, err = tx.Prepare("INSERT INTO datastore (key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value")
  77. if err != nil {
  78. return err
  79. }
  80. _, err = stmt.Exec(e.Key, dataGob.Bytes())
  81. if err != nil {
  82. return err
  83. }
  84. defer stmt.Close()
  85. if err = tx.Commit(); err != nil {
  86. log.Fatalln(err)
  87. }
  88. ds.SetCachedValue(e.Key, dataGob.Bytes())
  89. return nil
  90. }
  91. // Setup will create the datastore table and perform initial initialization.
  92. func (ds *Datastore) Setup() {
  93. ds.cache = make(map[string][]byte)
  94. ds.DB = GetDatabase()
  95. ds.DbLock = &sync.Mutex{}
  96. createTableSQL := `CREATE TABLE IF NOT EXISTS datastore (
  97. "key" string NOT NULL PRIMARY KEY,
  98. "value" BLOB,
  99. "timestamp" DATE DEFAULT CURRENT_TIMESTAMP NOT NULL
  100. );`
  101. ds.MustExec(createTableSQL)
  102. if !HasPopulatedDefaults() {
  103. PopulateDefaults()
  104. }
  105. if !hasPopulatedFederationDefaults() {
  106. if err := SetFederationGoLiveMessage(config.GetDefaults().FederationGoLiveMessage); err != nil {
  107. log.Errorln(err)
  108. }
  109. if err := _datastore.SetBool("HAS_POPULATED_FEDERATION_DEFAULTS", true); err != nil {
  110. log.Errorln(err)
  111. }
  112. }
  113. // Set the server initialization date if needed.
  114. if hasSetInitDate, _ := GetServerInitTime(); hasSetInitDate == nil || !hasSetInitDate.Valid {
  115. _ = SetServerInitTime(time.Now())
  116. }
  117. migrateDatastoreValues(_datastore)
  118. }
  119. // Reset will delete all config entries in the datastore and start over.
  120. func (ds *Datastore) Reset() {
  121. sql := "DELETE FROM datastore"
  122. stmt, err := ds.DB.Prepare(sql)
  123. if err != nil {
  124. log.Fatalln(err)
  125. }
  126. defer stmt.Close()
  127. if _, err = stmt.Exec(); err != nil {
  128. log.Fatalln(err)
  129. }
  130. PopulateDefaults()
  131. }
  132. // GetDatastore returns the shared instance of the owncast datastore.
  133. func GetDatastore() *Datastore {
  134. return _datastore
  135. }
  136. // MustExec will execute a SQL statement on a provided database instance.
  137. func (ds *Datastore) MustExec(s string) {
  138. stmt, err := ds.DB.Prepare(s)
  139. if err != nil {
  140. log.Panic(err)
  141. }
  142. defer stmt.Close()
  143. _, err = stmt.Exec()
  144. if err != nil {
  145. log.Warnln(err)
  146. }
  147. }