This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
package gateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/ssdomei232/goodBaby/handler/runner"
|
||||
"github.com/ssdomei232/goodBaby/internal/meta"
|
||||
"github.com/ssdomei232/goodBaby/model"
|
||||
)
|
||||
|
||||
// messageFields 规则配置里可以被投递消息覆盖的字段名
|
||||
var messageFields = []string{"msg", "message", "body"}
|
||||
|
||||
// titleField 规则配置里可以被投递标题覆盖的字段名
|
||||
const titleField = "title"
|
||||
|
||||
// TestMessage 是「测试」网关规则时使用的示例投递内容,
|
||||
// 让用户在页面上就能看到消息被替换后的效果。
|
||||
var TestMessage = Message{
|
||||
Title: "goodBaby 测试标题",
|
||||
Content: "这是一条来自消息网关的测试消息",
|
||||
}
|
||||
|
||||
// WebhookGateway 默认网关:外部系统 POST 一条消息来触发规则
|
||||
type WebhookGateway struct{}
|
||||
|
||||
func (g *WebhookGateway) GetType() string {
|
||||
return model.GatewayTypeWebhook
|
||||
}
|
||||
|
||||
func (g *WebhookGateway) Meta() meta.GatewayMeta {
|
||||
return meta.GatewayMeta{
|
||||
Type: model.GatewayTypeWebhook,
|
||||
Label: "Webhook",
|
||||
Description: "为外部系统生成一个 Webhook 地址,POST 一条消息即可触发绑定在该网关上的规则。",
|
||||
Docs: "docs/gateway-config.md",
|
||||
PayloadHint: `{"title": "监控告警", "message": "服务已恢复"}`,
|
||||
}
|
||||
}
|
||||
|
||||
// Deliver 逐条执行绑定在网关上的规则
|
||||
//
|
||||
// 单条规则失败不影响其它规则,失败原因汇总在 Result 里返回。
|
||||
func (g *WebhookGateway) Deliver(ctx context.Context, task *Task) (*Result, error) {
|
||||
// 初始化为空切片:nil 切片会被序列化成 JSON null,前端读 failed.length 时会报错
|
||||
failed := []string{}
|
||||
|
||||
for i := range task.Rules {
|
||||
rule := task.Rules[i]
|
||||
|
||||
executed := rule
|
||||
configJSON, applied, err := ApplyMessage(rule.ConfigJson, task.Message)
|
||||
if err != nil {
|
||||
failed = append(failed, rule.Name+": "+err.Error())
|
||||
continue
|
||||
}
|
||||
if applied {
|
||||
// 用投递进来的消息执行,但不改动数据库里的规则配置
|
||||
executed.ConfigJson = configJSON
|
||||
}
|
||||
if err := runner.ExecuteGatewayRuleWithContext(ctx, &executed, model.TriggerGateway); err != nil {
|
||||
failed = append(failed, rule.Name+": "+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return &Result{Total: len(task.Rules), Failed: failed}, nil
|
||||
}
|
||||
|
||||
// ApplyMessage 把投递进来的消息覆盖到规则配置的消息字段上。
|
||||
//
|
||||
// 返回覆盖后的配置;applied 为 false 表示配置里没有可覆盖的消息字段
|
||||
// (例如「公开 GitHub 仓库」「删除 DNS 记录」),此时按规则里保存的配置执行。
|
||||
func ApplyMessage(configJSON string, msg Message) (string, bool, error) {
|
||||
var config map[string]any
|
||||
if err := json.Unmarshal([]byte(configJSON), &config); err != nil {
|
||||
return configJSON, false, fmt.Errorf("解析规则配置失败: %v", err)
|
||||
}
|
||||
|
||||
matched := false
|
||||
for _, key := range messageFields {
|
||||
if _, ok := config[key]; ok {
|
||||
if msg.Content != "" {
|
||||
config[key] = msg.Content
|
||||
}
|
||||
matched = true
|
||||
}
|
||||
}
|
||||
|
||||
if msg.Title != "" {
|
||||
if _, ok := config[titleField]; ok {
|
||||
config[titleField] = msg.Title
|
||||
matched = true
|
||||
}
|
||||
}
|
||||
|
||||
if !matched {
|
||||
return configJSON, false, nil
|
||||
}
|
||||
|
||||
out, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return configJSON, false, fmt.Errorf("生成规则配置失败: %v", err)
|
||||
}
|
||||
return string(out), true, nil
|
||||
}
|
||||
Reference in New Issue
Block a user