Files
Ant-Browser/backend/automation_script_import_source.go

93 lines
3.2 KiB
Go

package backend
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"path/filepath"
"strings"
"time"
"ant-chrome/backend/internal/automation"
)
const (
automationRemoteImportTimeout = 20 * time.Second
maxAutomationRemoteScriptSize = 16 << 20
)
func (a *App) loadAutomationBundleFromSource(source automation.ScriptSource) (automation.ImportedBundle, error) {
sourceType := strings.TrimSpace(source.Type)
switch sourceType {
case "builtin":
return automation.ImportBuiltinBundleFromSource(source)
case "local-file":
path := firstNonBlank(source.URI, source.Path)
if path == "" {
return automation.ImportedBundle{}, fmt.Errorf("本地脚本文件路径缺失")
}
return automation.ImportBundleFromFileWithOptions(path, buildAutomationImportSourceLabel(source), a.automationScriptImportOptions())
case "local-dir":
path := firstNonBlank(source.URI, source.Path)
if path == "" {
return automation.ImportedBundle{}, fmt.Errorf("本地脚本目录路径缺失")
}
return automation.ImportBundleFromDirectoryWithOptions(path, "", buildAutomationImportSourceLabel(source), a.automationScriptImportOptions())
case "remote-url":
return a.loadAutomationRemoteBundle(source.URI)
case "git":
return a.loadAutomationGitBundle(source.URI, source.Ref, source.Path)
case "manual", "text", "":
return automation.ImportedBundle{}, fmt.Errorf("当前脚本来源不支持重新导入")
default:
return automation.ImportedBundle{}, fmt.Errorf("当前脚本来源 %q 不支持重新导入", sourceType)
}
}
func (a *App) loadAutomationRemoteBundle(rawURL string) (automation.ImportedBundle, error) {
normalizedURL := strings.TrimSpace(rawURL)
if normalizedURL == "" {
return automation.ImportedBundle{}, fmt.Errorf("远程脚本地址不能为空")
}
parsedURL, err := url.Parse(normalizedURL)
if err != nil || parsedURL.Scheme == "" || parsedURL.Host == "" {
return automation.ImportedBundle{}, fmt.Errorf("远程脚本地址不合法")
}
ctx, cancel := context.WithTimeout(context.Background(), automationRemoteImportTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, normalizedURL, nil)
if err != nil {
return automation.ImportedBundle{}, fmt.Errorf("创建远程脚本请求失败: %w", err)
}
resp, err := (&http.Client{Timeout: automationRemoteImportTimeout}).Do(req)
if err != nil {
return automation.ImportedBundle{}, fmt.Errorf("下载远程脚本失败: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
return automation.ImportedBundle{}, fmt.Errorf("下载远程脚本失败: HTTP %d", resp.StatusCode)
}
data, err := io.ReadAll(io.LimitReader(resp.Body, maxAutomationRemoteScriptSize+1))
if err != nil {
return automation.ImportedBundle{}, fmt.Errorf("读取远程脚本失败: %w", err)
}
if len(data) > maxAutomationRemoteScriptSize {
return automation.ImportedBundle{}, fmt.Errorf("远程脚本文件过大")
}
nameHint := filepath.Base(parsedURL.Path)
if nameHint == "" || nameHint == "." || nameHint == "/" {
nameHint = "remote-script.cjs"
}
return automation.ImportBundleFromBytesWithOptions(nameHint, data, "远程地址 "+normalizedURL, a.automationScriptImportOptions())
}