update 2026-01-12 00:30:14

This commit is contained in:
kenzok8
2026-01-12 00:30:14 +08:00
parent eb598228a6
commit c30ad0fb87
8 changed files with 240 additions and 58 deletions

View File

@@ -4,11 +4,11 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-natter2 PKG_NAME:=luci-app-natter2
PKG_VERSION:=1.0 PKG_VERSION:=1.0
PKG_RELEASE:=4 PKG_RELEASE:=5
LUCI_TITLE:=LuCI Support for Natter v2.2.1 LUCI_TITLE:=LuCI Support for Natter v2.2.1
LUCI_PKGARCH:=all LUCI_PKGARCH:=all
LUCI_DEPENDS:=+natter2 +coreutils-nohup LUCI_DEPENDS:=+natter2
include $(TOPDIR)/feeds/luci/luci.mk include $(TOPDIR)/feeds/luci/luci.mk

View File

@@ -1,5 +1,6 @@
#!/bin/sh /etc/rc.common #!/bin/sh /etc/rc.common
USE_PROCD=1
START=98 START=98
script_path="/usr/share/natter2/natter.py" script_path="/usr/share/natter2/natter.py"
@@ -11,20 +12,19 @@ start_service() {
enable_forwarding forwarding_method target_address target_port \ enable_forwarding forwarding_method target_address target_port \
enable_forwarding_retry enable_quit delay log_level enable_notify \ enable_forwarding_retry enable_quit delay log_level enable_notify \
notify_path enable_upnp_service" notify_path enable_upnp_service"
for i in $basic_list
do for i in $basic_list; do
local eval $i="$(uci_get_by_type base 0 $i)" local eval $i="$(uci_get_by_type base 0 $i)"
done ; unset i done ; unset i
if [ "$enable" == 1 ]
then if [ "$enable" == 1 ]; then
mkdir -p ${tmp_path} mkdir -p ${tmp_path}
mkdir -p /var/etc/natter2 mkdir -p /var/etc/natter2
for u in $(seq 0 $(($(uci show natter2 2> /dev/null | egrep '@instances\[[0-9]\]+=instances' | wc -l) - 1)))
for u in $(seq 0 $(($(uci show natter2 2> /dev/null | grep -E '@instances\[[0-9]\]+=instances' | wc -l) - 1)))
do do
for i in $instance_list for i in $instance_list; do
do
local eval $i="$(uci_get_by_type instances $u $i)" local eval $i="$(uci_get_by_type instances $u $i)"
# echo "$i : $(uci_get_by_type instances $u $i)"
done ; unset i done ; unset i
[ "$enable_instance" != 1 ] && continue [ "$enable_instance" != 1 ] && continue
@@ -32,27 +32,22 @@ start_service() {
[ "$protocol" == udp ] && script_command="$script_command -u" [ "$protocol" == udp ] && script_command="$script_command -u"
if [ "$enable_stun_server" == 1 ] if [ "$enable_stun_server" == 1 ]; then
then for i in $stun_server; do
for i in $stun_server
do
script_command="$script_command -s $i" script_command="$script_command -s $i"
done ; unset i done ; unset i
fi fi
[ "$enable_keepalive_server" == 1 ] && script_command="$script_command -h $keepalive_server" [ "$enable_keepalive_server" == 1 ] && script_command="$script_command -h $keepalive_server"
[ "$interval" ] && script_command="$script_command -k $interval" [ "$interval" ] && script_command="$script_command -k $interval"
[ "$enable_upnp_service" == 1 ] && script_command="$script_command -U" [ "$enable_upnp_service" == 1 ] && script_command="$script_command -U"
if [ "$enable_bonding" == 1 ] if [ "$enable_bonding" == 1 ]; then
then
[ "$bonding_interface" ] && script_command="$script_command -i $bonding_interface" [ "$bonding_interface" ] && script_command="$script_command -i $bonding_interface"
[ "$bonding_port" ] && script_command="$script_command -b $bonding_port" [ "$bonding_port" ] && script_command="$script_command -b $bonding_port"
fi fi
if [ "$enable_forwarding" == 1 ] if [ "$enable_forwarding" == 1 ]; then
then
[ "$forwarding_method" ] && script_command="$script_command -m $forwarding_method" [ "$forwarding_method" ] && script_command="$script_command -m $forwarding_method"
[ "$target_address" ] && script_command="$script_command -t $target_address" [ "$target_address" ] && script_command="$script_command -t $target_address"
[ "$target_port" ] && script_command="$script_command -p $target_port" [ "$target_port" ] && script_command="$script_command -p $target_port"
@@ -60,35 +55,30 @@ start_service() {
fi fi
[ "$enable_quit" == 1 ] && script_command="$script_command -q" [ "$enable_quit" == 1 ] && script_command="$script_command -q"
[ "$log_level" == "verbose" ] && script_command="$script_command -v" [ "$log_level" == "verbose" ] && script_command="$script_command -v"
if [ "$enable_notify" == 1 ] if [ "$enable_notify" == 1 ]; then
then
echo "$notify_path" > /var/etc/natter2/${id}-notify echo "$notify_path" > /var/etc/natter2/${id}-notify
var_file=/var/etc/natter2/${id}-${u}-1 var_file=/var/etc/natter2/${id}-${u}-1
else else
var_file=/var/etc/natter2/${id}-${u}-0 var_file=/var/etc/natter2/${id}-${u}-0
fi fi
log_file=${tmp_path}/natter2-${id}.log
cp -a /usr/share/luci-app-natter2/notify-base.sh $var_file cp -a /usr/share/luci-app-natter2/notify-base.sh $var_file
chmod +x $var_file chmod +x $var_file
# echo "log_file: $log_file" procd_open_instance "natter2_${id}"
# echo "var_file: $var_file" procd_set_param command $(command -v python) "$script_path" $script_command -e $var_file
sleep $delay procd_set_param stdout 1
for i in $(ps -efww | grep "$script_path" | grep -v grep | grep -v $$ | grep "$id" | awk '{print $1}') procd_set_param stderr 1
do
kill -9 "$i" 2> /dev/null
done
nohup $(command -v python) "$script_path" $script_command -e $var_file > "$log_file" 2>&1 & [ -n "$delay" ] && procd_set_param delay "$delay"
procd_set_param respawn
for i in $instance_list procd_close_instance
do
for i in $instance_list; do
unset $(echo $i) unset $(echo $i)
done ; unset i done ; unset i
unset script_command unset script_command
@@ -99,24 +89,13 @@ start_service() {
} }
stop_service() { stop_service() {
echo "Stopping Natter2 ..." rm -rf "/var/etc/natter2" 2> /dev/null
for i in $(ps -ww | grep "$script_path" | grep -v grep | grep -v $$ | awk '{print $1}') for u in $(seq 0 $(($(uci show natter2 2> /dev/null | grep -E '@instances\[[0-9]\]+=instances' | wc -l) - 1)))
do
kill -15 "$i" 2> /dev/null
done
rm -r "$tmp_path" 2> /dev/null
for u in $(seq 0 $(($(uci show natter2 2> /dev/null | egrep '@instances\[[0-9]\]+=instances' | wc -l) - 1)))
do do
uci set natter2.@instances[$u].tmp_public_port="" uci set natter2.@instances[$u].tmp_public_port=""
uci commit natter2 uci commit natter2
done done
rm -f /tmp/natter2_nat_type rm -f /tmp/natter2_nat_type
}
restart() {
stop_service
start_service
} }
service_triggers() { service_triggers() {
@@ -126,4 +105,4 @@ service_triggers() {
uci_get_by_type() { uci_get_by_type() {
local ret=$(uci get natter2.@$1[$2].$3 2>/dev/null) local ret=$(uci get natter2.@$1[$2].$3 2>/dev/null)
echo ${ret:=$4} echo ${ret:=$4}
} }

View File

@@ -243,6 +243,6 @@ o.cfgvalue = function(self, section)
section, translate("Manual subscription")) section, translate("Manual subscription"))
end end
s:append(Template(appname .. "/node_subscribe/js")) m:append(Template(appname .. "/node_subscribe/js"))
return m return m

View File

@@ -4,12 +4,10 @@ local api = require "luci.passwall.api"
<script src="<%=resource%>/view/<%=api.appname%>/Sortable.min.js?v=26.1.9"></script> <script src="<%=resource%>/view/<%=api.appname%>/Sortable.min.js?v=26.1.9"></script>
<style> <style>
<% if api.is_js_luci() then -%>
table .cbi-button-up, table .cbi-button-up,
table .cbi-button-down { table .cbi-button-down {
display: none !important; display: none !important;
} }
<%- end %>
.drag-handle { .drag-handle {
cursor: grab !important; cursor: grab !important;
@@ -21,7 +19,6 @@ table .cbi-button-down {
padding: 0 !important; padding: 0 !important;
line-height: inherit; line-height: inherit;
user-select: none; user-select: none;
color: #00000070;
align-self: stretch; align-self: stretch;
} }
@@ -83,6 +80,8 @@ table .cbi-button-down {
var section = document.getElementById("cbi-<%=api.appname%>-haproxy_config"); var section = document.getElementById("cbi-<%=api.appname%>-haproxy_config");
if (!section) return; if (!section) return;
hideSortColumn(section);
// === 插入 drag handle === // === 插入 drag handle ===
var delBtns = section.getElementsByClassName("cbi-button-remove"); var delBtns = section.getElementsByClassName("cbi-button-remove");
for (var i = 0; i < delBtns.length; i++) { for (var i = 0; i < delBtns.length; i++) {
@@ -150,6 +149,37 @@ table .cbi-button-down {
} }
} }
// 隐藏18.06 up/down 列
function hideSortColumn(section) {
var table = section.querySelector("table");
if (!table) return;
var ths = Array.prototype.slice.call(table.querySelectorAll("tr.cbi-section-table-titles > th"));
var dataRows = table.querySelectorAll("tr.cbi-section-table-row");
if (!ths.length || !dataRows.length) return;
var sortCol = -1;
for (var i = 0; i < ths.length; i++) {
var hasSort = false, invalid = false;
dataRows.forEach(function(tr) {
var td = tr.querySelectorAll(":scope > td")[i];
if (!td) return;
if (td.querySelector(".cbi-button-edit, .cbi-button-remove")) invalid = true;
if (td.querySelector(".cbi-button-up, .cbi-button-down")) hasSort = true;
});
if (!invalid && hasSort) { sortCol = i; break; }
}
if (sortCol === -1) return;
var rows = [table.querySelector("tr.cbi-section-table-titles")].concat(
Array.prototype.slice.call(dataRows),
Array.prototype.slice.call(table.querySelectorAll("tr.cbi-section-table-descr"))
);
rows.forEach(function(tr) {
var cells = Array.prototype.filter.call(tr.children, function(el) {
return el.tagName === "TH" || el.tagName === "TD";
});
if (cells[sortCol]) cells[sortCol].style.display = "none";
});
}
// === 等待 TypedSection 行稳定 === // === 等待 TypedSection 行稳定 ===
(function waitStable() { (function waitStable() {
var last = 0, stable = 0; var last = 0, stable = 0;

View File

@@ -68,7 +68,6 @@ table td, .table .td {
padding: 0 !important; padding: 0 !important;
line-height: inherit; line-height: inherit;
user-select: none; user-select: none;
color: #00000070;
align-self: stretch; align-self: stretch;
} }

View File

@@ -1,6 +1,33 @@
<% <%
local api = require "luci.passwall.api" local api = require "luci.passwall.api"
-%> -%>
<script src="<%=resource%>/view/<%=api.appname%>/Sortable.min.js?v=26.1.11"></script>
<style>
table .cbi-button-up,
table .cbi-button-down {
display: none !important;
}
.drag-handle {
cursor: grab !important;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 20px;
font-weight: 100;
padding: 0 !important;
line-height: inherit;
user-select: none;
align-self: stretch;
}
.dragging-row {
background-color: rgba(131, 191, 255, 0.7) !important;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
</style>
<script type="text/javascript"> <script type="text/javascript">
//<![CDATA[ //<![CDATA[
var appname = "<%= api.appname %>" var appname = "<%= api.appname %>"
@@ -107,5 +134,131 @@ local api = require "luci.passwall.api"
} }
}); });
} }
//订阅列表添加拖拽排序
(function () {
function initSortableForTable() {
var section = document.getElementById("cbi-<%=api.appname%>-subscribe_list");
if (!section) return;
hideSortColumn(section);
// === 插入 drag handle ===
var delBtns = section.getElementsByClassName("cbi-button-remove");
for (var i = 0; i < delBtns.length; i++) {
var btnsInRow = delBtns[i].closest("tr").getElementsByClassName("cbi-button-remove");
if (!btnsInRow || btnsInRow.length === 0) continue;
var btn = btnsInRow[btnsInRow.length - 1];
var parent = btn && btn.parentNode;
if (!parent || parent.getElementsByClassName("drag-handle").length) continue;
var handle = document.createElement("span");
handle.className = "drag-handle center";
handle.title = "<%:Drag to reorder%>";
handle.innerHTML = "⠿";
parent.insertBefore(handle, btn.nextSibling);
}
// === 初始化 Sortable ===
var table = section.getElementsByTagName("table")[0];
if (!table) return;
var root = table.tBodies[0] || table;
if (root._sortable_initialized) return root._sortable_instance;
root._sortable_initialized = true;
// 保存原始顺序
root._origOrder = getCurrentOrder(root);
try {
root._sortable_instance = Sortable.create(root, {
handle: ".drag-handle",
draggable: "tr.cbi-section-table-row",
animation: 150,
ghostClass: "dragging-row",
fallbackOnBody: true,
forceFallback: false,
swapThreshold: 0.65,
onEnd: function (evt) {
updateHiddenInput(root, section);
}
});
return root._sortable_instance;
} catch (e) {
root._sortable_initialized = false;
console.error("Sortable init failed:", e);
}
}
// 获取 table 当前行顺序
function getCurrentOrder(root) {
var order = [];
var rows = root.querySelectorAll("tr.cbi-section-table-row");
rows.forEach(function (tr) {
var id = tr.id || "";
if (id.startsWith("cbi-<%=api.appname%>-"))
id = id.replace("cbi-<%=api.appname%>-", "");
order.push(id);
});
return order;
}
// 拖拽完成后更新 hidden input
function updateHiddenInput(root, section) {
var newOrder = getCurrentOrder(root);
var changed = newOrder.join(" ") !== root._origOrder.join(" ");
var hiddenInput = section.querySelector('input[type="hidden"][id^="cbi.sts."]');
if (hiddenInput) {
hiddenInput.value = changed ? newOrder.join(" ") : "";
}
}
// 隐藏18.06 up/down 列
function hideSortColumn(section) {
var table = section.querySelector("table");
if (!table) return;
var ths = Array.prototype.slice.call(table.querySelectorAll("tr.cbi-section-table-titles > th"));
var dataRows = table.querySelectorAll("tr.cbi-section-table-row");
if (!ths.length || !dataRows.length) return;
var sortCol = -1;
for (var i = 0; i < ths.length; i++) {
var hasSort = false, invalid = false;
dataRows.forEach(function(tr) {
var td = tr.querySelectorAll(":scope > td")[i];
if (!td) return;
if (td.querySelector(".cbi-button-edit, .cbi-button-remove")) invalid = true;
if (td.querySelector(".cbi-button-up, .cbi-button-down")) hasSort = true;
});
if (!invalid && hasSort) { sortCol = i; break; }
}
if (sortCol === -1) return;
var rows = [table.querySelector("tr.cbi-section-table-titles")].concat(
Array.prototype.slice.call(dataRows),
Array.prototype.slice.call(table.querySelectorAll("tr.cbi-section-table-descr"))
);
rows.forEach(function(tr) {
var cells = Array.prototype.filter.call(tr.children, function(el) {
return el.tagName === "TH" || el.tagName === "TD";
});
if (cells[sortCol]) cells[sortCol].style.display = "none";
});
}
// === 等待 TypedSection 行稳定 ===
(function waitStable() {
var last = 0, stable = 0;
var THRESHOLD = 5;
function tick() {
var count = document.querySelectorAll("tr.cbi-section-table-row").length;
if (count && count === last) stable++;
else stable = 0;
last = count;
if (stable >= THRESHOLD)
initSortableForTable();
else
requestAnimationFrame(tick);
}
tick();
})();
})();
//]]> //]]>
</script> </script>

View File

@@ -4,12 +4,10 @@ local api = require "luci.passwall.api"
<script src="<%=resource%>/view/<%=api.appname%>/Sortable.min.js?v=26.1.9"></script> <script src="<%=resource%>/view/<%=api.appname%>/Sortable.min.js?v=26.1.9"></script>
<style> <style>
<% if api.is_js_luci() then -%>
table .cbi-button-up, table .cbi-button-up,
table .cbi-button-down { table .cbi-button-down {
display: none !important; display: none !important;
} }
<%- end %>
div.cbi-value[id$="-gfwlist_update"], div.cbi-value[id$="-gfwlist_update"],
div.cbi-value[id$="-chnroute_update"], div.cbi-value[id$="-chnroute_update"],
@@ -30,7 +28,6 @@ local api = require "luci.passwall.api"
padding: 0 !important; padding: 0 !important;
line-height: inherit; line-height: inherit;
user-select: none; user-select: none;
color: #00000070;
align-self: stretch; align-self: stretch;
} }
@@ -150,6 +147,8 @@ local api = require "luci.passwall.api"
var section = document.getElementById("cbi-<%=api.appname%>-shunt_rules"); var section = document.getElementById("cbi-<%=api.appname%>-shunt_rules");
if (!section) return; if (!section) return;
hideSortColumn(section);
// === 插入 drag handle === // === 插入 drag handle ===
var delBtns = section.getElementsByClassName("cbi-button-remove"); var delBtns = section.getElementsByClassName("cbi-button-remove");
for (var i = 0; i < delBtns.length; i++) { for (var i = 0; i < delBtns.length; i++) {
@@ -216,6 +215,28 @@ local api = require "luci.passwall.api"
hiddenInput.value = changed ? newOrder.join(" ") : ""; hiddenInput.value = changed ? newOrder.join(" ") : "";
} }
} }
// 隐藏18.06 up/down 列
function hideSortColumn(section) {
var table = section.getElementsByTagName("table")[0];
if(!table) return;
var rows = table.querySelectorAll("tr.cbi-section-table-row");
if(!rows.length) return;
var colCount = rows[0].children.length, sortCol = -1;
for(var col=0; col<colCount; col++){
var hasSort=false, invalid=false;
rows.forEach(function(tr){
var td=tr.children[col]; if(!td) return;
if(td.querySelector(".cbi-button-edit, .cbi-button-remove")) invalid=true;
if(td.querySelector(".cbi-button-up, .cbi-button-down")) hasSort=true;
});
if(!invalid && hasSort){ sortCol=col; break; }
}
if(sortCol===-1) return;
table.querySelectorAll("tr").forEach(function(tr){
var c=tr.children[sortCol]; if(c) c.style.display="none";
});
}
// === 等待 TypedSection 行稳定 === // === 等待 TypedSection 行稳定 ===
(function waitStable() { (function waitStable() {

View File

@@ -21,13 +21,13 @@ define Download/geoip
HASH:=ed2de9add79623e2e5dbc5930ee39cc7037a7c6e0ecd58ba528b6f73d61457b5 HASH:=ed2de9add79623e2e5dbc5930ee39cc7037a7c6e0ecd58ba528b6f73d61457b5
endef endef
GEOSITE_VER:=20260110143056 GEOSITE_VER:=20260111140131
GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER) GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
define Download/geosite define Download/geosite
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/ URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
URL_FILE:=dlc.dat URL_FILE:=dlc.dat
FILE:=$(GEOSITE_FILE) FILE:=$(GEOSITE_FILE)
HASH:=967c3f444b62de133dbd55f02b4117e4afd61168b6cb8fafa2c79d59324e4414 HASH:=60aa9988750f09431ad989e952afe0de0c08a5df18a9b867fc679ccbfc8c62de
endef endef
GEOSITE_IRAN_VER:=202601050049 GEOSITE_IRAN_VER:=202601050049