在新版luci页面中创建菜单用于切换v2ray运行模式
从 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" ]
}
}
}
}
最终菜单界面如下:
参考:
1)chatgpt
2)luci-app-samba4的配置文件