statping/core/database.go

292 lines
7.1 KiB
Go
Raw Normal View History

2018-08-16 06:22:20 +00:00
// Statup
// Copyright (C) 2018. Hunter Long and the project contributors
// Written by Hunter Long <info@socialeck.com> and the project contributors
//
// https://github.com/hunterlong/statup
//
// The licenses for most software and other practical works are designed
// to take away your freedom to share and change the works. By contrast,
// the GNU General Public License is intended to guarantee your freedom to
// share and change all versions of a program--to make sure it remains free
// software for all its users.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
2018-06-30 00:57:05 +00:00
package core
import (
"fmt"
"github.com/go-yaml/yaml"
2018-08-10 04:38:54 +00:00
"github.com/hunterlong/statup/source"
2018-06-30 00:57:05 +00:00
"github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils"
"os"
"strings"
"time"
"upper.io/db.v3"
"upper.io/db.v3/lib/sqlbuilder"
"upper.io/db.v3/mysql"
"upper.io/db.v3/postgresql"
"upper.io/db.v3/sqlite"
)
var (
sqliteSettings sqlite.ConnectionURL
postgresSettings postgresql.ConnectionURL
mysqlSettings mysql.ConnectionURL
DbSession sqlbuilder.Database
currentMigration int64
2018-06-30 00:57:05 +00:00
)
2018-08-19 08:48:02 +00:00
type DbConfig struct {
*types.DbConfig
}
2018-06-30 00:57:05 +00:00
2018-07-27 04:45:42 +00:00
func DbConnection(dbType string, retry bool, location string) error {
2018-06-30 00:57:05 +00:00
var err error
if dbType == "sqlite" {
sqliteSettings = sqlite.ConnectionURL{
2018-07-28 01:50:13 +00:00
Database: location + "/statup.db",
2018-06-30 00:57:05 +00:00
}
DbSession, err = sqlite.Open(sqliteSettings)
if err != nil {
return err
}
} else if dbType == "mysql" {
if Configs.Port == "" {
Configs.Port = "3306"
}
host := fmt.Sprintf("%v:%v", Configs.Host, Configs.Port)
2018-06-30 00:57:05 +00:00
mysqlSettings = mysql.ConnectionURL{
Database: Configs.Database,
Host: host,
2018-06-30 00:57:05 +00:00
User: Configs.User,
Password: Configs.Password,
2018-07-03 21:39:56 +00:00
Options: map[string]string{"parseTime": "true", "charset": "utf8"},
2018-06-30 00:57:05 +00:00
}
DbSession, err = mysql.Open(mysqlSettings)
if err != nil {
if retry {
utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", host))
return waitForDb(dbType)
} else {
return err
}
2018-06-30 00:57:05 +00:00
}
} else {
if Configs.Port == "" {
Configs.Port = "5432"
}
host := fmt.Sprintf("%v:%v", Configs.Host, Configs.Port)
postgresSettings = postgresql.ConnectionURL{
Database: Configs.Database,
Host: host,
User: Configs.User,
Password: Configs.Password,
}
DbSession, err = postgresql.Open(postgresSettings)
if err != nil {
if retry {
utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", host))
return waitForDb(dbType)
} else {
return err
}
2018-06-30 00:57:05 +00:00
}
}
err = DbSession.Ping()
if err == nil {
utils.Log(1, fmt.Sprintf("Database connection to '%v' was successful.", DbSession.Name()))
}
2018-06-30 00:57:05 +00:00
return err
}
func waitForDb(dbType string) error {
time.Sleep(5 * time.Second)
2018-08-20 03:48:28 +00:00
return DbConnection(dbType, true, utils.Directory)
}
2018-06-30 00:57:05 +00:00
func DatabaseMaintence() {
2018-07-28 16:44:52 +00:00
for range time.Tick(60 * time.Minute) {
utils.Log(1, "Checking for database records older than 7 days...")
since := time.Now().AddDate(0, 0, -7)
DeleteAllSince("failures", since)
DeleteAllSince("hits", since)
}
2018-06-30 00:57:05 +00:00
}
func DeleteAllSince(table string, date time.Time) {
sql := fmt.Sprintf("DELETE FROM %v WHERE created_at < '%v';", table, date.Format("2006-01-02"))
_, err := DbSession.Exec(db.Raw(sql))
if err != nil {
utils.Log(2, err)
}
}
func (c *DbConfig) Save() error {
var err error
2018-08-20 03:48:28 +00:00
config, err := os.Create(utils.Directory + "/config.yml")
2018-06-30 00:57:05 +00:00
if err != nil {
utils.Log(4, err)
2018-06-30 00:57:05 +00:00
return err
}
2018-08-19 20:07:32 +00:00
data, err := yaml.Marshal(c.DbConfig)
2018-06-30 00:57:05 +00:00
if err != nil {
utils.Log(3, err)
2018-06-30 00:57:05 +00:00
return err
}
config.WriteString(string(data))
config.Close()
Configs, err = LoadConfig()
if err != nil {
utils.Log(3, err)
2018-06-30 00:57:05 +00:00
return err
}
2018-07-27 04:45:42 +00:00
err = DbConnection(Configs.Connection, false, c.Location)
2018-06-30 00:57:05 +00:00
if err != nil {
utils.Log(4, err)
2018-06-30 00:57:05 +00:00
return err
}
DropDatabase()
CreateDatabase()
2018-07-17 09:18:20 +00:00
newCore := &types.Core{
2018-06-30 00:57:05 +00:00
Name: c.Project,
Description: c.Description,
Config: "config.yml",
2018-06-30 03:40:00 +00:00
ApiKey: utils.NewSHA1Hash(9),
ApiSecret: utils.NewSHA1Hash(16),
2018-06-30 00:57:05 +00:00
Domain: c.Domain,
MigrationId: time.Now().Unix(),
2018-06-30 00:57:05 +00:00
}
col := DbSession.Collection("core")
_, err = col.Insert(newCore)
if err == nil {
2018-07-17 09:18:20 +00:00
CoreApp = &Core{Core: newCore}
}
2018-07-04 09:00:16 +00:00
CoreApp, err = SelectCore()
if err != nil {
utils.Log(4, err)
}
2018-07-04 09:00:16 +00:00
CoreApp.DbConnection = c.DbConn
2018-06-30 00:57:05 +00:00
return err
}
func versionHigher(migrate int64) bool {
if CoreApp.MigrationId < migrate {
2018-07-04 09:00:16 +00:00
return true
}
return false
}
func reverseSlice(s []string) []string {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
return s
}
2018-07-04 09:00:16 +00:00
func RunDatabaseUpgrades() error {
var err error
currentMigration, err = SelectLastMigration()
if err != nil {
return err
}
utils.Log(1, fmt.Sprintf("Checking for Database Upgrades since #%v", currentMigration))
2018-08-10 04:38:54 +00:00
upgrade, _ := source.SqlBox.String(CoreApp.DbConnection + "_upgrade.sql")
2018-07-04 09:00:16 +00:00
// parse db version and upgrade file
ups := strings.Split(upgrade, "=========================================== ")
ups = reverseSlice(ups)
2018-07-04 09:00:16 +00:00
var ran int
var lastMigration int64
2018-07-04 09:00:16 +00:00
for _, v := range ups {
if len(v) == 0 {
continue
}
vers := strings.Split(v, "\n")
lastMigration = utils.StringInt(vers[0])
2018-07-04 09:00:16 +00:00
data := vers[1:]
2018-07-04 09:00:16 +00:00
//fmt.Printf("Checking Migration from v%v to v%v - %v\n", CoreApp.Version, version, versionHigher(version))
if currentMigration >= lastMigration {
2018-07-04 09:00:16 +00:00
continue
}
utils.Log(1, fmt.Sprintf("Migrating Database from #%v to #%v", currentMigration, lastMigration))
2018-07-04 09:00:16 +00:00
for _, m := range data {
if m == "" {
continue
}
utils.Log(1, fmt.Sprintf("Running Query: %v", m))
2018-07-04 09:00:16 +00:00
_, err := DbSession.Exec(db.Raw(m + ";"))
ran++
2018-07-04 09:00:16 +00:00
if err != nil {
utils.Log(2, err)
continue
}
2018-06-30 00:57:05 +00:00
}
currentMigration = lastMigration
2018-06-30 00:57:05 +00:00
}
2018-07-04 09:00:16 +00:00
if ran > 0 {
utils.Log(1, fmt.Sprintf("Database Upgraded %v queries ran, current #%v", ran, currentMigration))
2018-07-04 10:14:00 +00:00
CoreApp, err = SelectCore()
if err != nil {
panic(err)
}
CoreApp.MigrationId = currentMigration
2018-07-17 09:18:20 +00:00
UpdateCore(CoreApp)
2018-07-04 09:00:16 +00:00
}
return err
2018-06-30 00:57:05 +00:00
}
2018-07-27 04:45:42 +00:00
func DropDatabase() error {
utils.Log(1, "Dropping Database Tables...")
2018-08-10 04:38:54 +00:00
down, err := source.SqlBox.String("down.sql")
2018-07-27 04:45:42 +00:00
if err != nil {
return err
}
2018-06-30 00:57:05 +00:00
requests := strings.Split(down, ";")
for _, request := range requests {
_, err := DbSession.Exec(request)
if err != nil {
utils.Log(2, err)
}
}
2018-07-27 04:45:42 +00:00
return err
2018-06-30 00:57:05 +00:00
}
2018-07-27 04:45:42 +00:00
func CreateDatabase() error {
utils.Log(1, "Creating Database Tables...")
2018-06-30 00:57:05 +00:00
sql := "postgres_up.sql"
2018-07-04 09:00:16 +00:00
if CoreApp.DbConnection == "mysql" {
2018-06-30 00:57:05 +00:00
sql = "mysql_up.sql"
2018-07-04 09:00:16 +00:00
} else if CoreApp.DbConnection == "sqlite" {
2018-06-30 00:57:05 +00:00
sql = "sqlite_up.sql"
}
2018-08-10 04:38:54 +00:00
up, err := source.SqlBox.String(sql)
2018-06-30 00:57:05 +00:00
requests := strings.Split(up, ";")
for _, request := range requests {
_, err := DbSession.Exec(request)
if err != nil {
utils.Log(2, err)
}
}
//secret := NewSHA1Hash()
//db.QueryRow("INSERT INTO core (secret, version) VALUES ($1, $2);", secret, VERSION).Scan()
utils.Log(1, "Database Created")
2018-06-30 00:57:05 +00:00
//SampleData()
2018-07-27 04:45:42 +00:00
return err
2018-06-30 00:57:05 +00:00
}
func (c *DbConfig) Clean() *DbConfig {
if os.Getenv("DB_PORT") != "" {
if c.DbConn == "postgres" {
c.DbHost = c.DbHost + ":" + os.Getenv("DB_PORT")
}
}
return c
}