后端代码同步

pull/8/head
zhangchenhao 2025-05-08 11:19:53 +08:00
parent 5124663aab
commit 312f10d06d
7 changed files with 523 additions and 521 deletions

View File

@ -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)
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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

View File

@ -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
}

View File

@ -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("表为空,插入默认数据...")

View File

@ -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
}