mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-13 20:08:05 +08:00
🤞 Sync 2026-11-10 21:15:30
This commit is contained in:
1 parent
42de8331af
commit
4a38dae8ff
27 files changed
+1281
-235
No files matched your search
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=luci-app-passwall
|
PKG_NAME:=luci-app-passwall
|
||||||
PKG_VERSION:=26.11.3
|
PKG_VERSION:=26.11.3
|
||||||
PKG_RELEASE:=373
|
PKG_RELEASE:=374
|
||||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||||
|
|
||||||
PKG_CONFIG_DEPENDS:= \
|
PKG_CONFIG_DEPENDS:= \
|
||||||
|
|||||||
@@ -362,16 +362,22 @@ function gen_outbound(flag, node, tag, proxy_table)
|
|||||||
["User-Agent"] = node.user_agent
|
["User-Agent"] = node.user_agent
|
||||||
} or nil,
|
} or nil,
|
||||||
}
|
}
|
||||||
local path = api.UrlDecode(node.ws_path)
|
local path, query = (node.ws_path or "/"):match("^(.-)%?(.*)$")
|
||||||
local path_dat = api.split(path, "?")
|
local params, query_params = {}, {}
|
||||||
local params = {}
|
for v in (query or ""):gmatch("[^&]+") do
|
||||||
for _, v in pairs(api.split(path_dat[2], '&')) do
|
local t = api.split(api.UrlDecode(v), '=')
|
||||||
local t = api.split(v, '=')
|
|
||||||
params[t[1]] = t[2]
|
params[t[1]] = t[2]
|
||||||
|
if t[1] ~= "ed" and t[1] ~= "eh" then
|
||||||
|
table.insert(query_params, v)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local ed = tonumber(params.ed)
|
local ed = tonumber(params.ed)
|
||||||
if ed then
|
if ed then
|
||||||
v2ray_transport.path = path_dat[1]
|
-- Consume early-data options while preserving the remaining query.
|
||||||
|
v2ray_transport.path = path
|
||||||
|
if #query_params > 0 then
|
||||||
|
v2ray_transport.path = path .. "?" .. table.concat(query_params, "&")
|
||||||
|
end
|
||||||
v2ray_transport.max_early_data = ed
|
v2ray_transport.max_early_data = ed
|
||||||
end
|
end
|
||||||
v2ray_transport.early_data_header_name = params.eh or "Sec-WebSocket-Protocol"
|
v2ray_transport.early_data_header_name = params.eh or "Sec-WebSocket-Protocol"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ local GLOBAL = {
|
|||||||
|
|
||||||
local xray_version = api.get_app_version("xray")
|
local xray_version = api.get_app_version("xray")
|
||||||
|
|
||||||
local xray_min_version = "26.7.11"
|
local xray_min_version = "26.9.9"
|
||||||
|
|
||||||
local function get_domain_excluded()
|
local function get_domain_excluded()
|
||||||
local path = string.format("/etc/%s/rules/domains_excluded", api.c_config)
|
local path = string.format("/etc/%s/rules/domains_excluded", api.c_config)
|
||||||
@@ -355,6 +355,30 @@ function gen_outbound(flag, node, tag, proxy_table)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
udp[#udp+1] = r
|
udp[#udp+1] = r
|
||||||
|
elseif node.hysteria2_hop and node.hysteria2_hop ~= "" then
|
||||||
|
udp[#udp+1] = {
|
||||||
|
type = "udphop",
|
||||||
|
settings = {
|
||||||
|
mode = "intervallocal,intervalremote",
|
||||||
|
remotePorts = string.gsub(node.hysteria2_hop, ":", "-"),
|
||||||
|
interval = (function(v)
|
||||||
|
if not v then return 30 end
|
||||||
|
if v:find("-", 1, true) then
|
||||||
|
local min, max = v:match("^(%d+)%-(%d+)$")
|
||||||
|
min = tonumber(min)
|
||||||
|
max = tonumber(max)
|
||||||
|
if min and max then
|
||||||
|
min = (min >= 5) and min or 5
|
||||||
|
max = (max >= min) and max or min
|
||||||
|
return min .. "-" .. max
|
||||||
|
end
|
||||||
|
return 30
|
||||||
|
end
|
||||||
|
v = tonumber((v or "30"):match("^%d+"))
|
||||||
|
return (v and v >= 5) and v or 30
|
||||||
|
end)(node.hysteria2_hop_interval)
|
||||||
|
}
|
||||||
|
}
|
||||||
end
|
end
|
||||||
finalmask.udp = udp
|
finalmask.udp = udp
|
||||||
local up = tonumber(node.hysteria2_up_mbps) or 0
|
local up = tonumber(node.hysteria2_up_mbps) or 0
|
||||||
@@ -363,25 +387,6 @@ function gen_outbound(flag, node, tag, proxy_table)
|
|||||||
congestion = (up <= 0 and down <= 0) and "bbr" or "brutal",
|
congestion = (up <= 0 and down <= 0) and "bbr" or "brutal",
|
||||||
brutalUp = up > 0 and (up .. "mbps") or nil,
|
brutalUp = up > 0 and (up .. "mbps") or nil,
|
||||||
brutalDown = down > 0 and (down .. "mbps") or nil,
|
brutalDown = down > 0 and (down .. "mbps") or nil,
|
||||||
udpHop = (node.hysteria2_hop) and {
|
|
||||||
ports = string.gsub(node.hysteria2_hop, ":", "-"),
|
|
||||||
interval = (function(v)
|
|
||||||
if not v then return 30 end
|
|
||||||
if v:find("-", 1, true) then
|
|
||||||
local min, max = v:match("^(%d+)%-(%d+)$")
|
|
||||||
min = tonumber(min)
|
|
||||||
max = tonumber(max)
|
|
||||||
if min and max then
|
|
||||||
min = (min >= 5) and min or 5
|
|
||||||
max = (max >= min) and max or min
|
|
||||||
return min .. "-" .. max
|
|
||||||
end
|
|
||||||
return 30
|
|
||||||
end
|
|
||||||
v = tonumber((v or "30"):match("^%d+"))
|
|
||||||
return (v and v >= 5) and v or 30
|
|
||||||
end)(node.hysteria2_hop_interval)
|
|
||||||
} or nil,
|
|
||||||
maxIdleTimeout = (function(t)
|
maxIdleTimeout = (function(t)
|
||||||
t = tonumber(tostring(t or "30"):match("^%d+"))
|
t = tonumber(tostring(t or "30"):match("^%d+"))
|
||||||
return (t and t >= 4 and t <= 120) and t or 30
|
return (t and t >= 4 and t <= 120) and t or 30
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=luci-app-passwall2
|
PKG_NAME:=luci-app-passwall2
|
||||||
PKG_VERSION:=26.11.3
|
PKG_VERSION:=26.11.3
|
||||||
PKG_RELEASE:=174
|
PKG_RELEASE:=175
|
||||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||||
|
|
||||||
PKG_CONFIG_DEPENDS:= \
|
PKG_CONFIG_DEPENDS:= \
|
||||||
|
|||||||
@@ -810,16 +810,6 @@ o = s:option(Value, "ws_path", translate("WebSocket Path"))
|
|||||||
o.placeholder = "/"
|
o.placeholder = "/"
|
||||||
o:depends({ transport = "ws" })
|
o:depends({ transport = "ws" })
|
||||||
|
|
||||||
o = s:option(Flag, "ws_enableEarlyData", translate("Enable early data"))
|
|
||||||
o:depends({ transport = "ws" })
|
|
||||||
|
|
||||||
o = s:option(Value, "ws_maxEarlyData", translate("Early data length"))
|
|
||||||
o.default = "1024"
|
|
||||||
o:depends({ ws_enableEarlyData = true })
|
|
||||||
|
|
||||||
o = s:option(Value, "ws_earlyDataHeaderName", translate("Early data header name"), translate("Recommended value: Sec-WebSocket-Protocol"))
|
|
||||||
o:depends({ ws_enableEarlyData = true })
|
|
||||||
|
|
||||||
-- [[ HTTPUpgrade ]]--
|
-- [[ HTTPUpgrade ]]--
|
||||||
o = s:option(Value, "httpupgrade_host", translate("HTTPUpgrade Host"))
|
o = s:option(Value, "httpupgrade_host", translate("HTTPUpgrade Host"))
|
||||||
o:depends({ transport = "httpupgrade" })
|
o:depends({ transport = "httpupgrade" })
|
||||||
|
|||||||
@@ -459,6 +459,10 @@ o:depends({ transport = "ws" })
|
|||||||
o = s:option(Value, "ws_path", translate("WebSocket Path"))
|
o = s:option(Value, "ws_path", translate("WebSocket Path"))
|
||||||
o:depends({ transport = "ws" })
|
o:depends({ transport = "ws" })
|
||||||
|
|
||||||
|
o = s:option(Value, "ws_earlyDataHeaderName", translate("Early data header name"), translate("Recommended value: Sec-WebSocket-Protocol"))
|
||||||
|
o.placeholder = "Sec-WebSocket-Protocol"
|
||||||
|
o:depends({ transport = "ws" })
|
||||||
|
|
||||||
-- [[ HTTPUpgrade ]]--
|
-- [[ HTTPUpgrade ]]--
|
||||||
|
|
||||||
o = s:option(Value, "httpupgrade_host", translate("HTTPUpgrade Host"))
|
o = s:option(Value, "httpupgrade_host", translate("HTTPUpgrade Host"))
|
||||||
|
|||||||
@@ -366,9 +366,26 @@ function gen_outbound(flag, node, tag, proxy_table)
|
|||||||
Host = node.ws_host,
|
Host = node.ws_host,
|
||||||
["User-Agent"] = node.user_agent
|
["User-Agent"] = node.user_agent
|
||||||
} or nil,
|
} or nil,
|
||||||
max_early_data = tonumber(node.ws_maxEarlyData) or nil,
|
|
||||||
early_data_header_name = (node.ws_earlyDataHeaderName) and node.ws_earlyDataHeaderName or nil -- For compatibility with Xray-core, set it to Sec-WebSocket-Protocol. It needs to be consistent with the server.
|
|
||||||
}
|
}
|
||||||
|
local path, query = (node.ws_path or "/"):match("^(.-)%?(.*)$")
|
||||||
|
local params, query_params = {}, {}
|
||||||
|
for v in (query or ""):gmatch("[^&]+") do
|
||||||
|
local t = api.split(api.UrlDecode(v), '=')
|
||||||
|
params[t[1]] = t[2]
|
||||||
|
if t[1] ~= "ed" and t[1] ~= "eh" then
|
||||||
|
table.insert(query_params, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local ed = tonumber(params.ed)
|
||||||
|
if ed then
|
||||||
|
-- Consume early-data options while preserving the remaining query.
|
||||||
|
v2ray_transport.path = path
|
||||||
|
if #query_params > 0 then
|
||||||
|
v2ray_transport.path = path .. "?" .. table.concat(query_params, "&")
|
||||||
|
end
|
||||||
|
v2ray_transport.max_early_data = ed
|
||||||
|
end
|
||||||
|
v2ray_transport.early_data_header_name = params.eh or "Sec-WebSocket-Protocol"
|
||||||
end
|
end
|
||||||
|
|
||||||
if node.transport == "httpupgrade" then
|
if node.transport == "httpupgrade" then
|
||||||
@@ -822,7 +839,7 @@ function gen_config_server(node)
|
|||||||
type = "ws",
|
type = "ws",
|
||||||
path = node.ws_path or "/",
|
path = node.ws_path or "/",
|
||||||
headers = (node.ws_host ~= nil) and { Host = node.ws_host } or nil,
|
headers = (node.ws_host ~= nil) and { Host = node.ws_host } or nil,
|
||||||
early_data_header_name = (node.ws_earlyDataHeaderName) and node.ws_earlyDataHeaderName or nil -- For compatibility with Xray-core, set it to Sec-WebSocket-Protocol. It needs to be consistent with the server.
|
early_data_header_name = (node.ws_earlyDataHeaderName) and node.ws_earlyDataHeaderName or "Sec-WebSocket-Protocol"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ local GLOBAL = {
|
|||||||
|
|
||||||
local xray_version = api.get_app_version("xray")
|
local xray_version = api.get_app_version("xray")
|
||||||
|
|
||||||
local xray_min_version = "26.7.11"
|
local xray_min_version = "26.9.9"
|
||||||
|
|
||||||
local function get_domain_excluded()
|
local function get_domain_excluded()
|
||||||
local path = "/usr/share/passwall2/domains_excluded"
|
local path = "/usr/share/passwall2/domains_excluded"
|
||||||
@@ -364,6 +364,30 @@ function gen_outbound(flag, node, tag, proxy_table)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
udp[#udp+1] = r
|
udp[#udp+1] = r
|
||||||
|
elseif node.hysteria2_hop and node.hysteria2_hop ~= "" then
|
||||||
|
udp[#udp+1] = {
|
||||||
|
type = "udphop",
|
||||||
|
settings = {
|
||||||
|
mode = "intervallocal,intervalremote",
|
||||||
|
remotePorts = string.gsub(node.hysteria2_hop, ":", "-"),
|
||||||
|
interval = (function(v)
|
||||||
|
if not v then return 30 end
|
||||||
|
if v:find("-", 1, true) then
|
||||||
|
local min, max = v:match("^(%d+)%-(%d+)$")
|
||||||
|
min = tonumber(min)
|
||||||
|
max = tonumber(max)
|
||||||
|
if min and max then
|
||||||
|
min = (min >= 5) and min or 5
|
||||||
|
max = (max >= min) and max or min
|
||||||
|
return min .. "-" .. max
|
||||||
|
end
|
||||||
|
return 30
|
||||||
|
end
|
||||||
|
v = tonumber((v or "30"):match("^%d+"))
|
||||||
|
return (v and v >= 5) and v or 30
|
||||||
|
end)(node.hysteria2_hop_interval)
|
||||||
|
}
|
||||||
|
}
|
||||||
end
|
end
|
||||||
finalmask.udp = udp
|
finalmask.udp = udp
|
||||||
local up = tonumber(node.hysteria2_up_mbps) or 0
|
local up = tonumber(node.hysteria2_up_mbps) or 0
|
||||||
@@ -372,25 +396,6 @@ function gen_outbound(flag, node, tag, proxy_table)
|
|||||||
congestion = (up <= 0 and down <= 0) and "bbr" or "brutal",
|
congestion = (up <= 0 and down <= 0) and "bbr" or "brutal",
|
||||||
brutalUp = up > 0 and (up .. "mbps") or nil,
|
brutalUp = up > 0 and (up .. "mbps") or nil,
|
||||||
brutalDown = down > 0 and (down .. "mbps") or nil,
|
brutalDown = down > 0 and (down .. "mbps") or nil,
|
||||||
udpHop = (node.hysteria2_hop) and {
|
|
||||||
ports = string.gsub(node.hysteria2_hop, ":", "-"),
|
|
||||||
interval = (function(v)
|
|
||||||
if not v then return 30 end
|
|
||||||
if v:find("-", 1, true) then
|
|
||||||
local min, max = v:match("^(%d+)%-(%d+)$")
|
|
||||||
min = tonumber(min)
|
|
||||||
max = tonumber(max)
|
|
||||||
if min and max then
|
|
||||||
min = (min >= 5) and min or 5
|
|
||||||
max = (max >= min) and max or min
|
|
||||||
return min .. "-" .. max
|
|
||||||
end
|
|
||||||
return 30
|
|
||||||
end
|
|
||||||
v = tonumber((v or "30"):match("^%d+"))
|
|
||||||
return (v and v >= 5) and v or 30
|
|
||||||
end)(node.hysteria2_hop_interval)
|
|
||||||
} or nil,
|
|
||||||
maxIdleTimeout = (function(t)
|
maxIdleTimeout = (function(t)
|
||||||
t = tonumber(tostring(t or "30"):match("^%d+"))
|
t = tonumber(tostring(t or "30"):match("^%d+"))
|
||||||
return (t and t >= 4 and t <= 120) and t or 30
|
return (t and t >= 4 and t <= 120) and t or 30
|
||||||
|
|||||||
@@ -254,10 +254,6 @@ local current_node = map:get(section)
|
|||||||
if (v_transport === "ws") {
|
if (v_transport === "ws") {
|
||||||
params += opt.query("host", dom_prefix + "ws_host");
|
params += opt.query("host", dom_prefix + "ws_host");
|
||||||
params += opt.query("path", dom_prefix + "ws_path");
|
params += opt.query("path", dom_prefix + "ws_path");
|
||||||
if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
|
|
||||||
var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
|
|
||||||
params += "?ed=" + ws_maxEarlyData;
|
|
||||||
}
|
|
||||||
} else if (v_transport === "http") {
|
} else if (v_transport === "http") {
|
||||||
params += opt.query("host", dom_prefix + "http_host");
|
params += opt.query("host", dom_prefix + "http_host");
|
||||||
params += opt.query("path", dom_prefix + "http_path");
|
params += opt.query("path", dom_prefix + "http_path");
|
||||||
@@ -376,10 +372,6 @@ local current_node = map:get(section)
|
|||||||
if (v_transport === "ws") {
|
if (v_transport === "ws") {
|
||||||
info.host = opt.get(dom_prefix + "ws_host").value;
|
info.host = opt.get(dom_prefix + "ws_host").value;
|
||||||
info.path = opt.get(dom_prefix + "ws_path").value;
|
info.path = opt.get(dom_prefix + "ws_path").value;
|
||||||
if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
|
|
||||||
var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
|
|
||||||
info.path = info.path + "?ed=" + ws_maxEarlyData;
|
|
||||||
}
|
|
||||||
} else if (v_transport === "http") {
|
} else if (v_transport === "http") {
|
||||||
info.host = opt.get(dom_prefix + "http_host").value;
|
info.host = opt.get(dom_prefix + "http_host").value;
|
||||||
info.path = opt.get(dom_prefix + "http_path").value;
|
info.path = opt.get(dom_prefix + "http_path").value;
|
||||||
@@ -436,10 +428,6 @@ local current_node = map:get(section)
|
|||||||
if (v_transport === "ws") {
|
if (v_transport === "ws") {
|
||||||
params += opt.query("host", dom_prefix + "ws_host");
|
params += opt.query("host", dom_prefix + "ws_host");
|
||||||
params += opt.query("path", dom_prefix + "ws_path");
|
params += opt.query("path", dom_prefix + "ws_path");
|
||||||
if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
|
|
||||||
var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
|
|
||||||
params += encodeURIComponent("?ed=" + ws_maxEarlyData);
|
|
||||||
}
|
|
||||||
} else if (v_transport === "http") {
|
} else if (v_transport === "http") {
|
||||||
params += opt.query("host", dom_prefix + "http_host");
|
params += opt.query("host", dom_prefix + "http_host");
|
||||||
params += opt.query("path", dom_prefix + "http_path");
|
params += opt.query("path", dom_prefix + "http_path");
|
||||||
@@ -528,10 +516,6 @@ local current_node = map:get(section)
|
|||||||
if (v_transport === "ws") {
|
if (v_transport === "ws") {
|
||||||
params += opt.query("host", dom_prefix + "ws_host");
|
params += opt.query("host", dom_prefix + "ws_host");
|
||||||
params += opt.query("path", dom_prefix + "ws_path");
|
params += opt.query("path", dom_prefix + "ws_path");
|
||||||
if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
|
|
||||||
var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
|
|
||||||
params += "?ed=" + ws_maxEarlyData;
|
|
||||||
}
|
|
||||||
} else if (v_transport === "http") {
|
} else if (v_transport === "http") {
|
||||||
params += opt.query("host", dom_prefix + "http_host");
|
params += opt.query("host", dom_prefix + "http_host");
|
||||||
params += opt.query("path", dom_prefix + "http_path");
|
params += opt.query("path", dom_prefix + "http_path");
|
||||||
@@ -1111,24 +1095,6 @@ local current_node = map:get(section)
|
|||||||
} else if (queryParam.type === "ws") {
|
} else if (queryParam.type === "ws") {
|
||||||
opt.set(dom_prefix + 'ws_host', queryParam.host || "");
|
opt.set(dom_prefix + 'ws_host', queryParam.host || "");
|
||||||
opt.set(dom_prefix + 'ws_path', queryParam.path || "");
|
opt.set(dom_prefix + 'ws_path', queryParam.path || "");
|
||||||
if (dom_prefix == "singbox_" && queryParam.path && queryParam.path.length > 1) {
|
|
||||||
var ws_path_params = {};
|
|
||||||
var ws_path_dat = queryParam.path.split('?');
|
|
||||||
var ws_path = ws_path_dat[0];
|
|
||||||
var ws_path_params = {};
|
|
||||||
var ws_path_params_array = (ws_path_dat[1] || '').split('&');
|
|
||||||
for (i = 0; i < ws_path_params_array.length; i++) {
|
|
||||||
var kv = ws_path_params_array[i].split('=');
|
|
||||||
ws_path_params[decodeURIComponent(kv[0]).toLowerCase()] = decodeURIComponent(kv[1] || '');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ws_path_params.ed) {
|
|
||||||
opt.set(dom_prefix + 'ws_path', ws_path);
|
|
||||||
opt.set(dom_prefix + 'ws_enableEarlyData', true);
|
|
||||||
opt.set(dom_prefix + 'ws_maxEarlyData', ws_path_params.ed);
|
|
||||||
opt.set(dom_prefix + 'ws_earlyDataHeaderName', 'Sec-WebSocket-Protocol');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (queryParam.type === "http") {
|
} else if (queryParam.type === "http") {
|
||||||
if (dom_prefix == "xray_") {
|
if (dom_prefix == "xray_") {
|
||||||
opt.set(dom_prefix + 'xhttp_mode', "stream-one");
|
opt.set(dom_prefix + 'xhttp_mode', "stream-one");
|
||||||
@@ -1259,24 +1225,6 @@ local current_node = map:get(section)
|
|||||||
} else if (queryParam.type === "ws") {
|
} else if (queryParam.type === "ws") {
|
||||||
opt.set(dom_prefix + 'ws_host', queryParam.host || "");
|
opt.set(dom_prefix + 'ws_host', queryParam.host || "");
|
||||||
opt.set(dom_prefix + 'ws_path', queryParam.path || "");
|
opt.set(dom_prefix + 'ws_path', queryParam.path || "");
|
||||||
if (dom_prefix == "singbox_" && queryParam.path && queryParam.path.length > 1) {
|
|
||||||
var ws_path_params = {};
|
|
||||||
var ws_path_dat = queryParam.path.split('?');
|
|
||||||
var ws_path = ws_path_dat[0];
|
|
||||||
var ws_path_params = {};
|
|
||||||
var ws_path_params_array = (ws_path_dat[1] || '').split('&');
|
|
||||||
for (i = 0; i < ws_path_params_array.length; i++) {
|
|
||||||
var kv = ws_path_params_array[i].split('=');
|
|
||||||
ws_path_params[decodeURIComponent(kv[0]).toLowerCase()] = decodeURIComponent(kv[1] || '');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ws_path_params.ed) {
|
|
||||||
opt.set(dom_prefix + 'ws_path', ws_path);
|
|
||||||
opt.set(dom_prefix + 'ws_enableEarlyData', true);
|
|
||||||
opt.set(dom_prefix + 'ws_maxEarlyData', ws_path_params.ed);
|
|
||||||
opt.set(dom_prefix + 'ws_earlyDataHeaderName', 'Sec-WebSocket-Protocol');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (queryParam.type === "h2" || queryParam.type === "http") {
|
} else if (queryParam.type === "h2" || queryParam.type === "http") {
|
||||||
if (dom_prefix == "xray_") {
|
if (dom_prefix == "xray_") {
|
||||||
opt.set(dom_prefix + 'xhttp_mode', "stream-one");
|
opt.set(dom_prefix + 'xhttp_mode', "stream-one");
|
||||||
@@ -1446,24 +1394,6 @@ local current_node = map:get(section)
|
|||||||
} else if (ssm.net === "ws") {
|
} else if (ssm.net === "ws") {
|
||||||
opt.set(dom_prefix + 'ws_host', ssm.host);
|
opt.set(dom_prefix + 'ws_host', ssm.host);
|
||||||
opt.set(dom_prefix + 'ws_path', ssm.path);
|
opt.set(dom_prefix + 'ws_path', ssm.path);
|
||||||
if (dom_prefix == "singbox_" && ssm.path && ssm.path.length > 1) {
|
|
||||||
var ws_path_params = {};
|
|
||||||
var ws_path_dat = ssm.path.split('?');
|
|
||||||
var ws_path = ws_path_dat[0];
|
|
||||||
var ws_path_params = {};
|
|
||||||
var ws_path_params_array = (ws_path_dat[1] || '').split('&');
|
|
||||||
for (i = 0; i < ws_path_params_array.length; i++) {
|
|
||||||
var kv = ws_path_params_array[i].split('=');
|
|
||||||
ws_path_params[decodeURIComponent(kv[0]).toLowerCase()] = decodeURIComponent(kv[1] || '');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ws_path_params.ed) {
|
|
||||||
opt.set(dom_prefix + 'ws_path', ws_path);
|
|
||||||
opt.set(dom_prefix + 'ws_enableEarlyData', true);
|
|
||||||
opt.set(dom_prefix + 'ws_maxEarlyData', ws_path_params.ed);
|
|
||||||
opt.set(dom_prefix + 'ws_earlyDataHeaderName', 'Sec-WebSocket-Protocol');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (ssm.net === "http") {
|
} else if (ssm.net === "http") {
|
||||||
if (dom_prefix == "xray_") {
|
if (dom_prefix == "xray_") {
|
||||||
opt.set(dom_prefix + 'xhttp_mode', "stream-one");
|
opt.set(dom_prefix + 'xhttp_mode', "stream-one");
|
||||||
@@ -1589,24 +1519,6 @@ local current_node = map:get(section)
|
|||||||
} else if (queryParam.type === "ws") {
|
} else if (queryParam.type === "ws") {
|
||||||
opt.set(dom_prefix + 'ws_host', queryParam.host || "");
|
opt.set(dom_prefix + 'ws_host', queryParam.host || "");
|
||||||
opt.set(dom_prefix + 'ws_path', queryParam.path || "");
|
opt.set(dom_prefix + 'ws_path', queryParam.path || "");
|
||||||
if (dom_prefix == "singbox_" && queryParam.path && queryParam.path.length > 1) {
|
|
||||||
var ws_path_params = {};
|
|
||||||
var ws_path_dat = queryParam.path.split('?');
|
|
||||||
var ws_path = ws_path_dat[0];
|
|
||||||
var ws_path_params = {};
|
|
||||||
var ws_path_params_array = (ws_path_dat[1] || '').split('&');
|
|
||||||
for (i = 0; i < ws_path_params_array.length; i++) {
|
|
||||||
var kv = ws_path_params_array[i].split('=');
|
|
||||||
ws_path_params[decodeURIComponent(kv[0]).toLowerCase()] = decodeURIComponent(kv[1] || '');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ws_path_params.ed) {
|
|
||||||
opt.set(dom_prefix + 'ws_path', ws_path);
|
|
||||||
opt.set(dom_prefix + 'ws_enableEarlyData', true);
|
|
||||||
opt.set(dom_prefix + 'ws_maxEarlyData', ws_path_params.ed);
|
|
||||||
opt.set(dom_prefix + 'ws_earlyDataHeaderName', 'Sec-WebSocket-Protocol');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (queryParam.type === "h2" || queryParam.type === "http") {
|
} else if (queryParam.type === "h2" || queryParam.type === "http") {
|
||||||
if (dom_prefix == "xray_") {
|
if (dom_prefix == "xray_") {
|
||||||
opt.set(dom_prefix + 'xhttp_mode', "stream-one");
|
opt.set(dom_prefix + 'xhttp_mode', "stream-one");
|
||||||
|
|||||||
@@ -1585,12 +1585,6 @@ msgstr "همزمانی XUDP Mux"
|
|||||||
msgid "Padding"
|
msgid "Padding"
|
||||||
msgstr "پدینگ (Padding)"
|
msgstr "پدینگ (Padding)"
|
||||||
|
|
||||||
msgid "Enable early data"
|
|
||||||
msgstr "فعالسازی دادههای اولیه (Early Data)"
|
|
||||||
|
|
||||||
msgid "Early data length"
|
|
||||||
msgstr "طول دادههای اولیه"
|
|
||||||
|
|
||||||
msgid "Early data header name"
|
msgid "Early data header name"
|
||||||
msgstr "نام هدر دادههای اولیه"
|
msgstr "نام هدر دادههای اولیه"
|
||||||
|
|
||||||
|
|||||||
@@ -1586,12 +1586,6 @@ msgstr "Макс. параллельных соединений XUDP"
|
|||||||
msgid "Padding"
|
msgid "Padding"
|
||||||
msgstr "Заполнение"
|
msgstr "Заполнение"
|
||||||
|
|
||||||
msgid "Enable early data"
|
|
||||||
msgstr "Включить 0-RTT данные"
|
|
||||||
|
|
||||||
msgid "Early data length"
|
|
||||||
msgstr "Макс. длина 0-RTT данных"
|
|
||||||
|
|
||||||
msgid "Early data header name"
|
msgid "Early data header name"
|
||||||
msgstr "Имя HTTP-заголовка для 0-RTT"
|
msgstr "Имя HTTP-заголовка для 0-RTT"
|
||||||
|
|
||||||
|
|||||||
@@ -1577,12 +1577,6 @@ msgstr "XUDP 最大并发连接数"
|
|||||||
msgid "Padding"
|
msgid "Padding"
|
||||||
msgstr "填充"
|
msgstr "填充"
|
||||||
|
|
||||||
msgid "Enable early data"
|
|
||||||
msgstr "启用前置数据"
|
|
||||||
|
|
||||||
msgid "Early data length"
|
|
||||||
msgstr "前置数据最大长度"
|
|
||||||
|
|
||||||
msgid "Early data header name"
|
msgid "Early data header name"
|
||||||
msgstr "前置数据 HTTP 头名"
|
msgstr "前置数据 HTTP 头名"
|
||||||
|
|
||||||
|
|||||||
@@ -1577,12 +1577,6 @@ msgstr "XUDP 最大並發連接數"
|
|||||||
msgid "Padding"
|
msgid "Padding"
|
||||||
msgstr "填充"
|
msgstr "填充"
|
||||||
|
|
||||||
msgid "Enable early data"
|
|
||||||
msgstr "啟用前置數据"
|
|
||||||
|
|
||||||
msgid "Early data length"
|
|
||||||
msgstr "前置數据最大长度"
|
|
||||||
|
|
||||||
msgid "Early data header name"
|
msgid "Early data header name"
|
||||||
msgstr "前置數据 HTTP 头名"
|
msgstr "前置數据 HTTP 头名"
|
||||||
|
|
||||||
|
|||||||
@@ -679,21 +679,6 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
|||||||
if info.net == 'ws' then
|
if info.net == 'ws' then
|
||||||
result.ws_host = info.host
|
result.ws_host = info.host
|
||||||
result.ws_path = info.path
|
result.ws_path = info.path
|
||||||
if result.type == "sing-box" and info.path then
|
|
||||||
local ws_path_dat = split(info.path, "?")
|
|
||||||
local ws_path = ws_path_dat[1]
|
|
||||||
local ws_path_params = {}
|
|
||||||
for _, v in pairs(split(ws_path_dat[2], '&')) do
|
|
||||||
local t = split(v, '=')
|
|
||||||
ws_path_params[t[1]] = t[2]
|
|
||||||
end
|
|
||||||
if ws_path_params.ed and tonumber(ws_path_params.ed) then
|
|
||||||
result.ws_path = ws_path
|
|
||||||
result.ws_enableEarlyData = "1"
|
|
||||||
result.ws_maxEarlyData = tonumber(ws_path_params.ed)
|
|
||||||
result.ws_earlyDataHeaderName = "Sec-WebSocket-Protocol"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
if info.net == "http" then
|
if info.net == "http" then
|
||||||
if result.type == "Xray" then
|
if result.type == "Xray" then
|
||||||
@@ -936,21 +921,6 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
|||||||
if params.type == 'ws' then
|
if params.type == 'ws' then
|
||||||
result.ws_host = params.host
|
result.ws_host = params.host
|
||||||
result.ws_path = params.path
|
result.ws_path = params.path
|
||||||
if result.type == "sing-box" and params.path then
|
|
||||||
local ws_path_dat = split(params.path, "%?")
|
|
||||||
local ws_path = ws_path_dat[1]
|
|
||||||
local ws_path_params = {}
|
|
||||||
for _, v in pairs(split(ws_path_dat[2], '&')) do
|
|
||||||
local t = split(v, '=')
|
|
||||||
ws_path_params[t[1]] = t[2]
|
|
||||||
end
|
|
||||||
if ws_path_params.ed and tonumber(ws_path_params.ed) then
|
|
||||||
result.ws_path = ws_path
|
|
||||||
result.ws_enableEarlyData = "1"
|
|
||||||
result.ws_maxEarlyData = tonumber(ws_path_params.ed)
|
|
||||||
result.ws_earlyDataHeaderName = "Sec-WebSocket-Protocol"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
if params.type == "http" then
|
if params.type == "http" then
|
||||||
if result.type == "sing-box" then
|
if result.type == "sing-box" then
|
||||||
@@ -1152,21 +1122,6 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
|||||||
if params.type == 'ws' then
|
if params.type == 'ws' then
|
||||||
result.ws_host = params.host
|
result.ws_host = params.host
|
||||||
result.ws_path = params.path
|
result.ws_path = params.path
|
||||||
if result.type == "sing-box" and params.path then
|
|
||||||
local ws_path_dat = split(params.path, "%?")
|
|
||||||
local ws_path = ws_path_dat[1]
|
|
||||||
local ws_path_params = {}
|
|
||||||
for _, v in pairs(split(ws_path_dat[2], '&')) do
|
|
||||||
local t = split(v, '=')
|
|
||||||
ws_path_params[t[1]] = t[2]
|
|
||||||
end
|
|
||||||
if ws_path_params.ed and tonumber(ws_path_params.ed) then
|
|
||||||
result.ws_path = ws_path
|
|
||||||
result.ws_enableEarlyData = "1"
|
|
||||||
result.ws_maxEarlyData = tonumber(ws_path_params.ed)
|
|
||||||
result.ws_earlyDataHeaderName = "Sec-WebSocket-Protocol"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
if params.type == "http" then
|
if params.type == "http" then
|
||||||
if result.type == "sing-box" then
|
if result.type == "sing-box" then
|
||||||
@@ -1281,21 +1236,6 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
|||||||
if params.type == 'ws' then
|
if params.type == 'ws' then
|
||||||
result.ws_host = params.host
|
result.ws_host = params.host
|
||||||
result.ws_path = params.path
|
result.ws_path = params.path
|
||||||
if result.type == "sing-box" and params.path then
|
|
||||||
local ws_path_dat = split(params.path, "%?")
|
|
||||||
local ws_path = ws_path_dat[1]
|
|
||||||
local ws_path_params = {}
|
|
||||||
for _, v in pairs(split(ws_path_dat[2], '&')) do
|
|
||||||
local t = split(v, '=')
|
|
||||||
ws_path_params[t[1]] = t[2]
|
|
||||||
end
|
|
||||||
if ws_path_params.ed and tonumber(ws_path_params.ed) then
|
|
||||||
result.ws_path = ws_path
|
|
||||||
result.ws_enableEarlyData = "1"
|
|
||||||
result.ws_maxEarlyData = tonumber(ws_path_params.ed)
|
|
||||||
result.ws_earlyDataHeaderName = "Sec-WebSocket-Protocol"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
if params.type == "http" then
|
if params.type == "http" then
|
||||||
if result.type == "sing-box" then
|
if result.type == "sing-box" then
|
||||||
|
|||||||
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
# Copyright (C) 2026 Amr Fateem <amr.fateem@yahoo.com>
|
||||||
|
#
|
||||||
|
# LuCI application for v2rayA.
|
||||||
|
|
||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
LUCI_TITLE:=LuCI support for v2rayA
|
||||||
|
LUCI_DEPENDS:=+luci-base +v2raya
|
||||||
|
LUCI_PKGARCH:=all
|
||||||
|
LUCI_MAINTAINER:=Amr Fateem <amr.fateem@yahoo.com>
|
||||||
|
|
||||||
|
PKG_VERSION:=2.5.13
|
||||||
|
PKG_RELEASE:=1
|
||||||
|
|
||||||
|
PKG_LICENSE:=Apache-2.0
|
||||||
|
CONFLICTS:=luci-app-v2raya-nextgen
|
||||||
|
|
||||||
|
include $(TOPDIR)/feeds/luci/luci.mk
|
||||||
|
|
||||||
|
# call BuildPackage - OpenWrt buildroot signature
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
'use strict';
|
||||||
|
'require form';
|
||||||
|
'require uci';
|
||||||
|
'require ui';
|
||||||
|
'require view';
|
||||||
|
|
||||||
|
return view.extend({
|
||||||
|
load: function () {
|
||||||
|
return uci.load('v2raya');
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function () {
|
||||||
|
var m, s, o;
|
||||||
|
|
||||||
|
m = new form.Map('v2raya', _('v2rayA'),
|
||||||
|
_('Settings for the v2rayA service. Save & Apply restarts the service so the new values take effect. v2rayA 2.5.x uses only its bundled v2raya_core; Xray-core and sing-box are not supported backends.'));
|
||||||
|
|
||||||
|
s = m.section(form.NamedSection, 'config', 'v2raya');
|
||||||
|
s.tab('general', _('General'));
|
||||||
|
s.tab('proxy', _('Transparent proxy'),
|
||||||
|
_('The transparent proxy mode, routing rules and nodes are configured in the v2rayA web interface. These options control core start-up and hooks.'));
|
||||||
|
s.tab('logging', _('Logging'));
|
||||||
|
s.tab('advanced', _('Advanced'));
|
||||||
|
|
||||||
|
o = s.taboption('general', form.Flag, 'enabled', _('Enable service'));
|
||||||
|
o.default = '0';
|
||||||
|
o.rmempty = false;
|
||||||
|
o.description = _('Start v2rayA at boot. You can also start or stop it from the overview page.');
|
||||||
|
|
||||||
|
o = s.taboption('general', form.Value, 'address', _('Listening address'));
|
||||||
|
o.placeholder = '0.0.0.0:2017';
|
||||||
|
o.rmempty = false;
|
||||||
|
o.validate = function (section_id, value) {
|
||||||
|
if (!value)
|
||||||
|
return _('An address is required.');
|
||||||
|
|
||||||
|
if (!/^(\[[0-9a-fA-F:]+\]|[A-Za-z0-9._-]+):[0-9]{1,5}$/.test(value))
|
||||||
|
return _('Enter an address and port, for example 0.0.0.0:2017 or [::]:2017.');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
o.description = _('The web interface listens on this address. Use 127.0.0.1:2017 to keep it off the LAN.');
|
||||||
|
|
||||||
|
o = s.taboption('general', form.Value, 'baseurl', _('Base URL'));
|
||||||
|
o.placeholder = '/';
|
||||||
|
o.description = _('URL prefix when v2rayA runs behind a reverse proxy.');
|
||||||
|
o.validate = function (section_id, value) {
|
||||||
|
if (value && value.charAt(0) !== '/')
|
||||||
|
return _('The base URL must start with /.');
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
o = s.taboption('general', form.ListValue, 'ipv6_support', _('IPv6 support'));
|
||||||
|
o.value('auto', _('Auto'));
|
||||||
|
o.value('on', _('On'));
|
||||||
|
o.value('off', _('Off'));
|
||||||
|
o.default = 'auto';
|
||||||
|
o.description = _('Make sure IPv6 connectivity works before forcing it on.');
|
||||||
|
|
||||||
|
o = s.taboption('general', form.ListValue, 'nftables_support', _('nftables support'));
|
||||||
|
o.value('auto', _('Auto'));
|
||||||
|
o.value('on', _('On'));
|
||||||
|
o.value('off', _('Off'));
|
||||||
|
o.default = 'auto';
|
||||||
|
o.description = _('nftables is the default firewall backend on OpenWrt 22.03 and later.');
|
||||||
|
|
||||||
|
o = s.taboption('proxy', form.Value, 'core_startup_timeout', _('Core startup timeout'));
|
||||||
|
o.datatype = 'uinteger';
|
||||||
|
o.placeholder = '15';
|
||||||
|
o.default = '15';
|
||||||
|
o.description = _('Seconds to wait for v2raya_core to start. Raise this on slow MIPS routers.');
|
||||||
|
|
||||||
|
o = s.taboption('proxy', form.Flag, 'redirect_respect_bound_device', _('Respect bound devices in redirect mode'));
|
||||||
|
o.default = '0';
|
||||||
|
o.description = _('Let sockets bound to a device bypass the proxy. Requires Linux 5.14 or later and cgroup v2.');
|
||||||
|
|
||||||
|
o = s.taboption('proxy', form.Value, 'transparent_hook', _('Transparent proxy hook'));
|
||||||
|
o.placeholder = '/usr/bin/example-hook';
|
||||||
|
o.description = _('Executable called around transparent proxy setup and teardown.');
|
||||||
|
|
||||||
|
o = s.taboption('proxy', form.Value, 'core_hook', _('Core life-cycle hook'));
|
||||||
|
o.placeholder = '/usr/bin/example-hook';
|
||||||
|
o.description = _('Executable called around v2raya_core start and stop.');
|
||||||
|
|
||||||
|
o = s.taboption('proxy', form.Value, 'plugin_manager', _('Plugin manager'));
|
||||||
|
o.placeholder = '/usr/bin/example-plugin-manager';
|
||||||
|
o.description = _('Executable used to parse protocols that v2rayA does not know natively.');
|
||||||
|
|
||||||
|
o = s.taboption('logging', form.ListValue, 'log_level', _('Log level'));
|
||||||
|
o.value('trace', _('Trace'));
|
||||||
|
o.value('debug', _('Debug'));
|
||||||
|
o.value('info', _('Info'));
|
||||||
|
o.value('warn', _('Warning'));
|
||||||
|
o.value('error', _('Error'));
|
||||||
|
o.default = 'warn';
|
||||||
|
o.description = _('Warning keeps flash writes down. Use Info while debugging.');
|
||||||
|
|
||||||
|
o = s.taboption('logging', form.Value, 'log_max_days', _('Keep logs for'));
|
||||||
|
o.datatype = 'uinteger';
|
||||||
|
o.placeholder = '1';
|
||||||
|
o.default = '1';
|
||||||
|
o.description = _('Number of days to keep rotated log files.');
|
||||||
|
|
||||||
|
o = s.taboption('logging', form.Flag, 'log_disable_color', _('Disable colours in the log'));
|
||||||
|
o.default = '1';
|
||||||
|
o.description = _('The log file is plain text, so colours are not useful there.');
|
||||||
|
|
||||||
|
o = s.taboption('logging', form.Flag, 'log_disable_timestamp', _('Disable timestamps in the log'));
|
||||||
|
o.default = '0';
|
||||||
|
o.description = _('Only relevant when v2rayA writes to syslog or journald.');
|
||||||
|
|
||||||
|
o = s.taboption('advanced', form.Value, 'v2ray_assetsdir', _('Rule data directory'));
|
||||||
|
o.placeholder = '/usr/share/v2raya';
|
||||||
|
o.default = '/usr/share/v2raya';
|
||||||
|
o.description = _('Directory containing geoip.dat and geosite.dat. Leave empty for auto-detection.');
|
||||||
|
|
||||||
|
o = s.taboption('advanced', form.Value, 'v2ray_bin', _('Core binary (v2raya_core only)'));
|
||||||
|
o.placeholder = _('Auto-detect');
|
||||||
|
o.description = _('Path to v2raya_core. Leave empty to use the binary next to v2raya or in PATH. Only the matching v2raya_core is supported; Xray-core and sing-box use incompatible configuration formats.');
|
||||||
|
|
||||||
|
o = s.taboption('advanced', form.Value, 'v2ray_confdir', _('Extra configuration directory'));
|
||||||
|
o.placeholder = _('None');
|
||||||
|
o.description = _('Additional v2ray configuration files merged into the generated configuration.');
|
||||||
|
|
||||||
|
o = s.taboption('advanced', form.Value, 'gomemlimit', _('Go memory limit'));
|
||||||
|
o.placeholder = '64MiB';
|
||||||
|
o.default = '64MiB';
|
||||||
|
o.description = _('Soft memory limit for both v2raya and v2raya_core (GOMEMLIMIT). Use 0 to disable, or 96MiB on a larger router.');
|
||||||
|
|
||||||
|
o = s.taboption('advanced', form.Value, 'gomaxprocs', _('Go scheduler threads'));
|
||||||
|
o.datatype = 'uinteger';
|
||||||
|
o.placeholder = '2';
|
||||||
|
o.default = '2';
|
||||||
|
o.description = _('GOMAXPROCS. 0 uses every CPU core; 2 is enough for most routers.');
|
||||||
|
|
||||||
|
o = s.taboption('advanced', form.Value, 'gogc', _('Go GC percent'));
|
||||||
|
o.datatype = 'uinteger';
|
||||||
|
o.placeholder = '0';
|
||||||
|
o.default = '0';
|
||||||
|
o.description = _('GOGC. 0 keeps the Go default; lower values use less memory and more CPU.');
|
||||||
|
|
||||||
|
o = s.taboption('advanced', form.Value, 'nofile', _('Open file limit'));
|
||||||
|
o.datatype = 'uinteger';
|
||||||
|
o.placeholder = '16384';
|
||||||
|
o.default = '16384';
|
||||||
|
o.description = _('Maximum open file descriptors. 16384 is plenty for a home router and bounds a connection flood.');
|
||||||
|
|
||||||
|
return m.render();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSaveApply: function (ev, mode) {
|
||||||
|
/*
|
||||||
|
* Applying the UCI delta emits a config.change event; the init
|
||||||
|
* script's procd reload trigger restarts the service with the new
|
||||||
|
* values. Restarting here as well would stop and start it twice.
|
||||||
|
*/
|
||||||
|
return this.handleSave(ev).then(function () {
|
||||||
|
return uci.apply();
|
||||||
|
}).then(function () {
|
||||||
|
ui.addNotification(null, E('p', {},
|
||||||
|
_('Settings applied. The service is restarting.')), 'info');
|
||||||
|
}).catch(function (err) {
|
||||||
|
ui.addNotification(null, E('p', {},
|
||||||
|
_('The configuration was not applied: %s').format(err)), 'danger');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
'use strict';
|
||||||
|
'require dom';
|
||||||
|
'require fs';
|
||||||
|
'require poll';
|
||||||
|
'require ui';
|
||||||
|
'require view';
|
||||||
|
|
||||||
|
var LOG_PATH = '/var/log/v2raya/v2raya.log';
|
||||||
|
var MAX_LINES = 500;
|
||||||
|
|
||||||
|
return view.extend({
|
||||||
|
render: function () {
|
||||||
|
var logEl = E('pre', {
|
||||||
|
id: 'v2raya-log',
|
||||||
|
style: 'white-space:pre-wrap;word-break:break-all;max-height:65vh;overflow:auto;padding:8px;margin:0;background:rgba(0,0,0,0.04);border-radius:4px'
|
||||||
|
}, _('Loading…'));
|
||||||
|
|
||||||
|
var refresh = function () {
|
||||||
|
return L.resolveDefault(fs.read_direct(LOG_PATH, 'text'), null).then(function (text) {
|
||||||
|
if (text === null) {
|
||||||
|
dom.content(logEl, _('The log file does not exist yet. Start the service and try again.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines = text.replace(/\s+$/, '').split('\n');
|
||||||
|
if (lines.length > MAX_LINES)
|
||||||
|
lines = lines.slice(-MAX_LINES);
|
||||||
|
|
||||||
|
var atBottom = (logEl.scrollTop + logEl.clientHeight + 20) >= logEl.scrollHeight;
|
||||||
|
dom.content(logEl, lines.join('\n') || _('The log is empty.'));
|
||||||
|
|
||||||
|
if (atBottom)
|
||||||
|
logEl.scrollTop = logEl.scrollHeight;
|
||||||
|
}).catch(function (err) {
|
||||||
|
dom.content(logEl, _('Unable to read the log: %s').format(err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var refreshBtn = E('button', { class: 'btn cbi-button cbi-button-action' }, _('Refresh'));
|
||||||
|
var clearBtn = E('button', { class: 'btn cbi-button cbi-button-reset' }, _('Clear log'));
|
||||||
|
|
||||||
|
refreshBtn.addEventListener('click', function () { refresh(); });
|
||||||
|
clearBtn.addEventListener('click', function () {
|
||||||
|
if (!confirm(_('Clear the v2rayA log file?')))
|
||||||
|
return;
|
||||||
|
|
||||||
|
L.resolveDefault(fs.write(LOG_PATH, ''), null).then(function (res) {
|
||||||
|
if (res === null)
|
||||||
|
ui.addNotification(null, E('p', {}, _('Unable to clear the log file.')), 'danger');
|
||||||
|
else
|
||||||
|
ui.addNotification(null, E('p', {}, _('Log file cleared.')), 'info');
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
poll.add(refresh, 5);
|
||||||
|
|
||||||
|
return E('div', { class: 'cbi-map' }, [
|
||||||
|
E('h2', {}, _('v2rayA log')),
|
||||||
|
E('div', { class: 'cbi-map-descr' },
|
||||||
|
_('Showing the last %d lines of %s. Refreshes every %d seconds.')
|
||||||
|
.format(MAX_LINES, LOG_PATH, L.env.pollinterval || 5)),
|
||||||
|
E('div', { class: 'cbi-section' }, [
|
||||||
|
logEl,
|
||||||
|
E('div', { style: 'margin-top:8px' }, [ refreshBtn, ' ', clearBtn ])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSave: null,
|
||||||
|
handleSaveApply: null,
|
||||||
|
handleReset: null
|
||||||
|
});
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
'use strict';
|
||||||
|
'require view';
|
||||||
|
'require fs';
|
||||||
|
'require poll';
|
||||||
|
'require rpc';
|
||||||
|
'require uci';
|
||||||
|
'require ui';
|
||||||
|
|
||||||
|
var callServiceList = rpc.declare({
|
||||||
|
object: 'service',
|
||||||
|
method: 'list',
|
||||||
|
params: [ 'name' ],
|
||||||
|
expect: { '': {} }
|
||||||
|
});
|
||||||
|
|
||||||
|
function serviceRunning() {
|
||||||
|
return L.resolveDefault(callServiceList('v2raya'), {}).then(function (res) {
|
||||||
|
var inst = res && res.v2raya && res.v2raya.instances && res.v2raya.instances.v2raya;
|
||||||
|
return !!(inst && inst.running);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function commandVersion(command, args) {
|
||||||
|
return L.resolveDefault(fs.exec(command, args || []), null).then(function (res) {
|
||||||
|
if (!res || res.code !== 0 || !res.stdout)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var line = res.stdout.trim().split('\n')[0].trim();
|
||||||
|
return line || null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectBackends() {
|
||||||
|
return L.resolveDefault(fs.exec('/usr/libexec/v2raya-detect', []), null).then(function (res) {
|
||||||
|
var info = {};
|
||||||
|
|
||||||
|
if (!res || res.code !== 0)
|
||||||
|
return info;
|
||||||
|
|
||||||
|
(res.stdout || '').split('\n').forEach(function (line) {
|
||||||
|
var pos = line.indexOf('=');
|
||||||
|
if (pos > 0)
|
||||||
|
info[line.substring(0, pos)] = line.substring(pos + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
return info;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function backendRow(label, path, version, packageFlag, note) {
|
||||||
|
var field = [];
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
field.push(E('strong', {}, _('Detected')));
|
||||||
|
field.push(' — ', E('code', {}, path));
|
||||||
|
if (version)
|
||||||
|
field.push(E('div', { class: 'cbi-section-descr' }, version));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
field.push(E('span', { style: 'color:#777' }, _('Not installed')));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packageFlag === '1')
|
||||||
|
field.push(E('div', { class: 'cbi-section-descr' }, _('Package installed')));
|
||||||
|
|
||||||
|
if (note)
|
||||||
|
field.push(E('div', { class: 'cbi-section-descr' }, note));
|
||||||
|
|
||||||
|
return E('div', { class: 'cbi-value' }, [
|
||||||
|
E('label', { class: 'cbi-value-title' }, label),
|
||||||
|
E('div', { class: 'cbi-value-field' }, field)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseListenAddress(address) {
|
||||||
|
var match = String(address || '').match(/^\[?([^\]]*)\]?:(\d+)$/);
|
||||||
|
var host = match ? match[1] : '';
|
||||||
|
var port = match ? match[2] : '2017';
|
||||||
|
|
||||||
|
if (!host || host === '0.0.0.0' || host === '::')
|
||||||
|
host = window.location.hostname;
|
||||||
|
|
||||||
|
if (host.indexOf(':') !== -1)
|
||||||
|
host = '[' + host + ']';
|
||||||
|
|
||||||
|
return { host: host, port: port };
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderStatus(running) {
|
||||||
|
var el = document.getElementById('v2raya-status');
|
||||||
|
if (!el)
|
||||||
|
return;
|
||||||
|
|
||||||
|
el.textContent = running ? _('Running') : _('Stopped');
|
||||||
|
el.style.color = running ? '#2e7d32' : '#c62828';
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBusy(button, busy) {
|
||||||
|
if (!button)
|
||||||
|
return;
|
||||||
|
button.disabled = busy;
|
||||||
|
}
|
||||||
|
|
||||||
|
function runAction(action, button) {
|
||||||
|
setBusy(button, true);
|
||||||
|
|
||||||
|
return L.resolveDefault(fs.exec('/etc/init.d/v2raya', [ action ]), null).then(function (res) {
|
||||||
|
setBusy(button, false);
|
||||||
|
|
||||||
|
if (!res || res.code !== 0) {
|
||||||
|
ui.addNotification(null, E('p', {},
|
||||||
|
(res && (res.stderr || res.stdout)) || _('The service command failed.')), 'danger');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.addNotification(null, E('p', {}, _('Service action "%s" completed.').format(action)), 'info');
|
||||||
|
return serviceRunning().then(renderStatus);
|
||||||
|
}).catch(function (err) {
|
||||||
|
setBusy(button, false);
|
||||||
|
ui.addNotification(null, E('p', {}, _('Unable to run the service command: %s').format(err)), 'danger');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function startService(button) {
|
||||||
|
uci.set('v2raya', 'config', 'enabled', '1');
|
||||||
|
|
||||||
|
return L.resolveDefault(uci.save(), null).then(function () {
|
||||||
|
return runAction('start', button);
|
||||||
|
}).then(function () {
|
||||||
|
/*
|
||||||
|
* Persist enabled=1 so the service also starts after a reboot.
|
||||||
|
* The resulting config.change event may cause one more restart;
|
||||||
|
* that is expected after an apply and the page polls the state.
|
||||||
|
*/
|
||||||
|
return L.resolveDefault(uci.apply(), null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return view.extend({
|
||||||
|
load: function () {
|
||||||
|
return Promise.all([
|
||||||
|
uci.load('v2raya'),
|
||||||
|
commandVersion('/usr/bin/v2raya', [ '--version' ]),
|
||||||
|
commandVersion('/usr/bin/v2raya_core', [ 'version' ]),
|
||||||
|
detectBackends()
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function (data) {
|
||||||
|
var address = uci.get('v2raya', 'config', 'address') || '0.0.0.0:2017';
|
||||||
|
var baseurl = uci.get('v2raya', 'config', 'baseurl') || '/';
|
||||||
|
if (baseurl === '')
|
||||||
|
baseurl = '/';
|
||||||
|
var listen = parseListenAddress(address);
|
||||||
|
var weburl = 'http://' + listen.host + ':' + listen.port +
|
||||||
|
(baseurl === '/' ? '/' : '/' + baseurl.replace(/^\/+|\/+$/g, '') + '/');
|
||||||
|
|
||||||
|
var serviceVersion = data[1] || _('not detected');
|
||||||
|
var coreVersion = data[2] || _('not detected');
|
||||||
|
var backends = data[3] || {};
|
||||||
|
var detectAvailable = Object.keys(backends).length > 0;
|
||||||
|
var enabledServices = (backends.services_enabled || '').split(',').filter(function (name) {
|
||||||
|
return name && name !== 'v2raya';
|
||||||
|
});
|
||||||
|
|
||||||
|
var backendChildren = [
|
||||||
|
E('h3', {}, _('Detected cores and proxy services')),
|
||||||
|
E('p', { class: 'cbi-section-descr' },
|
||||||
|
_('v2rayA 2.5.x runs only its bundled v2raya_core. Existing Xray-core, v2ray and sing-box installations are detected here so they are not duplicated or replaced; they are never used as the v2rayA backend.'))
|
||||||
|
];
|
||||||
|
|
||||||
|
if (detectAvailable) {
|
||||||
|
backendChildren.push(
|
||||||
|
backendRow(_('v2raya_core (required)'), backends.core_path, backends.core_version, null,
|
||||||
|
_('This is the only core v2rayA 2.5.x supports.')),
|
||||||
|
backendRow(_('Xray-core'), backends.xray_path, backends.xray_version, backends.xray_package,
|
||||||
|
_('Left untouched. Do not point the core binary setting at this.')),
|
||||||
|
backendRow(_('v2ray-core'), backends.v2ray_path, backends.v2ray_version, backends.v2ray_package,
|
||||||
|
_('Left untouched. Do not point the core binary setting at this.')),
|
||||||
|
backendRow(_('sing-box'), backends.singbox_path, backends.singbox_version, backends.singbox_package,
|
||||||
|
_('Left untouched. sing-box uses a different configuration format and cannot run v2rayA configs.')),
|
||||||
|
E('div', { class: 'cbi-value' }, [
|
||||||
|
E('label', { class: 'cbi-value-title' }, _('Rule data')),
|
||||||
|
E('div', { class: 'cbi-value-field' },
|
||||||
|
(backends.geoip_present === '1' && backends.geosite_present === '1')
|
||||||
|
? _('geoip.dat and geosite.dat are installed')
|
||||||
|
: _('Missing. v2rayA downloads the data on first start and needs internet access; install v2raya-geoip and v2raya-geosite for offline use.'))
|
||||||
|
]),
|
||||||
|
E('div', { class: 'cbi-value' }, [
|
||||||
|
E('label', { class: 'cbi-value-title' }, _('Other proxy services')),
|
||||||
|
E('div', { class: 'cbi-value-field' },
|
||||||
|
backends.services_present ? backends.services_present.split(',').join(', ') : _('None detected'))
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
backendChildren.push(E('p', { class: 'cbi-section-descr' },
|
||||||
|
_('Core and service detection is unavailable. The installed v2raya package does not provide the detection helper; version 2.5.x and later install it.')));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detectAvailable && !backends.core_path)
|
||||||
|
backendChildren.push(E('div', { class: 'alert-message warning' },
|
||||||
|
_('v2raya_core is missing. Install the v2raya-core package.')));
|
||||||
|
|
||||||
|
if (detectAvailable && backends.old_v2raya_package === '1')
|
||||||
|
backendChildren.push(E('div', { class: 'alert-message warning' },
|
||||||
|
_('An older v2raya package is still installed. Remove it to avoid duplicate services.')));
|
||||||
|
|
||||||
|
if (detectAvailable && enabledServices.length)
|
||||||
|
backendChildren.push(E('div', { class: 'alert-message warning' },
|
||||||
|
_('These proxy services are enabled at boot: %s. Run only one transparent-proxy stack, otherwise duplicate firewall rules will conflict.').format(enabledServices.join(', '))));
|
||||||
|
|
||||||
|
var status = E('span', { id: 'v2raya-status', style: 'font-weight:bold' }, _('Checking…'));
|
||||||
|
|
||||||
|
var startBtn = E('button', { class: 'btn cbi-button cbi-button-apply' }, _('Start'));
|
||||||
|
var stopBtn = E('button', { class: 'btn cbi-button cbi-button-reset' }, _('Stop'));
|
||||||
|
var restartBtn = E('button', { class: 'btn cbi-button cbi-button-action' }, _('Restart'));
|
||||||
|
|
||||||
|
startBtn.addEventListener('click', function () { startService(startBtn); });
|
||||||
|
stopBtn.addEventListener('click', function () { runAction('stop', stopBtn); });
|
||||||
|
restartBtn.addEventListener('click', function () { runAction('restart', restartBtn); });
|
||||||
|
|
||||||
|
var refresh = function () {
|
||||||
|
return serviceRunning().then(renderStatus);
|
||||||
|
};
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
poll.add(refresh, 5);
|
||||||
|
|
||||||
|
return E('div', { class: 'cbi-map' }, [
|
||||||
|
E('h2', {}, _('v2rayA')),
|
||||||
|
E('div', { class: 'cbi-map-descr' }, [
|
||||||
|
_('A web client for its own Xray-based core, with transparent proxy support.'),
|
||||||
|
' ',
|
||||||
|
E('a', { href: weburl, target: '_blank', rel: 'noreferrer noopener' }, weburl)
|
||||||
|
]),
|
||||||
|
E('div', { class: 'cbi-section' }, [
|
||||||
|
E('div', { class: 'cbi-value' }, [
|
||||||
|
E('label', { class: 'cbi-value-title' }, _('Service')),
|
||||||
|
E('div', { class: 'cbi-value-field' }, status)
|
||||||
|
]),
|
||||||
|
E('div', { class: 'cbi-value' }, [
|
||||||
|
E('label', { class: 'cbi-value-title' }, _('v2rayA version')),
|
||||||
|
E('div', { class: 'cbi-value-field' }, serviceVersion)
|
||||||
|
]),
|
||||||
|
E('div', { class: 'cbi-value' }, [
|
||||||
|
E('label', { class: 'cbi-value-title' }, _('v2raya_core version')),
|
||||||
|
E('div', { class: 'cbi-value-field' }, coreVersion)
|
||||||
|
]),
|
||||||
|
E('div', { class: 'cbi-value' }, [
|
||||||
|
E('label', { class: 'cbi-value-title' }, _('Listening address')),
|
||||||
|
E('div', { class: 'cbi-value-field' }, address)
|
||||||
|
]),
|
||||||
|
E('div', { class: 'cbi-value' }, [
|
||||||
|
E('label', { class: 'cbi-value-title' }, _('Web interface')),
|
||||||
|
E('div', { class: 'cbi-value-field' },
|
||||||
|
E('a', { href: weburl, target: '_blank', rel: 'noreferrer noopener' }, _('Open v2rayA')))
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
E('div', { class: 'cbi-section' }, backendChildren),
|
||||||
|
E('div', { class: 'cbi-section' }, [
|
||||||
|
E('div', { class: 'cbi-value' }, [
|
||||||
|
E('label', { class: 'cbi-value-title' }, _('Actions')),
|
||||||
|
E('div', { class: 'cbi-value-field' }, [ startBtn, ' ', stopBtn, ' ', restartBtn ])
|
||||||
|
]),
|
||||||
|
E('p', { class: 'cbi-section-descr' },
|
||||||
|
_('These buttons control the background service. Connecting the proxy is done in the v2rayA web UI with the Connect button.'))
|
||||||
|
]),
|
||||||
|
E('div', { class: 'cbi-section' }, [
|
||||||
|
E('p', { class: 'cbi-section-descr' },
|
||||||
|
_('This independent, community-run packaging project is not affiliated with the upstream v2rayA authors. It is AI-assisted and human-maintained.'))
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSave: null,
|
||||||
|
handleSaveApply: null,
|
||||||
|
handleReset: null
|
||||||
|
});
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: luci-app-v2raya\n"
|
||||||
|
"Report-Msgid-Bugs-To: https://github.com/AmrFateem/luci-V2raya-NextGen/issues\n"
|
||||||
|
"POT-Creation-Date: 2026-11-07 00:00+0000\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
msgid "v2rayA"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Overview"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Log"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Stopped"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Checking…"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Start"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Stop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Restart"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Service"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "v2rayA version"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "v2raya_core version"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Listening address"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Web interface"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Open v2rayA"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Actions"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Enable service"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "General"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Transparent proxy"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Logging"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Advanced"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "IPv6 support"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "nftables support"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Auto"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "On"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Off"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Log level"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Trace"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Debug"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Info"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Warning"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Keep logs for"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Clear log"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Refresh"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "The log is empty."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "The log file does not exist yet. Start the service and try again."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "v2rayA log"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Settings for the v2rayA service. Save & Apply restarts the service so the new values take effect. v2rayA 2.5.x uses only its bundled v2raya_core; Xray-core and sing-box are not supported backends."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "This independent, community-run packaging project is not affiliated with the upstream v2rayA authors. It is AI-assisted and human-maintained."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Warning keeps flash writes down. Use Info while debugging."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Go memory limit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Soft memory limit for both v2raya and v2raya_core (GOMEMLIMIT). Use 0 to disable, or 96MiB on a larger router."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Go scheduler threads"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "GOMAXPROCS. 0 uses every CPU core; 2 is enough for most routers."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Go GC percent"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "GOGC. 0 keeps the Go default; lower values use less memory and more CPU."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Open file limit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Maximum open file descriptors. 16384 is plenty for a home router and bounds a connection flood."
|
||||||
|
msgstr ""
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"admin/services/v2raya": {
|
||||||
|
"title": "v2rayA",
|
||||||
|
"order": 60,
|
||||||
|
"action": {
|
||||||
|
"type": "firstchild"
|
||||||
|
},
|
||||||
|
"depends": {
|
||||||
|
"acl": [ "luci-app-v2raya" ],
|
||||||
|
"uci": { "v2raya": true }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"admin/services/v2raya/overview": {
|
||||||
|
"title": "Overview",
|
||||||
|
"order": 10,
|
||||||
|
"action": {
|
||||||
|
"type": "view",
|
||||||
|
"path": "v2raya/overview"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"admin/services/v2raya/config": {
|
||||||
|
"title": "Settings",
|
||||||
|
"order": 20,
|
||||||
|
"action": {
|
||||||
|
"type": "view",
|
||||||
|
"path": "v2raya/config"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"admin/services/v2raya/log": {
|
||||||
|
"title": "Log",
|
||||||
|
"order": 30,
|
||||||
|
"action": {
|
||||||
|
"type": "view",
|
||||||
|
"path": "v2raya/log"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"luci-app-v2raya": {
|
||||||
|
"description": "Grant access to the v2rayA service and configuration",
|
||||||
|
"read": {
|
||||||
|
"file": {
|
||||||
|
"/etc/init.d/v2raya": [ "exec" ],
|
||||||
|
"/usr/bin/v2raya": [ "exec" ],
|
||||||
|
"/usr/bin/v2raya_core": [ "exec" ],
|
||||||
|
"/usr/libexec/v2raya-detect": [ "exec" ],
|
||||||
|
"/var/log/v2raya/v2raya.log": [ "read" ]
|
||||||
|
},
|
||||||
|
"ubus": {
|
||||||
|
"service": [ "list" ]
|
||||||
|
},
|
||||||
|
"uci": [ "v2raya" ]
|
||||||
|
},
|
||||||
|
"write": {
|
||||||
|
"file": {
|
||||||
|
"/etc/init.d/v2raya": [ "exec" ],
|
||||||
|
"/var/log/v2raya/v2raya.log": [ "write" ]
|
||||||
|
},
|
||||||
|
"uci": [ "v2raya" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,10 +6,10 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_UPSTREAM_NAME:=natmap
|
PKG_UPSTREAM_NAME:=natmap
|
||||||
PKG_NAME:=natmapt
|
PKG_NAME:=natmapt
|
||||||
PKG_UPSTREAM_VERSION:=20260214
|
PKG_UPSTREAM_VERSION:=20261109
|
||||||
PKG_UPSTREAM_GITHASH:=
|
PKG_UPSTREAM_GITHASH:=
|
||||||
PKG_VERSION:=$(PKG_UPSTREAM_VERSION)$(if $(PKG_UPSTREAM_GITHASH),~$(call version_abbrev,$(PKG_UPSTREAM_GITHASH)))
|
PKG_VERSION:=$(PKG_UPSTREAM_VERSION)$(if $(PKG_UPSTREAM_GITHASH),~$(call version_abbrev,$(PKG_UPSTREAM_GITHASH)))
|
||||||
PKG_RELEASE:=19
|
PKG_RELEASE:=20
|
||||||
SCRIPTS_VERSION:=0.2026.01.24
|
SCRIPTS_VERSION:=0.2026.01.24
|
||||||
|
|
||||||
PKG_SOURCE_SUBDIR:=$(PKG_UPSTREAM_NAME)-$(PKG_UPSTREAM_VERSION)
|
PKG_SOURCE_SUBDIR:=$(PKG_UPSTREAM_NAME)-$(PKG_UPSTREAM_VERSION)
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
#
|
||||||
|
# Copyright (C) 2021 ImmortalWrt.org
|
||||||
|
# Copyright (C) 2026 Amr Fateem <amr.fateem@yahoo.com>
|
||||||
|
#
|
||||||
|
# v2raya_core for OpenWrt. This is the merged xray-core based binary from
|
||||||
|
# the v2rayA 2.5.x tree. It is built from the same source tarball as the
|
||||||
|
# service and must always carry the same version.
|
||||||
|
|
||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
PKG_NAME:=v2raya-core
|
||||||
|
PKG_VERSION:=2.5.14
|
||||||
|
PKG_RELEASE:=1
|
||||||
|
|
||||||
|
PKG_SOURCE:=v2rayA-$(PKG_VERSION).tar.gz
|
||||||
|
PKG_SOURCE_URL:=https://codeload.github.com/v2rayA/v2rayA/tar.gz/v$(PKG_VERSION)?
|
||||||
|
PKG_HASH:=skip
|
||||||
|
|
||||||
|
PKG_BUILD_DIR:=$(BUILD_DIR)/v2rayA-core-$(PKG_VERSION)/core
|
||||||
|
|
||||||
|
PKG_LICENSE:=MPL-2.0
|
||||||
|
PKG_LICENSE_FILES:=../LICENSE
|
||||||
|
PKG_MAINTAINER:=Amr Fateem <amr.fateem@yahoo.com>
|
||||||
|
|
||||||
|
PKG_BUILD_DEPENDS:=golang/host
|
||||||
|
PKG_BUILD_PARALLEL:=1
|
||||||
|
PKG_BUILD_FLAGS:=no-mips16
|
||||||
|
|
||||||
|
# Keep this in sync with v2raya/Makefile.
|
||||||
|
V2RAYA_GO_TOOLCHAIN?=go1.27.3+auto
|
||||||
|
|
||||||
|
GO_PKG:=github.com/v2rayA/v2raya-core
|
||||||
|
GO_PKG_BUILD_PKG:=github.com/v2rayA/v2raya-core/main
|
||||||
|
GO_PKG_LDFLAGS_X:=main.Version=$(PKG_VERSION)
|
||||||
|
|
||||||
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
|
||||||
|
|
||||||
|
# The core is pure Go. CGO stays disabled on every target, including mips:
|
||||||
|
# this is the same configuration upstream uses for its release binaries and
|
||||||
|
# it keeps the binary self-contained.
|
||||||
|
GO_PKG_TARGET_VARS:=$(filter-out CGO_ENABLED=%,$(GO_PKG_TARGET_VARS)) CGO_ENABLED=0
|
||||||
|
GO_PKG_DEFAULT_LDFLAGS:=$(filter-out -linkmode external,$(GO_PKG_DEFAULT_LDFLAGS))
|
||||||
|
GO_PKG_BUILD_VARS:=$(filter-out GOTOOLCHAIN=%,$(GO_PKG_BUILD_VARS)) GOTOOLCHAIN=$(V2RAYA_GO_TOOLCHAIN)
|
||||||
|
|
||||||
|
TAR_OPTIONS+= --strip-components 1
|
||||||
|
TAR_CMD=$(HOST_TAR) -C $(1)/.. $(TAR_OPTIONS)
|
||||||
|
|
||||||
|
define Package/v2raya-core
|
||||||
|
TITLE:=v2raya_core - the merged xray-core used by v2rayA
|
||||||
|
SECTION:=net
|
||||||
|
CATEGORY:=Network
|
||||||
|
SUBMENU:=Web Servers/Proxies
|
||||||
|
DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle
|
||||||
|
CONFLICTS:=v2raya-core-nextgen
|
||||||
|
URL:=https://github.com/v2rayA/v2rayA
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/v2raya-core/description
|
||||||
|
v2raya_core combines xray-core with the MultiObservatory support and the
|
||||||
|
extra protocols required by v2rayA 2.5.x. The service and the core must
|
||||||
|
always be installed at the same version.
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/v2raya-core/install
|
||||||
|
$(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR))
|
||||||
|
|
||||||
|
$(INSTALL_DIR) $(1)/usr/bin
|
||||||
|
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/main $(1)/usr/bin/v2raya_core
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call GoBinPackage,v2raya-core))
|
||||||
|
$(eval $(call BuildPackage,v2raya-core))
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
#
|
||||||
|
# Copyright (C) 2026 Amr Fateem <amr.fateem@yahoo.com>
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
v2raya-core)
|
||||||
|
/usr/bin/v2raya_core version | grep -F "$2"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
#
|
||||||
|
# Copyright (C) 2021 ImmortalWrt.org
|
||||||
|
# Copyright (C) 2026 Amr Fateem <amr.fateem@yahoo.com>
|
||||||
|
#
|
||||||
|
# GeoIP database used by v2rayA. The package is architecture independent and
|
||||||
|
# is updated independently of the v2rayA release by scripts/update-version.sh.
|
||||||
|
|
||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
PKG_NAME:=v2raya-geoip
|
||||||
|
PKG_VERSION:=202611050539
|
||||||
|
PKG_RELEASE:=1
|
||||||
|
|
||||||
|
PKG_LICENSE:=CC-BY-SA-4.0
|
||||||
|
PKG_MAINTAINER:=Amr Fateem <amr.fateem@yahoo.com>
|
||||||
|
|
||||||
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|
||||||
|
GEOIP_FILE:=geoip.dat.$(PKG_VERSION)
|
||||||
|
GEOIP_HASH:=eedb24b3b9fcba27e06b92c0428dab90d9496083091ae4cf39e11387fd99d0e2
|
||||||
|
|
||||||
|
define Download/geoip
|
||||||
|
URL:=https://github.com/v2fly/geoip/releases/download/$(PKG_VERSION)/
|
||||||
|
URL_FILE:=geoip.dat
|
||||||
|
FILE:=$(GEOIP_FILE)
|
||||||
|
HASH:=skip
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/v2raya-geoip
|
||||||
|
TITLE:=GeoIP database for v2rayA
|
||||||
|
SECTION:=net
|
||||||
|
CATEGORY:=Network
|
||||||
|
PKGARCH:=all
|
||||||
|
URL:=https://github.com/v2fly/geoip
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/v2raya-geoip/description
|
||||||
|
GeoIP database (geoip.dat) used by v2rayA and v2raya_core for routing.
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/v2raya-geoip/postinst
|
||||||
|
#!/bin/sh
|
||||||
|
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||||
|
if [ -x /etc/init.d/v2raya ] && /etc/init.d/v2raya enabled; then
|
||||||
|
/etc/init.d/v2raya restart
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Build/Prepare
|
||||||
|
$(call Build/Prepare/Default)
|
||||||
|
$(call Download,geoip)
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Build/Compile
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/v2raya-geoip/install
|
||||||
|
$(INSTALL_DIR) $(1)/usr/share/v2raya
|
||||||
|
$(INSTALL_DATA) $(DL_DIR)/$(GEOIP_FILE) $(1)/usr/share/v2raya/geoip.dat
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call Download,geoip))
|
||||||
|
$(eval $(call BuildPackage,v2raya-geoip))
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
#
|
||||||
|
# Copyright (C) 2021 ImmortalWrt.org
|
||||||
|
# Copyright (C) 2026 Amr Fateem <amr.fateem@yahoo.com>
|
||||||
|
#
|
||||||
|
# GeoSite database used by v2rayA. The package is architecture independent
|
||||||
|
# and is updated independently of the v2rayA release by
|
||||||
|
# scripts/update-version.sh.
|
||||||
|
|
||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
PKG_NAME:=v2raya-geosite
|
||||||
|
PKG_VERSION:=20261107053621
|
||||||
|
PKG_RELEASE:=1
|
||||||
|
|
||||||
|
PKG_LICENSE:=MIT
|
||||||
|
PKG_MAINTAINER:=Amr Fateem <amr.fateem@yahoo.com>
|
||||||
|
|
||||||
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|
||||||
|
GEOSITE_FILE:=dlc.dat.$(PKG_VERSION)
|
||||||
|
GEOSITE_HASH:=f110a7b96b3e3ed9c19cf18ae0ac5f8c46de54fa778863609c0a3b8f1738b58c
|
||||||
|
|
||||||
|
define Download/geosite
|
||||||
|
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(PKG_VERSION)/
|
||||||
|
URL_FILE:=dlc.dat
|
||||||
|
FILE:=$(GEOSITE_FILE)
|
||||||
|
HASH:=skip
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/v2raya-geosite
|
||||||
|
TITLE:=GeoSite database for v2rayA
|
||||||
|
SECTION:=net
|
||||||
|
CATEGORY:=Network
|
||||||
|
PKGARCH:=all
|
||||||
|
URL:=https://github.com/v2fly/domain-list-community
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/v2raya-geosite/description
|
||||||
|
GeoSite database (geosite.dat) used by v2rayA and v2raya_core for routing.
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/v2raya-geosite/postinst
|
||||||
|
#!/bin/sh
|
||||||
|
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||||
|
if [ -x /etc/init.d/v2raya ] && /etc/init.d/v2raya enabled; then
|
||||||
|
/etc/init.d/v2raya restart
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Build/Prepare
|
||||||
|
$(call Build/Prepare/Default)
|
||||||
|
$(call Download,geosite)
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Build/Compile
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/v2raya-geosite/install
|
||||||
|
$(INSTALL_DIR) $(1)/usr/share/v2raya
|
||||||
|
$(INSTALL_DATA) $(DL_DIR)/$(GEOSITE_FILE) $(1)/usr/share/v2raya/geosite.dat
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call Download,geosite))
|
||||||
|
$(eval $(call BuildPackage,v2raya-geosite))
|
||||||
Reference in new issue
Block a user