mirror of
https://github.com/usual2970/certimate.git
synced 2025-10-04 13:34:52 +00:00
fix conflict
This commit is contained in:
@@ -4,14 +4,16 @@ import (
|
||||
"log/slog"
|
||||
"sync"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
)
|
||||
|
||||
var instance *pocketbase.PocketBase
|
||||
var instance core.App
|
||||
|
||||
var intanceOnce sync.Once
|
||||
|
||||
func GetApp() *pocketbase.PocketBase {
|
||||
func GetApp() core.App {
|
||||
intanceOnce.Do(func() {
|
||||
instance = pocketbase.NewWithConfig(pocketbase.Config{
|
||||
HideStartBanner: true,
|
||||
@@ -21,6 +23,10 @@ func GetApp() *pocketbase.PocketBase {
|
||||
return instance
|
||||
}
|
||||
|
||||
func GetDB() dbx.Builder {
|
||||
return GetApp().DB()
|
||||
}
|
||||
|
||||
func GetLogger() *slog.Logger {
|
||||
return GetApp().Logger()
|
||||
}
|
||||
|
@@ -12,11 +12,13 @@ var scheduler *cron.Cron
|
||||
var schedulerOnce sync.Once
|
||||
|
||||
func GetScheduler() *cron.Cron {
|
||||
scheduler = GetApp().Cron()
|
||||
schedulerOnce.Do(func() {
|
||||
scheduler = cron.New()
|
||||
location, err := time.LoadLocation("Local")
|
||||
if err == nil {
|
||||
scheduler.Stop()
|
||||
scheduler.SetTimezone(location)
|
||||
scheduler.Start()
|
||||
}
|
||||
})
|
||||
|
||||
|
@@ -35,15 +35,17 @@ type Applicant interface {
|
||||
}
|
||||
|
||||
type applicantOptions struct {
|
||||
Domains []string
|
||||
ContactEmail string
|
||||
Provider domain.ApplyDNSProviderType
|
||||
ProviderAccessConfig map[string]any
|
||||
ProviderApplyConfig map[string]any
|
||||
KeyAlgorithm string
|
||||
Nameservers []string
|
||||
PropagationTimeout int32
|
||||
DisableFollowCNAME bool
|
||||
Domains []string
|
||||
ContactEmail string
|
||||
Provider domain.ApplyDNSProviderType
|
||||
ProviderAccessConfig map[string]any
|
||||
ProviderApplyConfig map[string]any
|
||||
KeyAlgorithm string
|
||||
Nameservers []string
|
||||
DnsPropagationTimeout int32
|
||||
DnsTTL int32
|
||||
DisableFollowCNAME bool
|
||||
SkipBeforeExpiryDays int32
|
||||
}
|
||||
|
||||
func NewWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
|
||||
@@ -51,11 +53,12 @@ func NewWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
|
||||
return nil, fmt.Errorf("node type is not apply")
|
||||
}
|
||||
|
||||
nodeConfig := node.GetConfigForApply()
|
||||
|
||||
accessRepo := repository.NewAccessRepository()
|
||||
accessId := node.GetConfigString("providerAccessId")
|
||||
access, err := accessRepo.GetById(context.Background(), accessId)
|
||||
access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get access #%s record: %w", accessId, err)
|
||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
|
||||
}
|
||||
|
||||
accessConfig, err := access.UnmarshalConfigToMap()
|
||||
@@ -64,15 +67,17 @@ func NewWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
|
||||
}
|
||||
|
||||
options := &applicantOptions{
|
||||
Domains: slices.Filter(strings.Split(node.GetConfigString("domains"), ";"), func(s string) bool { return s != "" }),
|
||||
ContactEmail: node.GetConfigString("contactEmail"),
|
||||
Provider: domain.ApplyDNSProviderType(node.GetConfigString("provider")),
|
||||
ProviderAccessConfig: accessConfig,
|
||||
ProviderApplyConfig: node.GetConfigMap("providerConfig"),
|
||||
KeyAlgorithm: node.GetConfigString("keyAlgorithm"),
|
||||
Nameservers: slices.Filter(strings.Split(node.GetConfigString("nameservers"), ";"), func(s string) bool { return s != "" }),
|
||||
PropagationTimeout: node.GetConfigInt32("propagationTimeout"),
|
||||
DisableFollowCNAME: node.GetConfigBool("disableFollowCNAME"),
|
||||
Domains: slices.Filter(strings.Split(nodeConfig.Domains, ";"), func(s string) bool { return s != "" }),
|
||||
ContactEmail: nodeConfig.ContactEmail,
|
||||
Provider: domain.ApplyDNSProviderType(nodeConfig.Provider),
|
||||
ProviderAccessConfig: accessConfig,
|
||||
ProviderApplyConfig: nodeConfig.ProviderConfig,
|
||||
KeyAlgorithm: nodeConfig.KeyAlgorithm,
|
||||
Nameservers: slices.Filter(strings.Split(nodeConfig.Nameservers, ";"), func(s string) bool { return s != "" }),
|
||||
DnsPropagationTimeout: nodeConfig.DnsPropagationTimeout,
|
||||
DnsTTL: nodeConfig.DnsTTL,
|
||||
DisableFollowCNAME: nodeConfig.DisableFollowCNAME,
|
||||
SkipBeforeExpiryDays: nodeConfig.SkipBeforeExpiryDays,
|
||||
}
|
||||
|
||||
applicant, err := createApplicant(options)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package applicant
|
||||
package applicant_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
@@ -36,11 +36,11 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerACMEHttpReq.NewChallengeProvider(&providerACMEHttpReq.ACMEHttpReqApplicantConfig{
|
||||
Endpoint: access.Endpoint,
|
||||
Mode: access.Mode,
|
||||
Username: access.Username,
|
||||
Password: access.Password,
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
Endpoint: access.Endpoint,
|
||||
Mode: access.Mode,
|
||||
Username: access.Username,
|
||||
Password: access.Password,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
@@ -53,9 +53,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerAliyun.NewChallengeProvider(&providerAliyun.AliyunApplicantConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
@@ -68,11 +69,12 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerAWSRoute53.NewChallengeProvider(&providerAWSRoute53.AWSRoute53ApplicantConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Region: maps.GetValueAsString(options.ProviderApplyConfig, "region"),
|
||||
HostedZoneId: maps.GetValueAsString(options.ProviderApplyConfig, "hostedZoneId"),
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Region: maps.GetValueAsString(options.ProviderApplyConfig, "region"),
|
||||
HostedZoneId: maps.GetValueAsString(options.ProviderApplyConfig, "hostedZoneId"),
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
@@ -85,11 +87,12 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerAzureDNS.NewChallengeProvider(&providerAzureDNS.AzureDNSApplicantConfig{
|
||||
TenantId: access.TenantId,
|
||||
ClientId: access.ClientId,
|
||||
ClientSecret: access.ClientSecret,
|
||||
CloudName: access.CloudName,
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
TenantId: access.TenantId,
|
||||
ClientId: access.ClientId,
|
||||
ClientSecret: access.ClientSecret,
|
||||
CloudName: access.CloudName,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
@@ -102,8 +105,9 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerCloudflare.NewChallengeProvider(&providerCloudflare.CloudflareApplicantConfig{
|
||||
DnsApiToken: access.DnsApiToken,
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
DnsApiToken: access.DnsApiToken,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
@@ -116,9 +120,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerGoDaddy.NewChallengeProvider(&providerGoDaddy.GoDaddyApplicantConfig{
|
||||
ApiKey: access.ApiKey,
|
||||
ApiSecret: access.ApiSecret,
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
ApiKey: access.ApiKey,
|
||||
ApiSecret: access.ApiSecret,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
@@ -131,10 +136,11 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerHuaweiCloud.NewChallengeProvider(&providerHuaweiCloud.HuaweiCloudApplicantConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Region: maps.GetValueAsString(options.ProviderApplyConfig, "region"),
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Region: maps.GetValueAsString(options.ProviderApplyConfig, "region"),
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
@@ -147,9 +153,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerNameDotCom.NewChallengeProvider(&providerNameDotCom.NameDotComApplicantConfig{
|
||||
Username: access.Username,
|
||||
ApiToken: access.ApiToken,
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
Username: access.Username,
|
||||
ApiToken: access.ApiToken,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
@@ -162,8 +169,9 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerNameSilo.NewChallengeProvider(&providerNameSilo.NameSiloApplicantConfig{
|
||||
ApiKey: access.ApiKey,
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
ApiKey: access.ApiKey,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
@@ -176,8 +184,9 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerNS1.NewChallengeProvider(&providerNS1.NS1ApplicantConfig{
|
||||
ApiKey: access.ApiKey,
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
ApiKey: access.ApiKey,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
@@ -190,9 +199,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerPowerDNS.NewChallengeProvider(&providerPowerDNS.PowerDNSApplicantConfig{
|
||||
ApiUrl: access.ApiUrl,
|
||||
ApiKey: access.ApiKey,
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
ApiUrl: access.ApiUrl,
|
||||
ApiKey: access.ApiKey,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
@@ -205,9 +215,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerTencentCloud.NewChallengeProvider(&providerTencentCloud.TencentCloudApplicantConfig{
|
||||
SecretId: access.SecretId,
|
||||
SecretKey: access.SecretKey,
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
SecretId: access.SecretId,
|
||||
SecretKey: access.SecretKey,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
@@ -220,9 +231,10 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
|
||||
}
|
||||
|
||||
applicant, err := providerVolcEngine.NewChallengeProvider(&providerVolcEngine.VolcEngineApplicantConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
PropagationTimeout: options.PropagationTimeout,
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
@@ -8,7 +10,9 @@ import (
|
||||
|
||||
"github.com/usual2970/certimate/internal/app"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/domain/dtos"
|
||||
"github.com/usual2970/certimate/internal/notify"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/certs"
|
||||
"github.com/usual2970/certimate/internal/repository"
|
||||
)
|
||||
|
||||
@@ -18,6 +22,7 @@ const (
|
||||
)
|
||||
|
||||
type certificateRepository interface {
|
||||
GetById(ctx context.Context, id string) (*domain.Certificate, error)
|
||||
ListExpireSoon(ctx context.Context) ([]*domain.Certificate, error)
|
||||
}
|
||||
|
||||
@@ -32,8 +37,7 @@ func NewCertificateService(repo certificateRepository) *CertificateService {
|
||||
}
|
||||
|
||||
func (s *CertificateService) InitSchedule(ctx context.Context) error {
|
||||
scheduler := app.GetScheduler()
|
||||
err := scheduler.Add("certificate", "0 0 * * *", func() {
|
||||
app.GetScheduler().MustAdd("certificateExpireSoonNotify", "0 0 * * *", func() {
|
||||
certs, err := s.repo.ListExpireSoon(context.Background())
|
||||
if err != nil {
|
||||
app.GetLogger().Error("failed to get certificates which expire soon", "err", err)
|
||||
@@ -49,15 +53,129 @@ func (s *CertificateService) InitSchedule(ctx context.Context) error {
|
||||
app.GetLogger().Error("failed to send notification", "err", err)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
app.GetLogger().Error("failed to add schedule", "err", err)
|
||||
return err
|
||||
}
|
||||
scheduler.Start()
|
||||
app.GetLogger().Info("certificate schedule started")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.CertificateArchiveFileReq) ([]byte, error) {
|
||||
certificate, err := s.repo.GetById(ctx, req.CertificateId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
zipWriter := zip.NewWriter(&buf)
|
||||
defer zipWriter.Close()
|
||||
|
||||
switch strings.ToUpper(req.Format) {
|
||||
case "", "PEM":
|
||||
{
|
||||
certWriter, err := zipWriter.Create("certbundle.pem")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = certWriter.Write([]byte(certificate.Certificate))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyWriter, err := zipWriter.Create("privkey.pem")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = keyWriter.Write([]byte(certificate.PrivateKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = zipWriter.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
case "PFX":
|
||||
{
|
||||
const pfxPassword = "certimate"
|
||||
|
||||
certPFX, err := certs.TransformCertificateFromPEMToPFX(certificate.Certificate, certificate.PrivateKey, pfxPassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certWriter, err := zipWriter.Create("cert.pfx")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = certWriter.Write(certPFX)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyWriter, err := zipWriter.Create("pfx-password.txt")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = keyWriter.Write([]byte(pfxPassword))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = zipWriter.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
case "JKS":
|
||||
{
|
||||
const jksPassword = "certimate"
|
||||
|
||||
certJKS, err := certs.TransformCertificateFromPEMToJKS(certificate.Certificate, certificate.PrivateKey, jksPassword, jksPassword, jksPassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certWriter, err := zipWriter.Create("cert.jks")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = certWriter.Write(certJKS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyWriter, err := zipWriter.Create("jks-password.txt")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = keyWriter.Write([]byte(jksPassword))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = zipWriter.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, domain.ErrInvalidParams
|
||||
}
|
||||
}
|
||||
|
||||
func buildExpireSoonNotification(certificates []*domain.Certificate) *struct {
|
||||
Subject string
|
||||
Message string
|
||||
@@ -70,11 +188,11 @@ func buildExpireSoonNotification(certificates []*domain.Certificate) *struct {
|
||||
message := defaultExpireMessage
|
||||
|
||||
// 查询模板信息
|
||||
settingRepo := repository.NewSettingsRepository()
|
||||
setting, err := settingRepo.GetByName(context.Background(), "notifyTemplates")
|
||||
settingsRepo := repository.NewSettingsRepository()
|
||||
settings, err := settingsRepo.GetByName(context.Background(), "notifyTemplates")
|
||||
if err == nil {
|
||||
var templates *domain.NotifyTemplatesSettingsContent
|
||||
json.Unmarshal([]byte(setting.Content), &templates)
|
||||
json.Unmarshal([]byte(settings.Content), &templates)
|
||||
|
||||
if templates != nil && len(templates.NotifyTemplates) > 0 {
|
||||
subject = templates.NotifyTemplates[0].Subject
|
||||
|
@@ -29,11 +29,12 @@ func NewWithDeployNode(node *domain.WorkflowNode, certdata struct {
|
||||
return nil, fmt.Errorf("node type is not deploy")
|
||||
}
|
||||
|
||||
nodeConfig := node.GetConfigForDeploy()
|
||||
|
||||
accessRepo := repository.NewAccessRepository()
|
||||
accessId := node.GetConfigString("providerAccessId")
|
||||
access, err := accessRepo.GetById(context.Background(), accessId)
|
||||
access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get access #%s record: %w", accessId, err)
|
||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
|
||||
}
|
||||
|
||||
accessConfig, err := access.UnmarshalConfigToMap()
|
||||
@@ -42,9 +43,9 @@ func NewWithDeployNode(node *domain.WorkflowNode, certdata struct {
|
||||
}
|
||||
|
||||
deployer, logger, err := createDeployer(&deployerOptions{
|
||||
Provider: domain.DeployProviderType(node.GetConfigString("provider")),
|
||||
Provider: domain.DeployProviderType(nodeConfig.Provider),
|
||||
ProviderAccessConfig: accessConfig,
|
||||
ProviderDeployConfig: node.GetConfigMap("providerConfig"),
|
||||
ProviderDeployConfig: nodeConfig.ProviderConfig,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -5,6 +5,8 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const CollectionNameAccess = "access"
|
||||
|
||||
type Access struct {
|
||||
Meta
|
||||
Name string `json:"name" db:"name"`
|
||||
|
@@ -4,6 +4,8 @@ import (
|
||||
"github.com/go-acme/lego/v4/registration"
|
||||
)
|
||||
|
||||
const CollectionNameAcmeAccount = "acme_accounts"
|
||||
|
||||
type AcmeAccount struct {
|
||||
Meta
|
||||
CA string `json:"ca" db:"ca"`
|
@@ -2,12 +2,7 @@ package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type CertificateSourceType string
|
||||
|
||||
const (
|
||||
CertificateSourceTypeWorkflow = CertificateSourceType("workflow")
|
||||
CertificateSourceTypeUpload = CertificateSourceType("upload")
|
||||
)
|
||||
const CollectionNameCertificate = "certificate"
|
||||
|
||||
type Certificate struct {
|
||||
Meta
|
||||
@@ -25,3 +20,10 @@ type Certificate struct {
|
||||
WorkflowOutputId string `json:"workflowOutputId" db:"workflowOutputId"`
|
||||
DeletedAt *time.Time `json:"deleted" db:"deleted"`
|
||||
}
|
||||
|
||||
type CertificateSourceType string
|
||||
|
||||
const (
|
||||
CertificateSourceTypeWorkflow = CertificateSourceType("workflow")
|
||||
CertificateSourceTypeUpload = CertificateSourceType("upload")
|
||||
)
|
||||
|
6
internal/domain/dtos/certificate.go
Normal file
6
internal/domain/dtos/certificate.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package dtos
|
||||
|
||||
type CertificateArchiveFileReq struct {
|
||||
CertificateId string `json:"-"`
|
||||
Format string `json:"format"`
|
||||
}
|
7
internal/domain/dtos/notify.go
Normal file
7
internal/domain/dtos/notify.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package dtos
|
||||
|
||||
import "github.com/usual2970/certimate/internal/domain"
|
||||
|
||||
type NotifyTestPushReq struct {
|
||||
Channel domain.NotifyChannelType `json:"channel"`
|
||||
}
|
8
internal/domain/dtos/workflow.go
Normal file
8
internal/domain/dtos/workflow.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package dtos
|
||||
|
||||
import "github.com/usual2970/certimate/internal/domain"
|
||||
|
||||
type WorkflowRunReq struct {
|
||||
WorkflowId string `json:"-"`
|
||||
Trigger domain.WorkflowTriggerType `json:"trigger"`
|
||||
}
|
@@ -18,7 +18,3 @@ const (
|
||||
NotifyChannelTypeWebhook = NotifyChannelType("webhook")
|
||||
NotifyChannelTypeWeCom = NotifyChannelType("wecom")
|
||||
)
|
||||
|
||||
type NotifyTestPushReq struct {
|
||||
Channel string `json:"channel"`
|
||||
}
|
||||
|
@@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const CollectionNameSettings = "settings"
|
||||
|
||||
type Settings struct {
|
||||
Meta
|
||||
Name string `json:"name" db:"name"`
|
||||
|
@@ -6,6 +6,23 @@ import (
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/maps"
|
||||
)
|
||||
|
||||
const CollectionNameWorkflow = "workflow"
|
||||
|
||||
type Workflow struct {
|
||||
Meta
|
||||
Name string `json:"name" db:"name"`
|
||||
Description string `json:"description" db:"description"`
|
||||
Trigger WorkflowTriggerType `json:"trigger" db:"trigger"`
|
||||
TriggerCron string `json:"triggerCron" db:"triggerCron"`
|
||||
Enabled bool `json:"enabled" db:"enabled"`
|
||||
Content *WorkflowNode `json:"content" db:"content"`
|
||||
Draft *WorkflowNode `json:"draft" db:"draft"`
|
||||
HasDraft bool `json:"hasDraft" db:"hasDraft"`
|
||||
LastRunId string `json:"lastRunId" db:"lastRunId"`
|
||||
LastRunStatus WorkflowRunStatusType `json:"lastRunStatus" db:"lastRunStatus"`
|
||||
LastRunTime time.Time `json:"lastRunTime" db:"lastRunTime"`
|
||||
}
|
||||
|
||||
type WorkflowNodeType string
|
||||
|
||||
const (
|
||||
@@ -28,25 +45,6 @@ const (
|
||||
WorkflowTriggerTypeManual = WorkflowTriggerType("manual")
|
||||
)
|
||||
|
||||
type Workflow struct {
|
||||
Meta
|
||||
Name string `json:"name" db:"name"`
|
||||
Description string `json:"description" db:"description"`
|
||||
Trigger WorkflowTriggerType `json:"trigger" db:"trigger"`
|
||||
TriggerCron string `json:"triggerCron" db:"triggerCron"`
|
||||
Enabled bool `json:"enabled" db:"enabled"`
|
||||
Content *WorkflowNode `json:"content" db:"content"`
|
||||
Draft *WorkflowNode `json:"draft" db:"draft"`
|
||||
HasDraft bool `json:"hasDraft" db:"hasDraft"`
|
||||
LastRunId string `json:"lastRunId" db:"lastRunId"`
|
||||
LastRunStatus WorkflowRunStatusType `json:"lastRunStatus" db:"lastRunStatus"`
|
||||
LastRunTime time.Time `json:"lastRunTime" db:"lastRunTime"`
|
||||
}
|
||||
|
||||
func (w *Workflow) Table() string {
|
||||
return "workflow"
|
||||
}
|
||||
|
||||
type WorkflowNode struct {
|
||||
Id string `json:"id"`
|
||||
Type WorkflowNodeType `json:"type"`
|
||||
@@ -62,23 +60,47 @@ type WorkflowNode struct {
|
||||
Validated bool `json:"validated"`
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) GetConfigString(key string) string {
|
||||
type WorkflowNodeConfigForApply struct {
|
||||
Domains string `json:"domains"` // 域名列表,以半角逗号分隔
|
||||
ContactEmail string `json:"contactEmail"` // 联系邮箱
|
||||
Provider string `json:"provider"` // DNS 提供商
|
||||
ProviderAccessId string `json:"providerAccessId"` // DNS 提供商授权记录 ID
|
||||
ProviderConfig map[string]any `json:"providerConfig"` // DNS 提供商额外配置
|
||||
KeyAlgorithm string `json:"keyAlgorithm"` // 密钥算法
|
||||
Nameservers string `json:"nameservers"` // DNS 服务器列表,以半角逗号分隔
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout"` // DNS 传播超时时间(默认取决于提供商)
|
||||
DnsTTL int32 `json:"dnsTTL"` // DNS TTL(默认取决于提供商)
|
||||
DisableFollowCNAME bool `json:"disableFollowCNAME"` // 是否禁用 CNAME 跟随
|
||||
SkipBeforeExpiryDays int32 `json:"skipBeforeExpiryDays"` // 证书到期前多少天前跳过续期(默认值:30)
|
||||
}
|
||||
|
||||
type WorkflowNodeConfigForDeploy struct {
|
||||
Certificate string `json:"certificate"` // 前序节点输出的证书,形如“${NodeId}#certificate”
|
||||
Provider string `json:"provider"` // 主机提供商
|
||||
ProviderAccessId string `json:"providerAccessId"` // 主机提供商授权记录 ID
|
||||
ProviderConfig map[string]any `json:"providerConfig"` // 主机提供商额外配置
|
||||
SkipOnLastSucceeded bool `json:"skipOnLastSucceeded"` // 上次部署成功时是否跳过
|
||||
}
|
||||
|
||||
type WorkflowNodeConfigForNotify struct {
|
||||
Channel string `json:"channel"` // 通知渠道
|
||||
Subject string `json:"subject"` // 通知主题
|
||||
Message string `json:"message"` // 通知内容
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) getConfigValueAsString(key string) string {
|
||||
return maps.GetValueAsString(n.Config, key)
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) GetConfigBool(key string) bool {
|
||||
func (n *WorkflowNode) getConfigValueAsBool(key string) bool {
|
||||
return maps.GetValueAsBool(n.Config, key)
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) GetConfigInt32(key string) int32 {
|
||||
func (n *WorkflowNode) getConfigValueAsInt32(key string) int32 {
|
||||
return maps.GetValueAsInt32(n.Config, key)
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) GetConfigInt64(key string) int64 {
|
||||
return maps.GetValueAsInt64(n.Config, key)
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) GetConfigMap(key string) map[string]any {
|
||||
func (n *WorkflowNode) getConfigValueAsMap(key string) map[string]any {
|
||||
if val, ok := n.Config[key]; ok {
|
||||
if result, ok := val.(map[string]any); ok {
|
||||
return result
|
||||
@@ -88,6 +110,45 @@ func (n *WorkflowNode) GetConfigMap(key string) map[string]any {
|
||||
return make(map[string]any)
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) GetConfigForApply() WorkflowNodeConfigForApply {
|
||||
skipBeforeExpiryDays := n.getConfigValueAsInt32("skipBeforeExpiryDays")
|
||||
if skipBeforeExpiryDays == 0 {
|
||||
skipBeforeExpiryDays = 30
|
||||
}
|
||||
|
||||
return WorkflowNodeConfigForApply{
|
||||
Domains: n.getConfigValueAsString("domains"),
|
||||
ContactEmail: n.getConfigValueAsString("contactEmail"),
|
||||
Provider: n.getConfigValueAsString("provider"),
|
||||
ProviderAccessId: n.getConfigValueAsString("providerAccessId"),
|
||||
ProviderConfig: n.getConfigValueAsMap("providerConfig"),
|
||||
KeyAlgorithm: n.getConfigValueAsString("keyAlgorithm"),
|
||||
Nameservers: n.getConfigValueAsString("nameservers"),
|
||||
DnsPropagationTimeout: n.getConfigValueAsInt32("dnsPropagationTimeout"),
|
||||
DnsTTL: n.getConfigValueAsInt32("dnsTTL"),
|
||||
DisableFollowCNAME: n.getConfigValueAsBool("disableFollowCNAME"),
|
||||
SkipBeforeExpiryDays: skipBeforeExpiryDays,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) GetConfigForDeploy() WorkflowNodeConfigForDeploy {
|
||||
return WorkflowNodeConfigForDeploy{
|
||||
Certificate: n.getConfigValueAsString("certificate"),
|
||||
Provider: n.getConfigValueAsString("provider"),
|
||||
ProviderAccessId: n.getConfigValueAsString("providerAccessId"),
|
||||
ProviderConfig: n.getConfigValueAsMap("providerConfig"),
|
||||
SkipOnLastSucceeded: n.getConfigValueAsBool("skipOnLastSucceeded"),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) GetConfigForNotify() WorkflowNodeConfigForNotify {
|
||||
return WorkflowNodeConfigForNotify{
|
||||
Channel: n.getConfigValueAsString("channel"),
|
||||
Subject: n.getConfigValueAsString("subject"),
|
||||
Message: n.getConfigValueAsString("message"),
|
||||
}
|
||||
}
|
||||
|
||||
type WorkflowNodeIO struct {
|
||||
Label string `json:"label"`
|
||||
Name string `json:"name"`
|
||||
@@ -102,7 +163,4 @@ type WorkflowNodeIOValueSelector struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type WorkflowRunReq struct {
|
||||
WorkflowId string `json:"workflowId"`
|
||||
Trigger WorkflowTriggerType `json:"trigger"`
|
||||
}
|
||||
const WorkflowNodeIONameCertificate string = "certificate"
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package domain
|
||||
|
||||
const CollectionNameWorkflowOutput = "workflow_output"
|
||||
|
||||
type WorkflowOutput struct {
|
||||
Meta
|
||||
WorkflowId string `json:"workflowId" db:"workflow"`
|
||||
@@ -8,5 +10,3 @@ type WorkflowOutput struct {
|
||||
Outputs []WorkflowNodeIO `json:"outputs" db:"outputs"`
|
||||
Succeeded bool `json:"succeeded" db:"succeeded"`
|
||||
}
|
||||
|
||||
const WORKFLOW_OUTPUT_CERTIFICATE = "certificate"
|
||||
|
@@ -2,14 +2,7 @@ package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type WorkflowRunStatusType string
|
||||
|
||||
const (
|
||||
WorkflowRunStatusTypePending WorkflowRunStatusType = "pending"
|
||||
WorkflowRunStatusTypeRunning WorkflowRunStatusType = "running"
|
||||
WorkflowRunStatusTypeSucceeded WorkflowRunStatusType = "succeeded"
|
||||
WorkflowRunStatusTypeFailed WorkflowRunStatusType = "failed"
|
||||
)
|
||||
const CollectionNameWorkflowRun = "workflow_run"
|
||||
|
||||
type WorkflowRun struct {
|
||||
Meta
|
||||
@@ -22,6 +15,15 @@ type WorkflowRun struct {
|
||||
Error string `json:"error" db:"error"`
|
||||
}
|
||||
|
||||
type WorkflowRunStatusType string
|
||||
|
||||
const (
|
||||
WorkflowRunStatusTypePending WorkflowRunStatusType = "pending"
|
||||
WorkflowRunStatusTypeRunning WorkflowRunStatusType = "running"
|
||||
WorkflowRunStatusTypeSucceeded WorkflowRunStatusType = "succeeded"
|
||||
WorkflowRunStatusTypeFailed WorkflowRunStatusType = "failed"
|
||||
)
|
||||
|
||||
type WorkflowRunLog struct {
|
||||
NodeId string `json:"nodeId"`
|
||||
NodeName string `json:"nodeName"`
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/domain/dtos"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -17,25 +18,25 @@ type settingsRepository interface {
|
||||
}
|
||||
|
||||
type NotifyService struct {
|
||||
settingRepo settingsRepository
|
||||
settingsRepo settingsRepository
|
||||
}
|
||||
|
||||
func NewNotifyService(settingRepo settingsRepository) *NotifyService {
|
||||
func NewNotifyService(settingsRepo settingsRepository) *NotifyService {
|
||||
return &NotifyService{
|
||||
settingRepo: settingRepo,
|
||||
settingsRepo: settingsRepo,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *NotifyService) Test(ctx context.Context, req *domain.NotifyTestPushReq) error {
|
||||
setting, err := n.settingRepo.GetByName(ctx, "notifyChannels")
|
||||
func (n *NotifyService) Test(ctx context.Context, req *dtos.NotifyTestPushReq) error {
|
||||
settings, err := n.settingsRepo.GetByName(ctx, "notifyChannels")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get notify channels settings: %w", err)
|
||||
}
|
||||
|
||||
channelConfig, err := setting.GetNotifyChannelConfig(req.Channel)
|
||||
channelConfig, err := settings.GetNotifyChannelConfig(string(req.Channel))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get notify channel \"%s\" config: %w", req.Channel, err)
|
||||
}
|
||||
|
||||
return SendToChannel(notifyTestTitle, notifyTestBody, req.Channel, channelConfig)
|
||||
return SendToChannel(notifyTestTitle, notifyTestBody, string(req.Channel), channelConfig)
|
||||
}
|
||||
|
@@ -10,11 +10,11 @@ import (
|
||||
)
|
||||
|
||||
type ACMEHttpReqApplicantConfig struct {
|
||||
Endpoint string `json:"endpoint"`
|
||||
Mode string `json:"mode"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Mode string `json:"mode"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *ACMEHttpReqApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -28,8 +28,8 @@ func NewChallengeProvider(config *ACMEHttpReqApplicantConfig) (challenge.Provide
|
||||
providerConfig.Mode = config.Mode
|
||||
providerConfig.Username = config.Username
|
||||
providerConfig.Password = config.Password
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
|
||||
provider, err := httpreq.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -9,9 +9,10 @@ import (
|
||||
)
|
||||
|
||||
type AliyunApplicantConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *AliyunApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -22,8 +23,11 @@ func NewChallengeProvider(config *AliyunApplicantConfig) (challenge.Provider, er
|
||||
providerConfig := alidns.NewDefaultConfig()
|
||||
providerConfig.APIKey = config.AccessKeyId
|
||||
providerConfig.SecretKey = config.AccessKeySecret
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
|
||||
provider, err := alidns.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -9,11 +9,12 @@ import (
|
||||
)
|
||||
|
||||
type AWSRoute53ApplicantConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
Region string `json:"region"`
|
||||
HostedZoneId string `json:"hostedZoneId"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
Region string `json:"region"`
|
||||
HostedZoneId string `json:"hostedZoneId"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *AWSRoute53ApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -26,8 +27,11 @@ func NewChallengeProvider(config *AWSRoute53ApplicantConfig) (challenge.Provider
|
||||
providerConfig.SecretAccessKey = config.SecretAccessKey
|
||||
providerConfig.Region = config.Region
|
||||
providerConfig.HostedZoneID = config.HostedZoneId
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
|
||||
provider, err := route53.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -12,11 +12,12 @@ import (
|
||||
)
|
||||
|
||||
type AzureDNSApplicantConfig struct {
|
||||
TenantId string `json:"tenantId"`
|
||||
ClientId string `json:"clientId"`
|
||||
ClientSecret string `json:"clientSecret"`
|
||||
CloudName string `json:"cloudName,omitempty"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
TenantId string `json:"tenantId"`
|
||||
ClientId string `json:"clientId"`
|
||||
ClientSecret string `json:"clientSecret"`
|
||||
CloudName string `json:"cloudName,omitempty"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *AzureDNSApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -40,8 +41,11 @@ func NewChallengeProvider(config *AzureDNSApplicantConfig) (challenge.Provider,
|
||||
return nil, fmt.Errorf("azuredns: unknown environment %s", config.CloudName)
|
||||
}
|
||||
}
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
|
||||
provider, err := azuredns.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -9,8 +9,9 @@ import (
|
||||
)
|
||||
|
||||
type CloudflareApplicantConfig struct {
|
||||
DnsApiToken string `json:"dnsApiToken"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
DnsApiToken string `json:"dnsApiToken"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *CloudflareApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -20,8 +21,11 @@ func NewChallengeProvider(config *CloudflareApplicantConfig) (challenge.Provider
|
||||
|
||||
providerConfig := cloudflare.NewDefaultConfig()
|
||||
providerConfig.AuthToken = config.DnsApiToken
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
|
||||
provider, err := cloudflare.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -9,9 +9,10 @@ import (
|
||||
)
|
||||
|
||||
type GoDaddyApplicantConfig struct {
|
||||
ApiKey string `json:"apiKey"`
|
||||
ApiSecret string `json:"apiSecret"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
ApiSecret string `json:"apiSecret"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *GoDaddyApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -22,8 +23,11 @@ func NewChallengeProvider(config *GoDaddyApplicantConfig) (challenge.Provider, e
|
||||
providerConfig := godaddy.NewDefaultConfig()
|
||||
providerConfig.APIKey = config.ApiKey
|
||||
providerConfig.APISecret = config.ApiSecret
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
|
||||
provider, err := godaddy.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -9,10 +9,11 @@ import (
|
||||
)
|
||||
|
||||
type HuaweiCloudApplicantConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
Region string `json:"region"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
Region string `json:"region"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *HuaweiCloudApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -30,8 +31,11 @@ func NewChallengeProvider(config *HuaweiCloudApplicantConfig) (challenge.Provide
|
||||
providerConfig.AccessKeyID = config.AccessKeyId
|
||||
providerConfig.SecretAccessKey = config.SecretAccessKey
|
||||
providerConfig.Region = region
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = config.DnsTTL
|
||||
}
|
||||
|
||||
provider, err := hwc.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -9,9 +9,10 @@ import (
|
||||
)
|
||||
|
||||
type NameDotComApplicantConfig struct {
|
||||
Username string `json:"username"`
|
||||
ApiToken string `json:"apiToken"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
Username string `json:"username"`
|
||||
ApiToken string `json:"apiToken"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *NameDotComApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -22,8 +23,11 @@ func NewChallengeProvider(config *NameDotComApplicantConfig) (challenge.Provider
|
||||
providerConfig := namedotcom.NewDefaultConfig()
|
||||
providerConfig.Username = config.Username
|
||||
providerConfig.APIToken = config.ApiToken
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
|
||||
provider, err := namedotcom.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -9,8 +9,9 @@ import (
|
||||
)
|
||||
|
||||
type NameSiloApplicantConfig struct {
|
||||
ApiKey string `json:"apiKey"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *NameSiloApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -20,8 +21,11 @@ func NewChallengeProvider(config *NameSiloApplicantConfig) (challenge.Provider,
|
||||
|
||||
providerConfig := namesilo.NewDefaultConfig()
|
||||
providerConfig.APIKey = config.ApiKey
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
|
||||
provider, err := namesilo.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -9,8 +9,9 @@ import (
|
||||
)
|
||||
|
||||
type NS1ApplicantConfig struct {
|
||||
ApiKey string `json:"apiKey"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *NS1ApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -20,8 +21,11 @@ func NewChallengeProvider(config *NS1ApplicantConfig) (challenge.Provider, error
|
||||
|
||||
providerConfig := ns1.NewDefaultConfig()
|
||||
providerConfig.APIKey = config.ApiKey
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
|
||||
provider, err := ns1.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -10,9 +10,10 @@ import (
|
||||
)
|
||||
|
||||
type PowerDNSApplicantConfig struct {
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *PowerDNSApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -24,8 +25,11 @@ func NewChallengeProvider(config *PowerDNSApplicantConfig) (challenge.Provider,
|
||||
providerConfig := pdns.NewDefaultConfig()
|
||||
providerConfig.Host = host
|
||||
providerConfig.APIKey = config.ApiKey
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
|
||||
provider, err := pdns.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -9,9 +9,10 @@ import (
|
||||
)
|
||||
|
||||
type TencentCloudApplicantConfig struct {
|
||||
SecretId string `json:"secretId"`
|
||||
SecretKey string `json:"secretKey"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
SecretId string `json:"secretId"`
|
||||
SecretKey string `json:"secretKey"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *TencentCloudApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -22,8 +23,11 @@ func NewChallengeProvider(config *TencentCloudApplicantConfig) (challenge.Provid
|
||||
providerConfig := tencentcloud.NewDefaultConfig()
|
||||
providerConfig.SecretID = config.SecretId
|
||||
providerConfig.SecretKey = config.SecretKey
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
|
||||
provider, err := tencentcloud.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -9,9 +9,10 @@ import (
|
||||
)
|
||||
|
||||
type VolcEngineApplicantConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *VolcEngineApplicantConfig) (challenge.Provider, error) {
|
||||
@@ -22,8 +23,11 @@ func NewChallengeProvider(config *VolcEngineApplicantConfig) (challenge.Provider
|
||||
providerConfig := volcengine.NewDefaultConfig()
|
||||
providerConfig.AccessKey = config.AccessKeyId
|
||||
providerConfig.SecretKey = config.SecretAccessKey
|
||||
if config.PropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
|
||||
provider, err := volcengine.NewDNSProviderConfig(providerConfig)
|
||||
|
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
providerScm "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/huaweicloud-scm"
|
||||
hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk"
|
||||
hwsdkCdn "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk/cdn"
|
||||
)
|
||||
|
||||
type HuaweiCloudCDNDeployerConfig struct {
|
||||
@@ -32,7 +31,7 @@ type HuaweiCloudCDNDeployerConfig struct {
|
||||
type HuaweiCloudCDNDeployer struct {
|
||||
config *HuaweiCloudCDNDeployerConfig
|
||||
logger logger.Logger
|
||||
sdkClient *hwsdkCdn.Client
|
||||
sdkClient *hcCdn.CdnClient
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
@@ -100,21 +99,21 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context, certPem string, pri
|
||||
// 更新加速域名配置
|
||||
// REF: https://support.huaweicloud.com/api-cdn/UpdateDomainMultiCertificates.html
|
||||
// REF: https://support.huaweicloud.com/usermanual-cdn/cdn_01_0306.html
|
||||
updateDomainMultiCertificatesReqBodyContent := &hwsdkCdn.UpdateDomainMultiCertificatesExRequestBodyContent{}
|
||||
updateDomainMultiCertificatesReqBodyContent := &hcCdnModel.UpdateDomainMultiCertificatesRequestBodyContent{}
|
||||
updateDomainMultiCertificatesReqBodyContent.DomainName = d.config.Domain
|
||||
updateDomainMultiCertificatesReqBodyContent.HttpsSwitch = 1
|
||||
updateDomainMultiCertificatesReqBodyContent.CertificateType = hwsdk.Int32Ptr(2)
|
||||
updateDomainMultiCertificatesReqBodyContent.SCMCertificateId = hwsdk.StringPtr(upres.CertId)
|
||||
updateDomainMultiCertificatesReqBodyContent.ScmCertificateId = hwsdk.StringPtr(upres.CertId)
|
||||
updateDomainMultiCertificatesReqBodyContent.CertName = hwsdk.StringPtr(upres.CertName)
|
||||
updateDomainMultiCertificatesReqBodyContent = updateDomainMultiCertificatesReqBodyContent.MergeConfig(showDomainFullConfigResp.Configs)
|
||||
updateDomainMultiCertificatesReq := &hwsdkCdn.UpdateDomainMultiCertificatesExRequest{
|
||||
Body: &hwsdkCdn.UpdateDomainMultiCertificatesExRequestBody{
|
||||
updateDomainMultiCertificatesReqBodyContent = assign(updateDomainMultiCertificatesReqBodyContent, showDomainFullConfigResp.Configs)
|
||||
updateDomainMultiCertificatesReq := &hcCdnModel.UpdateDomainMultiCertificatesRequest{
|
||||
Body: &hcCdnModel.UpdateDomainMultiCertificatesRequestBody{
|
||||
Https: updateDomainMultiCertificatesReqBodyContent,
|
||||
},
|
||||
}
|
||||
updateDomainMultiCertificatesResp, err := d.sdkClient.UploadDomainMultiCertificatesEx(updateDomainMultiCertificatesReq)
|
||||
updateDomainMultiCertificatesResp, err := d.sdkClient.UpdateDomainMultiCertificates(updateDomainMultiCertificatesReq)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.UploadDomainMultiCertificatesEx'")
|
||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.UploadDomainMultiCertificates'")
|
||||
}
|
||||
|
||||
d.logger.Logt("已更新加速域名配置", updateDomainMultiCertificatesResp)
|
||||
@@ -122,7 +121,7 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context, certPem string, pri
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(accessKeyId, secretAccessKey, region string) (*hwsdkCdn.Client, error) {
|
||||
func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcCdn.CdnClient, error) {
|
||||
if region == "" {
|
||||
region = "cn-north-1" // CDN 服务默认区域:华北一北京
|
||||
}
|
||||
@@ -148,6 +147,42 @@ func createSdkClient(accessKeyId, secretAccessKey, region string) (*hwsdkCdn.Cli
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := hwsdkCdn.NewClient(hcClient)
|
||||
client := hcCdn.NewCdnClient(hcClient)
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func assign(reqContent *hcCdnModel.UpdateDomainMultiCertificatesRequestBodyContent, target *hcCdnModel.ConfigsGetBody) *hcCdnModel.UpdateDomainMultiCertificatesRequestBodyContent {
|
||||
if target == nil {
|
||||
return reqContent
|
||||
}
|
||||
|
||||
// 华为云 API 中不传的字段表示使用默认值、而非保留原值,因此这里需要把原配置中的参数重新赋值回去。
|
||||
// 而且蛋疼的是查询接口返回的数据结构和更新接口传入的参数结构不一致,需要做很多转化。
|
||||
|
||||
if *target.OriginProtocol == "follow" {
|
||||
reqContent.AccessOriginWay = hwsdk.Int32Ptr(1)
|
||||
} else if *target.OriginProtocol == "http" {
|
||||
reqContent.AccessOriginWay = hwsdk.Int32Ptr(2)
|
||||
} else if *target.OriginProtocol == "https" {
|
||||
reqContent.AccessOriginWay = hwsdk.Int32Ptr(3)
|
||||
}
|
||||
|
||||
if target.ForceRedirect != nil {
|
||||
reqContent.ForceRedirectConfig = &hcCdnModel.ForceRedirect{}
|
||||
|
||||
if target.ForceRedirect.Status == "on" {
|
||||
reqContent.ForceRedirectConfig.Switch = 1
|
||||
reqContent.ForceRedirectConfig.RedirectType = target.ForceRedirect.Type
|
||||
} else {
|
||||
reqContent.ForceRedirectConfig.Switch = 0
|
||||
}
|
||||
}
|
||||
|
||||
if target.Https != nil {
|
||||
if *target.Https.Http2Status == "on" {
|
||||
reqContent.Http2 = hwsdk.Int32Ptr(1)
|
||||
}
|
||||
}
|
||||
|
||||
return reqContent
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"time"
|
||||
@@ -26,9 +28,23 @@ func TransformCertificateFromPEMToPFX(certPem string, privkeyPem string, pfxPass
|
||||
return nil, err
|
||||
}
|
||||
|
||||
privkey, err := ParsePKCS1PrivateKeyFromPEM(privkeyPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var privkey interface{}
|
||||
switch cert.PublicKey.(type) {
|
||||
case *rsa.PublicKey:
|
||||
{
|
||||
privkey, err = ParsePKCS1PrivateKeyFromPEM(privkeyPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
case *ecdsa.PublicKey:
|
||||
{
|
||||
privkey, err = ParseECPrivateKeyFromPEM(privkeyPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pfxData, err := pkcs12.LegacyRC2.Encode(privkey, cert, nil, pfxPassword)
|
||||
|
@@ -1,28 +0,0 @@
|
||||
package cdn
|
||||
|
||||
import (
|
||||
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core"
|
||||
hcCdn "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2"
|
||||
hcCdnModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2/model"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
hcCdn.CdnClient
|
||||
}
|
||||
|
||||
func NewClient(hcClient *core.HcHttpClient) *Client {
|
||||
return &Client{
|
||||
CdnClient: *hcCdn.NewCdnClient(hcClient),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) UploadDomainMultiCertificatesEx(request *UpdateDomainMultiCertificatesExRequest) (*UpdateDomainMultiCertificatesExResponse, error) {
|
||||
requestDef := hcCdn.GenReqDefForUpdateDomainMultiCertificates()
|
||||
|
||||
if resp, err := c.HcClient.Sync(request, requestDef); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
temp := resp.(*hcCdnModel.UpdateDomainMultiCertificatesResponse)
|
||||
return &UpdateDomainMultiCertificatesExResponse{UpdateDomainMultiCertificatesResponse: *temp}, nil
|
||||
}
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
package cdn
|
||||
|
||||
import (
|
||||
hcCdnModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2/model"
|
||||
|
||||
hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk"
|
||||
)
|
||||
|
||||
type UpdateDomainMultiCertificatesExRequestBodyContent struct {
|
||||
hcCdnModel.UpdateDomainMultiCertificatesRequestBodyContent `json:",inline"`
|
||||
|
||||
// 华为云官方 SDK 中目前提供的字段缺失,这里暂时先需自定义请求,可能需要等之后 SDK 更新。
|
||||
SCMCertificateId *string `json:"scm_certificate_id,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateDomainMultiCertificatesExRequestBody struct {
|
||||
Https *UpdateDomainMultiCertificatesExRequestBodyContent `json:"https,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateDomainMultiCertificatesExRequest struct {
|
||||
Body *UpdateDomainMultiCertificatesExRequestBody `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateDomainMultiCertificatesExResponse struct {
|
||||
hcCdnModel.UpdateDomainMultiCertificatesResponse
|
||||
}
|
||||
|
||||
func (m *UpdateDomainMultiCertificatesExRequestBodyContent) MergeConfig(src *hcCdnModel.ConfigsGetBody) *UpdateDomainMultiCertificatesExRequestBodyContent {
|
||||
if src == nil {
|
||||
return m
|
||||
}
|
||||
|
||||
// 华为云 API 中不传的字段表示使用默认值、而非保留原值,因此这里需要把原配置中的参数重新赋值回去。
|
||||
// 而且蛋疼的是查询接口返回的数据结构和更新接口传入的参数结构不一致,需要做很多转化。
|
||||
|
||||
if *src.OriginProtocol == "follow" {
|
||||
m.AccessOriginWay = hwsdk.Int32Ptr(1)
|
||||
} else if *src.OriginProtocol == "http" {
|
||||
m.AccessOriginWay = hwsdk.Int32Ptr(2)
|
||||
} else if *src.OriginProtocol == "https" {
|
||||
m.AccessOriginWay = hwsdk.Int32Ptr(3)
|
||||
}
|
||||
|
||||
if src.ForceRedirect != nil {
|
||||
m.ForceRedirectConfig = &hcCdnModel.ForceRedirect{}
|
||||
|
||||
if src.ForceRedirect.Status == "on" {
|
||||
m.ForceRedirectConfig.Switch = 1
|
||||
m.ForceRedirectConfig.RedirectType = src.ForceRedirect.Type
|
||||
} else {
|
||||
m.ForceRedirectConfig.Switch = 0
|
||||
}
|
||||
}
|
||||
|
||||
if src.Https != nil {
|
||||
if *src.Https.Http2Status == "on" {
|
||||
m.Http2 = hwsdk.Int32Ptr(1)
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
@@ -6,7 +6,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
|
||||
"github.com/usual2970/certimate/internal/app"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
@@ -18,7 +19,7 @@ func NewAccessRepository() *AccessRepository {
|
||||
}
|
||||
|
||||
func (r *AccessRepository) GetById(ctx context.Context, id string) (*domain.Access, error) {
|
||||
record, err := app.GetApp().Dao().FindRecordById("access", id)
|
||||
record, err := app.GetApp().FindRecordById(domain.CollectionNameAccess, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, domain.ErrRecordNotFound
|
||||
@@ -33,16 +34,16 @@ func (r *AccessRepository) GetById(ctx context.Context, id string) (*domain.Acce
|
||||
return r.castRecordToModel(record)
|
||||
}
|
||||
|
||||
func (r *AccessRepository) castRecordToModel(record *models.Record) (*domain.Access, error) {
|
||||
func (r *AccessRepository) castRecordToModel(record *core.Record) (*domain.Access, error) {
|
||||
if record == nil {
|
||||
return nil, fmt.Errorf("record is nil")
|
||||
}
|
||||
|
||||
access := &domain.Access{
|
||||
Meta: domain.Meta{
|
||||
Id: record.GetId(),
|
||||
CreatedAt: record.GetCreated().Time(),
|
||||
UpdatedAt: record.GetUpdated().Time(),
|
||||
Id: record.Id,
|
||||
CreatedAt: record.GetDateTime("created").Time(),
|
||||
UpdatedAt: record.GetDateTime("updated").Time(),
|
||||
},
|
||||
Name: record.GetString("name"),
|
||||
Provider: record.GetString("provider"),
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/go-acme/lego/v4/registration"
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"golang.org/x/sync/singleflight"
|
||||
|
||||
"github.com/usual2970/certimate/internal/app"
|
||||
@@ -22,8 +22,8 @@ var g singleflight.Group
|
||||
|
||||
func (r *AcmeAccountRepository) GetByCAAndEmail(ca, email string) (*domain.AcmeAccount, error) {
|
||||
resp, err, _ := g.Do(fmt.Sprintf("acme_account_%s_%s", ca, email), func() (interface{}, error) {
|
||||
resp, err := app.GetApp().Dao().FindFirstRecordByFilter(
|
||||
"acme_accounts",
|
||||
resp, err := app.GetApp().FindFirstRecordByFilter(
|
||||
domain.CollectionNameAcmeAccount,
|
||||
"ca={:ca} && email={:email}",
|
||||
dbx.Params{"ca": ca, "email": email},
|
||||
)
|
||||
@@ -40,7 +40,7 @@ func (r *AcmeAccountRepository) GetByCAAndEmail(ca, email string) (*domain.AcmeA
|
||||
return nil, domain.ErrRecordNotFound
|
||||
}
|
||||
|
||||
record, ok := resp.(*models.Record)
|
||||
record, ok := resp.(*core.Record)
|
||||
if !ok {
|
||||
return nil, domain.ErrRecordNotFound
|
||||
}
|
||||
@@ -49,20 +49,20 @@ func (r *AcmeAccountRepository) GetByCAAndEmail(ca, email string) (*domain.AcmeA
|
||||
}
|
||||
|
||||
func (r *AcmeAccountRepository) Save(ca, email, key string, resource *registration.Resource) error {
|
||||
collection, err := app.GetApp().Dao().FindCollectionByNameOrId("acme_accounts")
|
||||
collection, err := app.GetApp().FindCollectionByNameOrId(domain.CollectionNameAcmeAccount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
record := models.NewRecord(collection)
|
||||
record := core.NewRecord(collection)
|
||||
record.Set("ca", ca)
|
||||
record.Set("email", email)
|
||||
record.Set("key", key)
|
||||
record.Set("resource", resource)
|
||||
return app.GetApp().Dao().Save(record)
|
||||
return app.GetApp().Save(record)
|
||||
}
|
||||
|
||||
func (r *AcmeAccountRepository) castRecordToModel(record *models.Record) (*domain.AcmeAccount, error) {
|
||||
func (r *AcmeAccountRepository) castRecordToModel(record *core.Record) (*domain.AcmeAccount, error) {
|
||||
if record == nil {
|
||||
return nil, fmt.Errorf("record is nil")
|
||||
}
|
||||
@@ -74,9 +74,9 @@ func (r *AcmeAccountRepository) castRecordToModel(record *models.Record) (*domai
|
||||
|
||||
acmeAccount := &domain.AcmeAccount{
|
||||
Meta: domain.Meta{
|
||||
Id: record.GetId(),
|
||||
CreatedAt: record.GetCreated().Time(),
|
||||
UpdatedAt: record.GetUpdated().Time(),
|
||||
Id: record.Id,
|
||||
CreatedAt: record.GetDateTime("created").Time(),
|
||||
UpdatedAt: record.GetDateTime("updated").Time(),
|
||||
},
|
||||
CA: record.GetString("ca"),
|
||||
Email: record.GetString("email"),
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/usual2970/certimate/internal/app"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
@@ -19,8 +19,8 @@ func NewCertificateRepository() *CertificateRepository {
|
||||
}
|
||||
|
||||
func (r *CertificateRepository) ListExpireSoon(ctx context.Context) ([]*domain.Certificate, error) {
|
||||
records, err := app.GetApp().Dao().FindRecordsByFilter(
|
||||
"certificate",
|
||||
records, err := app.GetApp().FindRecordsByFilter(
|
||||
domain.CollectionNameCertificate,
|
||||
"expireAt>DATETIME('now') && expireAt<DATETIME('now', '+20 days') && deleted=null",
|
||||
"-created",
|
||||
0, 0,
|
||||
@@ -43,7 +43,7 @@ func (r *CertificateRepository) ListExpireSoon(ctx context.Context) ([]*domain.C
|
||||
}
|
||||
|
||||
func (r *CertificateRepository) GetById(ctx context.Context, id string) (*domain.Certificate, error) {
|
||||
record, err := app.GetApp().Dao().FindRecordById("certificate", id)
|
||||
record, err := app.GetApp().FindRecordById(domain.CollectionNameCertificate, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, domain.ErrRecordNotFound
|
||||
@@ -59,8 +59,8 @@ func (r *CertificateRepository) GetById(ctx context.Context, id string) (*domain
|
||||
}
|
||||
|
||||
func (r *CertificateRepository) GetByWorkflowNodeId(ctx context.Context, workflowNodeId string) (*domain.Certificate, error) {
|
||||
records, err := app.GetApp().Dao().FindRecordsByFilter(
|
||||
"certificate",
|
||||
records, err := app.GetApp().FindRecordsByFilter(
|
||||
domain.CollectionNameCertificate,
|
||||
"workflowNodeId={:workflowNodeId} && deleted=null",
|
||||
"-created", 1, 0,
|
||||
dbx.Params{"workflowNodeId": workflowNodeId},
|
||||
@@ -78,16 +78,16 @@ func (r *CertificateRepository) GetByWorkflowNodeId(ctx context.Context, workflo
|
||||
return r.castRecordToModel(records[0])
|
||||
}
|
||||
|
||||
func (r *CertificateRepository) castRecordToModel(record *models.Record) (*domain.Certificate, error) {
|
||||
func (r *CertificateRepository) castRecordToModel(record *core.Record) (*domain.Certificate, error) {
|
||||
if record == nil {
|
||||
return nil, fmt.Errorf("record is nil")
|
||||
}
|
||||
|
||||
certificate := &domain.Certificate{
|
||||
Meta: domain.Meta{
|
||||
Id: record.GetId(),
|
||||
CreatedAt: record.GetCreated().Time(),
|
||||
UpdatedAt: record.GetUpdated().Time(),
|
||||
Id: record.Id,
|
||||
CreatedAt: record.GetDateTime("created").Time(),
|
||||
UpdatedAt: record.GetDateTime("updated").Time(),
|
||||
},
|
||||
Source: domain.CertificateSourceType(record.GetString("source")),
|
||||
SubjectAltNames: record.GetString("subjectAltNames"),
|
||||
|
@@ -17,8 +17,8 @@ func NewSettingsRepository() *SettingsRepository {
|
||||
}
|
||||
|
||||
func (r *SettingsRepository) GetByName(ctx context.Context, name string) (*domain.Settings, error) {
|
||||
record, err := app.GetApp().Dao().FindFirstRecordByFilter(
|
||||
"settings",
|
||||
record, err := app.GetApp().FindFirstRecordByFilter(
|
||||
domain.CollectionNameSettings,
|
||||
"name={:name}",
|
||||
dbx.Params{"name": name},
|
||||
)
|
||||
@@ -31,9 +31,9 @@ func (r *SettingsRepository) GetByName(ctx context.Context, name string) (*domai
|
||||
|
||||
settings := &domain.Settings{
|
||||
Meta: domain.Meta{
|
||||
Id: record.GetId(),
|
||||
CreatedAt: record.GetCreated().Time(),
|
||||
UpdatedAt: record.GetUpdated().Time(),
|
||||
Id: record.Id,
|
||||
CreatedAt: record.GetDateTime("created").Time(),
|
||||
UpdatedAt: record.GetDateTime("updated").Time(),
|
||||
},
|
||||
Name: record.GetString("name"),
|
||||
Content: record.GetString("content"),
|
||||
|
@@ -20,7 +20,9 @@ func (r *StatisticsRepository) Get(ctx context.Context) (*domain.Statistics, err
|
||||
certTotal := struct {
|
||||
Total int `db:"total"`
|
||||
}{}
|
||||
if err := app.GetApp().Dao().DB().NewQuery("SELECT COUNT(*) AS total FROM certificate").One(&certTotal); err != nil {
|
||||
if err := app.GetDB().
|
||||
NewQuery("SELECT COUNT(*) AS total FROM certificate").
|
||||
One(&certTotal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rs.CertificateTotal = certTotal.Total
|
||||
@@ -29,7 +31,7 @@ func (r *StatisticsRepository) Get(ctx context.Context) (*domain.Statistics, err
|
||||
certExpireSoonTotal := struct {
|
||||
Total int `db:"total"`
|
||||
}{}
|
||||
if err := app.GetApp().Dao().DB().
|
||||
if err := app.GetDB().
|
||||
NewQuery("SELECT COUNT(*) AS total FROM certificate WHERE expireAt > DATETIME('now') and expireAt < DATETIME('now', '+20 days')").
|
||||
One(&certExpireSoonTotal); err != nil {
|
||||
return nil, err
|
||||
@@ -40,7 +42,7 @@ func (r *StatisticsRepository) Get(ctx context.Context) (*domain.Statistics, err
|
||||
certExpiredTotal := struct {
|
||||
Total int `db:"total"`
|
||||
}{}
|
||||
if err := app.GetApp().Dao().DB().
|
||||
if err := app.GetDB().
|
||||
NewQuery("SELECT COUNT(*) AS total FROM certificate WHERE expireAt < DATETIME('now')").
|
||||
One(&certExpiredTotal); err != nil {
|
||||
return nil, err
|
||||
@@ -51,7 +53,9 @@ func (r *StatisticsRepository) Get(ctx context.Context) (*domain.Statistics, err
|
||||
workflowTotal := struct {
|
||||
Total int `db:"total"`
|
||||
}{}
|
||||
if err := app.GetApp().Dao().DB().NewQuery("SELECT COUNT(*) AS total FROM workflow").One(&workflowTotal); err != nil {
|
||||
if err := app.GetDB().
|
||||
NewQuery("SELECT COUNT(*) AS total FROM workflow").
|
||||
One(&workflowTotal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rs.WorkflowTotal = workflowTotal.Total
|
||||
@@ -60,7 +64,9 @@ func (r *StatisticsRepository) Get(ctx context.Context) (*domain.Statistics, err
|
||||
workflowEnabledTotal := struct {
|
||||
Total int `db:"total"`
|
||||
}{}
|
||||
if err := app.GetApp().Dao().DB().NewQuery("SELECT COUNT(*) AS total FROM workflow WHERE enabled IS TRUE").One(&workflowEnabledTotal); err != nil {
|
||||
if err := app.GetDB().
|
||||
NewQuery("SELECT COUNT(*) AS total FROM workflow WHERE enabled IS TRUE").
|
||||
One(&workflowEnabledTotal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rs.WorkflowEnabled = workflowEnabledTotal.Total
|
||||
|
@@ -7,8 +7,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/daos"
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/usual2970/certimate/internal/app"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
@@ -20,8 +19,8 @@ func NewWorkflowRepository() *WorkflowRepository {
|
||||
}
|
||||
|
||||
func (r *WorkflowRepository) ListEnabledAuto(ctx context.Context) ([]*domain.Workflow, error) {
|
||||
records, err := app.GetApp().Dao().FindRecordsByFilter(
|
||||
"workflow",
|
||||
records, err := app.GetApp().FindRecordsByFilter(
|
||||
domain.CollectionNameWorkflow,
|
||||
"enabled={:enabled} && trigger={:trigger}",
|
||||
"-created",
|
||||
0, 0,
|
||||
@@ -45,7 +44,7 @@ func (r *WorkflowRepository) ListEnabledAuto(ctx context.Context) ([]*domain.Wor
|
||||
}
|
||||
|
||||
func (r *WorkflowRepository) GetById(ctx context.Context, id string) (*domain.Workflow, error) {
|
||||
record, err := app.GetApp().Dao().FindRecordById("workflow", id)
|
||||
record, err := app.GetApp().FindRecordById(domain.CollectionNameWorkflow, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, domain.ErrRecordNotFound
|
||||
@@ -57,15 +56,16 @@ func (r *WorkflowRepository) GetById(ctx context.Context, id string) (*domain.Wo
|
||||
}
|
||||
|
||||
func (r *WorkflowRepository) Save(ctx context.Context, workflow *domain.Workflow) error {
|
||||
collection, err := app.GetApp().Dao().FindCollectionByNameOrId(workflow.Table())
|
||||
collection, err := app.GetApp().FindCollectionByNameOrId(domain.CollectionNameWorkflow)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var record *models.Record
|
||||
|
||||
var record *core.Record
|
||||
if workflow.Id == "" {
|
||||
record = models.NewRecord(collection)
|
||||
record = core.NewRecord(collection)
|
||||
} else {
|
||||
record, err = app.GetApp().Dao().FindRecordById(workflow.Table(), workflow.Id)
|
||||
record, err = app.GetApp().FindRecordById(domain.CollectionNameWorkflow, workflow.Id)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return domain.ErrRecordNotFound
|
||||
@@ -86,40 +86,44 @@ func (r *WorkflowRepository) Save(ctx context.Context, workflow *domain.Workflow
|
||||
record.Set("lastRunStatus", string(workflow.LastRunStatus))
|
||||
record.Set("lastRunTime", workflow.LastRunTime)
|
||||
|
||||
return app.GetApp().Dao().SaveRecord(record)
|
||||
return app.GetApp().Save(record)
|
||||
}
|
||||
|
||||
func (r *WorkflowRepository) SaveRun(ctx context.Context, workflowRun *domain.WorkflowRun) error {
|
||||
collection, err := app.GetApp().Dao().FindCollectionByNameOrId("workflow_run")
|
||||
collection, err := app.GetApp().FindCollectionByNameOrId(domain.CollectionNameWorkflowRun)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = app.GetApp().Dao().RunInTransaction(func(txDao *daos.Dao) error {
|
||||
record := models.NewRecord(collection)
|
||||
record.Set("workflowId", workflowRun.WorkflowId)
|
||||
record.Set("trigger", string(workflowRun.Trigger))
|
||||
record.Set("status", string(workflowRun.Status))
|
||||
record.Set("startedAt", workflowRun.StartedAt)
|
||||
record.Set("endedAt", workflowRun.EndedAt)
|
||||
record.Set("logs", workflowRun.Logs)
|
||||
record.Set("error", workflowRun.Error)
|
||||
err = txDao.SaveRecord(record)
|
||||
err = app.GetApp().RunInTransaction(func(txApp core.App) error {
|
||||
workflowRunRecord := core.NewRecord(collection)
|
||||
workflowRunRecord.Id = workflowRun.Id
|
||||
workflowRunRecord.Set("workflowId", workflowRun.WorkflowId)
|
||||
workflowRunRecord.Set("trigger", string(workflowRun.Trigger))
|
||||
workflowRunRecord.Set("status", string(workflowRun.Status))
|
||||
workflowRunRecord.Set("startedAt", workflowRun.StartedAt)
|
||||
workflowRunRecord.Set("endedAt", workflowRun.EndedAt)
|
||||
workflowRunRecord.Set("logs", workflowRun.Logs)
|
||||
workflowRunRecord.Set("error", workflowRun.Error)
|
||||
err = txApp.Save(workflowRunRecord)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// unable trigger sse using DB()
|
||||
workflowRecord, err := txDao.FindRecordById("workflow", workflowRun.WorkflowId)
|
||||
workflowRecord, err := txApp.FindRecordById(domain.CollectionNameWorkflow, workflowRun.WorkflowId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
workflowRecord.Set("lastRunId", record.GetId())
|
||||
workflowRecord.Set("lastRunStatus", record.GetString("status"))
|
||||
workflowRecord.Set("lastRunTime", record.GetString("startedAt"))
|
||||
workflowRecord.Set("lastRunId", workflowRunRecord.Id)
|
||||
workflowRecord.Set("lastRunStatus", workflowRunRecord.GetString("status"))
|
||||
workflowRecord.Set("lastRunTime", workflowRunRecord.GetString("startedAt"))
|
||||
err = txApp.Save(workflowRecord)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return txDao.SaveRecord(workflowRecord)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -128,7 +132,7 @@ func (r *WorkflowRepository) SaveRun(ctx context.Context, workflowRun *domain.Wo
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *WorkflowRepository) castRecordToModel(record *models.Record) (*domain.Workflow, error) {
|
||||
func (r *WorkflowRepository) castRecordToModel(record *core.Record) (*domain.Workflow, error) {
|
||||
if record == nil {
|
||||
return nil, fmt.Errorf("record is nil")
|
||||
}
|
||||
@@ -145,9 +149,9 @@ func (r *WorkflowRepository) castRecordToModel(record *models.Record) (*domain.W
|
||||
|
||||
workflow := &domain.Workflow{
|
||||
Meta: domain.Meta{
|
||||
Id: record.GetId(),
|
||||
CreatedAt: record.GetCreated().Time(),
|
||||
UpdatedAt: record.GetUpdated().Time(),
|
||||
Id: record.Id,
|
||||
CreatedAt: record.GetDateTime("created").Time(),
|
||||
UpdatedAt: record.GetDateTime("updated").Time(),
|
||||
},
|
||||
Name: record.GetString("name"),
|
||||
Description: record.GetString("description"),
|
||||
|
@@ -6,7 +6,7 @@ import (
|
||||
"errors"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/usual2970/certimate/internal/app"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
@@ -18,8 +18,8 @@ func NewWorkflowOutputRepository() *WorkflowOutputRepository {
|
||||
}
|
||||
|
||||
func (r *WorkflowOutputRepository) GetByNodeId(ctx context.Context, nodeId string) (*domain.WorkflowOutput, error) {
|
||||
records, err := app.GetApp().Dao().FindRecordsByFilter(
|
||||
"workflow_output",
|
||||
records, err := app.GetApp().FindRecordsByFilter(
|
||||
domain.CollectionNameWorkflowOutput,
|
||||
"nodeId={:nodeId}",
|
||||
"-created",
|
||||
1, 0,
|
||||
@@ -48,9 +48,9 @@ func (r *WorkflowOutputRepository) GetByNodeId(ctx context.Context, nodeId strin
|
||||
|
||||
rs := &domain.WorkflowOutput{
|
||||
Meta: domain.Meta{
|
||||
Id: record.GetId(),
|
||||
CreatedAt: record.GetCreated().Time(),
|
||||
UpdatedAt: record.GetUpdated().Time(),
|
||||
Id: record.Id,
|
||||
CreatedAt: record.GetDateTime("created").Time(),
|
||||
UpdatedAt: record.GetDateTime("updated").Time(),
|
||||
},
|
||||
WorkflowId: record.GetString("workflowId"),
|
||||
NodeId: record.GetString("nodeId"),
|
||||
@@ -64,17 +64,17 @@ func (r *WorkflowOutputRepository) GetByNodeId(ctx context.Context, nodeId strin
|
||||
|
||||
// 保存节点输出
|
||||
func (r *WorkflowOutputRepository) Save(ctx context.Context, output *domain.WorkflowOutput, certificate *domain.Certificate, cb func(id string) error) error {
|
||||
var record *models.Record
|
||||
var record *core.Record
|
||||
var err error
|
||||
|
||||
if output.Id == "" {
|
||||
collection, err := app.GetApp().Dao().FindCollectionByNameOrId("workflow_output")
|
||||
collection, err := app.GetApp().FindCollectionByNameOrId(domain.CollectionNameWorkflowOutput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
record = models.NewRecord(collection)
|
||||
record = core.NewRecord(collection)
|
||||
} else {
|
||||
record, err = app.GetApp().Dao().FindRecordById("workflow_output", output.Id)
|
||||
record, err = app.GetApp().FindRecordById(domain.CollectionNameWorkflowOutput, output.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -85,21 +85,21 @@ func (r *WorkflowOutputRepository) Save(ctx context.Context, output *domain.Work
|
||||
record.Set("outputs", output.Outputs)
|
||||
record.Set("succeeded", output.Succeeded)
|
||||
|
||||
if err := app.GetApp().Dao().SaveRecord(record); err != nil {
|
||||
if err := app.GetApp().Save(record); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cb != nil && certificate != nil {
|
||||
if err := cb(record.GetId()); err != nil {
|
||||
if err := cb(record.Id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certCollection, err := app.GetApp().Dao().FindCollectionByNameOrId("certificate")
|
||||
certCollection, err := app.GetApp().FindCollectionByNameOrId(domain.CollectionNameCertificate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certRecord := models.NewRecord(certCollection)
|
||||
certRecord := core.NewRecord(certCollection)
|
||||
certRecord.Set("source", string(certificate.Source))
|
||||
certRecord.Set("subjectAltNames", certificate.SubjectAltNames)
|
||||
certRecord.Set("certificate", certificate.Certificate)
|
||||
@@ -113,21 +113,21 @@ func (r *WorkflowOutputRepository) Save(ctx context.Context, output *domain.Work
|
||||
certRecord.Set("workflowNodeId", certificate.WorkflowNodeId)
|
||||
certRecord.Set("workflowOutputId", certificate.WorkflowOutputId)
|
||||
|
||||
if err := app.GetApp().Dao().SaveRecord(certRecord); err != nil {
|
||||
if err := app.GetApp().Save(certRecord); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新 certificate
|
||||
for i, item := range output.Outputs {
|
||||
if item.Name == domain.WORKFLOW_OUTPUT_CERTIFICATE {
|
||||
output.Outputs[i].Value = certRecord.GetId()
|
||||
if item.Name == string(domain.WorkflowNodeIONameCertificate) {
|
||||
output.Outputs[i].Value = certRecord.Id
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
record.Set("outputs", output.Outputs)
|
||||
|
||||
if err := app.GetApp().Dao().SaveRecord(record); err != nil {
|
||||
if err := app.GetApp().Save(record); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
42
internal/rest/handlers/certificate.go
Normal file
42
internal/rest/handlers/certificate.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tools/router"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain/dtos"
|
||||
"github.com/usual2970/certimate/internal/rest/resp"
|
||||
)
|
||||
|
||||
type certificateService interface {
|
||||
ArchiveFile(ctx context.Context, req *dtos.CertificateArchiveFileReq) ([]byte, error)
|
||||
}
|
||||
|
||||
type CertificateHandler struct {
|
||||
service certificateService
|
||||
}
|
||||
|
||||
func NewCertificateHandler(router *router.RouterGroup[*core.RequestEvent], service certificateService) {
|
||||
handler := &CertificateHandler{
|
||||
service: service,
|
||||
}
|
||||
|
||||
group := router.Group("/certificates")
|
||||
group.POST("/{id}/archive", handler.run)
|
||||
}
|
||||
|
||||
func (handler *CertificateHandler) run(e *core.RequestEvent) error {
|
||||
req := &dtos.CertificateArchiveFileReq{}
|
||||
req.CertificateId = e.Request.PathValue("id")
|
||||
if err := e.BindBody(req); err != nil {
|
||||
return resp.Err(e, err)
|
||||
}
|
||||
|
||||
if bt, err := handler.service.ArchiveFile(e.Request.Context(), req); err != nil {
|
||||
return resp.Err(e, err)
|
||||
} else {
|
||||
return resp.Ok(e, bt)
|
||||
}
|
||||
}
|
41
internal/rest/handlers/notify.go
Normal file
41
internal/rest/handlers/notify.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tools/router"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain/dtos"
|
||||
"github.com/usual2970/certimate/internal/rest/resp"
|
||||
)
|
||||
|
||||
type notifyService interface {
|
||||
Test(ctx context.Context, req *dtos.NotifyTestPushReq) error
|
||||
}
|
||||
|
||||
type NotifyHandler struct {
|
||||
service notifyService
|
||||
}
|
||||
|
||||
func NewNotifyHandler(router *router.RouterGroup[*core.RequestEvent], service notifyService) {
|
||||
handler := &NotifyHandler{
|
||||
service: service,
|
||||
}
|
||||
|
||||
group := router.Group("/notify")
|
||||
group.POST("/test", handler.test)
|
||||
}
|
||||
|
||||
func (handler *NotifyHandler) test(e *core.RequestEvent) error {
|
||||
req := &dtos.NotifyTestPushReq{}
|
||||
if err := e.BindBody(req); err != nil {
|
||||
return resp.Err(e, err)
|
||||
}
|
||||
|
||||
if err := handler.service.Test(e.Request.Context(), req); err != nil {
|
||||
return resp.Err(e, err)
|
||||
}
|
||||
|
||||
return resp.Ok(e, nil)
|
||||
}
|
36
internal/rest/handlers/statistics.go
Normal file
36
internal/rest/handlers/statistics.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tools/router"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/rest/resp"
|
||||
)
|
||||
|
||||
type statisticsService interface {
|
||||
Get(ctx context.Context) (*domain.Statistics, error)
|
||||
}
|
||||
|
||||
type StatisticsHandler struct {
|
||||
service statisticsService
|
||||
}
|
||||
|
||||
func NewStatisticsHandler(router *router.RouterGroup[*core.RequestEvent], service statisticsService) {
|
||||
handler := &StatisticsHandler{
|
||||
service: service,
|
||||
}
|
||||
|
||||
group := router.Group("/statistics")
|
||||
group.GET("/get", handler.get)
|
||||
}
|
||||
|
||||
func (handler *StatisticsHandler) get(e *core.RequestEvent) error {
|
||||
if statistics, err := handler.service.Get(e.Request.Context()); err != nil {
|
||||
return resp.Err(e, err)
|
||||
} else {
|
||||
return resp.Ok(e, statistics)
|
||||
}
|
||||
}
|
43
internal/rest/handlers/workflow.go
Normal file
43
internal/rest/handlers/workflow.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tools/router"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain/dtos"
|
||||
"github.com/usual2970/certimate/internal/rest/resp"
|
||||
)
|
||||
|
||||
type workflowService interface {
|
||||
Run(ctx context.Context, req *dtos.WorkflowRunReq) error
|
||||
Stop(ctx context.Context)
|
||||
}
|
||||
|
||||
type WorkflowHandler struct {
|
||||
service workflowService
|
||||
}
|
||||
|
||||
func NewWorkflowHandler(router *router.RouterGroup[*core.RequestEvent], service workflowService) {
|
||||
handler := &WorkflowHandler{
|
||||
service: service,
|
||||
}
|
||||
|
||||
group := router.Group("/workflows")
|
||||
group.POST("/{id}/run", handler.run)
|
||||
}
|
||||
|
||||
func (handler *WorkflowHandler) run(e *core.RequestEvent) error {
|
||||
req := &dtos.WorkflowRunReq{}
|
||||
req.WorkflowId = e.Request.PathValue("id")
|
||||
if err := e.BindBody(req); err != nil {
|
||||
return resp.Err(e, err)
|
||||
}
|
||||
|
||||
if err := handler.service.Run(e.Request.Context(), req); err != nil {
|
||||
return resp.Err(e, err)
|
||||
}
|
||||
|
||||
return resp.Ok(e, nil)
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/rest/resp"
|
||||
|
||||
"github.com/labstack/echo/v5"
|
||||
)
|
||||
|
||||
type NotifyService interface {
|
||||
Test(ctx context.Context, req *domain.NotifyTestPushReq) error
|
||||
}
|
||||
|
||||
type notifyHandler struct {
|
||||
service NotifyService
|
||||
}
|
||||
|
||||
func NewNotifyHandler(route *echo.Group, service NotifyService) {
|
||||
handler := ¬ifyHandler{
|
||||
service: service,
|
||||
}
|
||||
|
||||
group := route.Group("/notify")
|
||||
|
||||
group.POST("/test", handler.test)
|
||||
}
|
||||
|
||||
func (handler *notifyHandler) test(c echo.Context) error {
|
||||
req := &domain.NotifyTestPushReq{}
|
||||
if err := c.Bind(req); err != nil {
|
||||
return resp.Err(c, err)
|
||||
}
|
||||
|
||||
if err := handler.service.Test(c.Request().Context(), req); err != nil {
|
||||
return resp.Err(c, err)
|
||||
}
|
||||
|
||||
return resp.Ok(c, nil)
|
||||
}
|
@@ -3,7 +3,7 @@ package resp
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v5"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
@@ -14,7 +14,7 @@ type Response struct {
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func Ok(e echo.Context, data interface{}) error {
|
||||
func Ok(e *core.RequestEvent, data interface{}) error {
|
||||
rs := &Response{
|
||||
Code: 0,
|
||||
Msg: "success",
|
||||
@@ -23,7 +23,7 @@ func Ok(e echo.Context, data interface{}) error {
|
||||
return e.JSON(http.StatusOK, rs)
|
||||
}
|
||||
|
||||
func Err(e echo.Context, err error) error {
|
||||
func Err(e *core.RequestEvent, err error) error {
|
||||
code := 500
|
||||
|
||||
xerr, ok := err.(*domain.Error)
|
||||
|
50
internal/rest/routes/routes.go
Normal file
50
internal/rest/routes/routes.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pocketbase/pocketbase/apis"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tools/router"
|
||||
|
||||
"github.com/usual2970/certimate/internal/certificate"
|
||||
"github.com/usual2970/certimate/internal/notify"
|
||||
"github.com/usual2970/certimate/internal/repository"
|
||||
"github.com/usual2970/certimate/internal/rest/handlers"
|
||||
"github.com/usual2970/certimate/internal/statistics"
|
||||
"github.com/usual2970/certimate/internal/workflow"
|
||||
)
|
||||
|
||||
var (
|
||||
certificateSvc *certificate.CertificateService
|
||||
workflowSvc *workflow.WorkflowService
|
||||
statisticsSvc *statistics.StatisticsService
|
||||
notifySvc *notify.NotifyService
|
||||
)
|
||||
|
||||
func Register(router *router.Router[*core.RequestEvent]) {
|
||||
certificateRepo := repository.NewCertificateRepository()
|
||||
certificateSvc = certificate.NewCertificateService(certificateRepo)
|
||||
|
||||
workflowRepo := repository.NewWorkflowRepository()
|
||||
workflowSvc = workflow.NewWorkflowService(workflowRepo)
|
||||
|
||||
statisticsRepo := repository.NewStatisticsRepository()
|
||||
statisticsSvc = statistics.NewStatisticsService(statisticsRepo)
|
||||
|
||||
notifyRepo := repository.NewSettingsRepository()
|
||||
notifySvc = notify.NewNotifyService(notifyRepo)
|
||||
|
||||
group := router.Group("/api")
|
||||
group.Bind(apis.RequireSuperuserAuth())
|
||||
handlers.NewCertificateHandler(group, certificateSvc)
|
||||
handlers.NewWorkflowHandler(group, workflowSvc)
|
||||
handlers.NewStatisticsHandler(group, statisticsSvc)
|
||||
handlers.NewNotifyHandler(group, notifySvc)
|
||||
}
|
||||
|
||||
func Unregister() {
|
||||
if workflowSvc != nil {
|
||||
workflowSvc.Stop(context.Background())
|
||||
}
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/labstack/echo/v5"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/rest/resp"
|
||||
)
|
||||
|
||||
type StatisticsService interface {
|
||||
Get(ctx context.Context) (*domain.Statistics, error)
|
||||
}
|
||||
|
||||
type statisticsHandler struct {
|
||||
service StatisticsService
|
||||
}
|
||||
|
||||
func NewStatisticsHandler(route *echo.Group, service StatisticsService) {
|
||||
handler := &statisticsHandler{
|
||||
service: service,
|
||||
}
|
||||
|
||||
group := route.Group("/statistics")
|
||||
|
||||
group.GET("/get", handler.get)
|
||||
}
|
||||
|
||||
func (handler *statisticsHandler) get(c echo.Context) error {
|
||||
if statistics, err := handler.service.Get(c.Request().Context()); err != nil {
|
||||
return resp.Err(c, err)
|
||||
} else {
|
||||
return resp.Ok(c, statistics)
|
||||
}
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/labstack/echo/v5"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/rest/resp"
|
||||
)
|
||||
|
||||
type WorkflowService interface {
|
||||
Run(ctx context.Context, req *domain.WorkflowRunReq) error
|
||||
Stop()
|
||||
}
|
||||
|
||||
type workflowHandler struct {
|
||||
service WorkflowService
|
||||
}
|
||||
|
||||
func NewWorkflowHandler(route *echo.Group, service WorkflowService) {
|
||||
handler := &workflowHandler{
|
||||
service: service,
|
||||
}
|
||||
|
||||
group := route.Group("/workflow")
|
||||
|
||||
group.POST("/run", handler.run)
|
||||
}
|
||||
|
||||
func (handler *workflowHandler) run(c echo.Context) error {
|
||||
req := &domain.WorkflowRunReq{}
|
||||
if err := c.Bind(req); err != nil {
|
||||
return resp.Err(c, err)
|
||||
}
|
||||
|
||||
if err := handler.service.Run(c.Request().Context(), req); err != nil {
|
||||
return resp.Err(c, err)
|
||||
}
|
||||
return resp.Ok(c, nil)
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/usual2970/certimate/internal/notify"
|
||||
"github.com/usual2970/certimate/internal/repository"
|
||||
"github.com/usual2970/certimate/internal/rest"
|
||||
"github.com/usual2970/certimate/internal/statistics"
|
||||
"github.com/usual2970/certimate/internal/workflow"
|
||||
|
||||
"github.com/labstack/echo/v5"
|
||||
"github.com/pocketbase/pocketbase/apis"
|
||||
)
|
||||
|
||||
var (
|
||||
workflowSvc rest.WorkflowService
|
||||
workflowSvcOnce sync.Once
|
||||
)
|
||||
|
||||
func getWorkflowService() rest.WorkflowService {
|
||||
workflowSvcOnce.Do(func() {
|
||||
workflowRepo := repository.NewWorkflowRepository()
|
||||
workflowSvc = workflow.NewWorkflowService(workflowRepo)
|
||||
})
|
||||
return workflowSvc
|
||||
}
|
||||
|
||||
func Register(e *echo.Echo) {
|
||||
group := e.Group("/api", apis.RequireAdminAuth())
|
||||
|
||||
notifyRepo := repository.NewSettingsRepository()
|
||||
notifySvc := notify.NewNotifyService(notifyRepo)
|
||||
|
||||
workflowSvc := getWorkflowService()
|
||||
|
||||
statisticsRepo := repository.NewStatisticsRepository()
|
||||
statisticsSvc := statistics.NewStatisticsService(statisticsRepo)
|
||||
|
||||
rest.NewWorkflowHandler(group, workflowSvc)
|
||||
|
||||
rest.NewNotifyHandler(group, notifySvc)
|
||||
|
||||
rest.NewStatisticsHandler(group, statisticsSvc)
|
||||
}
|
||||
|
||||
func Unregister() {
|
||||
getWorkflowService().Stop()
|
||||
}
|
@@ -2,10 +2,10 @@ package scheduler
|
||||
|
||||
import "context"
|
||||
|
||||
type CertificateService interface {
|
||||
type certificateService interface {
|
||||
InitSchedule(ctx context.Context) error
|
||||
}
|
||||
|
||||
func NewCertificateScheduler(service CertificateService) error {
|
||||
func NewCertificateScheduler(service certificateService) error {
|
||||
return service.InitSchedule(context.Background())
|
||||
}
|
||||
|
@@ -2,10 +2,10 @@ package scheduler
|
||||
|
||||
import "context"
|
||||
|
||||
type WorkflowService interface {
|
||||
type workflowService interface {
|
||||
InitSchedule(ctx context.Context) error
|
||||
}
|
||||
|
||||
func NewWorkflowScheduler(service WorkflowService) error {
|
||||
func NewWorkflowScheduler(service workflowService) error {
|
||||
return service.InitSchedule(context.Background())
|
||||
}
|
||||
|
@@ -5,49 +5,67 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
|
||||
"github.com/usual2970/certimate/internal/app"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/domain/dtos"
|
||||
"github.com/usual2970/certimate/internal/repository"
|
||||
)
|
||||
|
||||
const tableName = "workflow"
|
||||
|
||||
func Register() {
|
||||
app := app.GetApp()
|
||||
app.OnRecordCreateRequest(domain.CollectionNameWorkflow).BindFunc(func(e *core.RecordRequestEvent) error {
|
||||
if err := e.Next(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
app.OnRecordAfterCreateRequest(tableName).Add(func(e *core.RecordCreateEvent) error {
|
||||
return update(e.HttpContext.Request().Context(), e.Record)
|
||||
if err := onWorkflowRecordCreateOrUpdate(e.Request.Context(), e.Record); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
app.OnRecordUpdateRequest(domain.CollectionNameWorkflow).BindFunc(func(e *core.RecordRequestEvent) error {
|
||||
if err := e.Next(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
app.OnRecordAfterUpdateRequest(tableName).Add(func(e *core.RecordUpdateEvent) error {
|
||||
return update(e.HttpContext.Request().Context(), e.Record)
|
||||
if err := onWorkflowRecordCreateOrUpdate(e.Request.Context(), e.Record); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
app.OnRecordDeleteRequest(domain.CollectionNameWorkflow).BindFunc(func(e *core.RecordRequestEvent) error {
|
||||
if err := e.Next(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
app.OnRecordAfterDeleteRequest(tableName).Add(func(e *core.RecordDeleteEvent) error {
|
||||
return delete(e.HttpContext.Request().Context(), e.Record)
|
||||
if err := onWorkflowRecordDelete(e.Request.Context(), e.Record); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func update(ctx context.Context, record *models.Record) error {
|
||||
func onWorkflowRecordCreateOrUpdate(ctx context.Context, record *core.Record) error {
|
||||
scheduler := app.GetScheduler()
|
||||
|
||||
// 向数据库插入/更新时,同时更新定时任务
|
||||
workflowId := record.GetId()
|
||||
workflowId := record.Id
|
||||
enabled := record.GetBool("enabled")
|
||||
trigger := record.GetString("trigger")
|
||||
|
||||
// 如果是手动触发或未启用,移除定时任务
|
||||
if !enabled || trigger == string(domain.WorkflowTriggerTypeManual) {
|
||||
scheduler.Remove(fmt.Sprintf("workflow#%s", workflowId))
|
||||
scheduler.Start()
|
||||
return nil
|
||||
}
|
||||
|
||||
// 反之,重新添加定时任务
|
||||
err := scheduler.Add(fmt.Sprintf("workflow#%s", workflowId), record.GetString("triggerCron"), func() {
|
||||
NewWorkflowService(repository.NewWorkflowRepository()).Run(ctx, &domain.WorkflowRunReq{
|
||||
NewWorkflowService(repository.NewWorkflowRepository()).Run(ctx, &dtos.WorkflowRunReq{
|
||||
WorkflowId: workflowId,
|
||||
Trigger: domain.WorkflowTriggerTypeAuto,
|
||||
})
|
||||
@@ -57,18 +75,15 @@ func update(ctx context.Context, record *models.Record) error {
|
||||
return fmt.Errorf("add cron job failed: %w", err)
|
||||
}
|
||||
|
||||
scheduler.Start()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func delete(_ context.Context, record *models.Record) error {
|
||||
func onWorkflowRecordDelete(_ context.Context, record *core.Record) error {
|
||||
scheduler := app.GetScheduler()
|
||||
|
||||
// 从数据库删除时,同时移除定时任务
|
||||
workflowId := record.GetId()
|
||||
workflowId := record.Id
|
||||
scheduler.Remove(fmt.Sprintf("workflow#%s", workflowId))
|
||||
scheduler.Start()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -77,14 +77,14 @@ func (a *applyNode) Run(ctx context.Context) error {
|
||||
ACMECertStableUrl: applyResult.ACMECertStableUrl,
|
||||
EffectAt: certX509.NotBefore,
|
||||
ExpireAt: certX509.NotAfter,
|
||||
WorkflowId: GetWorkflowId(ctx),
|
||||
WorkflowId: getContextWorkflowId(ctx),
|
||||
WorkflowNodeId: a.node.Id,
|
||||
}
|
||||
|
||||
// 保存执行结果
|
||||
// TODO: 先保持一个节点始终只有一个输出,后续增加版本控制
|
||||
currentOutput := &domain.WorkflowOutput{
|
||||
WorkflowId: GetWorkflowId(ctx),
|
||||
WorkflowId: getContextWorkflowId(ctx),
|
||||
NodeId: a.node.Id,
|
||||
Node: a.node,
|
||||
Succeeded: true,
|
||||
@@ -109,32 +109,32 @@ func (a *applyNode) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (a *applyNode) checkCanSkip(ctx context.Context, lastOutput *domain.WorkflowOutput) (skip bool, reason string) {
|
||||
const validityDuration = time.Hour * 24 * 10
|
||||
|
||||
// TODO: 可控制是否强制申请
|
||||
if lastOutput != nil && lastOutput.Succeeded {
|
||||
// 比较和上次申请时的关键配置(即影响证书签发的)参数是否一致
|
||||
if lastOutput.Node.GetConfigString("domains") != a.node.GetConfigString("domains") {
|
||||
currentNodeConfig := a.node.GetConfigForApply()
|
||||
lastNodeConfig := lastOutput.Node.GetConfigForApply()
|
||||
if currentNodeConfig.Domains != lastNodeConfig.Domains {
|
||||
return false, "配置项变化:域名"
|
||||
}
|
||||
if lastOutput.Node.GetConfigString("contactEmail") != a.node.GetConfigString("contactEmail") {
|
||||
if currentNodeConfig.ContactEmail != lastNodeConfig.ContactEmail {
|
||||
return false, "配置项变化:联系邮箱"
|
||||
}
|
||||
if lastOutput.Node.GetConfigString("provider") != a.node.GetConfigString("provider") {
|
||||
if currentNodeConfig.ProviderAccessId != lastNodeConfig.ProviderAccessId {
|
||||
return false, "配置项变化:DNS 提供商授权"
|
||||
}
|
||||
if !maps.Equal(lastOutput.Node.GetConfigMap("providerConfig"), a.node.GetConfigMap("providerConfig")) {
|
||||
if !maps.Equal(currentNodeConfig.ProviderConfig, lastNodeConfig.ProviderConfig) {
|
||||
return false, "配置项变化:DNS 提供商参数"
|
||||
}
|
||||
if lastOutput.Node.GetConfigString("keyAlgorithm") != a.node.GetConfigString("keyAlgorithm") {
|
||||
if currentNodeConfig.KeyAlgorithm != lastNodeConfig.KeyAlgorithm {
|
||||
return false, "配置项变化:数字签名算法"
|
||||
}
|
||||
|
||||
lastCertificate, _ := a.certRepo.GetByWorkflowNodeId(ctx, a.node.Id)
|
||||
if lastCertificate != nil && time.Until(lastCertificate.ExpireAt) > validityDuration {
|
||||
renewalInterval := time.Duration(currentNodeConfig.SkipBeforeExpiryDays) * time.Hour * 24
|
||||
if lastCertificate != nil && time.Until(lastCertificate.ExpireAt) > renewalInterval {
|
||||
return true, "已申请过证书,且证书尚未临近过期"
|
||||
}
|
||||
}
|
||||
|
||||
return false, "无历史申请记录"
|
||||
return false, ""
|
||||
}
|
||||
|
@@ -38,13 +38,13 @@ func (d *deployNode) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
// 获取前序节点输出证书
|
||||
certSource := d.node.GetConfigString("certificate")
|
||||
certSourceSlice := strings.Split(certSource, "#")
|
||||
if len(certSourceSlice) != 2 {
|
||||
d.AddOutput(ctx, d.node.Name, "证书来源配置错误", certSource)
|
||||
return fmt.Errorf("证书来源配置错误: %s", certSource)
|
||||
previousNodeOutputCertificateSource := d.node.GetConfigForDeploy().Certificate
|
||||
previousNodeOutputCertificateSourceSlice := strings.Split(previousNodeOutputCertificateSource, "#")
|
||||
if len(previousNodeOutputCertificateSourceSlice) != 2 {
|
||||
d.AddOutput(ctx, d.node.Name, "证书来源配置错误", previousNodeOutputCertificateSource)
|
||||
return fmt.Errorf("证书来源配置错误: %s", previousNodeOutputCertificateSource)
|
||||
}
|
||||
certificate, err := d.certRepo.GetByWorkflowNodeId(ctx, certSourceSlice[0])
|
||||
certificate, err := d.certRepo.GetByWorkflowNodeId(ctx, previousNodeOutputCertificateSourceSlice[0])
|
||||
if err != nil {
|
||||
d.AddOutput(ctx, d.node.Name, "获取证书失败", err.Error())
|
||||
return err
|
||||
@@ -81,7 +81,7 @@ func (d *deployNode) Run(ctx context.Context) error {
|
||||
// TODO: 先保持一个节点始终只有一个输出,后续增加版本控制
|
||||
currentOutput := &domain.WorkflowOutput{
|
||||
Meta: domain.Meta{},
|
||||
WorkflowId: GetWorkflowId(ctx),
|
||||
WorkflowId: getContextWorkflowId(ctx),
|
||||
NodeId: d.node.Id,
|
||||
Node: d.node,
|
||||
Succeeded: true,
|
||||
@@ -99,18 +99,21 @@ func (d *deployNode) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (d *deployNode) checkCanSkip(ctx context.Context, lastOutput *domain.WorkflowOutput) (skip bool, reason string) {
|
||||
// TODO: 可控制是否强制部署
|
||||
if lastOutput != nil && lastOutput.Succeeded {
|
||||
// 比较和上次部署时的关键配置(即影响证书部署的)参数是否一致
|
||||
if lastOutput.Node.GetConfigString("provider") != d.node.GetConfigString("provider") {
|
||||
currentNodeConfig := d.node.GetConfigForDeploy()
|
||||
lastNodeConfig := lastOutput.Node.GetConfigForDeploy()
|
||||
if currentNodeConfig.ProviderAccessId != lastNodeConfig.ProviderAccessId {
|
||||
return false, "配置项变化:主机提供商授权"
|
||||
}
|
||||
if !maps.Equal(lastOutput.Node.GetConfigMap("providerConfig"), d.node.GetConfigMap("providerConfig")) {
|
||||
if !maps.Equal(currentNodeConfig.ProviderConfig, lastNodeConfig.ProviderConfig) {
|
||||
return false, "配置项变化:主机提供商参数"
|
||||
}
|
||||
|
||||
return true, "已部署过证书"
|
||||
if currentNodeConfig.SkipOnLastSucceeded {
|
||||
return true, "已部署过证书"
|
||||
}
|
||||
}
|
||||
|
||||
return false, "无历史部署记录"
|
||||
return false, ""
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
type notifyNode struct {
|
||||
node *domain.WorkflowNode
|
||||
settingsRepo settingRepository
|
||||
settingsRepo settingsRepository
|
||||
*nodeLogger
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ func NewNotifyNode(node *domain.WorkflowNode) *notifyNode {
|
||||
func (n *notifyNode) Run(ctx context.Context) error {
|
||||
n.AddOutput(ctx, n.node.Name, "开始执行")
|
||||
|
||||
nodeConfig := n.node.GetConfigForNotify()
|
||||
|
||||
// 获取通知配置
|
||||
settings, err := n.settingsRepo.GetByName(ctx, "notifyChannels")
|
||||
if err != nil {
|
||||
@@ -33,18 +35,14 @@ func (n *notifyNode) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
// 获取通知渠道
|
||||
channelConfig, err := settings.GetNotifyChannelConfig(n.node.GetConfigString("channel"))
|
||||
channelConfig, err := settings.GetNotifyChannelConfig(nodeConfig.Channel)
|
||||
if err != nil {
|
||||
n.AddOutput(ctx, n.node.Name, "获取通知渠道配置失败", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
// 发送通知
|
||||
if err := notify.SendToChannel(n.node.GetConfigString("subject"),
|
||||
n.node.GetConfigString("message"),
|
||||
n.node.GetConfigString("channel"),
|
||||
channelConfig,
|
||||
); err != nil {
|
||||
if err := notify.SendToChannel(nodeConfig.Subject, nodeConfig.Message, nodeConfig.Channel, channelConfig); err != nil {
|
||||
n.AddOutput(ctx, n.node.Name, "发送通知失败", err.Error())
|
||||
return err
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type nodeProcessor interface {
|
||||
type NodeProcessor interface {
|
||||
Run(ctx context.Context) error
|
||||
Log(ctx context.Context) *domain.WorkflowRunLog
|
||||
AddOutput(ctx context.Context, title, content string, err ...string)
|
||||
@@ -18,6 +18,19 @@ type nodeLogger struct {
|
||||
log *domain.WorkflowRunLog
|
||||
}
|
||||
|
||||
type certificateRepository interface {
|
||||
GetByWorkflowNodeId(ctx context.Context, workflowNodeId string) (*domain.Certificate, error)
|
||||
}
|
||||
|
||||
type workflowOutputRepository interface {
|
||||
GetByNodeId(ctx context.Context, nodeId string) (*domain.WorkflowOutput, error)
|
||||
Save(ctx context.Context, output *domain.WorkflowOutput, certificate *domain.Certificate, cb func(id string) error) error
|
||||
}
|
||||
|
||||
type settingsRepository interface {
|
||||
GetByName(ctx context.Context, name string) (*domain.Settings, error)
|
||||
}
|
||||
|
||||
func NewNodeLogger(node *domain.WorkflowNode) *nodeLogger {
|
||||
return &nodeLogger{
|
||||
log: &domain.WorkflowRunLog{
|
||||
@@ -45,7 +58,7 @@ func (l *nodeLogger) AddOutput(ctx context.Context, title, content string, err .
|
||||
l.log.Outputs = append(l.log.Outputs, output)
|
||||
}
|
||||
|
||||
func GetProcessor(node *domain.WorkflowNode) (nodeProcessor, error) {
|
||||
func GetProcessor(node *domain.WorkflowNode) (NodeProcessor, error) {
|
||||
switch node.Type {
|
||||
case domain.WorkflowNodeTypeStart:
|
||||
return NewStartNode(node), nil
|
||||
@@ -65,15 +78,6 @@ func GetProcessor(node *domain.WorkflowNode) (nodeProcessor, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
type certificateRepository interface {
|
||||
GetByWorkflowNodeId(ctx context.Context, workflowNodeId string) (*domain.Certificate, error)
|
||||
}
|
||||
|
||||
type workflowOutputRepository interface {
|
||||
GetByNodeId(ctx context.Context, nodeId string) (*domain.WorkflowOutput, error)
|
||||
Save(ctx context.Context, output *domain.WorkflowOutput, certificate *domain.Certificate, cb func(id string) error) error
|
||||
}
|
||||
|
||||
type settingRepository interface {
|
||||
GetByName(ctx context.Context, name string) (*domain.Settings, error)
|
||||
func getContextWorkflowId(ctx context.Context) string {
|
||||
return ctx.Value("workflow_id").(string)
|
||||
}
|
||||
|
@@ -1,9 +1,10 @@
|
||||
package nodeprocessor
|
||||
package processor
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
nodes "github.com/usual2970/certimate/internal/workflow/node-processor"
|
||||
)
|
||||
|
||||
type workflowProcessor struct {
|
||||
@@ -23,26 +24,26 @@ func (w *workflowProcessor) Log(ctx context.Context) []domain.WorkflowRunLog {
|
||||
}
|
||||
|
||||
func (w *workflowProcessor) Run(ctx context.Context) error {
|
||||
ctx = WithWorkflowId(ctx, w.workflow.Id)
|
||||
return w.runNode(ctx, w.workflow.Content)
|
||||
ctx = setContextWorkflowId(ctx, w.workflow.Id)
|
||||
return w.processNode(ctx, w.workflow.Content)
|
||||
}
|
||||
|
||||
func (w *workflowProcessor) runNode(ctx context.Context, node *domain.WorkflowNode) error {
|
||||
func (w *workflowProcessor) processNode(ctx context.Context, node *domain.WorkflowNode) error {
|
||||
current := node
|
||||
for current != nil {
|
||||
if current.Type == domain.WorkflowNodeTypeBranch || current.Type == domain.WorkflowNodeTypeExecuteResultBranch {
|
||||
for _, branch := range current.Branches {
|
||||
if err := w.runNode(ctx, &branch); err != nil {
|
||||
if err := w.processNode(ctx, &branch); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var runErr error
|
||||
var processor nodeProcessor
|
||||
var processor nodes.NodeProcessor
|
||||
for {
|
||||
if current.Type != domain.WorkflowNodeTypeBranch && current.Type != domain.WorkflowNodeTypeExecuteResultBranch {
|
||||
processor, runErr = GetProcessor(current)
|
||||
processor, runErr = nodes.GetProcessor(current)
|
||||
if runErr != nil {
|
||||
break
|
||||
}
|
||||
@@ -74,7 +75,7 @@ func (w *workflowProcessor) runNode(ctx context.Context, node *domain.WorkflowNo
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithWorkflowId(ctx context.Context, id string) context.Context {
|
||||
func setContextWorkflowId(ctx context.Context, id string) context.Context {
|
||||
return context.WithValue(ctx, "workflow_id", id)
|
||||
}
|
||||
|
@@ -9,21 +9,22 @@ import (
|
||||
|
||||
"github.com/usual2970/certimate/internal/app"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
nodeprocessor "github.com/usual2970/certimate/internal/workflow/node-processor"
|
||||
"github.com/usual2970/certimate/internal/domain/dtos"
|
||||
processor "github.com/usual2970/certimate/internal/workflow/processor"
|
||||
)
|
||||
|
||||
const defaultRoutines = 10
|
||||
|
||||
type workflowRunData struct {
|
||||
Workflow *domain.Workflow
|
||||
Options *domain.WorkflowRunReq
|
||||
Workflow *domain.Workflow
|
||||
RunTrigger domain.WorkflowTriggerType
|
||||
}
|
||||
|
||||
type workflowRepository interface {
|
||||
ListEnabledAuto(ctx context.Context) ([]*domain.Workflow, error)
|
||||
GetById(ctx context.Context, id string) (*domain.Workflow, error)
|
||||
Save(ctx context.Context, workflow *domain.Workflow) error
|
||||
SaveRun(ctx context.Context, run *domain.WorkflowRun) error
|
||||
SaveRun(ctx context.Context, workflowRun *domain.WorkflowRun) error
|
||||
}
|
||||
|
||||
type WorkflowService struct {
|
||||
@@ -74,7 +75,7 @@ func (s *WorkflowService) InitSchedule(ctx context.Context) error {
|
||||
scheduler := app.GetScheduler()
|
||||
for _, workflow := range workflows {
|
||||
err := scheduler.Add(fmt.Sprintf("workflow#%s", workflow.Id), workflow.TriggerCron, func() {
|
||||
s.Run(ctx, &domain.WorkflowRunReq{
|
||||
s.Run(ctx, &dtos.WorkflowRunReq{
|
||||
WorkflowId: workflow.Id,
|
||||
Trigger: domain.WorkflowTriggerTypeAuto,
|
||||
})
|
||||
@@ -84,18 +85,15 @@ func (s *WorkflowService) InitSchedule(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
scheduler.Start()
|
||||
|
||||
app.GetLogger().Info("workflow schedule started")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *WorkflowService) Run(ctx context.Context, options *domain.WorkflowRunReq) error {
|
||||
func (s *WorkflowService) Run(ctx context.Context, req *dtos.WorkflowRunReq) error {
|
||||
// 查询
|
||||
workflow, err := s.repo.GetById(ctx, options.WorkflowId)
|
||||
workflow, err := s.repo.GetById(ctx, req.WorkflowId)
|
||||
if err != nil {
|
||||
app.GetLogger().Error("failed to get workflow", "id", options.WorkflowId, "err", err)
|
||||
app.GetLogger().Error("failed to get workflow", "id", req.WorkflowId, "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -113,8 +111,8 @@ func (s *WorkflowService) Run(ctx context.Context, options *domain.WorkflowRunRe
|
||||
}
|
||||
|
||||
s.ch <- &workflowRunData{
|
||||
Workflow: workflow,
|
||||
Options: options,
|
||||
Workflow: workflow,
|
||||
RunTrigger: req.Trigger,
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -123,16 +121,15 @@ func (s *WorkflowService) Run(ctx context.Context, options *domain.WorkflowRunRe
|
||||
func (s *WorkflowService) run(ctx context.Context, runData *workflowRunData) error {
|
||||
// 执行
|
||||
workflow := runData.Workflow
|
||||
options := runData.Options
|
||||
|
||||
run := &domain.WorkflowRun{
|
||||
WorkflowId: workflow.Id,
|
||||
Status: domain.WorkflowRunStatusTypeRunning,
|
||||
Trigger: options.Trigger,
|
||||
Trigger: runData.RunTrigger,
|
||||
StartedAt: time.Now(),
|
||||
EndedAt: time.Now(),
|
||||
}
|
||||
processor := nodeprocessor.NewWorkflowProcessor(workflow)
|
||||
|
||||
processor := processor.NewWorkflowProcessor(workflow)
|
||||
if err := processor.Run(ctx); err != nil {
|
||||
run.Status = domain.WorkflowRunStatusTypeFailed
|
||||
run.EndedAt = time.Now()
|
||||
@@ -165,7 +162,7 @@ func (s *WorkflowService) run(ctx context.Context, runData *workflowRunData) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *WorkflowService) Stop() {
|
||||
func (s *WorkflowService) Stop(ctx context.Context) {
|
||||
s.cancel()
|
||||
s.wg.Wait()
|
||||
}
|
||||
|
Reference in New Issue
Block a user