mirror of https://github.com/allinssl/allinssl
后端代码同步
parent
5124663aab
commit
312f10d06d
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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("表为空,插入默认数据...")
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue