Files

289 lines
8.2 KiB
Go

package automation
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"time"
)
func stringifyImportJSONValue(value any) string {
if value == nil {
return ""
}
if text, ok := value.(string); ok {
return strings.TrimSpace(text)
}
encoded, err := json.MarshalIndent(value, "", " ")
if err != nil {
return strings.TrimSpace(fmt.Sprint(value))
}
return string(bytes.TrimSpace(encoded))
}
func mergeDescriptorValue(target map[string]any, key string, value string) {
if strings.TrimSpace(value) == "" {
return
}
if _, exists := target[key]; exists {
return
}
target[key] = strings.TrimSpace(value)
}
func mapStringSliceValue(payload map[string]any, key string) []string {
raw, exists := payload[key]
if !exists || raw == nil {
return nil
}
items, ok := raw.([]any)
if !ok {
if stringsValue, ok := raw.([]string); ok {
return normalizeScriptTags(stringsValue)
}
return nil
}
result := make([]string, 0, len(items))
for _, item := range items {
value := strings.TrimSpace(fmt.Sprint(item))
if value != "" {
result = append(result, value)
}
}
return normalizeScriptTags(result)
}
func mapStringValueAny(payload map[string]any, key string) string {
if payload == nil {
return ""
}
value, exists := payload[key]
if !exists || value == nil {
return ""
}
return strings.TrimSpace(fmt.Sprint(value))
}
func mapIntValueAny(payload map[string]any, key string) int {
if payload == nil {
return 0
}
value, exists := payload[key]
if !exists || value == nil {
return 0
}
switch typed := value.(type) {
case int:
return typed
case int32:
return int(typed)
case int64:
return int(typed)
case float64:
return int(typed)
case json.Number:
if parsed, err := typed.Int64(); err == nil {
return int(parsed)
}
}
return 0
}
func mapObjectValue(payload map[string]any, key string) map[string]any {
if payload == nil {
return nil
}
value, exists := payload[key]
if !exists || value == nil {
return nil
}
if object, ok := value.(map[string]any); ok {
return object
}
return nil
}
func inferImportSource(sourceLabel string) ScriptSource {
now := time.Now().Format(time.RFC3339)
trimmed := strings.TrimSpace(sourceLabel)
source := ScriptSource{
ImportedAt: now,
}
switch {
case strings.HasPrefix(trimmed, "本地文件 "):
source.Type = "local-file"
source.URI = strings.TrimSpace(strings.TrimPrefix(trimmed, "本地文件 "))
case strings.HasPrefix(trimmed, "本地目录 "):
source.Type = "local-dir"
source.URI = strings.TrimSpace(strings.TrimPrefix(trimmed, "本地目录 "))
case strings.HasPrefix(trimmed, "远程地址 "):
source.Type = "remote-url"
source.URI = strings.TrimSpace(strings.TrimPrefix(trimmed, "远程地址 "))
case strings.HasPrefix(trimmed, "Git "):
source.Type = "git"
rest := strings.TrimSpace(strings.TrimPrefix(trimmed, "Git "))
repo := rest
if index := strings.Index(rest, " : "); index >= 0 {
source.Path = strings.TrimSpace(rest[index+3:])
repo = strings.TrimSpace(rest[:index])
}
if index := strings.Index(repo, " @ "); index >= 0 {
source.Ref = strings.TrimSpace(repo[index+3:])
repo = strings.TrimSpace(repo[:index])
}
source.URI = repo
default:
if trimmed != "" {
source.Type = "manual"
source.URI = trimmed
}
}
return source
}
func mergeImportedSource(base ScriptSource, override map[string]any) ScriptSource {
if override == nil {
return base
}
next := base
if value := mapStringValueAny(override, "type"); value != "" {
next.Type = value
}
if value := firstNonEmpty(mapStringValueAny(override, "uri"), mapStringValueAny(override, "url")); value != "" {
next.URI = value
}
if value := mapStringValueAny(override, "ref"); value != "" {
next.Ref = value
}
if value := mapStringValueAny(override, "path"); value != "" {
next.Path = value
}
if value := mapStringValueAny(override, "importedAt"); value != "" {
next.ImportedAt = value
}
return next
}
func mapScriptTargetConfigValue(value any) ScriptTargetConfig {
object, ok := value.(map[string]any)
if !ok || object == nil {
return ScriptTargetConfig{}
}
return ScriptTargetConfig{
Mode: mapStringValueAny(object, "mode"),
Selector: mapScriptTargetSelectorValue(object["selector"]),
TemplateSelector: mapScriptTargetSelectorValue(object["templateSelector"]),
CreateNameTemplate: mapStringValueAny(object, "createNameTemplate"),
}
}
func mapScriptPublicAPIValue(value any) ScriptPublicAPIConfig {
object, ok := value.(map[string]any)
if !ok || object == nil {
return ScriptPublicAPIConfig{}
}
return ScriptPublicAPIConfig{
Enabled: mapBoolValueAny(object, "enabled"),
Method: mapStringValueAny(object, "method"),
Path: firstNonEmpty(mapStringValueAny(object, "path"), mapStringValueAny(object, "route")),
RequestMode: mapStringValueAny(object, "requestMode"),
ResponseMode: mapStringValueAny(object, "responseMode"),
TimeoutMs: mapIntValueAny(object, "timeoutMs"),
RequestBodyText: stringifyImportJSONValue(firstNonNil(object["requestBodyText"], object["requestBody"], object["requestExample"])),
ResponseBodyText: stringifyImportJSONValue(firstNonNil(object["responseBodyText"], object["responseBody"], object["responseExample"])),
Variables: mapScriptPublicAPIVariablesValue(object["variables"]),
}
}
func mapScriptPublicAPIVariablesValue(value any) []ScriptPublicAPIVariable {
switch typed := value.(type) {
case []ScriptPublicAPIVariable:
return normalizeScriptPublicAPIVariables(typed)
case []any:
variables := make([]ScriptPublicAPIVariable, 0, len(typed))
for _, item := range typed {
object, ok := item.(map[string]any)
if !ok || object == nil {
continue
}
variables = append(variables, ScriptPublicAPIVariable{
Name: firstNonEmpty(mapStringValueAny(object, "name"), mapStringValueAny(object, "key")),
DefaultValue: firstNonEmpty(mapStringValueAny(object, "defaultValue"), mapStringValueAny(object, "default"), mapStringValueAny(object, "value")),
Description: firstNonEmpty(mapStringValueAny(object, "description"), mapStringValueAny(object, "label"), mapStringValueAny(object, "note")),
Required: mapBoolValueAny(object, "required"),
})
}
return normalizeScriptPublicAPIVariables(variables)
case map[string]any:
variables := make([]ScriptPublicAPIVariable, 0, len(typed))
for key, rawValue := range typed {
variable := ScriptPublicAPIVariable{Name: key}
if object, ok := rawValue.(map[string]any); ok && object != nil {
variable.DefaultValue = firstNonEmpty(mapStringValueAny(object, "defaultValue"), mapStringValueAny(object, "default"), mapStringValueAny(object, "value"))
variable.Description = firstNonEmpty(mapStringValueAny(object, "description"), mapStringValueAny(object, "label"), mapStringValueAny(object, "note"))
variable.Required = mapBoolValueAny(object, "required")
} else if rawValue != nil {
variable.DefaultValue = strings.TrimSpace(fmt.Sprint(rawValue))
}
variables = append(variables, variable)
}
return normalizeScriptPublicAPIVariables(variables)
default:
return nil
}
}
func mapScriptTargetSelectorValue(value any) ScriptTargetSelector {
object, ok := value.(map[string]any)
if !ok || object == nil {
return ScriptTargetSelector{}
}
return ScriptTargetSelector{
Code: firstNonEmpty(mapStringValueAny(object, "code"), mapStringValueAny(object, "launchCode")),
ProfileID: mapStringValueAny(object, "profileId"),
ProfileName: mapStringValueAny(object, "profileName"),
GroupID: mapStringValueAny(object, "groupId"),
Keywords: mapStringSliceValue(object, "keywords"),
Tags: mapStringSliceValue(object, "tags"),
}
}
func mapBoolValueAny(payload map[string]any, key string) bool {
if payload == nil {
return false
}
value, exists := payload[key]
if !exists || value == nil {
return false
}
switch typed := value.(type) {
case bool:
return typed
case string:
switch strings.ToLower(strings.TrimSpace(typed)) {
case "true", "1", "yes", "enabled", "on":
return true
}
case float64:
return typed != 0
case int:
return typed != 0
case int64:
return typed != 0
}
return false
}
func firstNonNil(values ...any) any {
for _, value := range values {
if value != nil {
return value
}
}
return nil
}