Select Git revision
database.go

Jonah Husson authored
database.go 3.87 KiB
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2021 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package storage
import (
"fmt"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"time"
)
type database interface {
InsertMembers([]Member) error
InsertCommitment(Commitment) error
GetMember(hexID string) (*Member, error)
GetCommitment(id string) (*Commitment, error)
}
// DatabaseImpl struct implements the Database Interface with an underlying DB
type DatabaseImpl struct {
db *gorm.DB // Stored database connection
}
type Member struct {
Id []byte `gorm:"primary_key"`
Cert []byte `gorm:"NOT NULL"`
}
type Commitment struct {
Id []byte `gorm:"primary_key"`
Contract []byte `gorm:"not null"`
Wallet string `gorm:"not null"`
NominatorWallet string
Email string
Signature []byte `gorm:"not null"`
SelectedStake int
MaxStake int `gorm:"default:137068"`
CreatedAt time.Time
}
// newDatabase initializes the database interface with either Database or Map backend
// Returns a database interface and error
func newDatabase(username, password, dbName, address,
port string) (database, error) {
var err error
var db *gorm.DB
// Connect to the database if the correct information is provided
if address != "" && port != "" {
// Create the database connection
connectString := fmt.Sprintf(
"host=%s port=%s user=%s dbname=%s sslmode=disable",
address, port, username, dbName)
// Handle empty database password
if len(password) > 0 {
connectString += fmt.Sprintf(" password=%s", password)
}
db, err = gorm.Open(postgres.Open(connectString), &gorm.Config{
Logger: logger.New(jww.TRACE, logger.Config{LogLevel: logger.Info}),
})
}
// Return the map-backend interface
// in the event there is a database error or information is not provided
if (address == "" || port == "") || err != nil {
var failReason string
if err != nil {
failReason = fmt.Sprintf("Unable to initialize database backend: %+v", err)
jww.WARN.Printf(failReason)
} else {
failReason = "Database backend connection information not provided"
jww.WARN.Printf(failReason)
}
defer jww.INFO.Println("Map backend initialized successfully!")
mapImpl := &MapImpl{
members: map[string]Member{},
commitments: map[string]Commitment{},
}
return database(mapImpl), nil
}
// Get and configure the internal database ConnPool
sqlDb, err := db.DB()
if err != nil {
return database(&DatabaseImpl{}), errors.Errorf("Unable to configure database connection pool: %+v", err)
}
// SetMaxIdleConns sets the maximum number of connections in the idle connection pool.
sqlDb.SetMaxIdleConns(10)
// SetMaxOpenConns sets the maximum number of open connections to the Database.
sqlDb.SetMaxOpenConns(50)
// SetConnMaxLifetime sets the maximum amount of time a connection may be idle.
sqlDb.SetConnMaxIdleTime(10 * time.Minute)
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
sqlDb.SetConnMaxLifetime(12 * time.Hour)
// Initialize the database schema
// WARNING: Order is important. Do not change without database testing
models := []interface{}{Member{}, Commitment{}}
for _, model := range models {
err = db.AutoMigrate(model)
if err != nil {
return database(&DatabaseImpl{}), err
}
}
// Build the interface
di := &DatabaseImpl{
db: db,
}
jww.INFO.Println("Database backend initialized successfully!")
return database(di), nil
}