Files
EdgeCommon/pkg/configutils/variable.go

194 lines
4.4 KiB
Go
Raw Normal View History

2020-09-26 08:07:24 +08:00
package configutils
import (
2024-01-11 16:41:08 +08:00
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
"fmt"
stringutil "github.com/iwind/TeaGo/utils/string"
"net/url"
2020-09-26 08:07:24 +08:00
"regexp"
2024-05-01 19:44:11 +08:00
"strconv"
2020-09-26 08:07:24 +08:00
"strings"
"sync"
)
2021-06-27 22:00:02 +08:00
// VariableHolder 变量信息存储类型
2024-01-11 16:41:08 +08:00
type VariableHolder struct {
Param string
Modifiers []string
}
type VariableHolders = []any
2020-09-26 08:07:24 +08:00
2024-01-11 16:41:08 +08:00
var variableMapping = map[string][]any{} // source => [holder1, ...]
var variableLocker = &sync.RWMutex{}
var regexpNamedVariable = regexp.MustCompile(`\${[@\w.|-]+}`)
2020-09-26 08:07:24 +08:00
2022-04-04 19:44:45 +08:00
var stringBuilderPool = sync.Pool{
2024-01-11 16:41:08 +08:00
New: func() any {
2022-04-04 19:44:45 +08:00
return &strings.Builder{}
},
}
2021-06-27 22:00:02 +08:00
// ParseVariables 分析变量
2020-09-26 08:07:24 +08:00
func ParseVariables(source string, replacer func(varName string) (value string)) string {
2022-04-04 16:42:56 +08:00
if len(source) == 0 {
return ""
}
2020-09-26 08:07:24 +08:00
variableLocker.RLock()
holders, found := variableMapping[source]
variableLocker.RUnlock()
if !found {
2021-06-27 22:00:02 +08:00
holders = ParseHolders(source)
2020-09-26 08:07:24 +08:00
variableLocker.Lock()
variableMapping[source] = holders
variableLocker.Unlock()
}
// no variables
if len(holders) == 0 {
return source
}
2021-12-13 15:31:03 +08:00
// 只有一个占位时,我们快速返回
if len(holders) == 1 {
var h = holders[0]
holder, ok := h.(VariableHolder)
if ok {
2024-01-11 16:41:08 +08:00
var value = replacer(holder.Param)
if holder.Modifiers != nil {
value = doStringModifiers(value, holder.Modifiers)
}
return replacer(value)
2021-12-13 15:31:03 +08:00
}
return source
}
// 多个占位时使用Builder
2022-04-04 19:44:45 +08:00
var builder = stringBuilderPool.Get().(*strings.Builder)
builder.Reset()
defer stringBuilderPool.Put(builder)
2020-09-26 08:07:24 +08:00
for _, h := range holders {
holder, ok := h.(VariableHolder)
if ok {
2024-01-11 16:41:08 +08:00
var value = replacer(holder.Param)
if holder.Modifiers != nil {
value = doStringModifiers(value, holder.Modifiers)
}
builder.WriteString(value)
2020-09-26 08:07:24 +08:00
} else {
2022-04-04 16:42:56 +08:00
builder.Write(h.([]byte))
2020-09-26 08:07:24 +08:00
}
}
2022-04-04 16:42:56 +08:00
return builder.String()
2020-09-26 08:07:24 +08:00
}
2020-09-26 19:54:20 +08:00
2023-06-28 16:19:05 +08:00
func ParseVariablesError(source string, replacer func(varName string) (value string, err error)) (string, error) {
var resultErr error
var result = ParseVariables(source, func(varName string) (value string) {
replacedValue, err := replacer(varName)
if err != nil {
resultErr = err
}
return replacedValue
})
return result, resultErr
}
2021-06-27 22:00:02 +08:00
// ParseVariablesFromHolders 从占位中分析变量
func ParseVariablesFromHolders(holders VariableHolders, replacer func(varName string) (value string)) string {
// no variables
if len(holders) == 0 {
return ""
}
// replace
2024-01-11 16:41:08 +08:00
var result = strings.Builder{}
2021-06-27 22:00:02 +08:00
for _, h := range holders {
holder, ok := h.(VariableHolder)
if ok {
2024-01-11 16:41:08 +08:00
var value = replacer(holder.Param)
if holder.Modifiers != nil {
value = doStringModifiers(value, holder.Modifiers)
}
result.WriteString(value)
2021-06-27 22:00:02 +08:00
} else {
result.Write(h.([]byte))
}
}
return result.String()
}
// ParseHolders 分析占位
func ParseHolders(source string) (holders VariableHolders) {
2024-01-11 16:41:08 +08:00
var indexes = regexpNamedVariable.FindAllStringIndex(source, -1)
var before = 0
2021-06-27 22:00:02 +08:00
for _, loc := range indexes {
holders = append(holders, []byte(source[before:loc[0]]))
2024-01-11 16:41:08 +08:00
var holder = source[loc[0]+2 : loc[1]-1]
if strings.Contains(holder, "|") {
var holderPieces = strings.Split(holder, "|")
holders = append(holders, VariableHolder{
Param: holderPieces[0],
Modifiers: holderPieces[1:],
})
} else {
holders = append(holders, VariableHolder{
Param: holder,
Modifiers: nil,
})
}
2021-06-27 22:00:02 +08:00
before = loc[1]
}
if before < len(source) {
holders = append(holders, []byte(source[before:]))
}
return holders
}
// HasVariables 判断是否有变量
2020-09-26 19:54:20 +08:00
func HasVariables(source string) bool {
2022-04-04 16:42:56 +08:00
if len(source) == 0 {
return false
}
2020-09-26 19:54:20 +08:00
return regexpNamedVariable.MatchString(source)
}
2024-01-11 16:41:08 +08:00
// 执行变量后的修饰符
func doStringModifiers(value string, modifiers []string) string {
for _, modifier := range modifiers {
switch modifier {
case "urlEncode":
value = url.QueryEscape(value)
case "urlDecode":
value2, err := url.QueryUnescape(value)
if err == nil {
value = value2
}
case "base64Encode":
value = base64.StdEncoding.EncodeToString([]byte(value))
case "base64Decode":
value2, err := base64.StdEncoding.DecodeString(value)
if err == nil {
value = string(value2)
}
case "md5":
value = stringutil.Md5(value)
case "sha1":
value = fmt.Sprintf("%x", sha1.Sum([]byte(value)))
case "sha256":
value = fmt.Sprintf("%x", sha256.Sum256([]byte(value)))
case "toLowerCase":
value = strings.ToLower(value)
case "toUpperCase":
value = strings.ToUpper(value)
2024-05-01 19:44:11 +08:00
case "quote":
value = strconv.Quote(value)
2024-01-11 16:41:08 +08:00
}
}
return value
}