优化结构
This commit is contained in:
@@ -10,7 +10,11 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const IntegrationKindPayment = "payment"
|
||||
const (
|
||||
IntegrationKindPayment = "payment"
|
||||
IntegrationKindMQ = "mq"
|
||||
IntegrationKindWebSocket = "websocket"
|
||||
)
|
||||
|
||||
type IntegrationConfig struct {
|
||||
Kind string
|
||||
@@ -150,10 +154,79 @@ func mergeIntegrationDefaults(defaults, values map[string]any) map[string]any {
|
||||
}
|
||||
|
||||
func ValidateIntegrationConfig(kind, provider string, values map[string]any) error {
|
||||
if normalizeIntegrationPart(kind) != IntegrationKindPayment {
|
||||
kind = normalizeIntegrationPart(kind)
|
||||
provider = normalizeIntegrationPart(provider)
|
||||
switch kind {
|
||||
case IntegrationKindPayment:
|
||||
return validatePaymentIntegrationConfig(provider, values)
|
||||
case IntegrationKindMQ, IntegrationKindWebSocket:
|
||||
return validateCommunicationIntegrationConfig(kind, provider, values)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return validatePaymentIntegrationConfig(normalizeIntegrationPart(provider), values)
|
||||
}
|
||||
|
||||
func validateCommunicationIntegrationConfig(kind, provider string, values map[string]any) error {
|
||||
definition, ok := IntegrationDefinition(kind, provider)
|
||||
if !ok {
|
||||
return errors.New("不支持的通信集成")
|
||||
}
|
||||
for _, field := range definition.Fields {
|
||||
if field.Required && integrationText(values, field.Key) == "" {
|
||||
return fmt.Errorf("%s 缺少配置字段 %s", provider, field.Key)
|
||||
}
|
||||
}
|
||||
|
||||
switch kind + "/" + provider {
|
||||
case IntegrationKindMQ + "/emqx":
|
||||
broker := strings.ToLower(integrationText(values, "broker"))
|
||||
if !strings.HasPrefix(broker, "tcp://") && !strings.HasPrefix(broker, "ssl://") && !strings.HasPrefix(broker, "ws://") && !strings.HasPrefix(broker, "wss://") && !strings.HasPrefix(broker, "mqtt://") {
|
||||
return errors.New("emqx broker 必须使用 tcp、ssl、ws、wss 或 mqtt 协议")
|
||||
}
|
||||
if keepAlive := integrationInt64(values, "keep_alive", 0); keepAlive <= 0 {
|
||||
return errors.New("emqx keep_alive 必须大于 0")
|
||||
}
|
||||
if timeout := integrationInt64(values, "connect_timeout", 0); timeout <= 0 {
|
||||
return errors.New("emqx connect_timeout 必须大于 0")
|
||||
}
|
||||
case IntegrationKindMQ + "/rabbitmq":
|
||||
port := integrationInt64(values, "port", 0)
|
||||
if port < 1 || port > 65535 {
|
||||
return errors.New("rabbitmq port 必须在 1-65535 之间")
|
||||
}
|
||||
exchangeType := strings.ToLower(integrationText(values, "exchange_type"))
|
||||
if exchangeType != "direct" && exchangeType != "fanout" && exchangeType != "topic" && exchangeType != "headers" {
|
||||
return errors.New("rabbitmq exchange_type 必须是 direct、fanout、topic 或 headers")
|
||||
}
|
||||
if integrationInt64(values, "prefetch_count", -1) < 0 {
|
||||
return errors.New("rabbitmq prefetch_count 不能小于 0")
|
||||
}
|
||||
if integrationInt64(values, "heartbeat", -1) < 0 {
|
||||
return errors.New("rabbitmq heartbeat 不能小于 0")
|
||||
}
|
||||
if integrationInt64(values, "connect_timeout", 0) <= 0 {
|
||||
return errors.New("rabbitmq connect_timeout 必须大于 0")
|
||||
}
|
||||
case IntegrationKindWebSocket + "/melody":
|
||||
path := integrationText(values, "path")
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
return errors.New("websocket path 必须以 / 开头")
|
||||
}
|
||||
for _, key := range []string{"write_wait", "pong_wait", "ping_period"} {
|
||||
value := integrationText(values, key)
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
duration, err := time.ParseDuration(value)
|
||||
if err != nil || duration <= 0 {
|
||||
return fmt.Errorf("websocket %s 必须是大于 0 的时长", key)
|
||||
}
|
||||
}
|
||||
if integrationInt64(values, "max_message_size", -1) < 0 || integrationInt64(values, "message_buffer_size", -1) < 0 {
|
||||
return errors.New("websocket 消息大小和缓冲区不能小于 0")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatePaymentIntegrationConfig(provider string, values map[string]any) error {
|
||||
|
||||
@@ -89,6 +89,58 @@ func genericPaymentDefinition(provider, name, description string) IntegrationCon
|
||||
}
|
||||
|
||||
var integrationDefinitions = map[string][]IntegrationConfigDefinition{
|
||||
IntegrationKindMQ: {
|
||||
{
|
||||
Kind: IntegrationKindMQ, Provider: "emqx", Name: "EMQX", Description: "EMQX MQTT 消息服务",
|
||||
Defaults: map[string]any{"broker": "tcp://127.0.0.1:1883", "client_id": "kra", "username": "", "password": "", "keep_alive": 30, "clean_session": true, "connect_timeout": 10},
|
||||
Fields: []IntegrationConfigField{
|
||||
{Key: "broker", Label: "Broker 地址", Type: "text", Required: true, Placeholder: "tcp://127.0.0.1:1883"},
|
||||
{Key: "client_id", Label: "客户端 ID", Type: "text", Required: true, Placeholder: "kra"},
|
||||
{Key: "username", Label: "用户名", Type: "text"},
|
||||
{Key: "password", Label: "密码", Type: "password", Secret: true},
|
||||
{Key: "keep_alive", Label: "心跳间隔(秒)", Type: "number", Required: true},
|
||||
{Key: "clean_session", Label: "清理会话", Type: "switch", Description: "连接时不恢复 Broker 端保存的旧会话。"},
|
||||
{Key: "connect_timeout", Label: "连接超时(秒)", Type: "number", Required: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
Kind: IntegrationKindMQ, Provider: "rabbitmq", Name: "RabbitMQ", Description: "RabbitMQ AMQP 消息队列",
|
||||
Defaults: map[string]any{"host": "127.0.0.1", "port": 5672, "username": "guest", "password": "guest", "vhost": "/", "exchange": "kra", "exchange_type": "topic", "queue": "kra", "routing_key": "#", "durable": true, "auto_delete": false, "prefetch_count": 10, "heartbeat": 10, "connect_timeout": 10, "tls": false},
|
||||
Fields: []IntegrationConfigField{
|
||||
{Key: "host", Label: "主机", Type: "text", Required: true, Placeholder: "127.0.0.1"},
|
||||
{Key: "port", Label: "端口", Type: "number", Required: true},
|
||||
{Key: "username", Label: "用户名", Type: "text", Required: true},
|
||||
{Key: "password", Label: "密码", Type: "password", Required: true, Secret: true},
|
||||
{Key: "vhost", Label: "Virtual Host", Type: "text", Required: true, Placeholder: "/"},
|
||||
{Key: "exchange", Label: "Exchange", Type: "text", Required: true, Placeholder: "kra"},
|
||||
{Key: "exchange_type", Label: "Exchange 类型", Type: "select", Required: true, Options: []IntegrationConfigOption{{Label: "topic", Value: "topic"}, {Label: "direct", Value: "direct"}, {Label: "fanout", Value: "fanout"}, {Label: "headers", Value: "headers"}}},
|
||||
{Key: "queue", Label: "Queue", Type: "text", Required: true, Placeholder: "kra"},
|
||||
{Key: "routing_key", Label: "默认 Routing Key", Type: "text", Required: true, Placeholder: "#", Description: "业务未指定订阅键时使用;topic 类型支持 * 和 #。"},
|
||||
{Key: "durable", Label: "持久化", Type: "switch"},
|
||||
{Key: "auto_delete", Label: "自动删除", Type: "switch"},
|
||||
{Key: "prefetch_count", Label: "预取数量", Type: "number"},
|
||||
{Key: "heartbeat", Label: "心跳间隔(秒)", Type: "number"},
|
||||
{Key: "connect_timeout", Label: "连接超时(秒)", Type: "number", Required: true},
|
||||
{Key: "tls", Label: "启用 TLS", Type: "switch"},
|
||||
},
|
||||
},
|
||||
},
|
||||
IntegrationKindWebSocket: {
|
||||
{
|
||||
Kind: IntegrationKindWebSocket, Provider: "melody", Name: "WebSocket", Description: "WebSocket 实时连接服务",
|
||||
Defaults: map[string]any{"path": "/ws", "allow_origins": []string{}, "max_message_size": 0, "write_wait": "10s", "pong_wait": "60s", "ping_period": "54s", "message_buffer_size": 0, "concurrent_message_handling": false},
|
||||
Fields: []IntegrationConfigField{
|
||||
{Key: "path", Label: "访问路径", Type: "text", Required: true, Placeholder: "/ws"},
|
||||
{Key: "allow_origins", Label: "允许的来源", Type: "string-list", Placeholder: "https://admin.example.com", Description: "每行一个 Origin;留空时沿用 WebSocket 组件默认策略。"},
|
||||
{Key: "max_message_size", Label: "最大消息字节数", Type: "number", Description: "0 表示使用组件默认值。"},
|
||||
{Key: "write_wait", Label: "写入超时", Type: "text", Required: true, Placeholder: "10s"},
|
||||
{Key: "pong_wait", Label: "Pong 等待时间", Type: "text", Required: true, Placeholder: "60s"},
|
||||
{Key: "ping_period", Label: "Ping 间隔", Type: "text", Required: true, Placeholder: "54s"},
|
||||
{Key: "message_buffer_size", Label: "消息缓冲区", Type: "number", Description: "0 表示不额外缓冲。"},
|
||||
{Key: "concurrent_message_handling", Label: "并发处理消息", Type: "switch"},
|
||||
},
|
||||
},
|
||||
},
|
||||
IntegrationKindPayment: {
|
||||
paymentDefinition(PaymentAlipay, "支付宝", "支付宝 OpenAPI RSA2 支付", map[string]any{"app_id": "", "private_key": "", "public_key": "", "environment": "production", "sign_type": "RSA2", "gateway_url": "https://openapi.alipay.com/gateway.do", "method": "alipay.trade.create"},
|
||||
integrationField("app_id", "应用 ID", true, false, "text"), integrationField("private_key", "应用私钥", true, true, "textarea"), integrationField("public_key", "支付宝公钥", true, true, "textarea"),
|
||||
|
||||
Reference in New Issue
Block a user