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
|
|
|
|
|
|
}
|