package nodeprocessor import ( "context" "strings" "time" "github.com/usual2970/certimate/internal/applicant" "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/pkg/utils/x509" "github.com/usual2970/certimate/internal/repository" ) type applyNode struct { node *domain.WorkflowNode outputRepo WorkflowOutputRepository *Logger } var validityDuration = time.Hour * 24 * 10 func NewApplyNode(node *domain.WorkflowNode) *applyNode { return &applyNode{ node: node, Logger: NewLogger(node), outputRepo: repository.NewWorkflowOutputRepository(), } } type WorkflowOutputRepository interface { // 查询节点输出 Get(ctx context.Context, nodeId string) (*domain.WorkflowOutput, error) // 查询申请节点的证书 GetCertificate(ctx context.Context, nodeId string) (*domain.Certificate, error) // 保存节点输出 Save(ctx context.Context, output *domain.WorkflowOutput, certificate *domain.Certificate, cb func(id string) error) error } // 申请节点根据申请类型执行不同的操作 func (a *applyNode) Run(ctx context.Context) error { a.AddOutput(ctx, a.node.Name, "开始执行") // 查询是否申请过,已申请过则直接返回(先保持和 v0.2 一致) output, err := a.outputRepo.Get(ctx, a.node.Id) if err != nil && !domain.IsRecordNotFound(err) { a.AddOutput(ctx, a.node.Name, "查询申请记录失败", err.Error()) return err } if output != nil && output.Succeeded { cert, err := a.outputRepo.GetCertificate(ctx, a.node.Id) if err != nil { a.AddOutput(ctx, a.node.Name, "获取证书失败", err.Error()) return err } if time.Until(cert.ExpireAt) > validityDuration { a.AddOutput(ctx, a.node.Name, "已申请过证书,且证书在有效期内") return nil } } // 获取Applicant apply, err := applicant.GetWithApplyNode(a.node) if err != nil { a.AddOutput(ctx, a.node.Name, "获取申请对象失败", err.Error()) return err } // 申请 certificate, err := apply.Apply() if err != nil { a.AddOutput(ctx, a.node.Name, "申请失败", err.Error()) return err } a.AddOutput(ctx, a.node.Name, "申请成功") // 记录申请结果 // 保持一个节点只有一个输出 outputId := "" if output != nil { outputId = output.Id } output = &domain.WorkflowOutput{ Meta: domain.Meta{Id: outputId}, WorkflowId: GetWorkflowId(ctx), NodeId: a.node.Id, Node: a.node, Succeeded: true, Outputs: a.node.Outputs, } certX509, err := x509.ParseCertificateFromPEM(certificate.Certificate) if err != nil { a.AddOutput(ctx, a.node.Name, "解析证书失败", err.Error()) return err } certificateRecord := &domain.Certificate{ Source: string(domain.CERTIFICATE_SOURCE_WORKFLOW), SubjectAltNames: strings.Join(certX509.DNSNames, ";"), Certificate: certificate.Certificate, PrivateKey: certificate.PrivateKey, IssuerCertificate: certificate.IssuerCertificate, AcmeCertUrl: certificate.CertUrl, AcmeCertStableUrl: certificate.CertStableUrl, EffectAt: certX509.NotBefore, ExpireAt: certX509.NotAfter, WorkflowId: GetWorkflowId(ctx), WorkflowNodeId: a.node.Id, } if err := a.outputRepo.Save(ctx, output, certificateRecord, func(id string) error { if certificateRecord != nil { certificateRecord.WorkflowOutputId = id } return nil }); err != nil { a.AddOutput(ctx, a.node.Name, "保存申请记录失败", err.Error()) return err } a.AddOutput(ctx, a.node.Name, "保存申请记录成功") return nil }