Files

210 lines
6.0 KiB
Go

package automation
import (
"encoding/base64"
"encoding/json"
"fmt"
"sort"
"strings"
"unicode/utf8"
)
type scriptTemplateFile struct {
Path string `json:"path"`
Content string `json:"content"`
Encoding string `json:"encoding,omitempty"`
}
func MarshalScriptPackageManifest(record ScriptRecord) ([]byte, error) {
normalized, err := normalizeScriptRecord(record, ScriptRecord{})
if err != nil {
return nil, err
}
payload := map[string]any{
"format": normalized.PackageFormat,
"packageFormat": normalized.PackageFormat,
"manifestVersion": normalized.ManifestVersion,
"id": normalized.ID,
"name": normalized.Name,
"description": normalized.Description,
"type": normalized.Type,
"status": normalized.Status,
"entryFile": normalized.EntryFile,
"tags": append([]string{}, normalized.Tags...),
"notes": normalized.Notes,
"targetConfig": normalized.TargetConfig,
"publicAPI": normalized.PublicAPI,
"source": map[string]any{
"type": normalized.Source.Type,
"uri": normalized.Source.URI,
"ref": normalized.Source.Ref,
"path": normalized.Source.Path,
"importedAt": normalized.Source.ImportedAt,
},
"createdAt": normalized.CreatedAt,
"updatedAt": normalized.UpdatedAt,
}
if selectorValue := parseScriptTemplateJSON(normalized.SelectorText); selectorValue != nil {
payload["selector"] = selectorValue
}
if paramsValue := parseScriptTemplateJSON(normalized.ParamsText); paramsValue != nil {
payload["params"] = paramsValue
}
return json.MarshalIndent(payload, "", " ")
}
func MarshalScriptTemplate(bundle ImportedBundle) ([]byte, error) {
record, err := normalizeScriptRecord(bundle.Record, ScriptRecord{})
if err != nil {
return nil, err
}
files, err := buildTemplateFiles(bundle.Files, record.EntryFile)
if err != nil {
return nil, err
}
envelope := scriptImportEnvelope{
Format: record.PackageFormat,
PackageFormat: record.PackageFormat,
ManifestVersion: record.ManifestVersion,
Manifest: map[string]any{
"packageFormat": record.PackageFormat,
"manifestVersion": record.ManifestVersion,
"id": record.ID,
"name": record.Name,
"description": record.Description,
"type": record.Type,
"status": record.Status,
"entryFile": record.EntryFile,
"tags": append([]string{}, record.Tags...),
"notes": record.Notes,
"targetConfig": record.TargetConfig,
"publicAPI": record.PublicAPI,
"source": record.Source,
"createdAt": record.CreatedAt,
"updatedAt": record.UpdatedAt,
},
ScriptText: record.ScriptText,
Notes: record.Notes,
PublicAPI: map[string]any{
"enabled": record.PublicAPI.Enabled,
"method": record.PublicAPI.Method,
"path": record.PublicAPI.Path,
"requestMode": record.PublicAPI.RequestMode,
"responseMode": record.PublicAPI.ResponseMode,
"timeoutMs": record.PublicAPI.TimeoutMs,
"requestBodyText": record.PublicAPI.RequestBodyText,
"responseBodyText": record.PublicAPI.ResponseBodyText,
"variables": record.PublicAPI.Variables,
},
Source: map[string]any{
"type": record.Source.Type,
"uri": record.Source.URI,
"ref": record.Source.Ref,
"path": record.Source.Path,
"importedAt": record.Source.ImportedAt,
},
Files: files,
}
if selectorValue := parseScriptTemplateJSON(record.SelectorText); selectorValue != nil {
envelope.Selector = selectorValue
}
if paramsValue := parseScriptTemplateJSON(record.ParamsText); paramsValue != nil {
envelope.Params = paramsValue
}
return json.MarshalIndent(envelope, "", " ")
}
func decodeScriptTemplateFiles(files []scriptTemplateFile, entryFile string) ([]ImportedBundleFile, error) {
entryFile = strings.TrimSpace(entryFile)
result := make([]ImportedBundleFile, 0, len(files))
for _, file := range files {
normalizedPath, err := normalizeBundleFilePath(file.Path)
if err != nil {
return nil, err
}
if normalizedPath == entryFile {
continue
}
content, err := decodeScriptTemplateFileContent(file)
if err != nil {
return nil, fmt.Errorf("decode template file %s failed: %w", normalizedPath, err)
}
result = append(result, ImportedBundleFile{
Path: normalizedPath,
Content: content,
})
}
sort.Slice(result, func(i, j int) bool {
return result[i].Path < result[j].Path
})
return result, nil
}
func buildTemplateFiles(files []ImportedBundleFile, entryFile string) ([]scriptTemplateFile, error) {
entryFile = strings.TrimSpace(entryFile)
items := make([]scriptTemplateFile, 0, len(files))
for _, file := range files {
normalizedPath, err := normalizeBundleFilePath(file.Path)
if err != nil {
return nil, err
}
if normalizedPath == entryFile || normalizedPath == scriptStoreConfigFileName {
continue
}
content, encoding := encodeScriptTemplateFileContent(file.Content)
items = append(items, scriptTemplateFile{
Path: normalizedPath,
Content: content,
Encoding: encoding,
})
}
sort.Slice(items, func(i, j int) bool {
return items[i].Path < items[j].Path
})
return items, nil
}
func encodeScriptTemplateFileContent(content []byte) (string, string) {
if utf8.Valid(content) {
return string(content), "utf8"
}
return base64.StdEncoding.EncodeToString(content), "base64"
}
func decodeScriptTemplateFileContent(file scriptTemplateFile) ([]byte, error) {
switch strings.TrimSpace(strings.ToLower(file.Encoding)) {
case "", "utf8", "text":
return []byte(file.Content), nil
case "base64":
return base64.StdEncoding.DecodeString(strings.TrimSpace(file.Content))
default:
return nil, fmt.Errorf("unsupported encoding %q", file.Encoding)
}
}
func parseScriptTemplateJSON(text string) any {
trimmed := strings.TrimSpace(text)
if trimmed == "" {
return nil
}
var decoded any
if err := json.Unmarshal([]byte(trimmed), &decoded); err != nil {
return trimmed
}
return decoded
}