admin_backend/util/Mysql.go
2025-03-04 12:05:23 +08:00

209 lines
4.6 KiB
Go

package util
import (
"backend/Type"
"backend/common"
"context"
"fmt"
"log"
"net"
"strings"
"sync"
"github.com/go-sql-driver/mysql"
// _ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
"golang.org/x/crypto/ssh"
)
type MysqlPool struct {
lock sync.Mutex
poolList map[string]*poolInfo
}
type poolInfo struct {
DbList []*Db
Addr string
}
type Db struct {
*sqlx.DB
key string
}
func (db *Db) Close() error {
if db == nil {
return nil
}
MPool.putDb(db.key, db)
return nil
}
func (m *MysqlPool) getDb(key string) *Db {
m.lock.Lock()
defer m.lock.Unlock()
if pool, ok := m.poolList[key]; ok {
if len(pool.DbList) > 0 {
db := pool.DbList[0]
pool.DbList = pool.DbList[1:]
if err := db.Ping(); err != nil {
return nil
}
return db
}
}
return nil
}
func (m *MysqlPool) putDb(key string, db *Db) {
m.lock.Lock()
defer m.lock.Unlock()
pool := m.poolList[key]
if pool == nil {
pool = &poolInfo{Addr: key}
m.poolList[key] = pool
}
if len(pool.DbList) > 10 {
db.Close()
return
}
pool.DbList = append(pool.DbList, db)
}
func (m *MysqlPool) GetMysqlDB(Server, Mysql string, ServerId int) *Db {
key := fmt.Sprintf("%s_%s_%d", Server, Mysql, ServerId)
ADb := m.getDb(key)
if ADb != nil {
return ADb
}
var SQLDb *sqlx.DB
var err error
SQLDb, err = connectToMySQLViaSSH(Server, Mysql, ServerId)
if err != nil {
log.Printf("failed to connect to mysql: %v", err)
return nil
}
ADb = &Db{SQLDb, key}
// m.putDb(key, Db)
return ADb
}
func (m *MysqlPool) GetGameDB() *Db {
Server, Mysql := "log", "log"
key := fmt.Sprintf("%s_%s_game", Server, Mysql)
ADb := m.getDb(key)
if ADb != nil {
return ADb
}
SQLDb, err := ConnectMysql(Mysql, "game")
if err != nil {
return nil
}
ADb = &Db{SQLDb, key}
// m.putDb(key, Db)
return ADb
}
func (m *MysqlPool) GetTopicDB(Topic string) *Db {
Server, Mysql := "log", "log"
key := fmt.Sprintf("%s_%s_%s", Server, Mysql, Topic)
ADb := m.getDb(key)
if ADb != nil {
return ADb
}
SQLDb, err := ConnectMysql(Mysql, Topic)
if err != nil {
return nil
}
ADb = &Db{SQLDb, key}
// m.putDb(key, Db)
return ADb
}
func init() {
MPool = &MysqlPool{poolList: make(map[string]*poolInfo)}
}
var MPool *MysqlPool
func connectToMySQLViaSSH(ServerName, MysqlName string, ServerId int) (*sqlx.DB, error) {
SshConfig, err := common.GetServerConfig(ServerName)
if err != nil {
return nil, fmt.Errorf("failed to get SSH config: %v", err)
}
MysqlConfig, err := common.GetMysqlConfig(MysqlName)
if err != nil {
return nil, fmt.Errorf("failed to get MySQL config: %v", err)
}
SP, _ := Decrypt(SshConfig.Password)
// 创建 SSH 客户端配置
sshConfig := &ssh.ClientConfig{
User: SshConfig.Username,
Auth: []ssh.AuthMethod{
ssh.Password(SP),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
// 连接到 SSH 服务器
sshConn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", SshConfig.Host, SshConfig.Port), sshConfig)
if err != nil {
return nil, fmt.Errorf("failed to dial SSH: %v", err)
}
// 创建到 MySQL 服务器的隧道
mysqlConn, err := sshConn.Dial("tcp", fmt.Sprintf("%s:%d", MysqlConfig.Host, MysqlConfig.Port))
if err != nil {
return nil, fmt.Errorf("failed to dial MySQL: %v", err)
}
// 注册 MySQL 驱动
mysql.RegisterDialContext("mysql+tcp", func(ctx context.Context, addr string) (net.Conn, error) {
return mysqlConn, nil
})
var Database string
if strings.Contains(MysqlConfig.Database, "%") {
Database = fmt.Sprintf(MysqlConfig.Database, ServerId)
} else {
Database = MysqlConfig.Database
}
MP, _ := Decrypt(MysqlConfig.Password)
// 连接到 MySQL 数据库
dsn := fmt.Sprintf("%s:%s@mysql+tcp(%s:%d)/%s", MysqlConfig.Username, MP, MysqlConfig.Host, MysqlConfig.Port, Database)
db, err := sqlx.Open("mysql", dsn)
if err != nil {
return nil, fmt.Errorf("failed to open MySQL: %v", err)
}
return db, nil
}
func ConnectMysql(MysqlName, DataBase string) (*sqlx.DB, error) {
MysqlConfig, err := common.GetMysqlConfig(MysqlName)
if err != nil {
return nil, fmt.Errorf("failed to get MySQL config: %v", err)
}
MP, _ := Decrypt(MysqlConfig.Password)
// 连接到 MySQL 数据库
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", MysqlConfig.Username, MP, MysqlConfig.Host, MysqlConfig.Port, DataBase)
db, err := sqlx.Open("mysql", dsn)
if err != nil {
return nil, fmt.Errorf("failed to open MySQL: %v", err)
}
return db, nil
}
func GetAppConfig(AppId int) (*Type.AppStruct, error) {
Db := MPool.GetTopicDB("game")
defer Db.Close()
var app Type.AppStruct
err := Db.Get(&app, "SELECT * FROM app WHERE `AppId` = ?", AppId)
if err != nil {
return nil, fmt.Errorf("failed to scan rows: %v", err)
}
return &app, nil
}