Files
aiaa-notification-server/internal/engine/renderer.go
T
ryan a9b6234208 feat(通知模板): 支持 case 取值映射与事件名匹配渲染
Motivation:
让通知模板能够将 action、event 等原始枚举值映射为可读中文文案,并支持按事件名后缀匹配;同时简化 SafeW 消息发送格式,避免 Markdown 转义引入的显示问题。

Changes:

* 新增 `case` 模板函数,按值匹配 key/文案并支持末尾奇数参数作为默认值
* `case` 匹配兼容事件名后缀(如 trade.close 匹配 .close)
* `line` 前缀自动去除末尾冒号,避免重复冒号
* 模板渲染前自动注入 event 字段,便于模板按事件名取值
* SafeW 消息改为纯文本发送,移除 MarkdownV2 转义
2026-08-16 00:45:27 +08:00

98 lines
1.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package engine
import (
"bytes"
"fmt"
"strings"
"text/template"
)
type Renderer struct{}
func NewRenderer() *Renderer {
return &Renderer{}
}
func (r *Renderer) Render(tmplContent string, data map[string]interface{}) (string, error) {
tmpl, err := template.New("notify").
Option("missingkey=zero").
Funcs(template.FuncMap{
"line": templateLine,
"case": templateCase,
}).
Parse(tmplContent)
if err != nil {
return "", fmt.Errorf("parse template: %w", err)
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil {
return "", fmt.Errorf("execute template: %w", err)
}
return buf.String(), nil
}
// templateLine renders "labelvalue\n" or empty if value is missing/zero.
func templateLine(label string, v any) string {
if isEmptyValue(v) {
return ""
}
return strings.TrimRight(label, ":") + "" + fmt.Sprint(v) + "\n"
}
func templateCase(value any, pairs ...any) string {
got := stringify(value)
n := len(pairs)
def := got
if n%2 == 1 {
def = stringify(pairs[n-1])
pairs = pairs[:n-1]
}
for i := 0; i+1 < len(pairs); i += 2 {
if caseKeyMatch(got, stringify(pairs[i])) {
return stringify(pairs[i+1])
}
}
return def
}
func caseKeyMatch(value, key string) bool {
v := strings.ToLower(strings.TrimSpace(value))
k := strings.ToLower(strings.TrimSpace(key))
k = strings.TrimPrefix(k, ".")
vSeg := v
if i := strings.LastIndex(v, "."); i >= 0 {
vSeg = v[i+1:]
}
return k == v || k == strings.TrimPrefix(v, ".") || k == vSeg
}
func stringify(v any) string {
if v == nil {
return ""
}
return fmt.Sprint(v)
}
func isEmptyValue(v any) bool {
switch t := v.(type) {
case nil:
return true
case string:
return strings.TrimSpace(t) == ""
case bool:
return !t
case int:
return t == 0
case int32:
return t == 0
case int64:
return t == 0
case float32:
return t == 0
case float64:
return t == 0
default:
return false
}
}