| | package model |
| |
|
| | import ( |
| | "log" |
| | "one-api/common" |
| | "one-api/constant" |
| | "os" |
| | "strings" |
| | "sync" |
| | "time" |
| |
|
| | "github.com/glebarez/sqlite" |
| | "gorm.io/driver/mysql" |
| | "gorm.io/driver/postgres" |
| | "gorm.io/gorm" |
| | ) |
| |
|
| | var groupCol string |
| | var keyCol string |
| |
|
| | func initCol() { |
| | if common.UsingPostgreSQL { |
| | groupCol = `"group"` |
| | keyCol = `"key"` |
| |
|
| | } else { |
| | groupCol = "`group`" |
| | keyCol = "`key`" |
| | } |
| | } |
| |
|
| | var DB *gorm.DB |
| |
|
| | var LOG_DB *gorm.DB |
| |
|
| | func createRootAccountIfNeed() error { |
| | var user User |
| | |
| | if err := DB.First(&user).Error; err != nil { |
| | common.SysLog("no user exists, create a root user for you: username is root, password is 123456") |
| | hashedPassword, err := common.Password2Hash("123456") |
| | if err != nil { |
| | return err |
| | } |
| | rootUser := User{ |
| | Username: "root", |
| | Password: hashedPassword, |
| | Role: common.RoleRootUser, |
| | Status: common.UserStatusEnabled, |
| | DisplayName: "Root User", |
| | AccessToken: nil, |
| | Quota: 100000000, |
| | } |
| | DB.Create(&rootUser) |
| | } |
| | return nil |
| | } |
| |
|
| | func CheckSetup() { |
| | setup := GetSetup() |
| | if setup == nil { |
| | |
| | if RootUserExists() { |
| | common.SysLog("system is not initialized, but root user exists") |
| | |
| | newSetup := Setup{ |
| | Version: common.Version, |
| | InitializedAt: time.Now().Unix(), |
| | } |
| | err := DB.Create(&newSetup).Error |
| | if err != nil { |
| | common.SysLog("failed to create setup record: " + err.Error()) |
| | } |
| | constant.Setup = true |
| | } else { |
| | common.SysLog("system is not initialized and no root user exists") |
| | constant.Setup = false |
| | } |
| | } else { |
| | |
| | common.SysLog("system is already initialized at: " + time.Unix(setup.InitializedAt, 0).String()) |
| | constant.Setup = true |
| | } |
| | } |
| |
|
| | func chooseDB(envName string) (*gorm.DB, error) { |
| | defer func() { |
| | initCol() |
| | }() |
| | dsn := os.Getenv(envName) |
| | if dsn != "" { |
| | if strings.HasPrefix(dsn, "postgres://") || strings.HasPrefix(dsn, "postgresql://") { |
| | |
| | common.SysLog("using PostgreSQL as database") |
| | common.UsingPostgreSQL = true |
| | return gorm.Open(postgres.New(postgres.Config{ |
| | DSN: dsn, |
| | PreferSimpleProtocol: true, |
| | }), &gorm.Config{ |
| | PrepareStmt: true, |
| | }) |
| | } |
| | if strings.HasPrefix(dsn, "local") { |
| | common.SysLog("SQL_DSN not set, using SQLite as database") |
| | common.UsingSQLite = true |
| | return gorm.Open(sqlite.Open(common.SQLitePath), &gorm.Config{ |
| | PrepareStmt: true, |
| | }) |
| | } |
| | |
| | common.SysLog("using MySQL as database") |
| | |
| | if !strings.Contains(dsn, "parseTime") { |
| | if strings.Contains(dsn, "?") { |
| | dsn += "&parseTime=true" |
| | } else { |
| | dsn += "?parseTime=true" |
| | } |
| | } |
| | common.UsingMySQL = true |
| | return gorm.Open(mysql.Open(dsn), &gorm.Config{ |
| | PrepareStmt: true, |
| | }) |
| | } |
| | |
| | common.SysLog("SQL_DSN not set, using SQLite as database") |
| | common.UsingSQLite = true |
| | return gorm.Open(sqlite.Open(common.SQLitePath), &gorm.Config{ |
| | PrepareStmt: true, |
| | }) |
| | } |
| |
|
| | func InitDB() (err error) { |
| | db, err := chooseDB("SQL_DSN") |
| | if err == nil { |
| | if common.DebugEnabled { |
| | db = db.Debug() |
| | } |
| | DB = db |
| | sqlDB, err := DB.DB() |
| | if err != nil { |
| | return err |
| | } |
| | sqlDB.SetMaxIdleConns(common.GetEnvOrDefault("SQL_MAX_IDLE_CONNS", 100)) |
| | sqlDB.SetMaxOpenConns(common.GetEnvOrDefault("SQL_MAX_OPEN_CONNS", 1000)) |
| | sqlDB.SetConnMaxLifetime(time.Second * time.Duration(common.GetEnvOrDefault("SQL_MAX_LIFETIME", 60))) |
| |
|
| | if !common.IsMasterNode { |
| | return nil |
| | } |
| | if common.UsingMySQL { |
| | _, _ = sqlDB.Exec("ALTER TABLE channels MODIFY model_mapping TEXT;") |
| | } |
| | common.SysLog("database migration started") |
| | err = migrateDB() |
| | return err |
| | } else { |
| | common.FatalLog(err) |
| | } |
| | return err |
| | } |
| |
|
| | func InitLogDB() (err error) { |
| | if os.Getenv("LOG_SQL_DSN") == "" { |
| | LOG_DB = DB |
| | return |
| | } |
| | db, err := chooseDB("LOG_SQL_DSN") |
| | if err == nil { |
| | if common.DebugEnabled { |
| | db = db.Debug() |
| | } |
| | LOG_DB = db |
| | sqlDB, err := LOG_DB.DB() |
| | if err != nil { |
| | return err |
| | } |
| | sqlDB.SetMaxIdleConns(common.GetEnvOrDefault("SQL_MAX_IDLE_CONNS", 100)) |
| | sqlDB.SetMaxOpenConns(common.GetEnvOrDefault("SQL_MAX_OPEN_CONNS", 1000)) |
| | sqlDB.SetConnMaxLifetime(time.Second * time.Duration(common.GetEnvOrDefault("SQL_MAX_LIFETIME", 60))) |
| |
|
| | if !common.IsMasterNode { |
| | return nil |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | common.SysLog("database migration started") |
| | err = migrateLOGDB() |
| | return err |
| | } else { |
| | common.FatalLog(err) |
| | } |
| | return err |
| | } |
| |
|
| | func migrateDB() error { |
| | err := DB.AutoMigrate(&Channel{}) |
| | if err != nil { |
| | return err |
| | } |
| | err = DB.AutoMigrate(&Token{}) |
| | if err != nil { |
| | return err |
| | } |
| | err = DB.AutoMigrate(&User{}) |
| | if err != nil { |
| | return err |
| | } |
| | err = DB.AutoMigrate(&Option{}) |
| | if err != nil { |
| | return err |
| | } |
| | err = DB.AutoMigrate(&Redemption{}) |
| | if err != nil { |
| | return err |
| | } |
| | err = DB.AutoMigrate(&Ability{}) |
| | if err != nil { |
| | return err |
| | } |
| | err = DB.AutoMigrate(&Log{}) |
| | if err != nil { |
| | return err |
| | } |
| | err = DB.AutoMigrate(&Midjourney{}) |
| | if err != nil { |
| | return err |
| | } |
| | err = DB.AutoMigrate(&TopUp{}) |
| | if err != nil { |
| | return err |
| | } |
| | err = DB.AutoMigrate(&QuotaData{}) |
| | if err != nil { |
| | return err |
| | } |
| | err = DB.AutoMigrate(&Task{}) |
| | if err != nil { |
| | return err |
| | } |
| | err = DB.AutoMigrate(&Setup{}) |
| | common.SysLog("database migrated") |
| | |
| | return err |
| | } |
| |
|
| | func migrateLOGDB() error { |
| | var err error |
| | if err = LOG_DB.AutoMigrate(&Log{}); err != nil { |
| | return err |
| | } |
| | return nil |
| | } |
| |
|
| | func closeDB(db *gorm.DB) error { |
| | sqlDB, err := db.DB() |
| | if err != nil { |
| | return err |
| | } |
| | err = sqlDB.Close() |
| | return err |
| | } |
| |
|
| | func CloseDB() error { |
| | if LOG_DB != DB { |
| | err := closeDB(LOG_DB) |
| | if err != nil { |
| | return err |
| | } |
| | } |
| | return closeDB(DB) |
| | } |
| |
|
| | var ( |
| | lastPingTime time.Time |
| | pingMutex sync.Mutex |
| | ) |
| |
|
| | func PingDB() error { |
| | pingMutex.Lock() |
| | defer pingMutex.Unlock() |
| |
|
| | if time.Since(lastPingTime) < time.Second*10 { |
| | return nil |
| | } |
| |
|
| | sqlDB, err := DB.DB() |
| | if err != nil { |
| | log.Printf("Error getting sql.DB from GORM: %v", err) |
| | return err |
| | } |
| |
|
| | err = sqlDB.Ping() |
| | if err != nil { |
| | log.Printf("Error pinging DB: %v", err) |
| | return err |
| | } |
| |
|
| | lastPingTime = time.Now() |
| | common.SysLog("Database pinged successfully") |
| | return nil |
| | } |
| |
|