diff --git a/core/src/main/golang/native/config/fetch.go b/core/src/main/golang/native/config/fetch.go index ba08ebcc..1e1ac4dc 100644 --- a/core/src/main/golang/native/config/fetch.go +++ b/core/src/main/golang/native/config/fetch.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "fmt" + "github.com/metacubex/mihomo/log" + "gopkg.in/yaml.v3" "io" "net/http" U "net/url" @@ -34,6 +36,36 @@ func openUrl(ctx context.Context, url string) (io.ReadCloser, error) { return response.Body, nil } +func openUrlAsString(ctx context.Context, url string) (string, error) { + body, requestErr := openUrl(ctx, url) + + if requestErr != nil { + return "", requestErr + } + + // 读取所有数据并转换为byte数组 + data, err := io.ReadAll(body) + defer body.Close() + if err != nil { + return "", err + } + // 将数据转为字符串 + content := string(data) + return content, nil +} + +func openUrlAsYaml(ctx context.Context, url string) (map[string]interface{}, error) { + content, _ := openUrlAsString(ctx, url) + // 定义一个结构体来存储 YAML 解析结果 + var config map[string]interface{} // 假设 config 是一个 map + // 解析 YAML 内容 + err := yaml.Unmarshal([]byte(content), &config) + if err != nil { + return nil, err + } + return config, nil +} + func openContent(url string) (io.ReadCloser, error) { return app.OpenContent(url) } @@ -60,6 +92,14 @@ func fetch(url *U.URL, file string) error { defer reader.Close() + data, err := io.ReadAll(reader) + if err != nil { + return err + } + content := string(data) + parsedContent := applyParsers(ctx, content, url) + log.Debugln("最终subscribe:%s", parsedContent) + _ = os.MkdirAll(P.Dir(file), 0700) f, err := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600) @@ -69,7 +109,7 @@ func fetch(url *U.URL, file string) error { defer f.Close() - _, err = io.Copy(f, reader) + _, err = f.WriteString(parsedContent) if err != nil { _ = os.Remove(file) } @@ -77,6 +117,81 @@ func fetch(url *U.URL, file string) error { return err } +func applyParsers(ctx context.Context, subscribeOriginalStr string, subscribeUrl *U.URL) string { + if !subscribeUrl.Query().Has("parsers") { + log.Debugln("需要处理parsers") + return subscribeOriginalStr + } + + // 定义一个结构体来存储 YAML 解析结果 + var subscribe map[string]interface{} + + // 解析 YAML 内容 + err := yaml.Unmarshal([]byte(subscribeOriginalStr), &subscribe) + if err != nil { + // 如果解析出错,返回错误信息作为字符串 + log.Debugln("failed to parse YAML: %v", err) + return fmt.Sprintf("failed to parse YAML: %v", err) + } + + var parsersUrl = subscribeUrl.Query().Get("parsers") + log.Debugln("找到parsersURL: %s", parsersUrl) + parsersContainerYml, parsersErr := openUrlAsYaml(ctx, parsersUrl) + if parsersErr != nil { + log.Debugln("拉取parsers失败: %v", parsersErr) + return subscribeOriginalStr + } + + parsersContainer, parsersContainerExist := parsersContainerYml["parsers"].(map[string]interface{}) + if !parsersContainerExist { + log.Debugln("parsers容器中不存在parsers节点") + return subscribeOriginalStr + } + + parsers, parsersExist := parsersContainer["yaml"].(map[string]interface{}) + if !parsersExist { + log.Debugln("parsers容器中不存在yaml节点") + return subscribeOriginalStr + } + + subscribe = prependArr(subscribe, "proxies", parsers, "prepend-proxies") + subscribe = prependArr(subscribe, "proxy-groups", parsers, "prepend-proxy-groups") + subscribe = prependArr(subscribe, "rules", parsers, "prepend-rules") + + // 将解析后的数据结构转回 YAML 格式的字符串 + yamlBytes, err := yaml.Marshal(subscribe) + if err != nil { + log.Debugln("failed to marshal YAML: %v", err) + return fmt.Sprintf("failed to marshal YAML: %v", err) + } + + // 返回解析后的 YAML 字符串 + return string(yamlBytes) +} + +func prependArr(subscribe map[string]interface{}, subscribeKey string, parsers map[string]interface{}, parserKey string) map[string]interface{} { + // 处理prepend-rules + if arrToPrepend, arrToPrependExist := parsers[parserKey].([]interface{}); arrToPrependExist { + log.Debugln("parses找到%s", parserKey) + // 提取 originalArr 字段 + if originalArr, originalArrExist := subscribe[subscribeKey].([]interface{}); originalArrExist { + log.Debugln("subscribe找到%s", subscribeKey) + // 将新的规则添加到 originalArr 数组的头部 + log.Debugln("subscribe原始%s:%v", subscribeKey, originalArr) + originalArr = append(arrToPrepend, originalArr...) + // 更新 subscribe 中的 originalArr 字段 + subscribe[subscribeKey] = originalArr + log.Debugln("subscribe编辑后%s:%v", subscribeKey, subscribe[subscribeKey]) + } else { + subscribe[subscribeKey] = arrToPrepend + log.Debugln("subscribe编辑后%s:%v", subscribeKey, subscribe[subscribeKey]) + } + } else { + log.Debugln("parses未找到%s", parserKey) + } + return subscribe +} + func FetchAndValid( path string, url string,