core/db/db.go

200 lines
5.0 KiB
Go

package db
import (
"database/sql"
"fmt"
"log"
"time"
"gitea.meta-tech.academy/go/core/util"
"github.com/go-sql-driver/mysql"
)
const USER_DEFAULT_PRIVILEGES = "CREATE, CREATE VIEW, CREATE TEMPORARY TABLES, SELECT, INSERT, UPDATE, DELETE, EXECUTE, LOCK TABLES, TRIGGER"
var MAX_OPEN_CONNS = 500
var MAX_IDLE_CONNS = 0
type Db struct {
pool map[string]*sql.DB
}
type DbConfig struct {
host string
dbname string
user string
passwd string
port int
}
type PasswordDecode func(in string) (string, bool)
func (dbc *DbConfig) GetHost() string {
return fmt.Sprintf("%s:%d", dbc.host, dbc.port)
}
func (dbc *DbConfig) GetSqlConfig(passwdGet ...PasswordDecode) *mysql.Config {
var plain string = dbc.passwd
var done bool = len(passwdGet) == 0
if !done {
plain, done = passwdGet[0](dbc.passwd)
}
if done {
return &mysql.Config{
User: dbc.user,
Net: "tcp",
Addr: dbc.GetHost(),
DBName: dbc.dbname,
Passwd: plain,
AllowNativePasswords: true,
}
} else {
fmt.Printf("invalid password unable to connect")
time.Sleep(3 * time.Second)
}
return nil
}
func NewDbConfig(host string, dbname string, user string, passwd string, port int) *DbConfig {
return &DbConfig{host, dbname, user, passwd, port}
}
func (db *Db) AddDb(dbconf *DbConfig, passwdGet ...PasswordDecode) {
cnx, err := sql.Open("mysql", dbconf.GetSqlConfig(passwdGet...).FormatDSN())
if err != nil {
log.Fatal(err)
}
pingErr := cnx.Ping()
if pingErr != nil {
log.Fatal(pingErr)
}
cnx.SetMaxIdleConns(MAX_IDLE_CONNS)
cnx.SetMaxOpenConns(MAX_OPEN_CONNS)
db.pool[dbconf.dbname] = cnx
}
func NewDb() *Db {
pool := make(map[string]*sql.DB)
return &Db{pool}
}
func getFullUser(username string, hostname string) string {
return fmt.Sprintf("'%s'@'%s'", util.EscapeSquote(username), util.EscapeSquote(hostname))
}
func (db *Db) onDbExec(dbname string, instr DbInstruct) bool {
var done bool
if sqlDb, ok := db.pool[dbname]; ok {
return instr(sqlDb)
} else {
fmt.Printf("you should add db mysql first\n")
done = ok
}
return done
}
type DbInstruct func(database *sql.DB) bool
func (db *Db) CreateUser(username string, hostname string, passwd string) bool {
return db.onDbExec("mysql", func(sqlDb *sql.DB) bool {
query := fmt.Sprintf(
"CREATE USER IF NOT EXISTS %s IDENTIFIED BY '%s';",
getFullUser(username, hostname),
util.EscapeSquote(passwd),
)
_, err := sqlDb.Exec(query)
done := err == nil
if !done {
fmt.Printf("unable to add user %s\n%v\n", username, err)
}
return done
})
}
func (db *Db) GrantUserPrivileges(dbname string, username string, hostname string) bool {
return db.onDbExec("mysql", func(sqlDb *sql.DB) bool {
query := fmt.Sprintf(
"GRANT %s ON `%s`.* TO %s;",
USER_DEFAULT_PRIVILEGES,
util.EscapeBt(dbname),
getFullUser(username, hostname),
)
_, err := sqlDb.Exec(query)
done := err == nil
if !done {
fmt.Printf("query : %s\n", query)
fmt.Printf("unable to grant user privilege %s\n%v\n", username, err)
}
return done
})
}
func (db *Db) CreateDb(dbname string, collate string) bool {
return db.onDbExec("mysql", func(sqlDb *sql.DB) bool {
query := fmt.Sprintf(
"CREATE DATABASE IF NOT EXISTS `%s` CHARACTER SET '%s' COLLATE '%s_unicode_ci'",
util.EscapeBt(dbname),
util.EscapeSquote(collate),
util.EscapeSquote(collate),
)
_, err := db.pool["mysql"].Exec(query)
done := err == nil
if !done {
fmt.Printf("unable to create database %s\n%v\n", dbname, err)
}
return done
})
}
func (db *Db) SizeDb(dbname string) float32 {
type RsSize struct {
Dbname string
Size float32
}
rs := RsSize{Size: -1}
db.onDbExec("information_schema", func(sqlDb *sql.DB) bool {
query := "SELECT table_schema 'dbname', SUM(data_length + index_length)/1024/1024 'size' FROM TABLES WHERE table_schema = ? GROUP BY table_schema;"
row := sqlDb.QueryRow(query, dbname)
err := row.Scan(&rs.Dbname, &rs.Size)
done := err != nil
if !done {
if err == sql.ErrNoRows {
fmt.Printf(" cannot find db %s or db is empty\n", dbname)
} else if err != nil {
fmt.Printf(" what the fuck error : %+v\n", err)
}
}
return done
})
return rs.Size
}
type TableSize struct {
Table string
Size float32
}
func (db *Db) SizeTable(dbname string) []TableSize {
rs := make([]TableSize, 0)
db.onDbExec("information_schema", func(sqlDb *sql.DB) bool {
query := "SELECT `TABLE_NAME` AS `table`, ROUND(((`DATA_LENGTH` + `INDEX_LENGTH`) / 1024 / 1024), 2) `size` FROM `TABLES` WHERE `table_schema` = ? AND (`DATA_LENGTH` + `INDEX_LENGTH`) > 0 ORDER BY (`DATA_LENGTH` + `INDEX_LENGTH`) DESC;"
rows, err := sqlDb.Query(query, dbname)
if err != nil {
fmt.Printf("cannot get table size of db %s : %v", dbname, err)
return false
}
defer rows.Close()
for rows.Next() {
ts := TableSize{Size: -1}
if err := rows.Scan(&ts.Table, &ts.Size); err != nil {
fmt.Printf("cannot get table size of db %s : %v", dbname, err)
return false
}
rs = append(rs, ts)
}
return true
})
return rs
}