Files
gocryptotrader/engine/database.go
Andrew 0c76789b0d Database interface & auditing feature (#332)
* added audit manager

* Basic database DOA setup

* Added base config file

* added sqlite support and creation of schema

* added basic tests and config entry

* corrected issues of database is disabled

* fixed path for test

* WIP

* Added tests fixed config checking

* reverted files back to upstream

* reverted go.mod files

* no more test test test

* removed local testing details for psql

* hello

* added comments

* increased ping to 30 seconds

* renamed database table and added additional condition around test

* removed database test details

* goimport ran on all files

* WIP

* first attempt at migration

* fixes for migration system

* Migration system logger interface implemented

* fixes to print functions

* added write pooling pass

* gofmt :D

* formatted imports correctly

* removed old code

* added creation of migration

* gofmt

* :D Hello

*  🏎️

* maybe one day i will remember to revert go mod files

* checked err return condition correctly

* first changes for PR feedback

* code clean up

* protect Connected with RWmutex & event with mutex

* : D

* we can just pretend like it never happened

* MOved migrations back to source directory and added README

* readme formatting update

* Addd command line override for datadir

* use correct var when creating a migration and confirm folder is created

* Check if database version is newer than latest migration and also you know make migrations work.....

* uses filepath instead of manual path to use correct path seperator

* Add connection message and lower timeout

* Added support for sslmode for psql

* no longer force Close of database instead allow driver to maage

* Added closer func to test output

* sslmode added to example config
2019-08-20 16:35:06 +10:00

145 lines
3.2 KiB
Go

package engine
import (
"errors"
"fmt"
"sync/atomic"
"time"
"github.com/thrasher-corp/gocryptotrader/database"
db "github.com/thrasher-corp/gocryptotrader/database/drivers/postgres"
dbsqlite3 "github.com/thrasher-corp/gocryptotrader/database/drivers/sqlite"
mg "github.com/thrasher-corp/gocryptotrader/database/migration"
"github.com/thrasher-corp/gocryptotrader/database/repository/audit"
auditPSQL "github.com/thrasher-corp/gocryptotrader/database/repository/audit/postgres"
auditSQLite "github.com/thrasher-corp/gocryptotrader/database/repository/audit/sqlite"
log "github.com/thrasher-corp/gocryptotrader/logger"
)
var (
dbConn *database.Database
)
type databaseManager struct {
running atomic.Value
shutdown chan struct{}
}
func (a *databaseManager) Started() bool {
return a.running.Load() == true
}
func (a *databaseManager) Start() (err error) {
if a.Started() {
return errors.New("database manager already started")
}
log.Debugln(log.DatabaseMgr, "database manager starting...")
a.shutdown = make(chan struct{})
if Bot.Config.Database.Enabled {
if Bot.Config.Database.Driver == "postgres" {
dbConn, err = db.Connect()
if err != nil {
return fmt.Errorf("database failed to connect: %v Some features that utilise a database will be unavailable", err)
}
dbConn.SQL.SetMaxOpenConns(2)
dbConn.SQL.SetMaxIdleConns(1)
dbConn.SQL.SetConnMaxLifetime(time.Hour)
audit.Audit = auditPSQL.Audit()
} else if Bot.Config.Database.Driver == "sqlite" {
dbConn, err = dbsqlite3.Connect()
if err != nil {
return fmt.Errorf("database failed to connect: %v Some features that utilise a database will be unavailable", err)
}
audit.Audit = auditSQLite.Audit()
}
dbConn.Connected = true
log.Debugf(log.DatabaseMgr, "connection established to %v using %v", dbConn.Config.Host, dbConn.Config.Driver)
mLogger := mg.MLogger{}
migrations := mg.Migrator{
Log: mLogger,
}
migrations.Conn = dbConn
err := migrations.LoadMigrations()
if err != nil {
return err
}
err = migrations.RunMigration()
if err != nil {
return err
}
go a.run()
return nil
}
return errors.New("database support disabled")
}
func (a *databaseManager) Stop() error {
if !a.Started() {
return errors.New("database manager already stopped")
}
log.Debugln(log.DatabaseMgr, "database manager shutting down...")
err := dbConn.SQL.Close()
if err != nil {
log.Errorf(log.DatabaseMgr, "Failed to close database: %v", err)
}
close(a.shutdown)
return nil
}
func (a *databaseManager) run() {
log.Debugln(log.DatabaseMgr, "database manager started.")
Bot.ServicesWG.Add(1)
t := time.NewTicker(time.Second * 2)
a.running.Store(true)
defer func() {
t.Stop()
a.running.Store(false)
Bot.ServicesWG.Done()
log.Debugln(log.DatabaseMgr, "database manager shutdown.")
}()
for {
select {
case <-a.shutdown:
return
case <-t.C:
a.checkConnection()
}
}
}
func (a *databaseManager) checkConnection() {
dbConn.Mu.Lock()
defer dbConn.Mu.Unlock()
err := dbConn.SQL.Ping()
if err != nil {
log.Errorf(log.DatabaseMgr, "database connection error: %v", err)
dbConn.Connected = false
return
}
if !dbConn.Connected {
log.Info(log.DatabaseMgr, "database connection reestablished")
dbConn.Connected = true
}
}