refactor: clean code

This commit is contained in:
Fu Diwei 2025-01-21 00:42:28 +08:00
parent 6bdcfaaef0
commit d5568608f5
13 changed files with 85 additions and 91 deletions

View File

@ -82,9 +82,9 @@ type acmeAccountRepository interface {
var registerGroup singleflight.Group var registerGroup singleflight.Group
func registerAcmeUser(client *lego.Client, sslProviderConfig *acmeSSLProviderConfig, user *acmeUser) (*registration.Resource, error) { func registerAcmeUserWithSingleFlight(client *lego.Client, sslProviderConfig *acmeSSLProviderConfig, user *acmeUser) (*registration.Resource, error) {
resp, err, _ := registerGroup.Do(fmt.Sprintf("register_acme_user_%s_%s", sslProviderConfig.Provider, user.GetEmail()), func() (interface{}, error) { resp, err, _ := registerGroup.Do(fmt.Sprintf("register_acme_user_%s_%s", sslProviderConfig.Provider, user.GetEmail()), func() (interface{}, error) {
return register(client, sslProviderConfig, user) return registerAcmeUser(client, sslProviderConfig, user)
}) })
if err != nil { if err != nil {
@ -94,7 +94,7 @@ func registerAcmeUser(client *lego.Client, sslProviderConfig *acmeSSLProviderCon
return resp.(*registration.Resource), nil return resp.(*registration.Resource), nil
} }
func register(client *lego.Client, sslProviderConfig *acmeSSLProviderConfig, user *acmeUser) (*registration.Resource, error) { func registerAcmeUser(client *lego.Client, sslProviderConfig *acmeSSLProviderConfig, user *acmeUser) (*registration.Resource, error) {
var reg *registration.Resource var reg *registration.Resource
var err error var err error
switch sslProviderConfig.Provider { switch sslProviderConfig.Provider {
@ -123,7 +123,6 @@ func register(client *lego.Client, sslProviderConfig *acmeSSLProviderConfig, use
} }
repo := repository.NewAcmeAccountRepository() repo := repository.NewAcmeAccountRepository()
resp, err := repo.GetByCAAndEmail(sslProviderConfig.Provider, user.GetEmail()) resp, err := repo.GetByCAAndEmail(sslProviderConfig.Provider, user.GetEmail())
if err == nil { if err == nil {
user.privkey = resp.Key user.privkey = resp.Key

View File

@ -159,7 +159,7 @@ func apply(challengeProvider challenge.Provider, options *applicantOptions) (*Ap
// New users need to register first // New users need to register first
if !acmeUser.hasRegistration() { if !acmeUser.hasRegistration() {
reg, err := registerAcmeUser(client, sslProviderConfig, acmeUser) reg, err := registerAcmeUserWithSingleFlight(client, sslProviderConfig, acmeUser)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to register: %w", err) return nil, fmt.Errorf("failed to register: %w", err)
} }

View File

@ -68,11 +68,11 @@ type WorkflowNodeConfigForApply struct {
ProviderConfig map[string]any `json:"providerConfig"` // DNS 提供商额外配置 ProviderConfig map[string]any `json:"providerConfig"` // DNS 提供商额外配置
KeyAlgorithm string `json:"keyAlgorithm"` // 密钥算法 KeyAlgorithm string `json:"keyAlgorithm"` // 密钥算法
Nameservers string `json:"nameservers"` // DNS 服务器列表,以半角逗号分隔 Nameservers string `json:"nameservers"` // DNS 服务器列表,以半角逗号分隔
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout"` // DNS 传播超时时间(默认取决于提供商 DnsPropagationTimeout int32 `json:"dnsPropagationTimeout"` // DNS 传播超时时间(零值取决于提供商的默认值
DnsTTL int32 `json:"dnsTTL"` // DNS TTL默认取决于提供商 DnsTTL int32 `json:"dnsTTL"` // DNS TTL零值取决于提供商的默认值
DisableFollowCNAME bool `json:"disableFollowCNAME"` // 是否禁用 CNAME 跟随 DisableFollowCNAME bool `json:"disableFollowCNAME"` // 是否关闭 CNAME 跟随
DisableARI bool `json:"disableARI"` // 是否禁用 ARI DisableARI bool `json:"disableARI"` // 是否关闭 ARI
SkipBeforeExpiryDays int32 `json:"skipBeforeExpiryDays"` // 证书到期前多少天前跳过续期(默认值:30 SkipBeforeExpiryDays int32 `json:"skipBeforeExpiryDays"` // 证书到期前多少天前跳过续期(零值将使用默认值 30
} }
type WorkflowNodeConfigForDeploy struct { type WorkflowNodeConfigForDeploy struct {

View File

@ -5,6 +5,8 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
"github.com/usual2970/certimate/internal/pkg/utils/types"
) )
// 表示默认的日志记录器类型。 // 表示默认的日志记录器类型。
@ -21,7 +23,7 @@ func (l *DefaultLogger) Logt(tag string, data ...any) {
temp[0] = tag temp[0] = tag
for i, v := range data { for i, v := range data {
s := "" s := ""
if v == nil { if types.IsNil(v) {
s = "<nil>" s = "<nil>"
} else { } else {
switch reflect.ValueOf(v).Kind() { switch reflect.ValueOf(v).Kind() {

View File

@ -3,6 +3,7 @@
import "reflect" import "reflect"
// 判断对象是否为 nil。 // 判断对象是否为 nil。
// 与直接使用 `obj == nil` 不同,该函数会正确判断接口类型对象的真实值是否为空。
// //
// 入参: // 入参:
// - value待判断的对象。 // - value待判断的对象。

View File

@ -42,23 +42,23 @@ func (w *workflowProcessor) processNode(ctx context.Context, node *domain.Workfl
var runErr error var runErr error
var processor nodes.NodeProcessor var processor nodes.NodeProcessor
for { for {
if current.Type != domain.WorkflowNodeTypeBranch && current.Type != domain.WorkflowNodeTypeExecuteResultBranch { if current.Type == domain.WorkflowNodeTypeBranch || current.Type == domain.WorkflowNodeTypeExecuteResultBranch {
processor, runErr = nodes.GetProcessor(current) break
if runErr != nil { }
break
} processor, runErr = nodes.GetProcessor(current)
if runErr != nil {
runErr = processor.Run(ctx) break
}
log := processor.Log(ctx)
if log != nil { runErr = processor.Run(ctx)
w.logs = append(w.logs, *log) log := processor.Log(ctx)
} if log != nil {
if runErr != nil { w.logs = append(w.logs, *log)
break }
} if runErr != nil {
break
} }
break
} }
if runErr != nil && current.Next != nil && current.Next.Type != domain.WorkflowNodeTypeExecuteResultBranch { if runErr != nil && current.Next != nil && current.Next.Type != domain.WorkflowNodeTypeExecuteResultBranch {
@ -70,8 +70,8 @@ func (w *workflowProcessor) processNode(ctx context.Context, node *domain.Workfl
} else { } else {
current = current.Next current = current.Next
} }
} }
return nil return nil
} }
@ -79,10 +79,6 @@ func setContextWorkflowId(ctx context.Context, id string) context.Context {
return context.WithValue(ctx, "workflow_id", id) return context.WithValue(ctx, "workflow_id", id)
} }
func GetWorkflowId(ctx context.Context) string {
return ctx.Value("workflow_id").(string)
}
func getBranchByType(branches []domain.WorkflowNode, nodeType domain.WorkflowNodeType) *domain.WorkflowNode { func getBranchByType(branches []domain.WorkflowNode, nodeType domain.WorkflowNodeType) *domain.WorkflowNode {
for _, branch := range branches { for _, branch := range branches {
if branch.Type == nodeType { if branch.Type == nodeType {

View File

@ -26,13 +26,13 @@ const AddNode = ({ node, disabled }: AddNodeProps) => {
return [ return [
[WorkflowNodeType.Apply, "workflow_node.apply.label", <SolutionOutlinedIcon />], [WorkflowNodeType.Apply, "workflow_node.apply.label", <SolutionOutlinedIcon />],
[WorkflowNodeType.Deploy, "workflow_node.deploy.label", <CloudUploadOutlinedIcon />], [WorkflowNodeType.Deploy, "workflow_node.deploy.label", <CloudUploadOutlinedIcon />],
[WorkflowNodeType.Notify, "workflow_node.notify.label", <SendOutlinedIcon />],
[WorkflowNodeType.Branch, "workflow_node.branch.label", <SisternodeOutlinedIcon />], [WorkflowNodeType.Branch, "workflow_node.branch.label", <SisternodeOutlinedIcon />],
[WorkflowNodeType.ExecuteResultBranch, "workflow_node.execute_result_branch.label", <SisternodeOutlinedIcon />], [WorkflowNodeType.ExecuteResultBranch, "workflow_node.execute_result_branch.label", <SisternodeOutlinedIcon />],
[WorkflowNodeType.Notify, "workflow_node.notify.label", <SendOutlinedIcon />],
] ]
.filter(([type]) => { .filter(([type]) => {
if (node.type !== WorkflowNodeType.Apply && node.type !== WorkflowNodeType.Deploy && type === WorkflowNodeType.ExecuteResultBranch) { if (node.type !== WorkflowNodeType.Apply && node.type !== WorkflowNodeType.Deploy && node.type !== WorkflowNodeType.Notify) {
return false; return type !== WorkflowNodeType.ExecuteResultBranch;
} }
return true; return true;

View File

@ -16,6 +16,8 @@ const ConditionNode = ({ node, disabled, branchId, branchIndex }: ConditionNodeP
return ( return (
<> <>
<Popover <Popover
classNames={{ root: "shadow-md" }}
styles={{ body: { padding: 0 } }}
arrow={false} arrow={false}
content={ content={
<SharedNode.Menu <SharedNode.Menu
@ -26,8 +28,6 @@ const ConditionNode = ({ node, disabled, branchId, branchIndex }: ConditionNodeP
trigger={<Button color="primary" icon={<MoreOutlinedIcon />} variant="text" />} trigger={<Button color="primary" icon={<MoreOutlinedIcon />} variant="text" />}
/> />
} }
overlayClassName="shadow-md"
overlayInnerStyle={{ padding: 0 }}
placement="rightTop" placement="rightTop"
> >
<Card className="relative z-[1] mt-10 w-[256px] shadow-md" styles={{ body: { padding: 0 } }} hoverable> <Card className="relative z-[1] mt-10 w-[256px] shadow-md" styles={{ body: { padding: 0 } }} hoverable>

View File

@ -1,9 +1,12 @@
import { memo } from "react"; import { memo } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { MoreOutlined as MoreOutlinedIcon } from "@ant-design/icons"; import {
import { Button, Card, Popover } from "antd"; CheckCircleOutlined as CheckCircleOutlinedIcon,
CloseCircleOutlined as CloseCircleOutlinedIcon,
MoreOutlined as MoreOutlinedIcon,
} from "@ant-design/icons";
import { Button, Card, Popover, theme } from "antd";
import { CheckCircleIcon, XCircleIcon } from "lucide-react";
import { WorkflowNodeType } from "@/domain/workflow"; import { WorkflowNodeType } from "@/domain/workflow";
import AddNode from "./AddNode"; import AddNode from "./AddNode";
import SharedNode, { type SharedNodeProps } from "./_SharedNode"; import SharedNode, { type SharedNodeProps } from "./_SharedNode";
@ -16,9 +19,13 @@ export type ConditionNodeProps = SharedNodeProps & {
const ExecuteResultNode = ({ node, disabled, branchId, branchIndex }: ConditionNodeProps) => { const ExecuteResultNode = ({ node, disabled, branchId, branchIndex }: ConditionNodeProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { token: themeToken } = theme.useToken();
return ( return (
<> <>
<Popover <Popover
classNames={{ root: "shadow-md" }}
styles={{ body: { padding: 0 } }}
arrow={false} arrow={false}
content={ content={
<SharedNode.Menu <SharedNode.Menu
@ -29,8 +36,6 @@ const ExecuteResultNode = ({ node, disabled, branchId, branchIndex }: ConditionN
trigger={<Button color="primary" icon={<MoreOutlinedIcon />} variant="text" />} trigger={<Button color="primary" icon={<MoreOutlinedIcon />} variant="text" />}
/> />
} }
overlayClassName="shadow-md"
overlayInnerStyle={{ padding: 0 }}
placement="rightTop" placement="rightTop"
> >
<Card className="relative z-[1] mt-10 w-[256px] shadow-md" styles={{ body: { padding: 0 } }} hoverable> <Card className="relative z-[1] mt-10 w-[256px] shadow-md" styles={{ body: { padding: 0 } }} hoverable>
@ -38,12 +43,12 @@ const ExecuteResultNode = ({ node, disabled, branchId, branchIndex }: ConditionN
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
{node.type === WorkflowNodeType.ExecuteSuccess ? ( {node.type === WorkflowNodeType.ExecuteSuccess ? (
<> <>
<CheckCircleIcon size={18} className="text-green-500" /> <CheckCircleOutlinedIcon style={{ color: themeToken.colorSuccess }} />
<div>{t("workflow_node.execute_success.label")}</div> <div>{t("workflow_node.execute_success.label")}</div>
</> </>
) : ( ) : (
<> <>
<XCircleIcon size={18} className="text-red-500" /> <CloseCircleOutlinedIcon style={{ color: themeToken.colorError }} />
<div>{t("workflow_node.execute_failure.label")}</div> <div>{t("workflow_node.execute_failure.label")}</div>
</> </>
)} )}

View File

@ -64,6 +64,16 @@ type SharedNodeMenuProps = SharedNodeProps & {
afterDelete?: () => void; afterDelete?: () => void;
}; };
const isBranchingNode = (node: WorkflowNode) => {
return (
node.type === WorkflowNodeType.Branch ||
node.type === WorkflowNodeType.Condition ||
node.type === WorkflowNodeType.ExecuteResultBranch ||
node.type === WorkflowNodeType.ExecuteSuccess ||
node.type === WorkflowNodeType.ExecuteFailure
);
};
const SharedNodeMenu = ({ trigger, node, disabled, branchId, branchIndex, afterUpdate, afterDelete }: SharedNodeMenuProps) => { const SharedNodeMenu = ({ trigger, node, disabled, branchId, branchIndex, afterUpdate, afterDelete }: SharedNodeMenuProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -91,13 +101,7 @@ const SharedNodeMenu = ({ trigger, node, disabled, branchId, branchIndex, afterU
}; };
const handleDeleteClick = async () => { const handleDeleteClick = async () => {
if ( if (isBranchingNode(node)) {
node.type === WorkflowNodeType.Branch ||
node.type === WorkflowNodeType.Condition ||
node.type === WorkflowNodeType.ExecuteResultBranch ||
node.type === WorkflowNodeType.ExecuteSuccess ||
node.type === WorkflowNodeType.ExecuteFailure
) {
await removeBranch(branchId!, branchIndex!); await removeBranch(branchId!, branchIndex!);
} else { } else {
await removeNode(node.id); await removeNode(node.id);
@ -116,19 +120,13 @@ const SharedNodeMenu = ({ trigger, node, disabled, branchId, branchIndex, afterU
{ {
key: "rename", key: "rename",
disabled: disabled, disabled: disabled,
label: label: isBranchingNode(node) ? t("workflow_node.action.rename_branch") : t("workflow_node.action.rename_node"),
node.type === WorkflowNodeType.Branch || node.type === WorkflowNodeType.Condition
? t("workflow_node.action.rename_branch")
: t("workflow_node.action.rename_node"),
icon: <FormOutlinedIcon />, icon: <FormOutlinedIcon />,
onClick: () => { onClick: () => {
nameRef.current = node.name; nameRef.current = node.name;
const dialog = modalApi.confirm({ const dialog = modalApi.confirm({
title: title: isBranchingNode(node) ? t("workflow_node.action.rename_branch") : t("workflow_node.action.rename_node"),
node.type === WorkflowNodeType.Branch || node.type === WorkflowNodeType.Condition
? t("workflow_node.action.rename_branch")
: t("workflow_node.action.rename_node"),
content: ( content: (
<div className="pb-2 pt-4"> <div className="pb-2 pt-4">
<Input <Input
@ -156,14 +154,7 @@ const SharedNodeMenu = ({ trigger, node, disabled, branchId, branchIndex, afterU
{ {
key: "remove", key: "remove",
disabled: disabled || node.type === WorkflowNodeType.Start, disabled: disabled || node.type === WorkflowNodeType.Start,
label: label: isBranchingNode(node) ? t("workflow_node.action.remove_branch") : t("workflow_node.action.remove_node"),
node.type === WorkflowNodeType.Branch ||
node.type === WorkflowNodeType.Condition ||
node.type === WorkflowNodeType.ExecuteResultBranch ||
node.type === WorkflowNodeType.ExecuteSuccess ||
node.type === WorkflowNodeType.ExecuteFailure
? t("workflow_node.action.remove_branch")
: t("workflow_node.action.remove_node"),
icon: <CloseCircleOutlinedIcon />, icon: <CloseCircleOutlinedIcon />,
danger: true, danger: true,
onClick: handleDeleteClick, onClick: handleDeleteClick,
@ -193,10 +184,10 @@ const SharedNodeBlock = ({ children, node, disabled, onClick }: SharedNodeBlockP
return ( return (
<> <>
<Popover <Popover
classNames={{ root: "shadow-md" }}
styles={{ body: { padding: 0 } }}
arrow={false} arrow={false}
content={<SharedNodeMenu node={node} disabled={disabled} trigger={<Button color="primary" icon={<MoreOutlinedIcon />} variant="text" />} />} content={<SharedNodeMenu node={node} disabled={disabled} trigger={<Button color="primary" icon={<MoreOutlinedIcon />} variant="text" />} />}
overlayClassName="shadow-md"
overlayInnerStyle={{ padding: 0 }}
placement="rightTop" placement="rightTop"
> >
<Card className="relative w-[256px] overflow-hidden shadow-md" styles={{ body: { padding: 0 } }} hoverable> <Card className="relative w-[256px] overflow-hidden shadow-md" styles={{ body: { padding: 0 } }} hoverable>

View File

@ -29,28 +29,28 @@ export type WorkflowTriggerType = (typeof WORKFLOW_TRIGGERS)[keyof typeof WORKFL
export enum WorkflowNodeType { export enum WorkflowNodeType {
Start = "start", Start = "start",
End = "end", End = "end",
Branch = "branch",
ExecuteResultBranch = "execute_result_branch",
ExecuteSuccess = "execute_success",
ExecuteFailure = "execute_failure",
Condition = "condition",
Apply = "apply", Apply = "apply",
Deploy = "deploy", Deploy = "deploy",
Notify = "notify", Notify = "notify",
Branch = "branch",
Condition = "condition",
ExecuteResultBranch = "execute_result_branch",
ExecuteSuccess = "execute_success",
ExecuteFailure = "execute_failure",
Custom = "custom", Custom = "custom",
} }
const workflowNodeTypeDefaultNames: Map<WorkflowNodeType, string> = new Map([ const workflowNodeTypeDefaultNames: Map<WorkflowNodeType, string> = new Map([
[WorkflowNodeType.Start, i18n.t("workflow_node.start.label")], [WorkflowNodeType.Start, i18n.t("workflow_node.start.label")],
[WorkflowNodeType.End, i18n.t("workflow_node.end.label")], [WorkflowNodeType.End, i18n.t("workflow_node.end.label")],
[WorkflowNodeType.Branch, i18n.t("workflow_node.branch.label")],
[WorkflowNodeType.ExecuteResultBranch, i18n.t("workflow_node.execute_result_branch.label")],
[WorkflowNodeType.ExecuteSuccess, i18n.t("workflow_node.execute_success.label")],
[WorkflowNodeType.ExecuteFailure, i18n.t("workflow_node.execute_failure.label")],
[WorkflowNodeType.Condition, i18n.t("workflow_node.condition.label")],
[WorkflowNodeType.Apply, i18n.t("workflow_node.apply.label")], [WorkflowNodeType.Apply, i18n.t("workflow_node.apply.label")],
[WorkflowNodeType.Deploy, i18n.t("workflow_node.deploy.label")], [WorkflowNodeType.Deploy, i18n.t("workflow_node.deploy.label")],
[WorkflowNodeType.Notify, i18n.t("workflow_node.notify.label")], [WorkflowNodeType.Notify, i18n.t("workflow_node.notify.label")],
[WorkflowNodeType.Branch, i18n.t("workflow_node.branch.label")],
[WorkflowNodeType.Condition, i18n.t("workflow_node.condition.label")],
[WorkflowNodeType.ExecuteResultBranch, i18n.t("workflow_node.execute_result_branch.label")],
[WorkflowNodeType.ExecuteSuccess, i18n.t("workflow_node.execute_success.label")],
[WorkflowNodeType.ExecuteFailure, i18n.t("workflow_node.execute_failure.label")],
[WorkflowNodeType.Custom, i18n.t("workflow_node.custom.title")], [WorkflowNodeType.Custom, i18n.t("workflow_node.custom.title")],
]); ]);

View File

@ -1,5 +1,5 @@
{ {
"workflow_node.action.configure_node": "Configure", "workflow_node.action.configure_node": "Configure node",
"workflow_node.action.add_node": "Add node", "workflow_node.action.add_node": "Add node",
"workflow_node.action.rename_node": "Rename node", "workflow_node.action.rename_node": "Rename node",
"workflow_node.action.remove_node": "Delete node", "workflow_node.action.remove_node": "Delete node",
@ -379,13 +379,13 @@
"workflow_node.end.label": "End", "workflow_node.end.label": "End",
"workflow_node.branch.label": "Branch", "workflow_node.branch.label": "Parallel branch",
"workflow_node.execute_result_branch.label": "Execute result branch", "workflow_node.condition.label": "Branch",
"workflow_node.execute_success.label": "Execute success", "workflow_node.execute_result_branch.label": "Execution result branch",
"workflow_node.execute_failure.label": "Execute failure", "workflow_node.execute_success.label": "If the previous node succeeded ...",
"workflow_node.condition.label": "Condition" "workflow_node.execute_failure.label": "If the previous node failed ..."
} }

View File

@ -3,7 +3,7 @@
"workflow_node.branch.add_node": "添加节点", "workflow_node.branch.add_node": "添加节点",
"workflow_node.action.rename_node": "重命名", "workflow_node.action.rename_node": "重命名",
"workflow_node.action.remove_node": "删除节点", "workflow_node.action.remove_node": "删除节点",
"workflow_node.action.add_branch": "添加分支", "workflow_node.action.add_branch": "添加并行分支",
"workflow_node.action.rename_branch": "重命名", "workflow_node.action.rename_branch": "重命名",
"workflow_node.action.remove_branch": "删除分支", "workflow_node.action.remove_branch": "删除分支",
@ -379,13 +379,13 @@
"workflow_node.end.label": "结束", "workflow_node.end.label": "结束",
"workflow_node.branch.label": "分支", "workflow_node.branch.label": "并行分支",
"workflow_node.condition.label": "分支",
"workflow_node.execute_result_branch.label": "执行结果分支", "workflow_node.execute_result_branch.label": "执行结果分支",
"workflow_node.execute_success.label": "执行成功", "workflow_node.execute_success.label": "若前一节点执行成功",
"workflow_node.execute_failure.label": "执行失败", "workflow_node.execute_failure.label": "若前一节点执行失败…"
"workflow_node.condition.label": "条件"
} }