# 配置文件预处理

# 版本要求

0.10.1 版本更新后,支持使用 JavaScript 对下载后的配置文件进行预处理

0.11.10 版本更新后,支持使用 YAML 对下载后配置文件进行简单预处理

# 简便方法(YAML)

如果需要对下载地址为https://example.com/profile.yaml的配置文件进行预处理,操作如下:

  1. 进入 Settings 界面

  2. 滚动至 Profiles 栏

  3. 点击 Parsers 右边 Edit 打开编辑器,填入:

    parsers:
      - url: https://example.com/profile.yaml
        yaml:
          prepend-rules:
            - DOMAIN,test.com,DIRECT # rules最前面增加一个规则
          append-proxies:
            - name: test # proxies最后面增加一个服务
              type: http
              server: 123.123.123.123
              port: 456
    
  4. 点击编辑器右下角保存按钮

当配置文件触发刷新(包括自动更新)时,CFW 会读取yaml字段定义的值,将对应值插入/合并到原配置文件中

# 参数说明

值类型 操作
append-rules 数组 数组合并至原配置rules数组
prepend-rules 数组 数组合并至原配置rules数组
append-proxies 数组 数组合并至原配置proxies数组
prepend-proxies 数组 数组合并至原配置proxies数组
append-proxy-groups 数组 数组合并至原配置proxy-groups数组
prepend-proxy-groups 数组 数组合并至原配置proxy-groups数组
mix-proxy-providers 对象 对象合并至原配置proxy-providers
mix-rule-providers 对象 对象合并至原配置rule-providers
mix-object 对象 对象合并至原配置最外层中
commands 数组 在上面操作完成后执行简单命令操作配置文件

# Commands 使用方法(beta)

commands 是一组简单的命令,作为上面操作的补充

例子:

commands:
  - dns.enable=false # 命令1
  - proxy-groups.0.proxies.2+DIRECT # 命令2

每个命令可以被分为三个部分,分别是:定位+操作+设定值

命令 1 中,定位是dns.enable,操作是=,设定值是false

命令 2 中,定位是proxy-groups.0.proxies.2,操作是+,设定值是DIRECT

# 定位

定位中每个层级以.分割,数组类型的定位下标由 0 开始计算,命令 2 中proxy-groups.0即表示定位至第 1 个策略组,.proxies表示访问第一个策略组的 proxies 属性,.proxies.2表示 proxies 属性的第 3 个位置

如果不想用序号定位,也可以使用name值定位,proxies以及proxy-groups中的每个项目都会有name属性。例如在proxies中已经定义了名为debug的节点,那么修改其udp参数的定位即为proxies.(debug).udp,名称两边的()是保证识别,如果节点名不包括+.=这几个符号,也可以省略不写

# 操作

目前支持三种操作:

  • =:覆盖
  • +:插入
  • -:删除

命令 1 中,=表示将dnsenable的值覆盖为false

命令 2 中,+表示在定位的策略组中的proxies数组中添加一个名为DIRECT的值,原本其他值被向后移动 1 位。如果此处改成=,则会覆盖原来第一个值

# 设定值

设定值是用于插入或覆盖的值,如果操作是-,则此值可有可无,例如:

commands:
  - proxies.0- # 命令3

此处可以将配置文件proxies的第 1 个节点删除

如果设定值为纯数字,则会被识别为整数,为true|false则识别为布尔类型,如果 JSON 编码通过则识别为对象

v0.13.7 版本更新后,支持 3 个内置值用于设置策略组节点,分别是[]proxyNames[]groupNames[]shuffledProxyNames,并支持使用正则过滤其中节点,例子如下:

yaml:
  prepend-proxy-groups:
    - name: myGroup # 建立新策略组
      type: fallback
      url: "http://www.gstatic.com/generate_204"
      interval: 300
      proxies:
        - DIRECT

  commands:
    - proxy-groups.myGroup.proxies=[]proxyNames|HK # 向策略组添加所有定义的节点名,并按“HK”正则表达式过滤

# 进阶方法(JavaScript)

如果需要对下载地址为https://example.com/profile.yaml的配置文件进行预处理,操作如下:

  1. 进入 Settings 界面

  2. 滚动至 Profiles 栏

  3. 点击 Parsers 右边 Edit 打开编辑器,填入:

    parsers:
      - url: https://example.com/profile.yaml
        code: |
          module.exports.parse = async (raw, { axios, yaml, notify, console }, { name, url, interval, selected }) => {
            const obj = yaml.parse(raw)
            return yaml.stringify(obj)
          }
    
  4. 点击编辑器右下角保存按钮

当配置文件触发刷新(包括自动更新)时,CFW 会调用此方法对下载的配置文件内容进行处理,再写入本地文件中

当然,parsers 也支持使用路径引入代码:

parsers:
  - url: https://example.com/profile.yaml
    file: "C:/Users/cfw/parser.js"

TIP

使用文件时,允许调用该文件目录下的 node_modules 模块

版本 0.20.10 开始支持从远端获取

parsers:
  - url: https://example.com/profile.yaml
    remote:
      url: https://gist.githubusercontent.com/Fndroid/40e6117252f794aa629b875aa1ecadea/raw/d1ba6d230746c9d2ecfbef211c52fd9a567a781e/parser.js
      cache: true # 默认为false,指示是否对重复下载此预处理代码使用缓存

注意

使用远端配置请选择可信的代码提供者,如不能信任代码提供者,可以从远端拷贝代码然后使用code填入而非使用remote方式引入!

# 参数说明

CFW 调用用户定义的parse方法时,会传入 3 个参数,分别是配置文件文本内容工具类对象/方法以及配置文件元数据

# 配置文件文本内容

raw 是一个字符串,一般需要用 yaml 库解析成 JavaScript 对象

# 工具类对象/方法

包括:

  • axios:网络请求框架,GitHub (opens new window)
  • yaml:yaml 框架,GitHub (opens new window)
  • notify:发出系统通知方法,签名为function notify(title:string, message:string, silent:bool)
  • console:日志输出至文件,方便调试,在 Settings 界面中 Parser 设置下方打开
  • homeDir:Home Directory 目录

TIP

除了以上工具类,在使用.js文件时,也可以通过npm引入第三方模块

# 配置文件元数据

元数据为 JavaScript 对象,包括:

  • name:名称
  • url:下载地址
  • interval:更新周期
  • selected:策略组选择缓存,数组
  • mode:模式缓存

TIP

元数据在配置文件首次下载时只有 url 参数

# 返回说明

parse方法需要返回一个字符串,CFW 会将返回的字符串存入对应的配置文件中

# 多处理器及正则匹配

# 正则匹配

上面例子中,使用url匹配配置文件地址,如果一个处理器需要处理多个配置文件,也可以使用正则表达式进行匹配,使用关键字reg设置

parsers:
  - reg: https://test.com.+$ # 正则匹配域名
    yaml:
      prepend-rules:
        - DOMAIN,test.com,DIRECT

# 多处理器

parser 定义的数组支持多个处理器从上至下按顺序执行,例如:

parsers:
  - reg: https://test.com.+$ # 第一个执行的parser
    file: "C:/Users/cfw/parser.yaml"
  - url: https://example.com/profile.yaml # 对上一个parser执行的结果进行处理
    file: "C:/Users/cfw/parser.js"

TIP

file 同时支持 yaml 及 js 格式的文件

# 使用案例

# 向本地配置文件添加订阅信息

  1. 准备一个本地配置文件的副本,记下文件名和路径。为方便后续说明,以下用myprofile.yml指代此文件名,用C:\...\myprofile.yml指代此文件路径。

NOTICE

配置完成后,此副本文件将作为 CFW 配置文件的订阅源使用,对配置文件的非临时性修改需要在此副本文件中进行编辑,并在修改后执行订阅更新。移动、重命名此文件后需要修改 CFW 中相应的配置选项。

TIP

此处使用 CFW 创建的配置文件本身而非副本作为订阅源虽然可以实现相同的功能,但无法保证运行时的可靠性,如果没有特殊情况不建议这样使用。

  1. 准备一个包含订阅信息subscription-userinfo (opens new window)的订阅链接。为方便后续说明,以下用https://example.com/subscription_url指代此订阅链接。

TIP

可使用curl -I 'https://example.com/subscription_url'检查订阅链接是否包含订阅信息。

  1. 修改 CFW 中的配置文件选项,在URL中填写副本文件的本地映射地址file:///C:\...\myprofile.yml。保存后执行订阅更新并确保没有报错。

  2. 添加对应的预处理脚本,并确保正常匹配到配置文件。

parsers: # array
  - reg: "myprofile.yml"
    code: |
      module.exports.parse = async (raw, { axios, yaml, notify, console }) => {
        raw = raw.replace(/# upload=\d*; download=\d*; total=\d*; expire=\d*;*\n/gm,'')
        const url = 'https://example.com/subscription_url'
        let { headers:{"subscription-userinfo": si = ""}={}, status } = await axios.head(url)
        si = si.replace(/;*$/g,'')
        if (status === 200 && si) {
          return `# ${si};\n${raw}`
        }
        return raw
      }
  1. 执行订阅更新,配置文件模块中出现订阅信息即说明配置成功。

TIP

配置完成后可自行设置自动更新选项。