2021-12-16 04:11:33 +00:00
|
|
|
package store
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"path/filepath"
|
|
|
|
"time"
|
|
|
|
|
2021-12-20 02:23:08 +00:00
|
|
|
"github.com/rs/zerolog"
|
2021-12-16 04:11:33 +00:00
|
|
|
"github.com/spf13/viper"
|
|
|
|
"gorm.io/driver/mysql"
|
|
|
|
"gorm.io/driver/postgres"
|
|
|
|
"gorm.io/driver/sqlite"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"gorm.io/gorm/logger"
|
|
|
|
"kumoly.io/kumoly/app/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
type DBTYPE string
|
|
|
|
|
|
|
|
const (
|
|
|
|
MYSQL DBTYPE = "mysql"
|
|
|
|
SQLITE DBTYPE = "sqlite"
|
|
|
|
POSTGRES DBTYPE = "postgres"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Store struct {
|
|
|
|
TYPE DBTYPE
|
|
|
|
DB *gorm.DB
|
|
|
|
User string
|
|
|
|
Password string
|
|
|
|
Host string
|
|
|
|
Port string
|
|
|
|
Name string
|
|
|
|
AutoMigrate bool
|
|
|
|
Prod bool
|
|
|
|
Path string
|
|
|
|
|
|
|
|
config *gorm.Config
|
|
|
|
}
|
|
|
|
|
|
|
|
var DB *gorm.DB
|
|
|
|
var std *Store
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
// Database
|
|
|
|
// type [mysql,sqlite]
|
|
|
|
viper.SetDefault("db.type", string(MYSQL))
|
|
|
|
|
|
|
|
// mysql default
|
|
|
|
viper.SetDefault("db.user", "root")
|
|
|
|
viper.SetDefault("db.passwd", "admin")
|
|
|
|
viper.SetDefault("db.host", "127.0.0.1")
|
|
|
|
viper.SetDefault("db.port", "3306")
|
|
|
|
viper.SetDefault("db.name", "app")
|
|
|
|
|
|
|
|
viper.SetDefault("db.reconnect_interval", 5)
|
|
|
|
viper.SetDefault("db.automigrate", true)
|
|
|
|
}
|
|
|
|
|
2021-12-20 02:23:08 +00:00
|
|
|
var l zerolog.Logger
|
|
|
|
|
2021-12-16 04:11:33 +00:00
|
|
|
// Init initialize default db using New() followed by Connect()
|
|
|
|
func Setup() {
|
2021-12-20 02:23:08 +00:00
|
|
|
l = util.Klog.With().Str("mod", "store").Logger()
|
2021-12-16 04:11:33 +00:00
|
|
|
var err error
|
|
|
|
std = New(DBTYPE(viper.GetString("db.type")))
|
|
|
|
DB, err = std.Connect()
|
|
|
|
if err != nil {
|
2021-12-20 02:23:08 +00:00
|
|
|
l.Error().Err(err).Msg("std connection error")
|
2021-12-16 04:11:33 +00:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Migrate(dst ...interface{}) error {
|
|
|
|
return std.Migrate(dst...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(t DBTYPE) *Store {
|
|
|
|
s := &Store{
|
|
|
|
TYPE: t,
|
|
|
|
Prod: viper.GetBool("prod"),
|
|
|
|
Name: viper.GetString("db.name"),
|
|
|
|
AutoMigrate: viper.GetBool("db.automigrate"),
|
|
|
|
}
|
|
|
|
if t == MYSQL || t == POSTGRES {
|
|
|
|
s.User = viper.GetString("db.user")
|
|
|
|
s.Password = viper.GetString("db.passwd")
|
|
|
|
s.Host = viper.GetString("db.host")
|
|
|
|
s.Port = viper.GetString("db.port")
|
|
|
|
} else if t == SQLITE {
|
|
|
|
s.Path = viper.GetString("data")
|
|
|
|
} else {
|
|
|
|
err := fmt.Errorf("unknown db type %s", t)
|
2021-12-20 02:23:08 +00:00
|
|
|
l.Error().Err(err).Msg("unknown db type")
|
2021-12-16 04:11:33 +00:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
// Connect to db and store db connection to var DB
|
|
|
|
func (s *Store) Connect() (db *gorm.DB, err error) {
|
2022-01-08 19:33:48 +00:00
|
|
|
|
|
|
|
glog := logger.Default
|
2022-01-08 19:40:03 +00:00
|
|
|
l.Trace().Int("level", viper.GetInt("log.level")).
|
2022-01-08 19:41:47 +00:00
|
|
|
Bool("tog_info", (zerolog.Level(viper.GetInt("log.level")) <= zerolog.DebugLevel)).
|
2022-01-08 19:40:03 +00:00
|
|
|
Msg("log level")
|
2022-01-08 19:34:22 +00:00
|
|
|
if zerolog.Level(viper.GetInt("log.level")) <= zerolog.DebugLevel {
|
2022-01-08 19:35:51 +00:00
|
|
|
l.Debug().Msg("set gorm log level to info")
|
2022-01-08 19:33:48 +00:00
|
|
|
glog.LogMode(logger.Info)
|
|
|
|
}
|
|
|
|
|
2021-12-16 04:11:33 +00:00
|
|
|
s.config = &gorm.Config{
|
2022-01-08 19:33:48 +00:00
|
|
|
Logger: glog,
|
2021-12-16 04:11:33 +00:00
|
|
|
SkipDefaultTransaction: true,
|
|
|
|
}
|
|
|
|
if s.Prod {
|
|
|
|
s.config.Logger = logger.Discard
|
|
|
|
}
|
|
|
|
switch s.TYPE {
|
|
|
|
case MYSQL:
|
|
|
|
return s.DB, s.mysqlConnector()
|
|
|
|
case POSTGRES:
|
|
|
|
return s.DB, s.postgresConnector()
|
|
|
|
case SQLITE:
|
|
|
|
return s.DB, s.sqliteConnector()
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unknown db type %s", s.TYPE)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Store) postgresConnector() error {
|
2021-12-20 02:23:08 +00:00
|
|
|
l.Info().Msg("Connecting to postgres...")
|
2021-12-16 04:11:33 +00:00
|
|
|
dsn := fmt.Sprintf(
|
|
|
|
"host=%v user=%v password=%v dbname=%v port=%v sslmode=disable TimeZone=Asia/Taipei",
|
|
|
|
s.Host, s.User, s.Password, s.Name, s.Port,
|
|
|
|
)
|
|
|
|
for {
|
|
|
|
db, err := gorm.Open(postgres.New(postgres.Config{
|
|
|
|
DSN: dsn, // data source name
|
|
|
|
// PreferSimpleProtocol: true, // disables implicit prepared statement usage
|
|
|
|
}), s.config)
|
|
|
|
if err == nil {
|
|
|
|
s.DB = db
|
|
|
|
break
|
|
|
|
}
|
|
|
|
inter := viper.GetDuration("db.reconnect_interval")
|
|
|
|
if inter <= 0 {
|
|
|
|
inter = 5
|
|
|
|
}
|
2021-12-20 02:23:08 +00:00
|
|
|
l.Warn().Err(err).Msg("Unable to connect to database")
|
|
|
|
l.Warn().Msgf("Retrying in %v second.", inter)
|
2021-12-16 04:11:33 +00:00
|
|
|
time.Sleep(time.Second * inter)
|
|
|
|
}
|
2021-12-20 02:23:08 +00:00
|
|
|
l.Info().Msg("Connection to postgres, ok.")
|
2021-12-16 04:11:33 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//mysqlConnector connection
|
|
|
|
func (s *Store) mysqlConnector() error {
|
2021-12-20 02:23:08 +00:00
|
|
|
l.Info().Msg("Connecting to mysql...")
|
2021-12-16 04:11:33 +00:00
|
|
|
dsn := fmt.Sprintf(
|
|
|
|
"%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local",
|
|
|
|
s.User, s.Password, s.Host, s.Port, s.Name,
|
|
|
|
)
|
2021-12-20 02:23:08 +00:00
|
|
|
// l.Debug(dsn)
|
2021-12-16 04:11:33 +00:00
|
|
|
for {
|
|
|
|
db, err := gorm.Open(mysql.New(mysql.Config{
|
|
|
|
DSN: dsn, // data source name
|
|
|
|
DefaultStringSize: 256, // default size for string fields
|
|
|
|
}), s.config)
|
|
|
|
if err == nil {
|
|
|
|
s.DB = db
|
|
|
|
break
|
|
|
|
}
|
|
|
|
inter := viper.GetDuration("db.reconnect_interval")
|
|
|
|
if inter <= 0 {
|
|
|
|
inter = 5
|
|
|
|
}
|
2021-12-20 02:23:08 +00:00
|
|
|
l.Warn().Err(err).Msg("Unable to connect to database")
|
|
|
|
l.Warn().Msgf("Retrying in %v second.", inter)
|
2021-12-16 04:11:33 +00:00
|
|
|
time.Sleep(time.Second * inter)
|
|
|
|
}
|
2021-12-20 02:23:08 +00:00
|
|
|
l.Info().Msg("Connection to mysql, ok.")
|
2021-12-16 04:11:33 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//sqliteConnector connection
|
|
|
|
func (s *Store) sqliteConnector() error {
|
|
|
|
util.Mkdir(s.Path)
|
|
|
|
dbPath := filepath.Join(s.Path, s.Name+".db")
|
2021-12-20 02:23:08 +00:00
|
|
|
l.Info().Str("path", dbPath).Msg("Connecting to sqlite...")
|
2021-12-16 04:11:33 +00:00
|
|
|
db, err := gorm.Open(sqlite.Open(dbPath), s.config)
|
|
|
|
if err != nil {
|
2021-12-20 02:23:08 +00:00
|
|
|
l.Error().Err(err).Msg("failed to connect database")
|
2021-12-16 04:11:33 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
s.DB = db
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Store) Migrate(dst ...interface{}) error {
|
|
|
|
if !s.AutoMigrate {
|
2021-12-20 02:23:08 +00:00
|
|
|
l.Debug().Msg("AutoMigration is set to off, migration skipped")
|
2021-12-16 04:11:33 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return s.DB.AutoMigrate(dst...)
|
|
|
|
}
|