refactor: clean code

This commit is contained in:
Fu Diwei 2025-01-05 00:08:12 +08:00
parent 3b9a7fe805
commit 61843a4997
69 changed files with 972 additions and 839 deletions

View File

@ -1,43 +0,0 @@
package applicant
import (
"encoding/json"
"net/url"
"time"
"github.com/go-acme/lego/v4/providers/dns/httpreq"
"github.com/usual2970/certimate/internal/domain"
)
type acmeHttpReqApplicant struct {
option *ApplyOption
}
func NewACMEHttpReqApplicant(option *ApplyOption) Applicant {
return &acmeHttpReqApplicant{
option: option,
}
}
func (a *acmeHttpReqApplicant) Apply() (*Certificate, error) {
access := &domain.ACMEHttpReqAccessConfig{}
json.Unmarshal([]byte(a.option.AccessConfig), access)
config := httpreq.NewDefaultConfig()
endpoint, _ := url.Parse(access.Endpoint)
config.Endpoint = endpoint
config.Mode = access.Mode
config.Username = access.Username
config.Password = access.Password
if a.option.PropagationTimeout != 0 {
config.PropagationTimeout = time.Duration(a.option.PropagationTimeout) * time.Second
}
provider, err := httpreq.NewDNSProviderConfig(config)
if err != nil {
return nil, err
}
return apply(a.option, provider)
}

View File

@ -1,39 +0,0 @@
package applicant
import (
"encoding/json"
"time"
"github.com/go-acme/lego/v4/providers/dns/alidns"
"github.com/usual2970/certimate/internal/domain"
)
type aliyunApplicant struct {
option *ApplyOption
}
func NewAliyunApplicant(option *ApplyOption) Applicant {
return &aliyunApplicant{
option: option,
}
}
func (a *aliyunApplicant) Apply() (*Certificate, error) {
access := &domain.AliyunAccessConfig{}
json.Unmarshal([]byte(a.option.AccessConfig), access)
config := alidns.NewDefaultConfig()
config.APIKey = access.AccessKeyId
config.SecretKey = access.AccessKeySecret
if a.option.PropagationTimeout != 0 {
config.PropagationTimeout = time.Duration(a.option.PropagationTimeout) * time.Second
}
provider, err := alidns.NewDNSProviderConfig(config)
if err != nil {
return nil, err
}
return apply(a.option, provider)
}

View File

@ -50,10 +50,10 @@ type Certificate struct {
PrivateKey string `json:"privateKey"` PrivateKey string `json:"privateKey"`
Certificate string `json:"certificate"` Certificate string `json:"certificate"`
IssuerCertificate string `json:"issuerCertificate"` IssuerCertificate string `json:"issuerCertificate"`
Csr string `json:"csr"` CSR string `json:"csr"`
} }
type ApplyOption struct { type applyConfig struct {
Domains string `json:"domains"` Domains string `json:"domains"`
ContactEmail string `json:"contactEmail"` ContactEmail string `json:"contactEmail"`
AccessConfig string `json:"accessConfig"` AccessConfig string `json:"accessConfig"`
@ -63,65 +63,79 @@ type ApplyOption struct {
DisableFollowCNAME bool `json:"disableFollowCNAME"` DisableFollowCNAME bool `json:"disableFollowCNAME"`
} }
type ApplyUser struct { type applyUser struct {
Ca string CA string
Email string Email string
Registration *registration.Resource Registration *registration.Resource
key string
privkey string
} }
func newApplyUser(ca, email string) (*ApplyUser, error) { func newApplyUser(ca, email string) (*applyUser, error) {
repo := getAcmeAccountRepository() repo := getAcmeAccountRepository()
rs := &ApplyUser{
Ca: ca, applyUser := &applyUser{
CA: ca,
Email: email, Email: email,
} }
resp, err := repo.GetByCAAndEmail(ca, email)
if err != nil {
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, err
}
keyStr, err := x509.ConvertECPrivateKeyToPEM(privateKey)
if err != nil {
return nil, err
}
rs.key = keyStr
return rs, nil acmeAccount, err := repo.GetByCAAndEmail(ca, email)
if err != nil {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, err
}
keyStr, err := x509.ConvertECPrivateKeyToPEM(key)
if err != nil {
return nil, err
}
applyUser.privkey = keyStr
return applyUser, nil
} }
rs.Registration = resp.Resource applyUser.Registration = acmeAccount.Resource
rs.key = resp.Key applyUser.privkey = acmeAccount.Key
return rs, nil return applyUser, nil
} }
func (u *ApplyUser) GetEmail() string { func (u *applyUser) GetEmail() string {
return u.Email return u.Email
} }
func (u ApplyUser) GetRegistration() *registration.Resource { func (u applyUser) GetRegistration() *registration.Resource {
return u.Registration return u.Registration
} }
func (u *ApplyUser) GetPrivateKey() crypto.PrivateKey { func (u *applyUser) GetPrivateKey() crypto.PrivateKey {
rs, _ := x509.ParseECPrivateKeyFromPEM(u.key) rs, _ := x509.ParseECPrivateKeyFromPEM(u.privkey)
return rs return rs
} }
func (u *ApplyUser) hasRegistration() bool { func (u *applyUser) hasRegistration() bool {
return u.Registration != nil return u.Registration != nil
} }
func (u *ApplyUser) getPrivateKeyString() string { func (u *applyUser) getPrivateKeyString() string {
return u.key return u.privkey
} }
type Applicant interface { type Applicant interface {
Apply() (*Certificate, error) Apply() (*Certificate, error)
} }
// TODO: 暂时使用代理模式以兼容之前版本代码,后续重新实现此处逻辑
type proxyApplicant struct {
applyConfig *applyConfig
applicant challenge.Provider
}
func (d *proxyApplicant) Apply() (*Certificate, error) {
return apply(d.applyConfig, d.applicant)
}
func GetWithApplyNode(node *domain.WorkflowNode) (Applicant, error) { func GetWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
// 获取授权配置 // 获取授权配置
accessRepo := repository.NewAccessRepository() accessRepo := repository.NewAccessRepository()
@ -131,7 +145,7 @@ func GetWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
return nil, fmt.Errorf("access record not found: %w", err) return nil, fmt.Errorf("access record not found: %w", err)
} }
applyConfig := &ApplyOption{ applyConfig := &applyConfig{
Domains: node.GetConfigString("domains"), Domains: node.GetConfigString("domains"),
ContactEmail: node.GetConfigString("contactEmail"), ContactEmail: node.GetConfigString("contactEmail"),
AccessConfig: access.Config, AccessConfig: access.Config,
@ -141,40 +155,15 @@ func GetWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
DisableFollowCNAME: node.GetConfigBool("disableFollowCNAME"), DisableFollowCNAME: node.GetConfigBool("disableFollowCNAME"),
} }
return GetWithTypeOption(domain.AccessProviderType(access.Provider), applyConfig) challengeProvider, err := createChallengeProvider(domain.AccessProviderType(access.Provider), access.Config, applyConfig)
} if err != nil {
return nil, err
func GetWithTypeOption(provider domain.AccessProviderType, option *ApplyOption) (Applicant, error) {
/*
注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order.
*/
switch provider {
case domain.ACCESS_PROVIDER_ACMEHTTPREQ:
return NewACMEHttpReqApplicant(option), nil
case domain.ACCESS_PROVIDER_ALIYUN:
return NewAliyunApplicant(option), nil
case domain.ACCESS_PROVIDER_AWS:
return NewAWSApplicant(option), nil
case domain.ACCESS_PROVIDER_CLOUDFLARE:
return NewCloudflareApplicant(option), nil
case domain.ACCESS_PROVIDER_GODADDY:
return NewGoDaddyApplicant(option), nil
case domain.ACCESS_PROVIDER_HUAWEICLOUD:
return NewHuaweiCloudApplicant(option), nil
case domain.ACCESS_PROVIDER_NAMEDOTCOM:
return NewNameDotComApplicant(option), nil
case domain.ACCESS_PROVIDER_NAMESILO:
return NewNamesiloApplicant(option), nil
case domain.ACCESS_PROVIDER_POWERDNS:
return NewPowerDNSApplicant(option), nil
case domain.ACCESS_PROVIDER_TENCENTCLOUD:
return NewTencentCloudApplicant(option), nil
case domain.ACCESS_PROVIDER_VOLCENGINE:
return NewVolcEngineApplicant(option), nil
default:
return nil, fmt.Errorf("unsupported applicant provider type: %s", provider)
} }
return &proxyApplicant{
applyConfig: applyConfig,
applicant: challengeProvider,
}, nil
} }
type SSLProviderConfig struct { type SSLProviderConfig struct {
@ -192,7 +181,7 @@ type SSLProviderEab struct {
EabKid string `json:"eabKid"` EabKid string `json:"eabKid"`
} }
func apply(option *ApplyOption, provider challenge.Provider) (*Certificate, error) { func apply(option *applyConfig, provider challenge.Provider) (*Certificate, error) {
record, _ := app.GetApp().Dao().FindFirstRecordByFilter("settings", "name='sslProvider'") record, _ := app.GetApp().Dao().FindFirstRecordByFilter("settings", "name='sslProvider'")
sslProvider := &SSLProviderConfig{ sslProvider := &SSLProviderConfig{
@ -259,7 +248,7 @@ func apply(option *ApplyOption, provider challenge.Provider) (*Certificate, erro
PrivateKey: string(certificates.PrivateKey), PrivateKey: string(certificates.PrivateKey),
Certificate: string(certificates.Certificate), Certificate: string(certificates.Certificate),
IssuerCertificate: string(certificates.IssuerCertificate), IssuerCertificate: string(certificates.IssuerCertificate),
Csr: string(certificates.CSR), CSR: string(certificates.CSR),
}, nil }, nil
} }
@ -272,7 +261,9 @@ func getAcmeAccountRepository() AcmeAccountRepository {
return repository.NewAcmeAccountRepository() return repository.NewAcmeAccountRepository()
} }
func getReg(client *lego.Client, sslProvider *SSLProviderConfig, user *ApplyUser) (*registration.Resource, error) { func getReg(client *lego.Client, sslProvider *SSLProviderConfig, user *applyUser) (*registration.Resource, error) {
// TODO: fix 潜在的并发问题
var reg *registration.Resource var reg *registration.Resource
var err error var err error
switch sslProvider.Provider { switch sslProvider.Provider {
@ -304,7 +295,7 @@ func getReg(client *lego.Client, sslProvider *SSLProviderConfig, user *ApplyUser
resp, err := repo.GetByCAAndEmail(sslProvider.Provider, user.GetEmail()) resp, err := repo.GetByCAAndEmail(sslProvider.Provider, user.GetEmail())
if err == nil { if err == nil {
user.key = resp.Key user.privkey = resp.Key
return resp.Resource, nil return resp.Resource, nil
} }

View File

@ -1,41 +0,0 @@
package applicant
import (
"encoding/json"
"time"
"github.com/go-acme/lego/v4/providers/dns/route53"
"github.com/usual2970/certimate/internal/domain"
)
type awsApplicant struct {
option *ApplyOption
}
func NewAWSApplicant(option *ApplyOption) Applicant {
return &awsApplicant{
option: option,
}
}
func (a *awsApplicant) Apply() (*Certificate, error) {
access := &domain.AWSAccessConfig{}
json.Unmarshal([]byte(a.option.AccessConfig), access)
config := route53.NewDefaultConfig()
config.AccessKeyID = access.AccessKeyId
config.SecretAccessKey = access.SecretAccessKey
config.Region = access.Region
config.HostedZoneID = access.HostedZoneId
if a.option.PropagationTimeout != 0 {
config.PropagationTimeout = time.Duration(a.option.PropagationTimeout) * time.Second
}
provider, err := route53.NewDNSProviderConfig(config)
if err != nil {
return nil, err
}
return apply(a.option, provider)
}

View File

@ -1,38 +0,0 @@
package applicant
import (
"encoding/json"
"time"
"github.com/go-acme/lego/v4/providers/dns/cloudflare"
"github.com/usual2970/certimate/internal/domain"
)
type cloudflareApplicant struct {
option *ApplyOption
}
func NewCloudflareApplicant(option *ApplyOption) Applicant {
return &cloudflareApplicant{
option: option,
}
}
func (a *cloudflareApplicant) Apply() (*Certificate, error) {
access := &domain.CloudflareAccessConfig{}
json.Unmarshal([]byte(a.option.AccessConfig), access)
config := cloudflare.NewDefaultConfig()
config.AuthToken = access.DnsApiToken
if a.option.PropagationTimeout != 0 {
config.PropagationTimeout = time.Duration(a.option.PropagationTimeout) * time.Second
}
provider, err := cloudflare.NewDNSProviderConfig(config)
if err != nil {
return nil, err
}
return apply(a.option, provider)
}

View File

@ -1,39 +0,0 @@
package applicant
import (
"encoding/json"
"time"
"github.com/go-acme/lego/v4/providers/dns/godaddy"
"github.com/usual2970/certimate/internal/domain"
)
type godaddyApplicant struct {
option *ApplyOption
}
func NewGoDaddyApplicant(option *ApplyOption) Applicant {
return &godaddyApplicant{
option: option,
}
}
func (a *godaddyApplicant) Apply() (*Certificate, error) {
access := &domain.GoDaddyAccessConfig{}
json.Unmarshal([]byte(a.option.AccessConfig), access)
config := godaddy.NewDefaultConfig()
config.APIKey = access.ApiKey
config.APISecret = access.ApiSecret
if a.option.PropagationTimeout != 0 {
config.PropagationTimeout = time.Duration(a.option.PropagationTimeout) * time.Second
}
provider, err := godaddy.NewDNSProviderConfig(config)
if err != nil {
return nil, err
}
return apply(a.option, provider)
}

View File

@ -1,46 +0,0 @@
package applicant
import (
"encoding/json"
"time"
huaweicloud "github.com/go-acme/lego/v4/providers/dns/huaweicloud"
"github.com/usual2970/certimate/internal/domain"
)
type huaweicloudApplicant struct {
option *ApplyOption
}
func NewHuaweiCloudApplicant(option *ApplyOption) Applicant {
return &huaweicloudApplicant{
option: option,
}
}
func (a *huaweicloudApplicant) Apply() (*Certificate, error) {
access := &domain.HuaweiCloudAccessConfig{}
json.Unmarshal([]byte(a.option.AccessConfig), access)
region := access.Region
if region == "" {
// 华为云的 SDK 要求必须传一个区域,实际上 DNS-01 流程里用不到,但不传会报错
region = "cn-north-1"
}
config := huaweicloud.NewDefaultConfig()
config.AccessKeyID = access.AccessKeyId
config.SecretAccessKey = access.SecretAccessKey
config.Region = region
if a.option.PropagationTimeout != 0 {
config.PropagationTimeout = time.Duration(a.option.PropagationTimeout) * time.Second
}
provider, err := huaweicloud.NewDNSProviderConfig(config)
if err != nil {
return nil, err
}
return apply(a.option, provider)
}

View File

@ -1,38 +0,0 @@
package applicant
import (
"encoding/json"
"time"
"github.com/go-acme/lego/v4/providers/dns/namedotcom"
"github.com/usual2970/certimate/internal/domain"
)
type nameDotComApplicant struct {
option *ApplyOption
}
func NewNameDotComApplicant(option *ApplyOption) Applicant {
return &nameDotComApplicant{
option: option,
}
}
func (a *nameDotComApplicant) Apply() (*Certificate, error) {
access := &domain.NameDotComAccessConfig{}
json.Unmarshal([]byte(a.option.AccessConfig), access)
config := namedotcom.NewDefaultConfig()
config.Username = access.Username
config.APIToken = access.ApiToken
if a.option.PropagationTimeout != 0 {
config.PropagationTimeout = time.Duration(a.option.PropagationTimeout) * time.Second
}
provider, err := namedotcom.NewDNSProviderConfig(config)
if err != nil {
return nil, err
}
return apply(a.option, provider)
}

View File

@ -1,38 +0,0 @@
package applicant
import (
"encoding/json"
"time"
namesilo "github.com/go-acme/lego/v4/providers/dns/namesilo"
"github.com/usual2970/certimate/internal/domain"
)
type namesiloApplicant struct {
option *ApplyOption
}
func NewNamesiloApplicant(option *ApplyOption) Applicant {
return &namesiloApplicant{
option: option,
}
}
func (a *namesiloApplicant) Apply() (*Certificate, error) {
access := &domain.NameSiloAccessConfig{}
json.Unmarshal([]byte(a.option.AccessConfig), access)
config := namesilo.NewDefaultConfig()
config.APIKey = access.ApiKey
if a.option.PropagationTimeout != 0 {
config.PropagationTimeout = time.Duration(a.option.PropagationTimeout) * time.Second
}
provider, err := namesilo.NewDNSProviderConfig(config)
if err != nil {
return nil, err
}
return apply(a.option, provider)
}

View File

@ -1,41 +0,0 @@
package applicant
import (
"encoding/json"
"net/url"
"time"
"github.com/go-acme/lego/v4/providers/dns/pdns"
"github.com/usual2970/certimate/internal/domain"
)
type powerdnsApplicant struct {
option *ApplyOption
}
func NewPowerDNSApplicant(option *ApplyOption) Applicant {
return &powerdnsApplicant{
option: option,
}
}
func (a *powerdnsApplicant) Apply() (*Certificate, error) {
access := &domain.PowerDNSAccessConfig{}
json.Unmarshal([]byte(a.option.AccessConfig), access)
config := pdns.NewDefaultConfig()
host, _ := url.Parse(access.ApiUrl)
config.Host = host
config.APIKey = access.ApiKey
if a.option.PropagationTimeout != 0 {
config.PropagationTimeout = time.Duration(a.option.PropagationTimeout) * time.Second
}
provider, err := pdns.NewDNSProviderConfig(config)
if err != nil {
return nil, err
}
return apply(a.option, provider)
}

View File

@ -0,0 +1,199 @@
package applicant
import (
"encoding/json"
"fmt"
"github.com/go-acme/lego/v4/challenge"
"github.com/usual2970/certimate/internal/domain"
providerACMEHttpReq "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/acmehttpreq"
providerAliyun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun"
providerAWS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aws"
providerCloudflare "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudflare"
providerGoDaddy "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/godaddy"
providerHuaweiCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud"
providerNameDotCom "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom"
providerNameSilo "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo"
providerPowerDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns"
providerTencentCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud"
providerVolcEngine "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/volcengine"
)
func createChallengeProvider(provider domain.AccessProviderType, accessConfig string, applyConfig *applyConfig) (challenge.Provider, error) {
/*
注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order.
*/
switch provider {
case domain.AccessProviderTypeACMEHttpReq:
{
access := &domain.AccessConfigForACMEHttpReq{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
}
applicant, err := providerACMEHttpReq.NewChallengeProvider(&providerACMEHttpReq.ACMEHttpReqApplicantConfig{
Endpoint: access.Endpoint,
Mode: access.Mode,
Username: access.Username,
Password: access.Password,
PropagationTimeout: applyConfig.PropagationTimeout,
})
return applicant, err
}
case domain.AccessProviderTypeAliyun:
{
access := &domain.AccessConfigForAliyun{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
}
applicant, err := providerAliyun.NewChallengeProvider(&providerAliyun.AliyunApplicantConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
PropagationTimeout: applyConfig.PropagationTimeout,
})
return applicant, err
}
case domain.AccessProviderTypeAWS:
{
access := &domain.AccessConfigForAWS{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
}
applicant, err := providerAWS.NewChallengeProvider(&providerAWS.AWSApplicantConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
Region: access.Region,
HostedZoneId: access.HostedZoneId,
PropagationTimeout: applyConfig.PropagationTimeout,
})
return applicant, err
}
case domain.AccessProviderTypeCloudflare:
{
access := &domain.AccessConfigForCloudflare{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
}
applicant, err := providerCloudflare.NewChallengeProvider(&providerCloudflare.CloudflareApplicantConfig{
DnsApiToken: access.DnsApiToken,
PropagationTimeout: applyConfig.PropagationTimeout,
})
return applicant, err
}
case domain.AccessProviderTypeGoDaddy:
{
access := &domain.AccessConfigForGoDaddy{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
}
applicant, err := providerGoDaddy.NewChallengeProvider(&providerGoDaddy.GoDaddyApplicantConfig{
ApiKey: access.ApiKey,
ApiSecret: access.ApiSecret,
PropagationTimeout: applyConfig.PropagationTimeout,
})
return applicant, err
}
case domain.AccessProviderTypeHuaweiCloud:
{
access := &domain.AccessConfigForHuaweiCloud{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
}
applicant, err := providerHuaweiCloud.NewChallengeProvider(&providerHuaweiCloud.HuaweiCloudApplicantConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
Region: access.Region,
PropagationTimeout: applyConfig.PropagationTimeout,
})
return applicant, err
}
case domain.AccessProviderTypeNameDotCom:
{
access := &domain.AccessConfigForNameDotCom{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
}
applicant, err := providerNameDotCom.NewChallengeProvider(&providerNameDotCom.NameDotComApplicantConfig{
Username: access.Username,
ApiToken: access.ApiToken,
PropagationTimeout: applyConfig.PropagationTimeout,
})
return applicant, err
}
case domain.AccessProviderTypeNameSilo:
{
access := &domain.AccessConfigForNameSilo{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
}
applicant, err := providerNameSilo.NewChallengeProvider(&providerNameSilo.NameSiloApplicantConfig{
ApiKey: access.ApiKey,
PropagationTimeout: applyConfig.PropagationTimeout,
})
return applicant, err
}
case domain.AccessProviderTypePowerDNS:
{
access := &domain.AccessConfigForPowerDNS{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
}
applicant, err := providerPowerDNS.NewChallengeProvider(&providerPowerDNS.PowerDNSApplicantConfig{
ApiUrl: access.ApiUrl,
ApiKey: access.ApiKey,
PropagationTimeout: applyConfig.PropagationTimeout,
})
return applicant, err
}
case domain.AccessProviderTypeTencentCloud:
{
access := &domain.AccessConfigForTencentCloud{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
}
applicant, err := providerTencentCloud.NewChallengeProvider(&providerTencentCloud.TencentCloudApplicantConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
PropagationTimeout: applyConfig.PropagationTimeout,
})
return applicant, err
}
case domain.AccessProviderTypeVolcEngine:
{
access := &domain.AccessConfigForVolcEngine{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, fmt.Errorf("failed to unmarshal access config: %w", err)
}
applicant, err := providerVolcEngine.NewChallengeProvider(&providerVolcEngine.VolcEngineApplicantConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
PropagationTimeout: applyConfig.PropagationTimeout,
})
return applicant, err
}
}
return nil, fmt.Errorf("unsupported applicant provider: %s", provider)
}

View File

@ -1,39 +0,0 @@
package applicant
import (
"encoding/json"
"time"
"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
"github.com/usual2970/certimate/internal/domain"
)
type tencentcloudApplicant struct {
option *ApplyOption
}
func NewTencentCloudApplicant(option *ApplyOption) Applicant {
return &tencentcloudApplicant{
option: option,
}
}
func (a *tencentcloudApplicant) Apply() (*Certificate, error) {
access := &domain.TencentCloudAccessConfig{}
json.Unmarshal([]byte(a.option.AccessConfig), access)
config := tencentcloud.NewDefaultConfig()
config.SecretID = access.SecretId
config.SecretKey = access.SecretKey
if a.option.PropagationTimeout != 0 {
config.PropagationTimeout = time.Duration(a.option.PropagationTimeout) * time.Second
}
provider, err := tencentcloud.NewDNSProviderConfig(config)
if err != nil {
return nil, err
}
return apply(a.option, provider)
}

View File

@ -1,38 +0,0 @@
package applicant
import (
"encoding/json"
"time"
"github.com/go-acme/lego/v4/providers/dns/volcengine"
"github.com/usual2970/certimate/internal/domain"
)
type volcengineApplicant struct {
option *ApplyOption
}
func NewVolcEngineApplicant(option *ApplyOption) Applicant {
return &volcengineApplicant{
option: option,
}
}
func (a *volcengineApplicant) Apply() (*Certificate, error) {
access := &domain.VolcEngineAccessConfig{}
json.Unmarshal([]byte(a.option.AccessConfig), access)
config := volcengine.NewDefaultConfig()
config.AccessKey = access.AccessKeyId
config.SecretKey = access.SecretAccessKey
if a.option.PropagationTimeout != 0 {
config.PropagationTimeout = time.Duration(a.option.PropagationTimeout) * time.Second
}
provider, err := volcengine.NewDNSProviderConfig(config)
if err != nil {
return nil, err
}
return apply(a.option, provider)
}

View File

@ -2,7 +2,6 @@ package deployer
import ( import (
"context" "context"
"fmt"
"github.com/usual2970/certimate/internal/applicant" "github.com/usual2970/certimate/internal/applicant"
"github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/domain"
@ -10,39 +9,6 @@ import (
"github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/logger"
) )
/*
提供商部署目标常量值
短横线前的部分始终等于提供商类型
注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order.
*/
const (
targetAliyunALB = "aliyun-alb"
targetAliyunCDN = "aliyun-cdn"
targetAliyunCLB = "aliyun-clb"
targetAliyunDCDN = "aliyun-dcdn"
targetAliyunNLB = "aliyun-nlb"
targetAliyunOSS = "aliyun-oss"
targetBaiduCloudCDN = "baiducloud-cdn"
targetBytePlusCDN = "byteplus-cdn"
targetDogeCloudCDN = "dogecloud-cdn"
targetHuaweiCloudCDN = "huaweicloud-cdn"
targetHuaweiCloudELB = "huaweicloud-elb"
targetK8sSecret = "k8s-secret"
targetLocal = "local"
targetQiniuCDN = "qiniu-cdn"
targetSSH = "ssh"
targetTencentCloudCDN = "tencentcloud-cdn"
targetTencentCloudCLB = "tencentcloud-clb"
targetTencentCloudCOS = "tencentcloud-cos"
targetTencentCloudECDN = "tencentcloud-ecdn"
targetTencentCloudEO = "tencentcloud-eo"
targetVolcEngineCDN = "volcengine-cdn"
targetVolcEngineLive = "volcengine-live"
targetWebhook = "webhook"
)
type DeployerOption struct { type DeployerOption struct {
NodeId string `json:"nodeId"` NodeId string `json:"nodeId"`
Domains string `json:"domains"` Domains string `json:"domains"`
@ -50,17 +16,14 @@ type DeployerOption struct {
AccessRecord *domain.Access `json:"-"` AccessRecord *domain.Access `json:"-"`
DeployConfig domain.DeployConfig `json:"deployConfig"` DeployConfig domain.DeployConfig `json:"deployConfig"`
Certificate applicant.Certificate `json:"certificate"` Certificate applicant.Certificate `json:"certificate"`
Variables map[string]string `json:"variables"`
} }
type Deployer interface { type Deployer interface {
Deploy(ctx context.Context) error Deploy(ctx context.Context) error
GetInfos() []string
GetID() string
} }
func GetWithTypeAndOption(deployType string, option *DeployerOption) (Deployer, error) { func GetWithProviderAndOption(provider string, option *DeployerOption) (Deployer, error) {
deployer, logger, err := createDeployer(deployType, option.AccessRecord.Config, option.DeployConfig.NodeConfig) deployer, logger, err := createDeployer(domain.DeployProviderType(provider), option.AccessRecord.Config, option.DeployConfig.NodeConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -79,14 +42,6 @@ type proxyDeployer struct {
deployer deployer.Deployer deployer deployer.Deployer
} }
func (d *proxyDeployer) GetID() string {
return fmt.Sprintf("%s-%s", d.option.AccessRecord.Name, d.option.AccessRecord.Id)
}
func (d *proxyDeployer) GetInfos() []string {
return d.logger.GetRecords()
}
func (d *proxyDeployer) Deploy(ctx context.Context) error { func (d *proxyDeployer) Deploy(ctx context.Context) error {
_, err := d.deployer.Deploy(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) _, err := d.deployer.Deploy(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
return err return err

View File

@ -34,23 +34,23 @@ import (
"github.com/usual2970/certimate/internal/pkg/utils/maps" "github.com/usual2970/certimate/internal/pkg/utils/maps"
) )
func createDeployer(target string, accessConfig string, deployConfig map[string]any) (deployer.Deployer, logger.Logger, error) { func createDeployer(provider domain.DeployProviderType, accessConfig string, deployConfig map[string]any) (deployer.Deployer, logger.Logger, error) {
logger := logger.NewDefaultLogger() logger := logger.NewDefaultLogger()
/* /*
注意如果追加新的常量值请保持以 ASCII 排序 注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order. NOTICE: If you add new constant, please keep ASCII order.
*/ */
switch target { switch provider {
case targetAliyunALB, targetAliyunCDN, targetAliyunCLB, targetAliyunDCDN, targetAliyunNLB, targetAliyunOSS: case domain.DeployProviderTypeAliyunALB, domain.DeployProviderTypeAliyunCDN, domain.DeployProviderTypeAliyunCLB, domain.DeployProviderTypeAliyunDCDN, domain.DeployProviderTypeAliyunNLB, domain.DeployProviderTypeAliyunOSS:
{ {
access := &domain.AliyunAccessConfig{} access := &domain.AccessConfigForAliyun{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil { if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err) return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err)
} }
switch target { switch provider {
case targetAliyunALB: case domain.DeployProviderTypeAliyunALB:
deployer, err := providerAliyunALB.NewWithLogger(&providerAliyunALB.AliyunALBDeployerConfig{ deployer, err := providerAliyunALB.NewWithLogger(&providerAliyunALB.AliyunALBDeployerConfig{
AccessKeyId: access.AccessKeyId, AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret, AccessKeySecret: access.AccessKeySecret,
@ -61,7 +61,7 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
}, logger) }, logger)
return deployer, logger, err return deployer, logger, err
case targetAliyunCDN: case domain.DeployProviderTypeAliyunCDN:
deployer, err := providerAliyunCDN.NewWithLogger(&providerAliyunCDN.AliyunCDNDeployerConfig{ deployer, err := providerAliyunCDN.NewWithLogger(&providerAliyunCDN.AliyunCDNDeployerConfig{
AccessKeyId: access.AccessKeyId, AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret, AccessKeySecret: access.AccessKeySecret,
@ -69,7 +69,7 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
}, logger) }, logger)
return deployer, logger, err return deployer, logger, err
case targetAliyunCLB: case domain.DeployProviderTypeAliyunCLB:
deployer, err := providerAliyunCLB.NewWithLogger(&providerAliyunCLB.AliyunCLBDeployerConfig{ deployer, err := providerAliyunCLB.NewWithLogger(&providerAliyunCLB.AliyunCLBDeployerConfig{
AccessKeyId: access.AccessKeyId, AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret, AccessKeySecret: access.AccessKeySecret,
@ -80,7 +80,7 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
}, logger) }, logger)
return deployer, logger, err return deployer, logger, err
case targetAliyunDCDN: case domain.DeployProviderTypeAliyunDCDN:
deployer, err := providerAliyunDCDN.NewWithLogger(&providerAliyunDCDN.AliyunDCDNDeployerConfig{ deployer, err := providerAliyunDCDN.NewWithLogger(&providerAliyunDCDN.AliyunDCDNDeployerConfig{
AccessKeyId: access.AccessKeyId, AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret, AccessKeySecret: access.AccessKeySecret,
@ -88,7 +88,7 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
}, logger) }, logger)
return deployer, logger, err return deployer, logger, err
case targetAliyunNLB: case domain.DeployProviderTypeAliyunNLB:
deployer, err := providerAliyunNLB.NewWithLogger(&providerAliyunNLB.AliyunNLBDeployerConfig{ deployer, err := providerAliyunNLB.NewWithLogger(&providerAliyunNLB.AliyunNLBDeployerConfig{
AccessKeyId: access.AccessKeyId, AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret, AccessKeySecret: access.AccessKeySecret,
@ -99,7 +99,7 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
}, logger) }, logger)
return deployer, logger, err return deployer, logger, err
case targetAliyunOSS: case domain.DeployProviderTypeAliyunOSS:
deployer, err := providerAliyunOSS.NewWithLogger(&providerAliyunOSS.AliyunOSSDeployerConfig{ deployer, err := providerAliyunOSS.NewWithLogger(&providerAliyunOSS.AliyunOSSDeployerConfig{
AccessKeyId: access.AccessKeyId, AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret, AccessKeySecret: access.AccessKeySecret,
@ -114,9 +114,9 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
} }
} }
case targetBaiduCloudCDN: case domain.DeployProviderTypeBaiduCloudCDN:
{ {
access := &domain.BaiduCloudAccessConfig{} access := &domain.AccessConfigForBaiduCloud{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil { if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err) return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err)
} }
@ -129,9 +129,9 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
return deployer, logger, err return deployer, logger, err
} }
case targetBytePlusCDN: case domain.DeployProviderTypeBytePlusCDN:
{ {
access := &domain.BytePlusAccessConfig{} access := &domain.AccessConfigForBytePlus{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil { if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err) return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err)
} }
@ -144,9 +144,9 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
return deployer, logger, err return deployer, logger, err
} }
case targetDogeCloudCDN: case domain.DeployProviderTypeDogeCloudCDN:
{ {
access := &domain.DogeCloudAccessConfig{} access := &domain.AccessConfigForDogeCloud{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil { if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err) return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err)
} }
@ -159,15 +159,15 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
return deployer, logger, err return deployer, logger, err
} }
case targetHuaweiCloudCDN, targetHuaweiCloudELB: case domain.DeployProviderTypeHuaweiCloudCDN, domain.DeployProviderTypeHuaweiCloudELB:
{ {
access := &domain.HuaweiCloudAccessConfig{} access := &domain.AccessConfigForHuaweiCloud{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil { if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err) return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err)
} }
switch target { switch provider {
case targetHuaweiCloudCDN: case domain.DeployProviderTypeHuaweiCloudCDN:
deployer, err := providerHuaweiCloudCDN.NewWithLogger(&providerHuaweiCloudCDN.HuaweiCloudCDNDeployerConfig{ deployer, err := providerHuaweiCloudCDN.NewWithLogger(&providerHuaweiCloudCDN.HuaweiCloudCDNDeployerConfig{
AccessKeyId: access.AccessKeyId, AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey, SecretAccessKey: access.SecretAccessKey,
@ -176,7 +176,7 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
}, logger) }, logger)
return deployer, logger, err return deployer, logger, err
case targetHuaweiCloudELB: case domain.DeployProviderTypeHuaweiCloudELB:
deployer, err := providerHuaweiCloudELB.NewWithLogger(&providerHuaweiCloudELB.HuaweiCloudELBDeployerConfig{ deployer, err := providerHuaweiCloudELB.NewWithLogger(&providerHuaweiCloudELB.HuaweiCloudELBDeployerConfig{
AccessKeyId: access.AccessKeyId, AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey, SecretAccessKey: access.SecretAccessKey,
@ -193,7 +193,7 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
} }
} }
case targetLocal: case domain.DeployProviderTypeLocal:
{ {
deployer, err := providerLocal.NewWithLogger(&providerLocal.LocalDeployerConfig{ deployer, err := providerLocal.NewWithLogger(&providerLocal.LocalDeployerConfig{
ShellEnv: providerLocal.ShellEnvType(maps.GetValueAsString(deployConfig, "shellEnv")), ShellEnv: providerLocal.ShellEnvType(maps.GetValueAsString(deployConfig, "shellEnv")),
@ -210,9 +210,9 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
return deployer, logger, err return deployer, logger, err
} }
case targetK8sSecret: case domain.DeployProviderTypeK8sSecret:
{ {
access := &domain.KubernetesAccessConfig{} access := &domain.AccessConfigForKubernetes{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil { if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err) return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err)
} }
@ -228,9 +228,9 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
return deployer, logger, err return deployer, logger, err
} }
case targetQiniuCDN: case domain.DeployProviderTypeQiniuCDN:
{ {
access := &domain.QiniuAccessConfig{} access := &domain.AccessConfigForQiniu{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil { if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err) return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err)
} }
@ -243,9 +243,9 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
return deployer, logger, err return deployer, logger, err
} }
case targetSSH: case domain.DeployProviderTypeSSH:
{ {
access := &domain.SSHAccessConfig{} access := &domain.AccessConfigForSSH{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil { if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err) return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err)
} }
@ -271,15 +271,15 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
return deployer, logger, err return deployer, logger, err
} }
case targetTencentCloudCDN, targetTencentCloudCLB, targetTencentCloudCOS, targetTencentCloudECDN, targetTencentCloudEO: case domain.DeployProviderTypeTencentCloudCDN, domain.DeployProviderTypeTencentCloudCLB, domain.DeployProviderTypeTencentCloudCOS, domain.DeployProviderTypeTencentCloudECDN, domain.DeployProviderTypeTencentCloudEO:
{ {
access := &domain.TencentCloudAccessConfig{} access := &domain.AccessConfigForTencentCloud{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil { if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err) return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err)
} }
switch target { switch provider {
case targetTencentCloudCDN: case domain.DeployProviderTypeTencentCloudCDN:
deployer, err := providerTencentCloudCDN.NewWithLogger(&providerTencentCloudCDN.TencentCloudCDNDeployerConfig{ deployer, err := providerTencentCloudCDN.NewWithLogger(&providerTencentCloudCDN.TencentCloudCDNDeployerConfig{
SecretId: access.SecretId, SecretId: access.SecretId,
SecretKey: access.SecretKey, SecretKey: access.SecretKey,
@ -287,7 +287,7 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
}, logger) }, logger)
return deployer, logger, err return deployer, logger, err
case targetTencentCloudCLB: case domain.DeployProviderTypeTencentCloudCLB:
deployer, err := providerTencentCloudCLB.NewWithLogger(&providerTencentCloudCLB.TencentCloudCLBDeployerConfig{ deployer, err := providerTencentCloudCLB.NewWithLogger(&providerTencentCloudCLB.TencentCloudCLBDeployerConfig{
SecretId: access.SecretId, SecretId: access.SecretId,
SecretKey: access.SecretKey, SecretKey: access.SecretKey,
@ -299,7 +299,7 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
}, logger) }, logger)
return deployer, logger, err return deployer, logger, err
case targetTencentCloudCOS: case domain.DeployProviderTypeTencentCloudCOS:
deployer, err := providerTencentCloudCOD.NewWithLogger(&providerTencentCloudCOD.TencentCloudCOSDeployerConfig{ deployer, err := providerTencentCloudCOD.NewWithLogger(&providerTencentCloudCOD.TencentCloudCOSDeployerConfig{
SecretId: access.SecretId, SecretId: access.SecretId,
SecretKey: access.SecretKey, SecretKey: access.SecretKey,
@ -309,7 +309,7 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
}, logger) }, logger)
return deployer, logger, err return deployer, logger, err
case targetTencentCloudECDN: case domain.DeployProviderTypeTencentCloudECDN:
deployer, err := providerTencentCloudECDN.NewWithLogger(&providerTencentCloudECDN.TencentCloudECDNDeployerConfig{ deployer, err := providerTencentCloudECDN.NewWithLogger(&providerTencentCloudECDN.TencentCloudECDNDeployerConfig{
SecretId: access.SecretId, SecretId: access.SecretId,
SecretKey: access.SecretKey, SecretKey: access.SecretKey,
@ -317,7 +317,7 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
}, logger) }, logger)
return deployer, logger, err return deployer, logger, err
case targetTencentCloudEO: case domain.DeployProviderTypeTencentCloudEO:
deployer, err := providerTencentCloudEO.NewWithLogger(&providerTencentCloudEO.TencentCloudEODeployerConfig{ deployer, err := providerTencentCloudEO.NewWithLogger(&providerTencentCloudEO.TencentCloudEODeployerConfig{
SecretId: access.SecretId, SecretId: access.SecretId,
SecretKey: access.SecretKey, SecretKey: access.SecretKey,
@ -331,15 +331,15 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
} }
} }
case targetVolcEngineCDN, targetVolcEngineLive: case domain.DeployProviderTypeVolcEngineCDN, domain.DeployProviderTypeVolcEngineLive:
{ {
access := &domain.VolcEngineAccessConfig{} access := &domain.AccessConfigForVolcEngine{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil { if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err) return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err)
} }
switch target { switch provider {
case targetVolcEngineCDN: case domain.DeployProviderTypeVolcEngineCDN:
deployer, err := providerVolcEngineCDN.NewWithLogger(&providerVolcEngineCDN.VolcEngineCDNDeployerConfig{ deployer, err := providerVolcEngineCDN.NewWithLogger(&providerVolcEngineCDN.VolcEngineCDNDeployerConfig{
AccessKey: access.AccessKeyId, AccessKey: access.AccessKeyId,
SecretKey: access.SecretAccessKey, SecretKey: access.SecretAccessKey,
@ -347,7 +347,7 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
}, logger) }, logger)
return deployer, logger, err return deployer, logger, err
case targetVolcEngineLive: case domain.DeployProviderTypeVolcEngineLive:
deployer, err := providerVolcEngineLive.NewWithLogger(&providerVolcEngineLive.VolcEngineLiveDeployerConfig{ deployer, err := providerVolcEngineLive.NewWithLogger(&providerVolcEngineLive.VolcEngineLiveDeployerConfig{
AccessKey: access.AccessKeyId, AccessKey: access.AccessKeyId,
SecretKey: access.SecretAccessKey, SecretKey: access.SecretAccessKey,
@ -360,9 +360,9 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
} }
} }
case targetWebhook: case domain.DeployProviderTypeWebhook:
{ {
access := &domain.WebhookAccessConfig{} access := &domain.AccessConfigForWebhook{}
if err := json.Unmarshal([]byte(accessConfig), access); err != nil { if err := json.Unmarshal([]byte(accessConfig), access); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err) return nil, nil, fmt.Errorf("failed to unmarshal access config: %w", err)
} }
@ -375,5 +375,5 @@ func createDeployer(target string, accessConfig string, deployConfig map[string]
} }
} }
return nil, nil, fmt.Errorf("unsupported deployer target: %s", target) return nil, nil, fmt.Errorf("unsupported deployer provider: %s", provider)
} }

View File

@ -11,111 +11,81 @@ type Access struct {
DeletedAt time.Time `json:"deleted" db:"deleted"` DeletedAt time.Time `json:"deleted" db:"deleted"`
} }
type AccessProviderType string type AccessConfigForACMEHttpReq struct {
/*
提供商类型常量值
注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order.
*/
const (
ACCESS_PROVIDER_ACMEHTTPREQ = AccessProviderType("acmehttpreq")
ACCESS_PROVIDER_ALIYUN = AccessProviderType("aliyun")
ACCESS_PROVIDER_AWS = AccessProviderType("aws")
ACCESS_PROVIDER_BAIDUCLOUD = AccessProviderType("baiducloud")
ACCESS_PROVIDER_BYTEPLUS = AccessProviderType("byteplus")
ACCESS_PROVIDER_CLOUDFLARE = AccessProviderType("cloudflare")
ACCESS_PROVIDER_DOGECLOUD = AccessProviderType("dogecloud")
ACCESS_PROVIDER_GODADDY = AccessProviderType("godaddy")
ACCESS_PROVIDER_HUAWEICLOUD = AccessProviderType("huaweicloud")
ACCESS_PROVIDER_KUBERNETES = AccessProviderType("k8s")
ACCESS_PROVIDER_LOCAL = AccessProviderType("local")
ACCESS_PROVIDER_NAMEDOTCOM = AccessProviderType("namedotcom")
ACCESS_PROVIDER_NAMESILO = AccessProviderType("namesilo")
ACCESS_PROVIDER_POWERDNS = AccessProviderType("powerdns")
ACCESS_PROVIDER_QINIU = AccessProviderType("qiniu")
ACCESS_PROVIDER_SSH = AccessProviderType("ssh")
ACCESS_PROVIDER_TENCENTCLOUD = AccessProviderType("tencentcloud")
ACCESS_PROVIDER_VOLCENGINE = AccessProviderType("volcengine")
ACCESS_PROVIDER_WEBHOOK = AccessProviderType("webhook")
)
type ACMEHttpReqAccessConfig struct {
Endpoint string `json:"endpoint"` Endpoint string `json:"endpoint"`
Mode string `json:"mode"` Mode string `json:"mode"`
Username string `json:"username"` Username string `json:"username"`
Password string `json:"password"` Password string `json:"password"`
} }
type AliyunAccessConfig struct { type AccessConfigForAliyun struct {
AccessKeyId string `json:"accessKeyId"` AccessKeyId string `json:"accessKeyId"`
AccessKeySecret string `json:"accessKeySecret"` AccessKeySecret string `json:"accessKeySecret"`
} }
type AWSAccessConfig struct { type AccessConfigForAWS struct {
AccessKeyId string `json:"accessKeyId"` AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"` SecretAccessKey string `json:"secretAccessKey"`
Region string `json:"region"` Region string `json:"region"`
HostedZoneId string `json:"hostedZoneId"` HostedZoneId string `json:"hostedZoneId"`
} }
type BaiduCloudAccessConfig struct { type AccessConfigForBaiduCloud struct {
AccessKeyId string `json:"accessKeyId"` AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"` SecretAccessKey string `json:"secretAccessKey"`
} }
type BytePlusAccessConfig struct { type AccessConfigForBytePlus struct {
AccessKey string `json:"accessKey"` AccessKey string `json:"accessKey"`
SecretKey string `json:"secretKey"` SecretKey string `json:"secretKey"`
} }
type CloudflareAccessConfig struct { type AccessConfigForCloudflare struct {
DnsApiToken string `json:"dnsApiToken"` DnsApiToken string `json:"dnsApiToken"`
} }
type DogeCloudAccessConfig struct { type AccessConfigForDogeCloud struct {
AccessKey string `json:"accessKey"` AccessKey string `json:"accessKey"`
SecretKey string `json:"secretKey"` SecretKey string `json:"secretKey"`
} }
type GoDaddyAccessConfig struct { type AccessConfigForGoDaddy struct {
ApiKey string `json:"apiKey"` ApiKey string `json:"apiKey"`
ApiSecret string `json:"apiSecret"` ApiSecret string `json:"apiSecret"`
} }
type HuaweiCloudAccessConfig struct { type AccessConfigForHuaweiCloud struct {
AccessKeyId string `json:"accessKeyId"` AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"` SecretAccessKey string `json:"secretAccessKey"`
Region string `json:"region"` Region string `json:"region"`
} }
type LocalAccessConfig struct{} type AccessConfigForLocal struct{}
type KubernetesAccessConfig struct { type AccessConfigForKubernetes struct {
KubeConfig string `json:"kubeConfig"` KubeConfig string `json:"kubeConfig"`
} }
type NameDotComAccessConfig struct { type AccessConfigForNameDotCom struct {
Username string `json:"username"` Username string `json:"username"`
ApiToken string `json:"apiToken"` ApiToken string `json:"apiToken"`
} }
type NameSiloAccessConfig struct { type AccessConfigForNameSilo struct {
ApiKey string `json:"apiKey"` ApiKey string `json:"apiKey"`
} }
type PowerDNSAccessConfig struct { type AccessConfigForPowerDNS struct {
ApiUrl string `json:"apiUrl"` ApiUrl string `json:"apiUrl"`
ApiKey string `json:"apiKey"` ApiKey string `json:"apiKey"`
} }
type QiniuAccessConfig struct { type AccessConfigForQiniu struct {
AccessKey string `json:"accessKey"` AccessKey string `json:"accessKey"`
SecretKey string `json:"secretKey"` SecretKey string `json:"secretKey"`
} }
type SSHAccessConfig struct { type AccessConfigForSSH struct {
Host string `json:"host"` Host string `json:"host"`
Port string `json:"port"` Port string `json:"port"`
Username string `json:"username"` Username string `json:"username"`
@ -124,16 +94,16 @@ type SSHAccessConfig struct {
KeyPassphrase string `json:"keyPassphrase"` KeyPassphrase string `json:"keyPassphrase"`
} }
type TencentCloudAccessConfig struct { type AccessConfigForTencentCloud struct {
SecretId string `json:"secretId"` SecretId string `json:"secretId"`
SecretKey string `json:"secretKey"` SecretKey string `json:"secretKey"`
} }
type VolcEngineAccessConfig struct { type AccessConfigForVolcEngine struct {
AccessKeyId string `json:"accessKeyId"` AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"` SecretAccessKey string `json:"secretAccessKey"`
} }
type WebhookAccessConfig struct { type AccessConfigForWebhook struct {
Url string `json:"url"` Url string `json:"url"`
} }

View File

@ -18,8 +18,8 @@ type Certificate struct {
IssuerCertificate string `json:"issuerCertificate" db:"issuerCertificate"` IssuerCertificate string `json:"issuerCertificate" db:"issuerCertificate"`
EffectAt time.Time `json:"effectAt" db:"effectAt"` EffectAt time.Time `json:"effectAt" db:"effectAt"`
ExpireAt time.Time `json:"expireAt" db:"expireAt"` ExpireAt time.Time `json:"expireAt" db:"expireAt"`
AcmeCertUrl string `json:"acmeCertUrl" db:"acmeCertUrl"` ACMECertUrl string `json:"acmeCertUrl" db:"acmeCertUrl"`
AcmeCertStableUrl string `json:"acmeCertStableUrl" db:"acmeCertStableUrl"` ACMECertStableUrl string `json:"acmeCertStableUrl" db:"acmeCertStableUrl"`
WorkflowId string `json:"workflowId" db:"workflowId"` WorkflowId string `json:"workflowId" db:"workflowId"`
WorkflowNodeId string `json:"workflowNodeId" db:"workflowNodeId"` WorkflowNodeId string `json:"workflowNodeId" db:"workflowNodeId"`
WorkflowOutputId string `json:"workflowOutputId" db:"workflowOutputId"` WorkflowOutputId string `json:"workflowOutputId" db:"workflowOutputId"`

View File

@ -9,14 +9,14 @@ type NotifyChannelType string
NOTICE: If you add new constant, please keep ASCII order. NOTICE: If you add new constant, please keep ASCII order.
*/ */
const ( const (
NOTIFY_CHANNEL_BARK = NotifyChannelType("bark") NotifyChannelTypeBark = NotifyChannelType("bark")
NOTIFY_CHANNEL_DINGTALK = NotifyChannelType("dingtalk") NotifyChannelTypeDingTalk = NotifyChannelType("dingtalk")
NOTIFY_CHANNEL_EMAIL = NotifyChannelType("email") NotifyChannelTypeEmail = NotifyChannelType("email")
NOTIFY_CHANNEL_LARK = NotifyChannelType("lark") NotifyChannelTypeLark = NotifyChannelType("lark")
NOTIFY_CHANNEL_SERVERCHAN = NotifyChannelType("serverchan") NotifyChannelTypeServerChan = NotifyChannelType("serverchan")
NOTIFY_CHANNEL_TELEGRAM = NotifyChannelType("telegram") NotifyChannelTypeTelegram = NotifyChannelType("telegram")
NOTIFY_CHANNEL_WEBHOOK = NotifyChannelType("webhook") NotifyChannelTypeWebhook = NotifyChannelType("webhook")
NOTIFY_CHANNEL_WECOM = NotifyChannelType("wecom") NotifyChannelTypeWeCom = NotifyChannelType("wecom")
) )
type NotifyTestPushReq struct { type NotifyTestPushReq struct {

View File

@ -0,0 +1,66 @@
package domain
type AccessProviderType string
/*
提供商类型常量值
注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order.
*/
const (
AccessProviderTypeACMEHttpReq = AccessProviderType("acmehttpreq")
AccessProviderTypeAliyun = AccessProviderType("aliyun")
AccessProviderTypeAWS = AccessProviderType("aws")
AccessProviderTypeBaiduCloud = AccessProviderType("baiducloud")
AccessProviderTypeBytePlus = AccessProviderType("byteplus")
AccessProviderTypeCloudflare = AccessProviderType("cloudflare")
AccessProviderTypeDogeCloud = AccessProviderType("dogecloud")
AccessProviderTypeGoDaddy = AccessProviderType("godaddy")
AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud")
AccessProviderTypeKubernetes = AccessProviderType("k8s")
AccessProviderTypeLocal = AccessProviderType("local")
AccessProviderTypeNameDotCom = AccessProviderType("namedotcom")
AccessProviderTypeNameSilo = AccessProviderType("namesilo")
AccessProviderTypePowerDNS = AccessProviderType("powerdns")
AccessProviderTypeQiniu = AccessProviderType("qiniu")
AccessProviderTypeSSH = AccessProviderType("ssh")
AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud")
AccessProviderTypeVolcEngine = AccessProviderType("volcengine")
AccessProviderTypeWebhook = AccessProviderType("webhook")
)
type DeployProviderType string
/*
提供商部署目标常量值
短横线前的部分始终等于提供商类型
注意如果追加新的常量值请保持以 ASCII 排序
NOTICE: If you add new constant, please keep ASCII order.
*/
const (
DeployProviderTypeAliyunALB = DeployProviderType("aliyun-alb")
DeployProviderTypeAliyunCDN = DeployProviderType("aliyun-cdn")
DeployProviderTypeAliyunCLB = DeployProviderType("aliyun-clb")
DeployProviderTypeAliyunDCDN = DeployProviderType("aliyun-dcdn")
DeployProviderTypeAliyunNLB = DeployProviderType("aliyun-nlb")
DeployProviderTypeAliyunOSS = DeployProviderType("aliyun-oss")
DeployProviderTypeBaiduCloudCDN = DeployProviderType("baiducloud-cdn")
DeployProviderTypeBytePlusCDN = DeployProviderType("byteplus-cdn")
DeployProviderTypeDogeCloudCDN = DeployProviderType("dogecloud-cdn")
DeployProviderTypeHuaweiCloudCDN = DeployProviderType("huaweicloud-cdn")
DeployProviderTypeHuaweiCloudELB = DeployProviderType("huaweicloud-elb")
DeployProviderTypeK8sSecret = DeployProviderType("k8s-secret")
DeployProviderTypeLocal = DeployProviderType("local")
DeployProviderTypeQiniuCDN = DeployProviderType("qiniu-cdn")
DeployProviderTypeSSH = DeployProviderType("ssh")
DeployProviderTypeTencentCloudCDN = DeployProviderType("tencentcloud-cdn")
DeployProviderTypeTencentCloudCLB = DeployProviderType("tencentcloud-clb")
DeployProviderTypeTencentCloudCOS = DeployProviderType("tencentcloud-cos")
DeployProviderTypeTencentCloudECDN = DeployProviderType("tencentcloud-ecdn")
DeployProviderTypeTencentCloudEO = DeployProviderType("tencentcloud-eo")
DeployProviderTypeVolcEngineCDN = DeployProviderType("volcengine-cdn")
DeployProviderTypeVolcEngineLive = DeployProviderType("volcengine-live")
DeployProviderTypeWebhook = DeployProviderType("webhook")
)

View File

@ -1,7 +1,5 @@
package domain package domain
const WorkflowOutputCertificate = "certificate"
type WorkflowOutput struct { type WorkflowOutput struct {
Meta Meta
WorkflowId string `json:"workflowId" db:"workflow"` WorkflowId string `json:"workflowId" db:"workflow"`
@ -10,3 +8,5 @@ type WorkflowOutput struct {
Outputs []WorkflowNodeIO `json:"outputs" db:"outputs"` Outputs []WorkflowNodeIO `json:"outputs" db:"outputs"`
Succeeded bool `json:"succeeded" db:"succeeded"` Succeeded bool `json:"succeeded" db:"succeeded"`
} }
const WORKFLOW_OUTPUT_CERTIFICATE = "certificate"

View File

@ -22,19 +22,19 @@ func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]a
NOTICE: If you add new constant, please keep ASCII order. NOTICE: If you add new constant, please keep ASCII order.
*/ */
switch channel { switch channel {
case domain.NOTIFY_CHANNEL_BARK: case domain.NotifyChannelTypeBark:
return providerBark.New(&providerBark.BarkNotifierConfig{ return providerBark.New(&providerBark.BarkNotifierConfig{
DeviceKey: maps.GetValueAsString(channelConfig, "deviceKey"), DeviceKey: maps.GetValueAsString(channelConfig, "deviceKey"),
ServerUrl: maps.GetValueAsString(channelConfig, "serverUrl"), ServerUrl: maps.GetValueAsString(channelConfig, "serverUrl"),
}) })
case domain.NOTIFY_CHANNEL_DINGTALK: case domain.NotifyChannelTypeDingTalk:
return providerDingTalk.New(&providerDingTalk.DingTalkNotifierConfig{ return providerDingTalk.New(&providerDingTalk.DingTalkNotifierConfig{
AccessToken: maps.GetValueAsString(channelConfig, "accessToken"), AccessToken: maps.GetValueAsString(channelConfig, "accessToken"),
Secret: maps.GetValueAsString(channelConfig, "secret"), Secret: maps.GetValueAsString(channelConfig, "secret"),
}) })
case domain.NOTIFY_CHANNEL_EMAIL: case domain.NotifyChannelTypeEmail:
return providerEmail.New(&providerEmail.EmailNotifierConfig{ return providerEmail.New(&providerEmail.EmailNotifierConfig{
SmtpHost: maps.GetValueAsString(channelConfig, "smtpHost"), SmtpHost: maps.GetValueAsString(channelConfig, "smtpHost"),
SmtpPort: maps.GetValueAsInt32(channelConfig, "smtpPort"), SmtpPort: maps.GetValueAsInt32(channelConfig, "smtpPort"),
@ -45,28 +45,28 @@ func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]a
ReceiverAddress: maps.GetValueAsString(channelConfig, "receiverAddress"), ReceiverAddress: maps.GetValueAsString(channelConfig, "receiverAddress"),
}) })
case domain.NOTIFY_CHANNEL_LARK: case domain.NotifyChannelTypeLark:
return providerLark.New(&providerLark.LarkNotifierConfig{ return providerLark.New(&providerLark.LarkNotifierConfig{
WebhookUrl: maps.GetValueAsString(channelConfig, "webhookUrl"), WebhookUrl: maps.GetValueAsString(channelConfig, "webhookUrl"),
}) })
case domain.NOTIFY_CHANNEL_SERVERCHAN: case domain.NotifyChannelTypeServerChan:
return providerServerChan.New(&providerServerChan.ServerChanNotifierConfig{ return providerServerChan.New(&providerServerChan.ServerChanNotifierConfig{
Url: maps.GetValueAsString(channelConfig, "url"), Url: maps.GetValueAsString(channelConfig, "url"),
}) })
case domain.NOTIFY_CHANNEL_TELEGRAM: case domain.NotifyChannelTypeTelegram:
return providerTelegram.New(&providerTelegram.TelegramNotifierConfig{ return providerTelegram.New(&providerTelegram.TelegramNotifierConfig{
ApiToken: maps.GetValueAsString(channelConfig, "apiToken"), ApiToken: maps.GetValueAsString(channelConfig, "apiToken"),
ChatId: maps.GetValueAsInt64(channelConfig, "chatId"), ChatId: maps.GetValueAsInt64(channelConfig, "chatId"),
}) })
case domain.NOTIFY_CHANNEL_WEBHOOK: case domain.NotifyChannelTypeWebhook:
return providerWebhook.New(&providerWebhook.WebhookNotifierConfig{ return providerWebhook.New(&providerWebhook.WebhookNotifierConfig{
Url: maps.GetValueAsString(channelConfig, "url"), Url: maps.GetValueAsString(channelConfig, "url"),
}) })
case domain.NOTIFY_CHANNEL_WECOM: case domain.NotifyChannelTypeWeCom:
return providerWeCom.New(&providerWeCom.WeComNotifierConfig{ return providerWeCom.New(&providerWeCom.WeComNotifierConfig{
WebhookUrl: maps.GetValueAsString(channelConfig, "webhookUrl"), WebhookUrl: maps.GetValueAsString(channelConfig, "webhookUrl"),
}) })

View File

@ -0,0 +1,41 @@
package acmehttpreq
import (
"errors"
"net/url"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/httpreq"
)
type ACMEHttpReqApplicantConfig struct {
Endpoint string `json:"endpoint"`
Mode string `json:"mode"`
Username string `json:"username"`
Password string `json:"password"`
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
}
func NewChallengeProvider(config *ACMEHttpReqApplicantConfig) (challenge.Provider, error) {
if config == nil {
return nil, errors.New("config is nil")
}
endpoint, _ := url.Parse(config.Endpoint)
providerConfig := httpreq.NewDefaultConfig()
providerConfig.Endpoint = endpoint
providerConfig.Mode = config.Mode
providerConfig.Username = config.Username
providerConfig.Password = config.Password
if config.PropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
}
provider, err := httpreq.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1,35 @@
package aliyun
import (
"errors"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/alidns"
)
type AliyunApplicantConfig struct {
AccessKeyId string `json:"accessKeyId"`
AccessKeySecret string `json:"accessKeySecret"`
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
}
func NewChallengeProvider(config *AliyunApplicantConfig) (challenge.Provider, error) {
if config == nil {
return nil, errors.New("config is nil")
}
providerConfig := alidns.NewDefaultConfig()
providerConfig.APIKey = config.AccessKeyId
providerConfig.SecretKey = config.AccessKeySecret
if config.PropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
}
provider, err := alidns.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1,39 @@
package aws
import (
"errors"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/route53"
)
type AWSApplicantConfig struct {
AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"`
Region string `json:"region"`
HostedZoneId string `json:"hostedZoneId"`
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
}
func NewChallengeProvider(config *AWSApplicantConfig) (challenge.Provider, error) {
if config == nil {
return nil, errors.New("config is nil")
}
providerConfig := route53.NewDefaultConfig()
providerConfig.AccessKeyID = config.AccessKeyId
providerConfig.SecretAccessKey = config.SecretAccessKey
providerConfig.Region = config.Region
providerConfig.HostedZoneID = config.HostedZoneId
if config.PropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
}
provider, err := route53.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1,33 @@
package cloudflare
import (
"errors"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/cloudflare"
)
type CloudflareApplicantConfig struct {
DnsApiToken string `json:"dnsApiToken"`
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
}
func NewChallengeProvider(config *CloudflareApplicantConfig) (challenge.Provider, error) {
if config == nil {
return nil, errors.New("config is nil")
}
providerConfig := cloudflare.NewDefaultConfig()
providerConfig.AuthToken = config.DnsApiToken
if config.PropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
}
provider, err := cloudflare.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1,35 @@
package godaddy
import (
"errors"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/godaddy"
)
type GoDaddyApplicantConfig struct {
ApiKey string `json:"apiKey"`
ApiSecret string `json:"apiSecret"`
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
}
func NewChallengeProvider(config *GoDaddyApplicantConfig) (challenge.Provider, error) {
if config == nil {
return nil, errors.New("config is nil")
}
providerConfig := godaddy.NewDefaultConfig()
providerConfig.APIKey = config.ApiKey
providerConfig.APISecret = config.ApiSecret
if config.PropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
}
provider, err := godaddy.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1,43 @@
package huaweicloud
import (
"errors"
"time"
"github.com/go-acme/lego/v4/challenge"
hwc "github.com/go-acme/lego/v4/providers/dns/huaweicloud"
)
type HuaweiCloudApplicantConfig struct {
AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"`
Region string `json:"region"`
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
}
func NewChallengeProvider(config *HuaweiCloudApplicantConfig) (challenge.Provider, error) {
if config == nil {
return nil, errors.New("config is nil")
}
region := config.Region
if region == "" {
// 华为云的 SDK 要求必须传一个区域,实际上 DNS-01 流程里用不到,但不传会报错
region = "cn-north-1"
}
providerConfig := hwc.NewDefaultConfig()
providerConfig.AccessKeyID = config.AccessKeyId
providerConfig.SecretAccessKey = config.SecretAccessKey
providerConfig.Region = region
if config.PropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
}
provider, err := hwc.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1,35 @@
package namedotcom
import (
"errors"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/namedotcom"
)
type NameDotComApplicantConfig struct {
Username string `json:"username"`
ApiToken string `json:"apiToken"`
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
}
func NewChallengeProvider(config *NameDotComApplicantConfig) (challenge.Provider, error) {
if config == nil {
return nil, errors.New("config is nil")
}
providerConfig := namedotcom.NewDefaultConfig()
providerConfig.Username = config.Username
providerConfig.APIToken = config.ApiToken
if config.PropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
}
provider, err := namedotcom.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1,33 @@
package namesilo
import (
"errors"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/namesilo"
)
type NameSiloApplicantConfig struct {
ApiKey string `json:"apiKey"`
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
}
func NewChallengeProvider(config *NameSiloApplicantConfig) (challenge.Provider, error) {
if config == nil {
return nil, errors.New("config is nil")
}
providerConfig := namesilo.NewDefaultConfig()
providerConfig.APIKey = config.ApiKey
if config.PropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
}
provider, err := namesilo.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1,37 @@
package namesilo
import (
"errors"
"net/url"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/pdns"
)
type PowerDNSApplicantConfig struct {
ApiUrl string `json:"apiUrl"`
ApiKey string `json:"apiKey"`
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
}
func NewChallengeProvider(config *PowerDNSApplicantConfig) (challenge.Provider, error) {
if config == nil {
return nil, errors.New("config is nil")
}
host, _ := url.Parse(config.ApiUrl)
providerConfig := pdns.NewDefaultConfig()
providerConfig.Host = host
providerConfig.APIKey = config.ApiKey
if config.PropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
}
provider, err := pdns.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1,35 @@
package tencentcloud
import (
"errors"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
)
type TencentCloudApplicantConfig struct {
SecretId string `json:"secretId"`
SecretKey string `json:"secretKey"`
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
}
func NewChallengeProvider(config *TencentCloudApplicantConfig) (challenge.Provider, error) {
if config == nil {
return nil, errors.New("config is nil")
}
providerConfig := tencentcloud.NewDefaultConfig()
providerConfig.SecretID = config.SecretId
providerConfig.SecretKey = config.SecretKey
if config.PropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
}
provider, err := tencentcloud.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1,35 @@
package volcengine
import (
"errors"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/volcengine"
)
type VolcEngineApplicantConfig struct {
AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"`
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
}
func NewChallengeProvider(config *VolcEngineApplicantConfig) (challenge.Provider, error) {
if config == nil {
return nil, errors.New("config is nil")
}
providerConfig := volcengine.NewDefaultConfig()
providerConfig.AccessKey = config.AccessKeyId
providerConfig.SecretKey = config.SecretAccessKey
if config.PropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
}
provider, err := volcengine.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -14,11 +14,13 @@ func NewCertificateRepository() *CertificateRepository {
} }
func (c *CertificateRepository) ListExpireSoon(ctx context.Context) ([]domain.Certificate, error) { func (c *CertificateRepository) ListExpireSoon(ctx context.Context) ([]domain.Certificate, error) {
rs := []domain.Certificate{} certificates := []domain.Certificate{}
if err := app.GetApp().Dao().DB(). err := app.GetApp().Dao().DB().
NewQuery("SELECT * FROM certificate WHERE expireAt > DATETIME('now') AND expireAt < DATETIME('now', '+20 days')"). NewQuery("SELECT * FROM certificate WHERE expireAt > DATETIME('now') AND expireAt < DATETIME('now', '+20 days')").
All(&rs); err != nil { All(&certificates)
if err != nil {
return nil, err return nil, err
} }
return rs, nil
return certificates, nil
} }

View File

@ -20,7 +20,7 @@ func (s *SettingsRepository) GetByName(ctx context.Context, name string) (*domai
return nil, err return nil, err
} }
rs := &domain.Settings{ settings := &domain.Settings{
Meta: domain.Meta{ Meta: domain.Meta{
Id: record.GetId(), Id: record.GetId(),
CreatedAt: record.GetCreated().Time(), CreatedAt: record.GetCreated().Time(),
@ -29,6 +29,5 @@ func (s *SettingsRepository) GetByName(ctx context.Context, name string) (*domai
Name: record.GetString("name"), Name: record.GetString("name"),
Content: record.GetString("content"), Content: record.GetString("content"),
} }
return settings, nil
return rs, nil
} }

View File

@ -15,6 +15,7 @@ func NewStatisticsRepository() *StatisticsRepository {
func (r *StatisticsRepository) Get(ctx context.Context) (*domain.Statistics, error) { func (r *StatisticsRepository) Get(ctx context.Context) (*domain.Statistics, error) {
rs := &domain.Statistics{} rs := &domain.Statistics{}
// 所有证书 // 所有证书
certTotal := struct { certTotal := struct {
Total int `db:"total"` Total int `db:"total"`

View File

@ -82,7 +82,7 @@ func (w *WorkflowRepository) SaveRun(ctx context.Context, run *domain.WorkflowRu
return nil return nil
} }
func (w *WorkflowRepository) Get(ctx context.Context, id string) (*domain.Workflow, error) { func (w *WorkflowRepository) GetById(ctx context.Context, id string) (*domain.Workflow, error) {
record, err := app.GetApp().Dao().FindRecordById("workflow", id) record, err := app.GetApp().Dao().FindRecordById("workflow", id)
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {

View File

@ -17,7 +17,7 @@ func NewWorkflowOutputRepository() *WorkflowOutputRepository {
return &WorkflowOutputRepository{} return &WorkflowOutputRepository{}
} }
func (w *WorkflowOutputRepository) Get(ctx context.Context, nodeId string) (*domain.WorkflowOutput, error) { func (w *WorkflowOutputRepository) GetByNodeId(ctx context.Context, nodeId string) (*domain.WorkflowOutput, error) {
records, err := app.GetApp().Dao().FindRecordsByFilter("workflow_output", "nodeId={:nodeId}", "-created", 1, 0, dbx.Params{"nodeId": nodeId}) records, err := app.GetApp().Dao().FindRecordsByFilter("workflow_output", "nodeId={:nodeId}", "-created", 1, 0, dbx.Params{"nodeId": nodeId})
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {
@ -56,7 +56,7 @@ func (w *WorkflowOutputRepository) Get(ctx context.Context, nodeId string) (*dom
return rs, nil return rs, nil
} }
func (w *WorkflowOutputRepository) GetCertificate(ctx context.Context, nodeId string) (*domain.Certificate, error) { func (w *WorkflowOutputRepository) GetCertificateByNodeId(ctx context.Context, nodeId string) (*domain.Certificate, error) {
records, err := app.GetApp().Dao().FindRecordsByFilter("certificate", "workflowNodeId={:workflowNodeId}", "-created", 1, 0, dbx.Params{"workflowNodeId": nodeId}) records, err := app.GetApp().Dao().FindRecordsByFilter("certificate", "workflowNodeId={:workflowNodeId}", "-created", 1, 0, dbx.Params{"workflowNodeId": nodeId})
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {
@ -83,8 +83,8 @@ func (w *WorkflowOutputRepository) GetCertificate(ctx context.Context, nodeId st
IssuerCertificate: record.GetString("issuerCertificate"), IssuerCertificate: record.GetString("issuerCertificate"),
EffectAt: record.GetTime("effectAt"), EffectAt: record.GetTime("effectAt"),
ExpireAt: record.GetTime("expireAt"), ExpireAt: record.GetTime("expireAt"),
AcmeCertUrl: record.GetString("acmeCertUrl"), ACMECertUrl: record.GetString("acmeCertUrl"),
AcmeCertStableUrl: record.GetString("acmeCertStableUrl"), ACMECertStableUrl: record.GetString("acmeCertStableUrl"),
WorkflowId: record.GetString("workflowId"), WorkflowId: record.GetString("workflowId"),
WorkflowNodeId: record.GetString("workflowNodeId"), WorkflowNodeId: record.GetString("workflowNodeId"),
WorkflowOutputId: record.GetString("workflowOutputId"), WorkflowOutputId: record.GetString("workflowOutputId"),
@ -137,8 +137,8 @@ func (w *WorkflowOutputRepository) Save(ctx context.Context, output *domain.Work
certRecord.Set("issuerCertificate", certificate.IssuerCertificate) certRecord.Set("issuerCertificate", certificate.IssuerCertificate)
certRecord.Set("effectAt", certificate.EffectAt) certRecord.Set("effectAt", certificate.EffectAt)
certRecord.Set("expireAt", certificate.ExpireAt) certRecord.Set("expireAt", certificate.ExpireAt)
certRecord.Set("acmeCertUrl", certificate.AcmeCertUrl) certRecord.Set("acmeCertUrl", certificate.ACMECertUrl)
certRecord.Set("acmeCertStableUrl", certificate.AcmeCertStableUrl) certRecord.Set("acmeCertStableUrl", certificate.ACMECertStableUrl)
certRecord.Set("workflowId", certificate.WorkflowId) certRecord.Set("workflowId", certificate.WorkflowId)
certRecord.Set("workflowNodeId", certificate.WorkflowNodeId) certRecord.Set("workflowNodeId", certificate.WorkflowNodeId)
certRecord.Set("workflowOutputId", certificate.WorkflowOutputId) certRecord.Set("workflowOutputId", certificate.WorkflowOutputId)
@ -149,7 +149,7 @@ func (w *WorkflowOutputRepository) Save(ctx context.Context, output *domain.Work
// 更新 certificate // 更新 certificate
for i, item := range output.Outputs { for i, item := range output.Outputs {
if item.Name == "certificate" { if item.Name == domain.WORKFLOW_OUTPUT_CERTIFICATE {
output.Outputs[i].Value = certRecord.GetId() output.Outputs[i].Value = certRecord.GetId()
break break
} }

View File

@ -14,7 +14,7 @@ import (
const tableName = "workflow" const tableName = "workflow"
func AddEvent() error { func RegisterEvents() error {
app := app.GetApp() app := app.GetApp()
app.OnRecordAfterCreateRequest(tableName).Add(func(e *core.RecordCreateEvent) error { app.OnRecordAfterCreateRequest(tableName).Add(func(e *core.RecordCreateEvent) error {
@ -32,30 +32,23 @@ func AddEvent() error {
return nil return nil
} }
func delete(_ context.Context, record *models.Record) error {
id := record.Id
scheduler := app.GetScheduler()
scheduler.Remove(id)
scheduler.Start()
return nil
}
func update(ctx context.Context, record *models.Record) error { func update(ctx context.Context, record *models.Record) error {
// 是不是自动 scheduler := app.GetScheduler()
// 是不是 enabled
workflowId := record.Id // 向数据库插入/更新时,同时更新定时任务
workflowId := record.GetId()
enabled := record.GetBool("enabled") enabled := record.GetBool("enabled")
trigger := record.GetString("trigger") trigger := record.GetString("trigger")
scheduler := app.GetScheduler() // 如果是手动触发或未启用,移除定时任务
if !enabled || trigger == string(domain.WorkflowTriggerTypeManual) { if !enabled || trigger == string(domain.WorkflowTriggerTypeManual) {
scheduler.Remove(workflowId) scheduler.Remove(fmt.Sprintf("workflow#%s", workflowId))
scheduler.Start() scheduler.Start()
return nil return nil
} }
err := scheduler.Add(workflowId, record.GetString("triggerCron"), func() { // 反之,重新添加定时任务
err := scheduler.Add(fmt.Sprintf("workflow#%s", workflowId), record.GetString("triggerCron"), func() {
NewWorkflowService(repository.NewWorkflowRepository()).Run(ctx, &domain.WorkflowRunReq{ NewWorkflowService(repository.NewWorkflowRepository()).Run(ctx, &domain.WorkflowRunReq{
WorkflowId: workflowId, WorkflowId: workflowId,
Trigger: domain.WorkflowTriggerTypeAuto, Trigger: domain.WorkflowTriggerTypeAuto,
@ -65,8 +58,19 @@ func update(ctx context.Context, record *models.Record) error {
app.GetLogger().Error("add cron job failed", "err", err) app.GetLogger().Error("add cron job failed", "err", err)
return fmt.Errorf("add cron job failed: %w", err) return fmt.Errorf("add cron job failed: %w", err)
} }
app.GetLogger().Error("add cron job failed", "subjectAltNames", record.GetString("subjectAltNames"))
scheduler.Start() scheduler.Start()
return nil
}
func delete(_ context.Context, record *models.Record) error {
scheduler := app.GetScheduler()
// 从数据库删除时,同时移除定时任务
workflowId := record.GetId()
scheduler.Remove(fmt.Sprintf("workflow#%s", workflowId))
scheduler.Start()
return nil return nil
} }

View File

@ -29,10 +29,10 @@ func NewApplyNode(node *domain.WorkflowNode) *applyNode {
type WorkflowOutputRepository interface { type WorkflowOutputRepository interface {
// 查询节点输出 // 查询节点输出
Get(ctx context.Context, nodeId string) (*domain.WorkflowOutput, error) GetByNodeId(ctx context.Context, nodeId string) (*domain.WorkflowOutput, error)
// 查询申请节点的证书 // 查询申请节点的证书
GetCertificate(ctx context.Context, nodeId string) (*domain.Certificate, error) GetCertificateByNodeId(ctx context.Context, nodeId string) (*domain.Certificate, error)
// 保存节点输出 // 保存节点输出
Save(ctx context.Context, output *domain.WorkflowOutput, certificate *domain.Certificate, cb func(id string) error) error Save(ctx context.Context, output *domain.WorkflowOutput, certificate *domain.Certificate, cb func(id string) error) error
@ -42,14 +42,14 @@ type WorkflowOutputRepository interface {
func (a *applyNode) Run(ctx context.Context) error { func (a *applyNode) Run(ctx context.Context) error {
a.AddOutput(ctx, a.node.Name, "开始执行") a.AddOutput(ctx, a.node.Name, "开始执行")
// 查询是否申请过,已申请过则直接返回(先保持和 v0.2 一致) // 查询是否申请过,已申请过则直接返回(先保持和 v0.2 一致)
output, err := a.outputRepo.Get(ctx, a.node.Id) output, err := a.outputRepo.GetByNodeId(ctx, a.node.Id)
if err != nil && !domain.IsRecordNotFound(err) { if err != nil && !domain.IsRecordNotFound(err) {
a.AddOutput(ctx, a.node.Name, "查询申请记录失败", err.Error()) a.AddOutput(ctx, a.node.Name, "查询申请记录失败", err.Error())
return err return err
} }
if output != nil && output.Succeeded { if output != nil && output.Succeeded {
cert, err := a.outputRepo.GetCertificate(ctx, a.node.Id) cert, err := a.outputRepo.GetCertificateByNodeId(ctx, a.node.Id)
if err != nil { if err != nil {
a.AddOutput(ctx, a.node.Name, "获取证书失败", err.Error()) a.AddOutput(ctx, a.node.Name, "获取证书失败", err.Error())
return err return err
@ -62,14 +62,14 @@ func (a *applyNode) Run(ctx context.Context) error {
} }
// 获取Applicant // 获取Applicant
apply, err := applicant.GetWithApplyNode(a.node) applicant, err := applicant.GetWithApplyNode(a.node)
if err != nil { if err != nil {
a.AddOutput(ctx, a.node.Name, "获取申请对象失败", err.Error()) a.AddOutput(ctx, a.node.Name, "获取申请对象失败", err.Error())
return err return err
} }
// 申请 // 申请
certificate, err := apply.Apply() certificate, err := applicant.Apply()
if err != nil { if err != nil {
a.AddOutput(ctx, a.node.Name, "申请失败", err.Error()) a.AddOutput(ctx, a.node.Name, "申请失败", err.Error())
return err return err
@ -103,8 +103,8 @@ func (a *applyNode) Run(ctx context.Context) error {
Certificate: certificate.Certificate, Certificate: certificate.Certificate,
PrivateKey: certificate.PrivateKey, PrivateKey: certificate.PrivateKey,
IssuerCertificate: certificate.IssuerCertificate, IssuerCertificate: certificate.IssuerCertificate,
AcmeCertUrl: certificate.CertUrl, ACMECertUrl: certificate.CertUrl,
AcmeCertStableUrl: certificate.CertStableUrl, ACMECertStableUrl: certificate.CertStableUrl,
EffectAt: certX509.NotBefore, EffectAt: certX509.NotBefore,
ExpireAt: certX509.NotAfter, ExpireAt: certX509.NotAfter,
WorkflowId: GetWorkflowId(ctx), WorkflowId: GetWorkflowId(ctx),

View File

@ -28,7 +28,7 @@ func NewDeployNode(node *domain.WorkflowNode) *deployNode {
func (d *deployNode) Run(ctx context.Context) error { func (d *deployNode) Run(ctx context.Context) error {
d.AddOutput(ctx, d.node.Name, "开始执行") d.AddOutput(ctx, d.node.Name, "开始执行")
// 检查是否部署过(部署过则直接返回,和 v0.2 暂时保持一致) // 检查是否部署过(部署过则直接返回,和 v0.2 暂时保持一致)
output, err := d.outputRepo.Get(ctx, d.node.Id) output, err := d.outputRepo.GetByNodeId(ctx, d.node.Id)
if err != nil && !domain.IsRecordNotFound(err) { if err != nil && !domain.IsRecordNotFound(err) {
d.AddOutput(ctx, d.node.Name, "查询部署记录失败", err.Error()) d.AddOutput(ctx, d.node.Name, "查询部署记录失败", err.Error())
return err return err
@ -43,7 +43,7 @@ func (d *deployNode) Run(ctx context.Context) error {
return fmt.Errorf("证书来源配置错误: %s", certSource) return fmt.Errorf("证书来源配置错误: %s", certSource)
} }
cert, err := d.outputRepo.GetCertificate(ctx, certSourceSlice[0]) cert, err := d.outputRepo.GetCertificateByNodeId(ctx, certSourceSlice[0])
if err != nil { if err != nil {
d.AddOutput(ctx, d.node.Name, "获取证书失败", err.Error()) d.AddOutput(ctx, d.node.Name, "获取证书失败", err.Error())
return err return err
@ -71,8 +71,8 @@ func (d *deployNode) Run(ctx context.Context) error {
AccessConfig: access.Config, AccessConfig: access.Config,
AccessRecord: access, AccessRecord: access,
Certificate: applicant.Certificate{ Certificate: applicant.Certificate{
CertUrl: cert.AcmeCertUrl, CertUrl: cert.ACMECertUrl,
CertStableUrl: cert.AcmeCertStableUrl, CertStableUrl: cert.ACMECertStableUrl,
PrivateKey: cert.PrivateKey, PrivateKey: cert.PrivateKey,
Certificate: cert.Certificate, Certificate: cert.Certificate,
IssuerCertificate: cert.IssuerCertificate, IssuerCertificate: cert.IssuerCertificate,
@ -85,7 +85,7 @@ func (d *deployNode) Run(ctx context.Context) error {
}, },
} }
deploy, err := deployer.GetWithTypeAndOption(d.node.GetConfigString("provider"), option) deploy, err := deployer.GetWithProviderAndOption(d.node.GetConfigString("provider"), option)
if err != nil { if err != nil {
d.AddOutput(ctx, d.node.Name, "获取部署对象失败", err.Error()) d.AddOutput(ctx, d.node.Name, "获取部署对象失败", err.Error())
return err return err

View File

@ -11,7 +11,7 @@ import (
) )
type WorkflowRepository interface { type WorkflowRepository interface {
Get(ctx context.Context, id string) (*domain.Workflow, error) GetById(ctx context.Context, id string) (*domain.Workflow, error)
SaveRun(ctx context.Context, run *domain.WorkflowRun) error SaveRun(ctx context.Context, run *domain.WorkflowRun) error
ListEnabledAuto(ctx context.Context) ([]domain.Workflow, error) ListEnabledAuto(ctx context.Context) ([]domain.Workflow, error)
} }
@ -27,7 +27,6 @@ func NewWorkflowService(repo WorkflowRepository) *WorkflowService {
} }
func (s *WorkflowService) InitSchedule(ctx context.Context) error { func (s *WorkflowService) InitSchedule(ctx context.Context) error {
// 查询所有的 enabled auto workflow
workflows, err := s.repo.ListEnabledAuto(ctx) workflows, err := s.repo.ListEnabledAuto(ctx)
if err != nil { if err != nil {
return err return err
@ -35,7 +34,7 @@ func (s *WorkflowService) InitSchedule(ctx context.Context) error {
scheduler := app.GetScheduler() scheduler := app.GetScheduler()
for _, workflow := range workflows { for _, workflow := range workflows {
err := scheduler.Add(workflow.Id, workflow.TriggerCron, func() { err := scheduler.Add(fmt.Sprintf("workflow#%s", workflow.Id), workflow.TriggerCron, func() {
s.Run(ctx, &domain.WorkflowRunReq{ s.Run(ctx, &domain.WorkflowRunReq{
WorkflowId: workflow.Id, WorkflowId: workflow.Id,
Trigger: domain.WorkflowTriggerTypeAuto, Trigger: domain.WorkflowTriggerTypeAuto,
@ -55,21 +54,12 @@ func (s *WorkflowService) InitSchedule(ctx context.Context) error {
func (s *WorkflowService) Run(ctx context.Context, options *domain.WorkflowRunReq) error { func (s *WorkflowService) Run(ctx context.Context, options *domain.WorkflowRunReq) error {
// 查询 // 查询
if options.WorkflowId == "" { workflow, err := s.repo.GetById(ctx, options.WorkflowId)
return domain.ErrInvalidParams
}
workflow, err := s.repo.Get(ctx, options.WorkflowId)
if err != nil { if err != nil {
app.GetLogger().Error("failed to get workflow", "id", options.WorkflowId, "err", err) app.GetLogger().Error("failed to get workflow", "id", options.WorkflowId, "err", err)
return err return err
} }
if !workflow.Enabled {
app.GetLogger().Error("workflow is disabled", "id", options.WorkflowId)
return fmt.Errorf("workflow is disabled")
}
// 执行 // 执行
run := &domain.WorkflowRun{ run := &domain.WorkflowRun{
WorkflowId: workflow.Id, WorkflowId: workflow.Id,
@ -78,7 +68,6 @@ func (s *WorkflowService) Run(ctx context.Context, options *domain.WorkflowRunRe
StartedAt: time.Now(), StartedAt: time.Now(),
EndedAt: time.Now(), EndedAt: time.Now(),
} }
processor := nodeprocessor.NewWorkflowProcessor(workflow) processor := nodeprocessor.NewWorkflowProcessor(workflow)
if err := processor.Run(ctx); err != nil { if err := processor.Run(ctx); err != nil {
run.Status = domain.WorkflowRunStatusTypeFailed run.Status = domain.WorkflowRunStatusTypeFailed
@ -93,7 +82,7 @@ func (s *WorkflowService) Run(ctx context.Context, options *domain.WorkflowRunRe
return fmt.Errorf("failed to run workflow: %w", err) return fmt.Errorf("failed to run workflow: %w", err)
} }
// 保存执行日志 // 保存日志
logs := processor.Log(ctx) logs := processor.Log(ctx)
runStatus := domain.WorkflowRunStatusTypeSucceeded runStatus := domain.WorkflowRunStatusTypeSucceeded
runError := domain.WorkflowRunLogs(logs).FirstError() runError := domain.WorkflowRunLogs(logs).FirstError()

View File

@ -39,7 +39,7 @@ func main() {
Automigrate: isGoRun, Automigrate: isGoRun,
}) })
workflow.AddEvent() workflow.RegisterEvents()
app.OnBeforeServe().Add(func(e *core.ServeEvent) error { app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
routes.Register(e.Router) routes.Register(e.Router)

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input, Select } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type ACMEHttpReqAccessConfig } from "@/domain/access"; import { type AccessConfigForACMEHttpReq } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormACMEHttpReqConfigFieldValues = Partial<ACMEHttpReqAccessConfig>; type AccessEditFormACMEHttpReqConfigFieldValues = Partial<AccessConfigForACMEHttpReq>;
export type AccessEditFormACMEHttpReqConfigProps = { export type AccessEditFormACMEHttpReqConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type AWSAccessConfig } from "@/domain/access"; import { type AccessConfigForAWS } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormAWSConfigFieldValues = Partial<AWSAccessConfig>; type AccessEditFormAWSConfigFieldValues = Partial<AccessConfigForAWS>;
export type AccessEditFormAWSConfigProps = { export type AccessEditFormAWSConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type AliyunAccessConfig } from "@/domain/access"; import { type AccessConfigForAliyun } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormAliyunConfigFieldValues = Partial<AliyunAccessConfig>; type AccessEditFormAliyunConfigFieldValues = Partial<AccessConfigForAliyun>;
export type AccessEditFormAliyunConfigProps = { export type AccessEditFormAliyunConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type BaiduCloudAccessConfig } from "@/domain/access"; import { type AccessConfigForBaiduCloud } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormBaiduCloudConfigFieldValues = Partial<BaiduCloudAccessConfig>; type AccessEditFormBaiduCloudConfigFieldValues = Partial<AccessConfigForBaiduCloud>;
export type AccessEditFormBaiduCloudConfigProps = { export type AccessEditFormBaiduCloudConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type BytePlusAccessConfig } from "@/domain/access"; import { type AccessConfigForBytePlus } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormBytePlusConfigFieldValues = Partial<BytePlusAccessConfig>; type AccessEditFormBytePlusConfigFieldValues = Partial<AccessConfigForBytePlus>;
export type AccessEditFormBytePlusConfigProps = { export type AccessEditFormBytePlusConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type CloudflareAccessConfig } from "@/domain/access"; import { type AccessConfigForCloudflare } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormCloudflareConfigFieldValues = Partial<CloudflareAccessConfig>; type AccessEditFormCloudflareConfigFieldValues = Partial<AccessConfigForCloudflare>;
export type AccessEditFormCloudflareConfigProps = { export type AccessEditFormCloudflareConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type DogeCloudAccessConfig } from "@/domain/access"; import { type AccessConfigForDogeCloud } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormDogeCloudConfigFieldValues = Partial<DogeCloudAccessConfig>; type AccessEditFormDogeCloudConfigFieldValues = Partial<AccessConfigForDogeCloud>;
export type AccessEditFormDogeCloudConfigProps = { export type AccessEditFormDogeCloudConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type GoDaddyAccessConfig } from "@/domain/access"; import { type AccessConfigForGoDaddy } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormGoDaddyConfigFieldValues = Partial<GoDaddyAccessConfig>; type AccessEditFormGoDaddyConfigFieldValues = Partial<AccessConfigForGoDaddy>;
export type AccessEditFormGoDaddyConfigProps = { export type AccessEditFormGoDaddyConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type HuaweiCloudAccessConfig } from "@/domain/access"; import { type AccessConfigForHuaweiCloud } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormHuaweiCloudConfigFieldValues = Partial<HuaweiCloudAccessConfig>; type AccessEditFormHuaweiCloudConfigFieldValues = Partial<AccessConfigForHuaweiCloud>;
export type AccessEditFormHuaweiCloudConfigProps = { export type AccessEditFormHuaweiCloudConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -7,11 +7,11 @@ import { Button, Form, type FormInstance, Input, Upload, type UploadFile, type U
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type KubernetesAccessConfig } from "@/domain/access"; import { type AccessConfigForKubernetes } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
import { readFileContent } from "@/utils/file"; import { readFileContent } from "@/utils/file";
type AccessEditFormKubernetesConfigFieldValues = Partial<KubernetesAccessConfig>; type AccessEditFormKubernetesConfigFieldValues = Partial<AccessConfigForKubernetes>;
export type AccessEditFormKubernetesConfigProps = { export type AccessEditFormKubernetesConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -1,9 +1,9 @@
import { Form, type FormInstance } from "antd"; import { Form, type FormInstance } from "antd";
import { type LocalAccessConfig } from "@/domain/access"; import { type AccessConfigForLocal } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormLocalConfigFieldValues = Partial<LocalAccessConfig>; type AccessEditFormLocalConfigFieldValues = Partial<AccessConfigForLocal>;
export type AccessEditFormLocalConfigProps = { export type AccessEditFormLocalConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type NameDotComAccessConfig } from "@/domain/access"; import { type AccessConfigForNameDotCom } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormNameDotComConfigFieldValues = Partial<NameDotComAccessConfig>; type AccessEditFormNameDotComConfigFieldValues = Partial<AccessConfigForNameDotCom>;
export type AccessEditFormNameDotComConfigProps = { export type AccessEditFormNameDotComConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type NameSiloAccessConfig } from "@/domain/access"; import { type AccessConfigForNameSilo } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormNameSiloConfigFieldValues = Partial<NameSiloAccessConfig>; type AccessEditFormNameSiloConfigFieldValues = Partial<AccessConfigForNameSilo>;
export type AccessEditFormNameSiloConfigProps = { export type AccessEditFormNameSiloConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type PowerDNSAccessConfig } from "@/domain/access"; import { type AccessConfigForPowerDNS } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormPowerDNSConfigFieldValues = Partial<PowerDNSAccessConfig>; type AccessEditFormPowerDNSConfigFieldValues = Partial<AccessConfigForPowerDNS>;
export type AccessEditFormPowerDNSConfigProps = { export type AccessEditFormPowerDNSConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type QiniuAccessConfig } from "@/domain/access"; import { type AccessConfigForQiniu } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormQiniuConfigFieldValues = Partial<QiniuAccessConfig>; type AccessEditFormQiniuConfigFieldValues = Partial<AccessConfigForQiniu>;
export type AccessEditFormQiniuConfigProps = { export type AccessEditFormQiniuConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -7,12 +7,12 @@ import { Button, Form, type FormInstance, Input, InputNumber, Upload, type Uploa
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type SSHAccessConfig } from "@/domain/access"; import { type AccessConfigForSSH } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
import { readFileContent } from "@/utils/file"; import { readFileContent } from "@/utils/file";
import { validDomainName, validIPv4Address, validIPv6Address } from "@/utils/validators"; import { validDomainName, validIPv4Address, validIPv6Address } from "@/utils/validators";
type AccessEditFormSSHConfigFieldValues = Partial<SSHAccessConfig>; type AccessEditFormSSHConfigFieldValues = Partial<AccessConfigForSSH>;
export type AccessEditFormSSHConfigProps = { export type AccessEditFormSSHConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type TencentCloudAccessConfig } from "@/domain/access"; import { type AccessConfigForTencentCloud } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormTencentCloudConfigFieldValues = Partial<TencentCloudAccessConfig>; type AccessEditFormTencentCloudConfigFieldValues = Partial<AccessConfigForTencentCloud>;
export type AccessEditFormTencentCloudConfigProps = { export type AccessEditFormTencentCloudConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type VolcEngineAccessConfig } from "@/domain/access"; import { type AccessConfigForVolcEngine } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormVolcEngineConfigFieldValues = Partial<VolcEngineAccessConfig>; type AccessEditFormVolcEngineConfigFieldValues = Partial<AccessConfigForVolcEngine>;
export type AccessEditFormVolcEngineConfigProps = { export type AccessEditFormVolcEngineConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -3,10 +3,10 @@ import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
import { type WebhookAccessConfig } from "@/domain/access"; import { type AccessConfigForWebhook } from "@/domain/access";
import { useAntdForm } from "@/hooks"; import { useAntdForm } from "@/hooks";
type AccessEditFormWebhookConfigFieldValues = Partial<WebhookAccessConfig>; type AccessEditFormWebhookConfigFieldValues = Partial<AccessConfigForWebhook>;
export type AccessEditFormWebhookConfigProps = { export type AccessEditFormWebhookConfigProps = {
form: FormInstance; form: FormInstance;

View File

@ -96,16 +96,14 @@ const CertificateDetail = ({ data, ...props }: CertificateDetailProps) => {
key: "PFX", key: "PFX",
label: "PFX", label: "PFX",
onClick: () => { onClick: () => {
// TODO: 下载 PFX 格式证书 alert("TODO: 暂时不支持下载 PFX 证书");
alert("TODO");
}, },
}, },
{ {
key: "JKS", key: "JKS",
label: "JKS", label: "JKS",
onClick: () => { onClick: () => {
// TODO: 下载 JKS 格式证书 alert("TODO: 暂时不支持下载 JKS 证书");
alert("TODO");
}, },
}, },
], ],

View File

@ -9,10 +9,10 @@ import { notifyChannelsMap } from "@/domain/settings";
import { import {
WORKFLOW_TRIGGERS, WORKFLOW_TRIGGERS,
type WorkflowNode, type WorkflowNode,
type WorkflowNodeConfigAsApply, type WorkflowNodeConfigForApply,
type WorkflowNodeConfigAsDeploy, type WorkflowNodeConfigForDeploy,
type WorkflowNodeConfigAsNotify, type WorkflowNodeConfigForNotify,
type WorkflowNodeConfigAsStart, type WorkflowNodeConfigForStart,
WorkflowNodeType, WorkflowNodeType,
} from "@/domain/workflow"; } from "@/domain/workflow";
import { useZustandShallowSelector } from "@/hooks"; import { useZustandShallowSelector } from "@/hooks";
@ -40,7 +40,7 @@ const WorkflowElement = ({ node, disabled }: NodeProps) => {
switch (node.type) { switch (node.type) {
case WorkflowNodeType.Start: { case WorkflowNodeType.Start: {
const config = (node.config as WorkflowNodeConfigAsStart) ?? {}; const config = (node.config as WorkflowNodeConfigForStart) ?? {};
return ( return (
<div className="flex items-center justify-between space-x-2"> <div className="flex items-center justify-between space-x-2">
<Typography.Text className="truncate"> <Typography.Text className="truncate">
@ -58,12 +58,12 @@ const WorkflowElement = ({ node, disabled }: NodeProps) => {
} }
case WorkflowNodeType.Apply: { case WorkflowNodeType.Apply: {
const config = (node.config as WorkflowNodeConfigAsApply) ?? {}; const config = (node.config as WorkflowNodeConfigForApply) ?? {};
return <Typography.Text className="truncate">{config.domains || " "}</Typography.Text>; return <Typography.Text className="truncate">{config.domains || " "}</Typography.Text>;
} }
case WorkflowNodeType.Deploy: { case WorkflowNodeType.Deploy: {
const config = (node.config as WorkflowNodeConfigAsDeploy) ?? {}; const config = (node.config as WorkflowNodeConfigForDeploy) ?? {};
const provider = deployProvidersMap.get(config.provider); const provider = deployProvidersMap.get(config.provider);
return ( return (
<Space> <Space>
@ -74,7 +74,7 @@ const WorkflowElement = ({ node, disabled }: NodeProps) => {
} }
case WorkflowNodeType.Notify: { case WorkflowNodeType.Notify: {
const config = (node.config as WorkflowNodeConfigAsNotify) ?? {}; const config = (node.config as WorkflowNodeConfigForNotify) ?? {};
const channel = notifyChannelsMap.get(config.channel as string); const channel = notifyChannelsMap.get(config.channel as string);
return ( return (
<div className="flex items-center justify-between space-x-2"> <div className="flex items-center justify-between space-x-2">

View File

@ -12,7 +12,7 @@ import MultipleInput from "@/components/MultipleInput";
import AccessEditModal from "@/components/access/AccessEditModal"; import AccessEditModal from "@/components/access/AccessEditModal";
import AccessSelect from "@/components/access/AccessSelect"; import AccessSelect from "@/components/access/AccessSelect";
import { ACCESS_USAGES, accessProvidersMap } from "@/domain/provider"; import { ACCESS_USAGES, accessProvidersMap } from "@/domain/provider";
import { type WorkflowNode, type WorkflowNodeConfigAsApply } from "@/domain/workflow"; import { type WorkflowNode, type WorkflowNodeConfigForApply } from "@/domain/workflow";
import { useAntdForm, useZustandShallowSelector } from "@/hooks"; import { useAntdForm, useZustandShallowSelector } from "@/hooks";
import { useAccessesStore } from "@/stores/access"; import { useAccessesStore } from "@/stores/access";
import { useContactEmailsStore } from "@/stores/contact"; import { useContactEmailsStore } from "@/stores/contact";
@ -26,7 +26,7 @@ export type ApplyNodeFormProps = {
const MULTIPLE_INPUT_DELIMITER = ";"; const MULTIPLE_INPUT_DELIMITER = ";";
const initFormModel = (): Partial<WorkflowNodeConfigAsApply> => { const initFormModel = (): Partial<WorkflowNodeConfigForApply> => {
return { return {
keyAlgorithm: "RSA2048", keyAlgorithm: "RSA2048",
propagationTimeout: 60, propagationTimeout: 60,
@ -76,7 +76,7 @@ const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => {
formPending, formPending,
formProps, formProps,
} = useAntdForm<z.infer<typeof formSchema>>({ } = useAntdForm<z.infer<typeof formSchema>>({
initialValues: (node?.config as WorkflowNodeConfigAsApply) ?? initFormModel(), initialValues: (node?.config as WorkflowNodeConfigForApply) ?? initFormModel(),
onSubmit: async (values) => { onSubmit: async (values) => {
await formInst.validateFields(); await formInst.validateFields();
await addEmail(values.contactEmail); await addEmail(values.contactEmail);
@ -85,7 +85,7 @@ const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => {
draft.config = { draft.config = {
provider: accesses.find((e) => e.id === values.providerAccessId)?.provider, provider: accesses.find((e) => e.id === values.providerAccessId)?.provider,
...values, ...values,
} as WorkflowNodeConfigAsApply; } as WorkflowNodeConfigForApply;
draft.validated = true; draft.validated = true;
}) })
); );

View File

@ -12,7 +12,7 @@ import AccessSelect from "@/components/access/AccessSelect";
import DeployProviderPicker from "@/components/provider/DeployProviderPicker"; import DeployProviderPicker from "@/components/provider/DeployProviderPicker";
import DeployProviderSelect from "@/components/provider/DeployProviderSelect"; import DeployProviderSelect from "@/components/provider/DeployProviderSelect";
import { ACCESS_USAGES, DEPLOY_PROVIDERS, accessProvidersMap, deployProvidersMap } from "@/domain/provider"; import { ACCESS_USAGES, DEPLOY_PROVIDERS, accessProvidersMap, deployProvidersMap } from "@/domain/provider";
import { type WorkflowNode, type WorkflowNodeConfigAsDeploy } from "@/domain/workflow"; import { type WorkflowNode, type WorkflowNodeConfigForDeploy } from "@/domain/workflow";
import { useAntdForm, useZustandShallowSelector } from "@/hooks"; import { useAntdForm, useZustandShallowSelector } from "@/hooks";
import { useWorkflowStore } from "@/stores/workflow"; import { useWorkflowStore } from "@/stores/workflow";
import { usePanel } from "../PanelProvider"; import { usePanel } from "../PanelProvider";
@ -44,7 +44,7 @@ export type DeployFormProps = {
node: WorkflowNode; node: WorkflowNode;
}; };
const initFormModel = (): Partial<WorkflowNodeConfigAsDeploy> => { const initFormModel = (): Partial<WorkflowNodeConfigForDeploy> => {
return {}; return {};
}; };
@ -67,7 +67,7 @@ const DeployNodeForm = ({ node }: DeployFormProps) => {
formPending, formPending,
formProps, formProps,
} = useAntdForm<z.infer<typeof formSchema>>({ } = useAntdForm<z.infer<typeof formSchema>>({
initialValues: (node?.config as WorkflowNodeConfigAsDeploy) ?? initFormModel(), initialValues: (node?.config as WorkflowNodeConfigForDeploy) ?? initFormModel(),
onSubmit: async (values) => { onSubmit: async (values) => {
await formInst.validateFields(); await formInst.validateFields();
await updateNode( await updateNode(

View File

@ -8,7 +8,7 @@ import { produce } from "immer";
import { z } from "zod"; import { z } from "zod";
import { notifyChannelsMap } from "@/domain/settings"; import { notifyChannelsMap } from "@/domain/settings";
import { type WorkflowNode, type WorkflowNodeConfigAsNotify } from "@/domain/workflow"; import { type WorkflowNode, type WorkflowNodeConfigForNotify } from "@/domain/workflow";
import { useAntdForm, useZustandShallowSelector } from "@/hooks"; import { useAntdForm, useZustandShallowSelector } from "@/hooks";
import { useNotifyChannelsStore } from "@/stores/notify"; import { useNotifyChannelsStore } from "@/stores/notify";
import { useWorkflowStore } from "@/stores/workflow"; import { useWorkflowStore } from "@/stores/workflow";
@ -18,7 +18,7 @@ export type NotifyNodeFormProps = {
node: WorkflowNode; node: WorkflowNode;
}; };
const initFormModel = (): Partial<WorkflowNodeConfigAsNotify> => { const initFormModel = (): Partial<WorkflowNodeConfigForNotify> => {
return { return {
subject: "Completed!", subject: "Completed!",
message: "Your workflow has been completed on Certimate.", message: "Your workflow has been completed on Certimate.",
@ -57,7 +57,7 @@ const NotifyNodeForm = ({ node }: NotifyNodeFormProps) => {
formPending, formPending,
formProps, formProps,
} = useAntdForm<z.infer<typeof formSchema>>({ } = useAntdForm<z.infer<typeof formSchema>>({
initialValues: (node?.config as WorkflowNodeConfigAsNotify) ?? initFormModel(), initialValues: (node?.config as WorkflowNodeConfigForNotify) ?? initFormModel(),
onSubmit: async (values) => { onSubmit: async (values) => {
await formInst.validateFields(); await formInst.validateFields();
await updateNode( await updateNode(

View File

@ -7,7 +7,7 @@ import { produce } from "immer";
import { z } from "zod"; import { z } from "zod";
import Show from "@/components/Show"; import Show from "@/components/Show";
import { WORKFLOW_TRIGGERS, type WorkflowNode, type WorkflowNodeConfigAsStart } from "@/domain/workflow"; import { WORKFLOW_TRIGGERS, type WorkflowNode, type WorkflowNodeConfigForStart } from "@/domain/workflow";
import { useAntdForm, useZustandShallowSelector } from "@/hooks"; import { useAntdForm, useZustandShallowSelector } from "@/hooks";
import { useWorkflowStore } from "@/stores/workflow"; import { useWorkflowStore } from "@/stores/workflow";
import { getNextCronExecutions, validCronExpression } from "@/utils/cron"; import { getNextCronExecutions, validCronExpression } from "@/utils/cron";
@ -17,7 +17,7 @@ export type StartNodeFormProps = {
node: WorkflowNode; node: WorkflowNode;
}; };
const initFormModel = (): WorkflowNodeConfigAsStart => { const initFormModel = (): WorkflowNodeConfigForStart => {
return { return {
trigger: WORKFLOW_TRIGGERS.AUTO, trigger: WORKFLOW_TRIGGERS.AUTO,
triggerCron: "0 0 * * *", triggerCron: "0 0 * * *",
@ -54,7 +54,7 @@ const StartNodeForm = ({ node }: StartNodeFormProps) => {
formPending, formPending,
formProps, formProps,
} = useAntdForm<z.infer<typeof formSchema>>({ } = useAntdForm<z.infer<typeof formSchema>>({
initialValues: (node?.config as WorkflowNodeConfigAsStart) ?? initFormModel(), initialValues: (node?.config as WorkflowNodeConfigForStart) ?? initFormModel(),
onSubmit: async (values) => { onSubmit: async (values) => {
await formInst.validateFields(); await formInst.validateFields();
await updateNode( await updateNode(

View File

@ -1,6 +1,5 @@
import { type AccessUsageType } from "./provider"; import { type AccessUsageType } from "./provider";
// #region AccessModel
export interface AccessModel extends BaseModel { export interface AccessModel extends BaseModel {
name: string; name: string;
provider: string; provider: string;
@ -9,106 +8,105 @@ export interface AccessModel extends BaseModel {
NOTICE: If you add new type, please keep ASCII order. NOTICE: If you add new type, please keep ASCII order.
*/ Record<string, unknown> & */ Record<string, unknown> &
( (
| ACMEHttpReqAccessConfig | AccessConfigForACMEHttpReq
| AliyunAccessConfig | AccessConfigForAliyun
| AWSAccessConfig | AccessConfigForAWS
| BaiduCloudAccessConfig | AccessConfigForBaiduCloud
| BytePlusAccessConfig | AccessConfigForBytePlus
| CloudflareAccessConfig | AccessConfigForCloudflare
| DogeCloudAccessConfig | AccessConfigForDogeCloud
| GoDaddyAccessConfig | AccessConfigForGoDaddy
| HuaweiCloudAccessConfig | AccessConfigForHuaweiCloud
| KubernetesAccessConfig | AccessConfigForKubernetes
| LocalAccessConfig | AccessConfigForLocal
| NameDotComAccessConfig | AccessConfigForNameDotCom
| NameSiloAccessConfig | AccessConfigForNameSilo
| PowerDNSAccessConfig | AccessConfigForPowerDNS
| QiniuAccessConfig | AccessConfigForQiniu
| SSHAccessConfig | AccessConfigForSSH
| TencentCloudAccessConfig | AccessConfigForTencentCloud
| VolcEngineAccessConfig | AccessConfigForVolcEngine
| WebhookAccessConfig | AccessConfigForWebhook
); );
usage: AccessUsageType; usage: AccessUsageType;
} }
// #endregion
// #region AccessConfig // #region AccessConfig
export type ACMEHttpReqAccessConfig = { export type AccessConfigForACMEHttpReq = {
endpoint: string; endpoint: string;
mode?: string; mode?: string;
username?: string; username?: string;
password?: string; password?: string;
}; };
export type AliyunAccessConfig = { export type AccessConfigForAliyun = {
accessKeyId: string; accessKeyId: string;
accessKeySecret: string; accessKeySecret: string;
}; };
export type AWSAccessConfig = { export type AccessConfigForAWS = {
accessKeyId: string; accessKeyId: string;
secretAccessKey: string; secretAccessKey: string;
region?: string; region?: string;
hostedZoneId?: string; hostedZoneId?: string;
}; };
export type BaiduCloudAccessConfig = { export type AccessConfigForBaiduCloud = {
accessKeyId: string; accessKeyId: string;
secretAccessKey: string; secretAccessKey: string;
}; };
export type BytePlusAccessConfig = { export type AccessConfigForBytePlus = {
accessKey: string; accessKey: string;
secretKey: string; secretKey: string;
}; };
export type CloudflareAccessConfig = { export type AccessConfigForCloudflare = {
dnsApiToken: string; dnsApiToken: string;
}; };
export type DogeCloudAccessConfig = { export type AccessConfigForDogeCloud = {
accessKey: string; accessKey: string;
secretKey: string; secretKey: string;
}; };
export type GoDaddyAccessConfig = { export type AccessConfigForGoDaddy = {
apiKey: string; apiKey: string;
apiSecret: string; apiSecret: string;
}; };
export type HuaweiCloudAccessConfig = { export type AccessConfigForHuaweiCloud = {
accessKeyId: string; accessKeyId: string;
secretAccessKey: string; secretAccessKey: string;
region?: string; region?: string;
}; };
export type KubernetesAccessConfig = { export type AccessConfigForKubernetes = {
kubeConfig?: string; kubeConfig?: string;
}; };
export type LocalAccessConfig = NonNullable<unknown>; export type AccessConfigForLocal = NonNullable<unknown>;
export type NameDotComAccessConfig = { export type AccessConfigForNameDotCom = {
username: string; username: string;
apiToken: string; apiToken: string;
}; };
export type NameSiloAccessConfig = { export type AccessConfigForNameSilo = {
apiKey: string; apiKey: string;
}; };
export type PowerDNSAccessConfig = { export type AccessConfigForPowerDNS = {
apiUrl: string; apiUrl: string;
apiKey: string; apiKey: string;
}; };
export type QiniuAccessConfig = { export type AccessConfigForQiniu = {
accessKey: string; accessKey: string;
secretKey: string; secretKey: string;
}; };
export type SSHAccessConfig = { export type AccessConfigForSSH = {
host: string; host: string;
port: number; port: number;
username: string; username: string;
@ -117,17 +115,17 @@ export type SSHAccessConfig = {
keyPassphrase?: string; keyPassphrase?: string;
}; };
export type TencentCloudAccessConfig = { export type AccessConfigForTencentCloud = {
secretId: string; secretId: string;
secretKey: string; secretKey: string;
}; };
export type VolcEngineAccessConfig = { export type AccessConfigForVolcEngine = {
accessKeyId: string; accessKeyId: string;
secretAccessKey: string; secretAccessKey: string;
}; };
export type WebhookAccessConfig = { export type AccessConfigForWebhook = {
url: string; url: string;
}; };
// #endregion // #endregion

View File

@ -95,12 +95,12 @@ export type WorkflowNode = {
validated?: boolean; validated?: boolean;
}; };
export type WorkflowNodeConfigAsStart = { export type WorkflowNodeConfigForStart = {
trigger: string; trigger: string;
triggerCron?: string; triggerCron?: string;
}; };
export type WorkflowNodeConfigAsApply = { export type WorkflowNodeConfigForApply = {
domains: string; domains: string;
contactEmail: string; contactEmail: string;
provider: string; provider: string;
@ -111,22 +111,22 @@ export type WorkflowNodeConfigAsApply = {
disableFollowCNAME?: boolean; disableFollowCNAME?: boolean;
}; };
export type WorkflowNodeConfigAsDeploy = { export type WorkflowNodeConfigForDeploy = {
provider: string; provider: string;
providerAccessId: string; providerAccessId: string;
certificate: string; certificate: string;
[key: string]: unknown; [key: string]: unknown;
}; };
export type WorkflowNodeConfigAsNotify = { export type WorkflowNodeConfigForNotify = {
channel: string; channel: string;
subject: string; subject: string;
message: string; message: string;
}; };
export type WorkflowNodeConfigAsBranch = never; export type WorkflowNodeConfigForBranch = never;
export type WorkflowNodeConfigAsEnd = never; export type WorkflowNodeConfigForEnd = never;
export type WorkflowNodeIO = { export type WorkflowNodeIO = {
name: string; name: string;
@ -403,7 +403,7 @@ export const isAllNodesValidated = (node: WorkflowNode): boolean => {
*/ */
export const getExecuteMethod = (node: WorkflowNode): { trigger: string; triggerCron: string } => { export const getExecuteMethod = (node: WorkflowNode): { trigger: string; triggerCron: string } => {
if (node.type === WorkflowNodeType.Start) { if (node.type === WorkflowNodeType.Start) {
const config = node.config as WorkflowNodeConfigAsStart; const config = node.config as WorkflowNodeConfigForStart;
return { return {
trigger: config.trigger ?? "", trigger: config.trigger ?? "",
triggerCron: config.triggerCron ?? "", triggerCron: config.triggerCron ?? "",