From 312f10d06d9aa0f47ced236787687e92b4826e3b Mon Sep 17 00:00:00 2001 From: zhangchenhao Date: Thu, 8 May 2025 11:19:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E4=BB=A3=E7=A0=81=E5=90=8C?= =?UTF-8?q?=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/cert/deploy/deploy.go | 5 +- backend/internal/cert/deploy/ssh.go | 44 +- backend/internal/report/report.go | 378 +++++++++--------- backend/internal/setting/setting.go | 9 +- backend/internal/workflow/workflow_history.go | 234 +++++------ backend/migrations/init.go | 12 +- backend/public/utils.go | 362 ++++++++--------- 7 files changed, 523 insertions(+), 521 deletions(-) diff --git a/backend/internal/cert/deploy/deploy.go b/backend/internal/cert/deploy/deploy.go index 8487d24..d5b18a9 100644 --- a/backend/internal/cert/deploy/deploy.go +++ b/backend/internal/cert/deploy/deploy.go @@ -37,8 +37,9 @@ func Deploy(cfg map[string]any, logger *public.Logger) error { case "aliyun-cdn": logger.Debug("部署到阿里云CDN...") return DeployAliCdn(cfg) - // case "aliyun-oss": - + case "aliyun-oss": + logger.Debug("部署到阿里云OSS...") + return DeployOss(cfg) default: return fmt.Errorf("不支持的部署: %s", providerName) } diff --git a/backend/internal/cert/deploy/ssh.go b/backend/internal/cert/deploy/ssh.go index 7fbe234..12ccda3 100644 --- a/backend/internal/cert/deploy/ssh.go +++ b/backend/internal/cert/deploy/ssh.go @@ -14,7 +14,7 @@ type SSHConfig struct { Password string // 可选 PrivateKey string // 可选 Host string - Port string + Port float64 } type RemoteFile struct { @@ -24,7 +24,7 @@ type RemoteFile struct { func buildAuthMethods(password, privateKey string) ([]ssh.AuthMethod, error) { var methods []ssh.AuthMethod - + if privateKey != "" { signer, err := ssh.ParsePrivateKey([]byte(privateKey)) if err != nil { @@ -32,71 +32,71 @@ func buildAuthMethods(password, privateKey string) ([]ssh.AuthMethod, error) { } methods = append(methods, ssh.PublicKeys(signer)) } - + if password != "" { methods = append(methods, ssh.Password(password)) } - + if len(methods) == 0 { return nil, fmt.Errorf("no authentication methods provided") } - + return methods, nil } func writeMultipleFilesViaSSH(config SSHConfig, files []RemoteFile, preCmd, postCmd string) error { - addr := fmt.Sprintf("%s:%s", config.Host, config.Port) - + addr := fmt.Sprintf("%s:%d", config.Host, int(config.Port)) + authMethods, err := buildAuthMethods(config.Password, config.PrivateKey) if err != nil { return err } - + sshConfig := &ssh.ClientConfig{ User: config.User, Auth: authMethods, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } - + client, err := ssh.Dial("tcp", addr, sshConfig) if err != nil { return fmt.Errorf("failed to dial: %v", err) } defer client.Close() - + session, err := client.NewSession() if err != nil { return fmt.Errorf("会话创建失败: %v", err) } defer session.Close() - + var script bytes.Buffer - + if preCmd != "" { script.WriteString(preCmd + " && ") } - + for i, file := range files { if i > 0 { script.WriteString(" && ") } - + dirCmd := fmt.Sprintf("mkdir -p $(dirname %q)", file.Path) writeCmd := fmt.Sprintf("printf %%s '%s' > %s", file.Content, file.Path) - + script.WriteString(dirCmd + " && " + writeCmd) } - + if postCmd != "" { script.WriteString(" && " + postCmd) } - + cmd := script.String() - + if err := session.Run(cmd); err != nil { return fmt.Errorf("运行出错: %v", err) } - + return nil } @@ -127,7 +127,7 @@ func DeploySSH(cfg map[string]any) error { if !ok { return fmt.Errorf("参数错误:keyPath") } - certPath, ok := cfg["keyPath"].(string) + certPath, ok := cfg["certPath"].(string) if !ok { return fmt.Errorf("参数错误:certPath") } @@ -155,8 +155,8 @@ func DeploySSH(cfg map[string]any) error { } // 自动创建多级目录 files := []RemoteFile{ - {Path: keyPath, Content: certPem}, - {Path: certPath, Content: keyPem}, + {Path: certPath, Content: certPem}, + {Path: keyPath, Content: keyPem}, } err = writeMultipleFilesViaSSH(providerConfig, files, beforeCmd, afterCmd) if err != nil { diff --git a/backend/internal/report/report.go b/backend/internal/report/report.go index c23b76d..bd494f0 100644 --- a/backend/internal/report/report.go +++ b/backend/internal/report/report.go @@ -1,189 +1,189 @@ -package report - -import ( - "ALLinSSL/backend/public" - "crypto/tls" - "encoding/json" - "fmt" - "github.com/jordan-wright/email" - "net/smtp" - "time" -) - -func GetSqlite() (*public.Sqlite, error) { - s, err := public.NewSqlite("data/data.db", "") - if err != nil { - return nil, err - } - s.Connect() - s.TableName = "report" - return s, nil -} - -func GetList(search string, p, limit int64) ([]map[string]any, int, error) { - var data []map[string]any - var count int64 - s, err := GetSqlite() - if err != nil { - return data, 0, err - } - defer s.Close() - - var limits []int64 - if p >= 0 && limit >= 0 { - limits = []int64{0, limit} - if p > 1 { - limits[0] = (p - 1) * limit - limits[1] = p * limit - } - } - - if search != "" { - count, err = s.Where("name like ?", []interface{}{"%" + search + "%"}).Count() - data, err = s.Where("name like ?", []interface{}{"%" + search + "%"}).Limit(limits).Order("update_time", "desc").Select() - } else { - count, err = s.Count() - data, err = s.Order("update_time", "desc").Limit(limits).Select() - } - if err != nil { - return data, 0, err - } - return data, int(count), nil -} - -func GetReport(id string) (map[string]any, error) { - s, err := GetSqlite() - if err != nil { - return nil, err - } - defer s.Close() - data, err := s.Where("id=?", []interface{}{id}).Select() - if err != nil { - return nil, err - } - if len(data) == 0 { - return nil, fmt.Errorf("没有找到此通知配置") - } - return data[0], nil - -} - -func AddReport(Type, config, name string) error { - s, err := GetSqlite() - if err != nil { - return err - } - defer s.Close() - now := time.Now().Format("2006-01-02 15:04:05") - _, err = s.Insert(map[string]interface{}{ - "name": name, - "type": Type, - "config": config, - "create_time": now, - "update_time": now, - }) - return err -} - -func UpdReport(id, config, name string) error { - s, err := GetSqlite() - if err != nil { - return err - } - defer s.Close() - _, err = s.Where("id=?", []interface{}{id}).Update(map[string]interface{}{ - "name": name, - "config": config, - }) - return err -} - -func DelReport(id string) error { - s, err := GetSqlite() - if err != nil { - return err - } - defer s.Close() - _, err = s.Where("id=?", []interface{}{id}).Delete() - return err -} - -func NotifyTest(id string) error { - if id == "" { - return fmt.Errorf("缺少参数") - } - providerData, err := GetReport(id) - if err != nil { - return err - } - params := map[string]any{ - "provider_id": id, - "body": "测试消息通道", - "subject": "测试消息通道", - } - switch providerData["type"] { - case "mail": - err = NotifyMail(params) - } - return err -} - -func Notify(params map[string]any) error { - if params == nil { - return fmt.Errorf("缺少参数") - } - providerName, ok := params["provider"].(string) - if !ok { - return fmt.Errorf("通知类型错误") - } - switch providerName { - case "mail": - return NotifyMail(params) - // case "btpanel-site": - // return NotifyBt(params) - default: - return fmt.Errorf("不支持的通知类型") - } -} - -func NotifyMail(params map[string]any) error { - - if params == nil { - return fmt.Errorf("缺少参数") - } - providerID := params["provider_id"].(string) - // fmt.Println(providerID) - providerData, err := GetReport(providerID) - if err != nil { - return err - } - configStr := providerData["config"].(string) - var config map[string]string - err = json.Unmarshal([]byte(configStr), &config) - if err != nil { - return fmt.Errorf("解析配置失败: %v", err) - } - - e := email.NewEmail() - e.From = config["sender"] - e.To = []string{config["receiver"]} - e.Subject = params["subject"].(string) - - e.Text = []byte(params["body"].(string)) - - addr := fmt.Sprintf("%s:%s", config["smtpHost"], config["smtpPort"]) - - auth := smtp.PlainAuth("", config["sender"], config["password"], config["smtpHost"]) - - // 使用 SSL(通常是 465) - if config["smtpPort"] == "465" { - tlsConfig := &tls.Config{ - InsecureSkipVerify: true, // 开发阶段跳过证书验证,生产建议关闭 - ServerName: config["smtpHost"], - } - return e.SendWithTLS(addr, auth, tlsConfig) - } - - // 普通明文发送(25端口,非推荐) - return e.Send(addr, auth) -} +package report + +import ( + "ALLinSSL/backend/public" + "crypto/tls" + "encoding/json" + "fmt" + "github.com/jordan-wright/email" + "net/smtp" + "time" +) + +func GetSqlite() (*public.Sqlite, error) { + s, err := public.NewSqlite("data/data.db", "") + if err != nil { + return nil, err + } + s.Connect() + s.TableName = "report" + return s, nil +} + +func GetList(search string, p, limit int64) ([]map[string]any, int, error) { + var data []map[string]any + var count int64 + s, err := GetSqlite() + if err != nil { + return data, 0, err + } + defer s.Close() + + var limits []int64 + if p >= 0 && limit >= 0 { + limits = []int64{0, limit} + if p > 1 { + limits[0] = (p - 1) * limit + limits[1] = p * limit + } + } + + if search != "" { + count, err = s.Where("name like ?", []interface{}{"%" + search + "%"}).Count() + data, err = s.Where("name like ?", []interface{}{"%" + search + "%"}).Limit(limits).Order("update_time", "desc").Select() + } else { + count, err = s.Count() + data, err = s.Order("update_time", "desc").Limit(limits).Select() + } + if err != nil { + return data, 0, err + } + return data, int(count), nil +} + +func GetReport(id string) (map[string]any, error) { + s, err := GetSqlite() + if err != nil { + return nil, err + } + defer s.Close() + data, err := s.Where("id=?", []interface{}{id}).Select() + if err != nil { + return nil, err + } + if len(data) == 0 { + return nil, fmt.Errorf("没有找到此通知配置") + } + return data[0], nil + +} + +func AddReport(Type, config, name string) error { + s, err := GetSqlite() + if err != nil { + return err + } + defer s.Close() + now := time.Now().Format("2006-01-02 15:04:05") + _, err = s.Insert(map[string]interface{}{ + "name": name, + "type": Type, + "config": config, + "create_time": now, + "update_time": now, + }) + return err +} + +func UpdReport(id, config, name string) error { + s, err := GetSqlite() + if err != nil { + return err + } + defer s.Close() + _, err = s.Where("id=?", []interface{}{id}).Update(map[string]interface{}{ + "name": name, + "config": config, + }) + return err +} + +func DelReport(id string) error { + s, err := GetSqlite() + if err != nil { + return err + } + defer s.Close() + _, err = s.Where("id=?", []interface{}{id}).Delete() + return err +} + +func NotifyTest(id string) error { + if id == "" { + return fmt.Errorf("缺少参数") + } + providerData, err := GetReport(id) + if err != nil { + return err + } + params := map[string]any{ + "provider_id": id, + "body": "测试消息通道", + "subject": "测试消息通道", + } + switch providerData["type"] { + case "mail": + err = NotifyMail(params) + } + return err +} + +func Notify(params map[string]any) error { + if params == nil { + return fmt.Errorf("缺少参数") + } + providerName, ok := params["provider"].(string) + if !ok { + return fmt.Errorf("通知类型错误") + } + switch providerName { + case "mail": + return NotifyMail(params) + // case "btpanel-site": + // return NotifyBt(params) + default: + return fmt.Errorf("不支持的通知类型") + } +} + +func NotifyMail(params map[string]any) error { + + if params == nil { + return fmt.Errorf("缺少参数") + } + providerID := params["provider_id"].(string) + // fmt.Println(providerID) + providerData, err := GetReport(providerID) + if err != nil { + return err + } + configStr := providerData["config"].(string) + var config map[string]string + err = json.Unmarshal([]byte(configStr), &config) + if err != nil { + return fmt.Errorf("解析配置失败: %v", err) + } + + e := email.NewEmail() + e.From = config["sender"] + e.To = []string{config["receiver"]} + e.Subject = params["subject"].(string) + + e.Text = []byte(params["body"].(string)) + + addr := fmt.Sprintf("%s:%s", config["smtpHost"], config["smtpPort"]) + + auth := smtp.PlainAuth("", config["sender"], config["password"], config["smtpHost"]) + + // 使用 SSL(通常是 465) + if config["smtpPort"] == "465" { + tlsConfig := &tls.Config{ + InsecureSkipVerify: true, // 开发阶段跳过证书验证,生产建议关闭 + ServerName: config["smtpHost"], + } + return e.SendWithTLS(addr, auth, tlsConfig) + } + + // 普通明文发送(25端口,非推荐) + return e.Send(addr, auth) +} diff --git a/backend/internal/setting/setting.go b/backend/internal/setting/setting.go index 9d2b865..ac8db79 100644 --- a/backend/internal/setting/setting.go +++ b/backend/internal/setting/setting.go @@ -27,7 +27,7 @@ func Get() (Setting, error) { Timeout: public.TimeOut, Secure: public.Secure, } - + setting.Https = public.GetSettingIgnoreError("https") key, err := os.ReadFile("data/https/key.pem") if err != nil { @@ -60,7 +60,7 @@ func Get() (Setting, error) { func Save(setting *Setting) error { var restart bool var reload bool - + s, err := public.NewSqlite("data/data.db", "") if err != nil { return err @@ -79,7 +79,7 @@ func Save(setting *Setting) error { if setting.Username != "" { data["username"] = setting.Username } - + salt := user[0]["salt"].(string) passwd := setting.Password + salt // fmt.Println(passwd) @@ -98,10 +98,12 @@ func Save(setting *Setting) error { if setting.Timeout != 0 { s.Where("key = 'timeout'", []interface{}{}).Update(map[string]interface{}{"value": setting.Timeout}) public.TimeOut = setting.Timeout + restart = true } if setting.Secure != "" { s.Where("key = 'secure'", []interface{}{}).Update(map[string]interface{}{"value": setting.Secure}) public.TimeOut = setting.Timeout + restart = true } if setting.Https == "1" { if setting.Key == "" || setting.Cert == "" { @@ -122,7 +124,6 @@ func Save(setting *Setting) error { os.WriteFile("data/https/cert.pem", []byte(setting.Cert), 0644) restart = true } - if restart { Restart() return nil diff --git a/backend/internal/workflow/workflow_history.go b/backend/internal/workflow/workflow_history.go index e7ae9e4..8c8bdac 100644 --- a/backend/internal/workflow/workflow_history.go +++ b/backend/internal/workflow/workflow_history.go @@ -1,117 +1,117 @@ -package workflow - -import ( - "ALLinSSL/backend/public" - "os" - "path/filepath" - "time" -) - -// GetSqliteObjWH 工作流执行历史记录表对象 -func GetSqliteObjWH() (*public.Sqlite, error) { - s, err := public.NewSqlite("data/data.db", "") - if err != nil { - return nil, err - } - s.Connect() - s.TableName = "workflow_history" - return s, nil -} - -// GetListWH 获取工作流执行历史记录列表 -func GetListWH(id string, p, limit int64) ([]map[string]any, int, error) { - var data []map[string]any - var count int64 - s, err := GetSqliteObjWH() - if err != nil { - return data, 0, err - } - defer s.Close() - - var limits []int64 - if p >= 0 && limit >= 0 { - limits = []int64{0, limit} - if p > 1 { - limits[0] = (p - 1) * limit - limits[1] = p * limit - } - } - if id == "" { - count, err = s.Count() - data, err = s.Limit(limits).Order("create_time", "desc").Select() - } else { - count, err = s.Where("workflow_id=?", []interface{}{id}).Count() - data, err = s.Where("workflow_id=?", []interface{}{id}).Limit(limits).Order("create_time", "desc").Select() - } - - if err != nil { - return data, 0, err - } - return data, int(count), nil -} - -// 添加工作流执行历史记录 -func AddWorkflowHistory(workflowID, execType string) (string, error) { - s, err := GetSqliteObjWH() - if err != nil { - return "", err - } - defer s.Close() - now := time.Now().Format("2006-01-02 15:04:05") - ID := public.GenerateUUID() - _, err = s.Insert(map[string]interface{}{ - "id": ID, - "workflow_id": workflowID, - "status": "running", - "exec_type": execType, - "create_time": now, - }) - if err != nil { - return "", err - } - _ = UpdDb(workflowID, map[string]interface{}{"last_run_status": "running", "last_run_time": now}) - return ID, nil -} - -// 工作流执行结束 -func UpdateWorkflowHistory(id, status string) error { - s, err := GetSqliteObjWH() - if err != nil { - return err - } - defer s.Close() - now := time.Now().Format("2006-01-02 15:04:05") - _, err = s.Where("id=?", []interface{}{id}).Update(map[string]interface{}{ - "status": status, - "end_time": now, - }) - if err != nil { - return err - } - return nil -} - -func StopWorkflow(id string) error { - s, err := GetSqliteObjWH() - if err != nil { - return err - } - defer s.Close() - data, err := s.Where("id=?", []interface{}{id}).Select() - if err != nil { - return err - } - if len(data) == 0 { - return nil - } - SetWorkflowStatus(data[0]["workflow_id"].(string), id, "fail") - return nil -} - -func GetExecLog(id string) (string, error) { - log, err := os.ReadFile(filepath.Join(public.GetSettingIgnoreError("workflow_log_path"), id+".log")) - if err != nil { - return "", err - } - return string(log), nil -} +package workflow + +import ( + "ALLinSSL/backend/public" + "os" + "path/filepath" + "time" +) + +// GetSqliteObjWH 工作流执行历史记录表对象 +func GetSqliteObjWH() (*public.Sqlite, error) { + s, err := public.NewSqlite("data/data.db", "") + if err != nil { + return nil, err + } + s.Connect() + s.TableName = "workflow_history" + return s, nil +} + +// GetListWH 获取工作流执行历史记录列表 +func GetListWH(id string, p, limit int64) ([]map[string]any, int, error) { + var data []map[string]any + var count int64 + s, err := GetSqliteObjWH() + if err != nil { + return data, 0, err + } + defer s.Close() + + var limits []int64 + if p >= 0 && limit >= 0 { + limits = []int64{0, limit} + if p > 1 { + limits[0] = (p - 1) * limit + limits[1] = p * limit + } + } + if id == "" { + count, err = s.Count() + data, err = s.Limit(limits).Order("create_time", "desc").Select() + } else { + count, err = s.Where("workflow_id=?", []interface{}{id}).Count() + data, err = s.Where("workflow_id=?", []interface{}{id}).Limit(limits).Order("create_time", "desc").Select() + } + + if err != nil { + return data, 0, err + } + return data, int(count), nil +} + +// 添加工作流执行历史记录 +func AddWorkflowHistory(workflowID, execType string) (string, error) { + s, err := GetSqliteObjWH() + if err != nil { + return "", err + } + defer s.Close() + now := time.Now().Format("2006-01-02 15:04:05") + ID := public.GenerateUUID() + _, err = s.Insert(map[string]interface{}{ + "id": ID, + "workflow_id": workflowID, + "status": "running", + "exec_type": execType, + "create_time": now, + }) + if err != nil { + return "", err + } + _ = UpdDb(workflowID, map[string]interface{}{"last_run_status": "running", "last_run_time": now}) + return ID, nil +} + +// 工作流执行结束 +func UpdateWorkflowHistory(id, status string) error { + s, err := GetSqliteObjWH() + if err != nil { + return err + } + defer s.Close() + now := time.Now().Format("2006-01-02 15:04:05") + _, err = s.Where("id=?", []interface{}{id}).Update(map[string]interface{}{ + "status": status, + "end_time": now, + }) + if err != nil { + return err + } + return nil +} + +func StopWorkflow(id string) error { + s, err := GetSqliteObjWH() + if err != nil { + return err + } + defer s.Close() + data, err := s.Where("id=?", []interface{}{id}).Select() + if err != nil { + return err + } + if len(data) == 0 { + return nil + } + SetWorkflowStatus(data[0]["workflow_id"].(string), id, "fail") + return nil +} + +func GetExecLog(id string) (string, error) { + log, err := os.ReadFile(filepath.Join(public.GetSettingIgnoreError("workflow_log_path"), id+".log")) + if err != nil { + return "", err + } + return string(log), nil +} diff --git a/backend/migrations/init.go b/backend/migrations/init.go index fc0e9e6..046e731 100644 --- a/backend/migrations/init.go +++ b/backend/migrations/init.go @@ -11,7 +11,7 @@ import ( func init() { os.MkdirAll("data", os.ModePerm) - + dbPath := "data/data.db" _, _ = filepath.Abs(dbPath) // fmt.Println("数据库路径:", absPath) @@ -176,15 +176,15 @@ func init() { INSERT INTO access_type (name, type) VALUES ('ssh', 'host'); INSERT INTO access_type (name, type) VALUES ('btpanel', 'host'); INSERT INTO access_type (name, type) VALUES ('1panel', 'host');`) - + uuidStr := public.GenerateUUID() randomStr := public.RandomString(8) - + port, err := public.GetFreePort() if err != nil { port = 20773 } - + Isql := fmt.Sprintf( `INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('log_path', 'logs/ALLinSSL.log', '2025-04-15 15:58', '2025-04-15 15:58', 1, null); INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ( 'workflow_log_path', 'logs/workflows/', '2025-04-15 15:58', '2025-04-15 15:58', 1, null); @@ -194,7 +194,7 @@ INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('session_key', '%s', '2025-04-15 15:58', '2025-04-15 15:58', 1, null); INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('secure', '/%s', '2025-04-15 15:58', '2025-04-15 15:58', 1, null); INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('port', '%d', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);`, uuidStr, uuidStr, randomStr, port) - + insertDefaultData(db, "settings", Isql) } @@ -206,7 +206,7 @@ func insertDefaultData(db *sql.DB, table, insertSQL string) { // fmt.Println("检查数据行数失败:", err) return } - + // 如果表为空,则插入默认数据 if count == 0 { // fmt.Println("表为空,插入默认数据...") diff --git a/backend/public/utils.go b/backend/public/utils.go index d318ccc..a60431e 100644 --- a/backend/public/utils.go +++ b/backend/public/utils.go @@ -1,181 +1,181 @@ -package public - -import ( - "crypto/rand" - "fmt" - "github.com/google/uuid" - "io" - "math/big" - "net" - "net/http" - "strings" -) - -const defaultCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - -// GetSettingIgnoreError 获取系统配置-忽略错误 -func GetSettingIgnoreError(key string) string { - s, err := NewSqlite("data/data.db", "") - if err != nil { - return "" - } - s.Connect() - defer s.Close() - s.TableName = "settings" - res, err := s.Where("key=?", []interface{}{key}).Select() - if err != nil { - return "" - } - if len(res) == 0 { - return "" - } - setting, ok := res[0]["value"].(string) - if !ok { - return "" - } - return setting -} - -func UpdateSetting(key, val string) error { - s, err := NewSqlite("data/data.db", "") - if err != nil { - return err - } - s.Connect() - defer s.Close() - s.TableName = "settings" - _, err = s.Where("key=?", []interface{}{key}).Update(map[string]any{"value": val}) - if err != nil { - return err - } - return nil -} - -func GetSettingsFromType(typ string) ([]map[string]any, error) { - db := "data/data.db" - s, err := NewSqlite(db, "") - if err != nil { - return nil, err - } - s.Connect() - defer s.Close() - s.TableName = "settings" - res, err := s.Where("type=?", []interface{}{typ}).Select() - if err != nil { - return nil, err - } - - return res, nil -} - -// GetFreePort 获取一个可用的随机端口 -func GetFreePort() (int, error) { - // 端口为 0,表示让系统自动分配一个可用端口 - ln, err := net.Listen("tcp", "localhost:0") - if err != nil { - return 0, err - } - defer ln.Close() - - addr := ln.Addr().String() - // 提取端口号 - parts := strings.Split(addr, ":") - if len(parts) < 2 { - return 0, fmt.Errorf("invalid address: %s", addr) - } - - var port int - fmt.Sscanf(parts[len(parts)-1], "%d", &port) - return port, nil -} - -// RandomString 生成指定长度的随机字符串 -func RandomString(length int) string { - if str, err := RandomStringWithCharset(length, defaultCharset); err != nil { - return "allinssl" - } else { - return str - } -} - -// RandomStringWithCharset 使用指定字符集生成随机字符串 -func RandomStringWithCharset(length int, charset string) (string, error) { - result := make([]byte, length) - charsetLen := big.NewInt(int64(len(charset))) - - for i := 0; i < length; i++ { - num, err := rand.Int(rand.Reader, charsetLen) - if err != nil { - return "", err - } - result[i] = charset[num.Int64()] - } - - return string(result), nil -} - -// GenerateUUID 生成 UUID -func GenerateUUID() string { - // 生成一个新的 UUID - uuidStr := strings.ReplaceAll(uuid.New().String(), "-", "") - - // 返回 UUID 的字符串表示 - return uuidStr -} - -func GetLocalIP() (string, error) { - interfaces, err := net.Interfaces() - if err != nil { - return "", err - } - - for _, iface := range interfaces { - if iface.Flags&net.FlagUp == 0 { - continue // 接口未启用 - } - if iface.Flags&net.FlagLoopback != 0 { - continue // 忽略回环地址 - } - - addrs, err := iface.Addrs() - if err != nil { - continue - } - - for _, addr := range addrs { - var ip net.IP - switch v := addr.(type) { - case *net.IPNet: - ip = v.IP - case *net.IPAddr: - ip = v.IP - } - - // 只返回 IPv4 内网地址 - if ip != nil && ip.To4() != nil && !ip.IsLoopback() { - return ip.String(), nil - } - } - } - - return "", fmt.Errorf("没有找到内网 IP") -} - -func GetPublicIP() (string, error) { - resp, err := http.Get("https://www.bt.cn/Api/getIpAddress") - if err != nil { - return "", fmt.Errorf("请求失败: %v", err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf("HTTP状态错误: %v", resp.Status) - } - - body, err := io.ReadAll(resp.Body) - if err != nil { - return "", fmt.Errorf("读取响应失败: %v", err) - } - - return string(body), nil -} +package public + +import ( + "crypto/rand" + "fmt" + "github.com/google/uuid" + "io" + "math/big" + "net" + "net/http" + "strings" +) + +const defaultCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + +// GetSettingIgnoreError 获取系统配置-忽略错误 +func GetSettingIgnoreError(key string) string { + s, err := NewSqlite("data/data.db", "") + if err != nil { + return "" + } + s.Connect() + defer s.Close() + s.TableName = "settings" + res, err := s.Where("key=?", []interface{}{key}).Select() + if err != nil { + return "" + } + if len(res) == 0 { + return "" + } + setting, ok := res[0]["value"].(string) + if !ok { + return "" + } + return setting +} + +func UpdateSetting(key, val string) error { + s, err := NewSqlite("data/data.db", "") + if err != nil { + return err + } + s.Connect() + defer s.Close() + s.TableName = "settings" + _, err = s.Where("key=?", []interface{}{key}).Update(map[string]any{"value": val}) + if err != nil { + return err + } + return nil +} + +func GetSettingsFromType(typ string) ([]map[string]any, error) { + db := "data/data.db" + s, err := NewSqlite(db, "") + if err != nil { + return nil, err + } + s.Connect() + defer s.Close() + s.TableName = "settings" + res, err := s.Where("type=?", []interface{}{typ}).Select() + if err != nil { + return nil, err + } + + return res, nil +} + +// GetFreePort 获取一个可用的随机端口 +func GetFreePort() (int, error) { + // 端口为 0,表示让系统自动分配一个可用端口 + ln, err := net.Listen("tcp", "localhost:0") + if err != nil { + return 0, err + } + defer ln.Close() + + addr := ln.Addr().String() + // 提取端口号 + parts := strings.Split(addr, ":") + if len(parts) < 2 { + return 0, fmt.Errorf("invalid address: %s", addr) + } + + var port int + fmt.Sscanf(parts[len(parts)-1], "%d", &port) + return port, nil +} + +// RandomString 生成指定长度的随机字符串 +func RandomString(length int) string { + if str, err := RandomStringWithCharset(length, defaultCharset); err != nil { + return "allinssl" + } else { + return str + } +} + +// RandomStringWithCharset 使用指定字符集生成随机字符串 +func RandomStringWithCharset(length int, charset string) (string, error) { + result := make([]byte, length) + charsetLen := big.NewInt(int64(len(charset))) + + for i := 0; i < length; i++ { + num, err := rand.Int(rand.Reader, charsetLen) + if err != nil { + return "", err + } + result[i] = charset[num.Int64()] + } + + return string(result), nil +} + +// GenerateUUID 生成 UUID +func GenerateUUID() string { + // 生成一个新的 UUID + uuidStr := strings.ReplaceAll(uuid.New().String(), "-", "") + + // 返回 UUID 的字符串表示 + return uuidStr +} + +func GetLocalIP() (string, error) { + interfaces, err := net.Interfaces() + if err != nil { + return "", err + } + + for _, iface := range interfaces { + if iface.Flags&net.FlagUp == 0 { + continue // 接口未启用 + } + if iface.Flags&net.FlagLoopback != 0 { + continue // 忽略回环地址 + } + + addrs, err := iface.Addrs() + if err != nil { + continue + } + + for _, addr := range addrs { + var ip net.IP + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + } + + // 只返回 IPv4 内网地址 + if ip != nil && ip.To4() != nil && !ip.IsLoopback() { + return ip.String(), nil + } + } + } + + return "", fmt.Errorf("没有找到内网 IP") +} + +func GetPublicIP() (string, error) { + resp, err := http.Get("https://www.bt.cn/Api/getIpAddress") + if err != nil { + return "", fmt.Errorf("请求失败: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("HTTP状态错误: %v", resp.Status) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("读取响应失败: %v", err) + } + + return string(body), nil +}