diff --git a/internal/configs/simple_db_config.go b/internal/configs/simple_db_config.go new file mode 100644 index 00000000..f319043d --- /dev/null +++ b/internal/configs/simple_db_config.go @@ -0,0 +1,51 @@ +// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . + +package configs + +import ( + "fmt" + "github.com/iwind/TeaGo/Tea" + "github.com/iwind/TeaGo/dbs" + "gopkg.in/yaml.v3" + "net/url" + "os" +) + +type SimpleDBConfig struct { + User string `yaml:"user"` + Password string `yaml:"password"` + Database string `yaml:"database"` + Host string `yaml:"host"` + BoolFields []string `yaml:"boolFields,omitempty"` +} + +func (this *SimpleDBConfig) GenerateOldConfig(targetFile string) error { + var dbConfig = &dbs.DBConfig{ + Driver: "mysql", + Dsn: url.QueryEscape(this.User) + ":" + url.QueryEscape(this.Password) + "@tcp(" + this.Host + ")/" + url.PathEscape(this.Database) + "?charset=utf8mb4&timeout=30s&multiStatements=true", + Prefix: "edge", + } + dbConfig.Models.Package = "internal/db/models" + + var config = &dbs.Config{ + DBs: map[string]*dbs.DBConfig{ + Tea.Env: dbConfig, + }, + } + config.Default.DB = Tea.Env + config.Fields = map[string][]string{ + "bool": this.BoolFields, + } + + oldConfigYAML, encodeErr := yaml.Marshal(config) + if encodeErr != nil { + return encodeErr + } + + err := os.WriteFile(targetFile, oldConfigYAML, 0666) + if err != nil { + return fmt.Errorf("create database config file failed: %w", err) + } + + return nil +} diff --git a/internal/web/actions/default/settings/api/node/install.go b/internal/web/actions/default/settings/api/node/install.go index 284196fd..dafbb752 100644 --- a/internal/web/actions/default/settings/api/node/install.go +++ b/internal/web/actions/default/settings/api/node/install.go @@ -25,7 +25,7 @@ func (this *InstallAction) RunGet(params struct { this.ErrorPage(err) return } - node := nodeResp.ApiNode + var node = nodeResp.ApiNode if node == nil { this.NotFound("apiNode", params.NodeId) return @@ -39,12 +39,12 @@ func (this *InstallAction) RunGet(params struct { } // 数据库配置 - dbConfigMap := maps.Map{ + var dbConfigMap = maps.Map{ "config": "", "error": "", "isNotFound": false, } - dbConfigFile := Tea.ConfigFile("api_db.yaml") + var dbConfigFile = Tea.ConfigFile("api_db.yaml") data, err := os.ReadFile(dbConfigFile) dbConfigMap["config"] = string(data) if err != nil { diff --git a/internal/web/actions/default/settings/database/index.go b/internal/web/actions/default/settings/database/index.go index 485b939c..98a54656 100644 --- a/internal/web/actions/default/settings/database/index.go +++ b/internal/web/actions/default/settings/database/index.go @@ -1,12 +1,14 @@ package database import ( + "github.com/TeaOSLab/EdgeAdmin/internal/configs" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/go-sql-driver/mysql" "github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/maps" "gopkg.in/yaml.v3" + "net" "os" "strings" ) @@ -22,7 +24,7 @@ func (this *IndexAction) Init() { func (this *IndexAction) RunGet(params struct{}) { this.Data["error"] = "" - configFile := Tea.ConfigFile("api_db.yaml") + var configFile = Tea.ConfigFile("api_db.yaml") data, err := os.ReadFile(configFile) if err != nil { this.Data["error"] = "read config file failed: api_db.yaml: " + err.Error() @@ -30,8 +32,33 @@ func (this *IndexAction) RunGet(params struct{}) { return } - config := &dbs.Config{} + // new config + var config = &configs.SimpleDBConfig{} err = yaml.Unmarshal(data, config) + if err == nil && len(config.Host) > 0 { + host, port, splitErr := net.SplitHostPort(config.Host) + if splitErr != nil { + port = "3306" + } + + this.Data["dbConfig"] = maps.Map{ + "host": host, + "port": port, + "username": config.User, + "password": config.Password, + "database": config.Database, + } + + this.Show() + return + } + + this.parseOldConfig(data) +} + +func (this *IndexAction) parseOldConfig(data []byte) { + var config = &dbs.Config{} + err := yaml.Unmarshal(data, config) if err != nil { this.Data["error"] = "parse config file failed: api_db.yaml: " + err.Error() this.Show() @@ -49,7 +76,12 @@ func (this *IndexAction) RunGet(params struct{}) { dbConfig = db break } - dsn := dbConfig.Dsn + if dbConfig == nil { + this.Data["error"] = "no database configured in config file: api_db.yaml" + this.Show() + return + } + var dsn = dbConfig.Dsn cfg, err := mysql.ParseDSN(dsn) if err != nil { this.Data["error"] = "parse dsn error: " + err.Error() @@ -57,18 +89,19 @@ func (this *IndexAction) RunGet(params struct{}) { return } - host := cfg.Addr - port := "3306" - index := strings.LastIndex(host, ":") + var host = cfg.Addr + var port = "3306" + var index = strings.LastIndex(host, ":") if index > 0 { port = host[index+1:] host = host[:index] } - password := cfg.Passwd + var password = cfg.Passwd if len(password) > 0 { password = strings.Repeat("*", len(password)) } + this.Data["dbConfig"] = maps.Map{ "host": host, "port": port, diff --git a/internal/web/actions/default/settings/database/update.go b/internal/web/actions/default/settings/database/update.go index 6f05adea..c05dab55 100644 --- a/internal/web/actions/default/settings/database/update.go +++ b/internal/web/actions/default/settings/database/update.go @@ -2,6 +2,7 @@ package database import ( "fmt" + "github.com/TeaOSLab/EdgeAdmin/internal/configs" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeCommon/pkg/configutils" "github.com/TeaOSLab/EdgeCommon/pkg/langs/codes" @@ -40,55 +41,28 @@ func (this *UpdateAction) RunGet(params struct{}) { return } - config := &dbs.Config{} + // new config + var config = &configs.SimpleDBConfig{} err = yaml.Unmarshal(data, config) - if err != nil { - this.Show() - return - } - - if config.DBs == nil { - this.Show() - return - } - - var dbConfig *dbs.DBConfig - for _, db := range config.DBs { - dbConfig = db - break - } - - dsn := dbConfig.Dsn - cfg, err := mysql.ParseDSN(dsn) - if err != nil { - this.Data["dbConfig"] = maps.Map{ - "host": "", - "port": "", - "username": "", - "password": "", - "database": "", + if err == nil && len(config.Host) > 0 { + host, port, splitErr := net.SplitHostPort(config.Host) + if splitErr != nil { + port = "3306" } + + this.Data["dbConfig"] = maps.Map{ + "host": host, + "port": port, + "username": config.User, + "password": config.Password, + "database": config.Database, + } + this.Show() return } - host := cfg.Addr - port := "3306" - index := strings.LastIndex(cfg.Addr, ":") - if index > 0 { - host = cfg.Addr[:index] - port = cfg.Addr[index+1:] - } - - this.Data["dbConfig"] = maps.Map{ - "host": host, - "port": port, - "username": cfg.User, - "password": cfg.Passwd, - "database": cfg.DBName, - } - - this.Show() + this.parseOldConfig(data) } func (this *UpdateAction) RunPost(params struct { @@ -129,28 +103,91 @@ func (this *UpdateAction) RunPost(params struct { Require("请输入连接数据库的用户名"). Match(`^[\w\.-]+$`, "用户名中不能包含特殊字符") - // 保存 - dsn := params.Username + ":" + params.Password + "@tcp(" + configutils.QuoteIP(params.Host) + ":" + fmt.Sprintf("%d", params.Port) + ")/" + params.Database - - configFile := Tea.ConfigFile("api_db.yaml") - template := `default: - db: "prod" - prefix: "" - -dbs: - prod: - driver: "mysql" - dsn: "` + dsn + `?charset=utf8mb4&timeout=30s" - prefix: "edge" - models: - package: internal/web/models -` - err := os.WriteFile(configFile, []byte(template), 0666) + var config = &configs.SimpleDBConfig{ + User: params.Username, + Password: params.Password, + Database: params.Database, + Host: configutils.QuoteIP(params.Host) + ":" + fmt.Sprintf("%d", params.Port), + } + configYAML, err := yaml.Marshal(config) if err != nil { - this.Fail("保存配置失败:" + err.Error()) + this.ErrorPage(err) + return } - // TODO 让本地的节点生效 + // 保存 + + var configFile = Tea.ConfigFile("api_db.yaml") + err = os.WriteFile(configFile, configYAML, 0666) + if err != nil { + this.Fail("保存配置失败:" + err.Error()) + return + } + + // TODO 思考是否让本地的API节点生效 this.Success() } + +func (this *UpdateAction) parseOldConfig(data []byte) { + var config = &dbs.Config{} + err := yaml.Unmarshal(data, config) + if err != nil { + this.Show() + return + } + + if config.DBs == nil { + this.Show() + return + } + + var dbConfig *dbs.DBConfig + for _, db := range config.DBs { + dbConfig = db + break + } + if dbConfig == nil { + this.Data["dbConfig"] = maps.Map{ + "host": "", + "port": "", + "username": "", + "password": "", + "database": "", + } + this.Show() + return + } + + var dsn = dbConfig.Dsn + cfg, err := mysql.ParseDSN(dsn) + if err != nil { + this.Data["dbConfig"] = maps.Map{ + "host": "", + "port": "", + "username": "", + "password": "", + "database": "", + } + this.Show() + return + } + + var host = cfg.Addr + var port = "3306" + var index = strings.LastIndex(cfg.Addr, ":") + if index > 0 { + host = cfg.Addr[:index] + port = cfg.Addr[index+1:] + } + + this.Data["dbConfig"] = maps.Map{ + "host": host, + "port": port, + "username": cfg.User, + "password": cfg.Passwd, + "database": cfg.DBName, + } + + this.Show() +} diff --git a/internal/web/actions/default/setup/detectDB.go b/internal/web/actions/default/setup/detectDB.go index 46d6303b..50c42b62 100644 --- a/internal/web/actions/default/setup/detectDB.go +++ b/internal/web/actions/default/setup/detectDB.go @@ -8,6 +8,7 @@ import ( "github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/maps" "net" + "net/url" "os" "runtime" "strings" @@ -48,7 +49,7 @@ func (this *DetectDBAction) RunPost(params struct{}) { for _, pass := range passwords { db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{ Driver: "mysql", - Dsn: username + ":" + pass + "@tcp(" + configutils.QuoteIP(localHost) + ":" + localPort + ")/edges", + Dsn: url.QueryEscape(username) + ":" + url.QueryEscape(pass) + "@tcp(" + configutils.QuoteIP(localHost) + ":" + localPort + ")/edges", Prefix: "", }) if err == nil { diff --git a/internal/web/actions/default/setup/install.go b/internal/web/actions/default/setup/install.go index f594cc94..b517ed4f 100644 --- a/internal/web/actions/default/setup/install.go +++ b/internal/web/actions/default/setup/install.go @@ -12,7 +12,6 @@ import ( "github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs" "github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/actions" - "github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/maps" "github.com/iwind/gosock/pkg/gosock" @@ -80,34 +79,39 @@ func (this *InstallAction) RunPost(params struct { // 检查环境 var apiNodeDir = Tea.Root + "/edge-api" for _, dir := range []string{"edge-api", "edge-api/configs", "edge-api/bin"} { - apiNodeDir := Tea.Root + "/" + dir - _, err = os.Stat(apiNodeDir) + var searchDir = Tea.Root + "/" + dir + _, err = os.Stat(searchDir) if err != nil { if os.IsNotExist(err) { this.Fail("在当前目录(" + Tea.Root + ")下找不到" + dir + "目录,请将" + dir + "目录上传或者重新下载解压") } this.Fail("无法检查" + dir + "目录,发生错误:" + err.Error()) + return } } // 保存数据库配置 - var dsn = dbMap.GetString("username") + ":" + dbMap.GetString("password") + "@tcp(" + configutils.QuoteIP(dbMap.GetString("host")) + ":" + dbMap.GetString("port") + ")/" + dbMap.GetString("database") + "?charset=utf8mb4&timeout=30s" - dbConfig := &dbs.Config{ - DBs: map[string]*dbs.DBConfig{ - "prod": { - Driver: "mysql", - Dsn: dsn, - Prefix: "edge", - }}, + var dbConfig = &configs.SimpleDBConfig{ + User: dbMap.GetString("username"), + Password: dbMap.GetString("password"), + Database: dbMap.GetString("database"), + Host: configutils.QuoteIP(dbMap.GetString("host")) + ":" + dbMap.GetString("port"), } - dbConfig.Default.DB = "prod" dbConfigData, err := yaml.Marshal(dbConfig) if err != nil { this.Fail("生成数据库配置失败:" + err.Error()) + return } err = os.WriteFile(apiNodeDir+"/configs/db.yaml", dbConfigData, 0666) if err != nil { - this.Fail("保存数据库配置失败:" + err.Error()) + this.Fail("保存数据库配置失败(db.yaml):" + err.Error()) + return + } + + err = dbConfig.GenerateOldConfig(apiNodeDir + "/configs/.db.yaml") + if err != nil { + this.Fail("保存数据库配置失败(.db.yaml):" + err.Error()) + return } // 生成备份文件 @@ -130,7 +134,8 @@ func (this *InstallAction) RunPost(params struct { err = os.WriteFile(Tea.ConfigFile("/api_db.yaml"), dbConfigData, 0666) if err != nil { - this.Fail("保存数据库配置失败:" + err.Error()) + this.Fail("保存数据库配置失败(api_db.yaml):" + err.Error()) + return } // 生成备份文件 @@ -157,21 +162,25 @@ func (this *InstallAction) RunPost(params struct { { this.apiSetupFinished = false var cmd = exec.Command(apiNodeDir+"/bin/edge-api", "setup", "-api-node-protocol=http", "-api-node-host=\""+apiNodeMap.GetString("newHost")+"\"", "-api-node-port=\""+apiNodeMap.GetString("newPort")+"\"") - var output = bytes.NewBuffer([]byte{}) + var output = bytes.NewBuffer(nil) cmd.Stdout = output + var stderr = bytes.NewBuffer(nil) + cmd.Stderr = stderr + // 试图读取执行日志 go this.startReadingAPIInstallLog() err = cmd.Run() this.apiSetupFinished = true if err != nil { - this.Fail("安装失败:" + err.Error()) + this.Fail("安装失败:" + err.Error() + ": " + string(append(output.Bytes(), stderr.Bytes()...))) } var resultData = output.Bytes() err = json.Unmarshal(resultData, &resultMap) if err != nil { + this.Fail("安装节点时返回数据错误:" + err.Error() + "(" + string(resultData) + ")") } if !resultMap.GetBool("isOk") { diff --git a/internal/web/actions/default/setup/validateDb.go b/internal/web/actions/default/setup/validateDb.go index ffe008f1..bd171a44 100644 --- a/internal/web/actions/default/setup/validateDb.go +++ b/internal/web/actions/default/setup/validateDb.go @@ -9,6 +9,7 @@ import ( "github.com/iwind/TeaGo/maps" stringutil "github.com/iwind/TeaGo/utils/string" "net" + "net/url" "regexp" "strings" ) @@ -57,7 +58,7 @@ func (this *ValidateDbAction) RunPost(params struct { // 测试连接 db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{ Driver: "mysql", - Dsn: params.Username + ":" + params.Password + "@tcp(" + configutils.QuoteIP(params.Host) + ":" + params.Port + ")/" + params.Database, + Dsn: url.QueryEscape(params.Username) + ":" + url.QueryEscape(params.Password) + "@tcp(" + configutils.QuoteIP(params.Host) + ":" + params.Port + ")/" + params.Database, Prefix: "", }) if err != nil { diff --git a/web/views/@default/settings/database/update.html b/web/views/@default/settings/database/update.html index 818c22e0..23fa7808 100644 --- a/web/views/@default/settings/database/update.html +++ b/web/views/@default/settings/database/update.html @@ -2,7 +2,7 @@ {$template "menu"}
-

这里只能修改配置模板文件里的配置信息,并不能直接修改数据库的用户名、密码等信息。

+

这里只能修改配置模板文件里的配置信息,并不能直接修改数据库自身的用户名、密码等信息。