从 OpenWrt 22.x 开始,LuCI 的实现逐渐从 Lua 迁移到 ubus + ucode + JavaScript (client-side JS):

旧版 (≤21.02)

/usr/lib/lua/luci/      ← 主要的 Lua MVC 框架代码
/usr/lib/lua/luci/controller/
/usr/lib/lua/luci/model/
/usr/lib/lua/luci/view/

新版 (22.03 / 23.05 / 24.x)

/www/luci-static/resources/       ← 前端 JS/HTML/CSS 资源,用于生成网页菜单
/usr/share/luci/menu.d/           ← 网页菜单项,即菜单入口
/usr/share/rpcd/acl.d/            ← ACL 菜单访问权限 JSON 定义
/usr/share/rpcd/ucode/            → rpcd 插件(系统后端 RPC 接口(比如 UCI、文件操作、iwinfo 等),供所有 RPC 客户端(包括 LuCI)调用)
/usr/share/ucode/luci/            → LuCI 专用 ucode 模块(提供 UI 配置页面所需的功能,比如:表单生成、数据校验、调用 rpcd 接口等)

所以opkg软件源中很多luci-app-xxx的界面软件包都没了,为了能够在菜单中灵活切换v2ray的运行模式,进行了相关研究。

0)我在/etc/config/advancedconfig文件中定义了v2ray的三种运行模式:

config rules
	option v2raymode 'outlands'

其中:

a)境外全局代理模式,即所有国外网站(非国内ip段)都走代理,对应值:outlands

b)白名单代理模式,即所有被墙的网站(白名单中的网站)都走代理,对应值:gfwlist

c)墙内无代理模式,即跟平常没有代理上网一样,对应值:ingfw

这三种模式对应了/etc/init.d/v2ray中的配置,详见这里,为了能通过菜单进行模式切换,就需要创建菜单。

1)创建菜单项json(/usr/share/luci/menu.d/luci-app-advancedconfig.json)

{
  "admin/services/advancedconfig": {
    "title": "v2ray",
    "action": {
      "type": "view",
      "path": "advancedconfig"
    },
    "depends": { 
      "acl": [ "luci-app-advancedconfig" ],
      "uci": { "advancedconfig": true } 
    }
  }
}

2)创建菜单页面js(/www/luci-static/resources/view/advancedconfig.js)

'use strict';
'require view';
'require form';
'require uci';
'require rpc';

// 定义一个 RPC 调用,用来执行 /etc/init.d/v2ray restart
var callExec = rpc.declare({
    object: 'file',
    method: 'exec',
    params: [ 'command', 'params' ],
    expect: { code: 0 }
});

return view.extend({
    render: function() {
        // Map 对象名称必须和 UCI 文件名一致
        var m = new form.Map('advancedconfig', _('v2ray'), _('Advanced config for v2ray'));

        // 对应 config rules
        var s = m.section(form.TypedSection, 'rules', _('Rules'));
        s.anonymous = true;

        // 下拉选项
        var o = s.option(form.ListValue, 'v2raymode', _('代理模式'));
        o.value('outlands', _('境外全局代理模式(Outlands Mode)'));
        o.value('gfwlist', _('白名单代理模式 (GFWlist Mode)'));
        o.value('ingfw', _('墙内无代理模式 (China Mode)'));

        // write 函数:只有值变化才写入 UCI 内存
        o.write = function(section_id, formvalue) {
            var oldVal = this.cfgvalue(section_id);
            if (oldVal === formvalue)
                return;
            return uci.set('advancedconfig', section_id, 'v2raymode', formvalue);
        };

        // 保存时执行 uci commit + restart
        m.oncommit = function() {
            return callExec('/etc/init.d/v2ray', ['restart', 'force']);
        };

        return m.render();
    }

});

此步完成以后需要重启rpcd服务:

/etc/init.d/rpcd restart

3)创建ACL权限json(/usr/share/rpcd/acl.d/luci-app-advancedconfig.json)

{
  "luci-app-advancedconfig": {
    "description": "Grant UCI access for luci-app-advancedconfig",
    "read": {
      "file": { "/etc/config/advancedconfig": ["read"] },
      "uci": ["advancedconfig"]
    },
    "write": {
      "file": { "/etc/config/advancedconfig": ["write"] },
      "uci": ["advancedconfig"]
    },
    "exec": {
      "file": {
        "/etc/init.d/v2ray": [ "exec" ]
      }
    }
  }
}

最终菜单界面如下:

v2ray模式菜单

参考:

1)chatgpt

2)luci-app-samba4的配置文件