mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-26 18:52:51 +08:00
🤞 Sync 2026-09-30 23:44:05
This commit is contained in:
1 parent
e3fde93105
commit
44bb740ab2
206 files changed
+5736
-2799
No files matched your search
+4
-4
@@ -1,17 +1,17 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=clashoo
|
||||
PKG_SHORT_SHA:=63bd52e
|
||||
PKG_COMMIT_DATE:=2026.09.27
|
||||
PKG_SHORT_SHA:=1341769
|
||||
PKG_COMMIT_DATE:=2026.09.30
|
||||
|
||||
PKG_VERSION:=$(PKG_COMMIT_DATE)~$(PKG_SHORT_SHA)
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-alpha-$(PKG_SHORT_SHA).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-alpha-$(PKG_SHORT_SHA)
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-alpha-$(PKG_SHORT_SHA)
|
||||
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-clashoo/releases/download/mihomo-src
|
||||
PKG_SOURCE_VERSION:=16a867c31778167b5297025cafd444ea8463b108
|
||||
PKG_SOURCE_VERSION:=0165638d50cfe2125ce47770bd75e2e007bbaffa
|
||||
PKG_HASH:=skip
|
||||
PKG_BUILD_VERSION:=alpha-$(PKG_SHORT_SHA)
|
||||
|
||||
|
||||
@@ -101,8 +101,25 @@ if (keep_fakeip) {
|
||||
delete cfg['dns']['fake-ip-filter'];
|
||||
} else {
|
||||
let push_filter = function(f) {
|
||||
if (f == 'geosite:cn') { f = 'rule-set:cn_domain'; need_cn_rs = true; }
|
||||
else if (f == 'rule-set:cn_domain') need_cn_rs = true;
|
||||
f = trim(f || '');
|
||||
if (!length(f)) return;
|
||||
if (filter_mode == 'rule') {
|
||||
if (match(f, /,(fake-ip|real-ip)$/)) { push(cfg['dns']['fake-ip-filter'], f); return; }
|
||||
if (index(f, ',') >= 0) { push(cfg['dns']['fake-ip-filter'], f + ',real-ip'); return; }
|
||||
if (f == 'geosite:cn') { f = 'RULE-SET,cn_domain,real-ip'; need_cn_rs = true; }
|
||||
else if (match(f, /^geosite:/)) { f = 'GEOSITE,' + substr(f, 8) + ',real-ip'; }
|
||||
else if (match(f, /^rule-set:/)) {
|
||||
let rs = substr(f, 9);
|
||||
if (rs == 'cn_domain') need_cn_rs = true;
|
||||
f = 'RULE-SET,' + rs + ',real-ip';
|
||||
}
|
||||
else if (match(f, /^\+\./)) { f = 'DOMAIN-SUFFIX,' + substr(f, 2) + ',real-ip'; }
|
||||
else if (match(f, /\*/)) { f = 'DOMAIN-WILDCARD,' + f + ',real-ip'; }
|
||||
else { f = 'DOMAIN,' + f + ',real-ip'; }
|
||||
} else {
|
||||
if (f == 'geosite:cn') { f = 'rule-set:cn_domain'; need_cn_rs = true; }
|
||||
else if (f == 'rule-set:cn_domain') need_cn_rs = true;
|
||||
}
|
||||
push(cfg['dns']['fake-ip-filter'], f);
|
||||
};
|
||||
let filters = a('fake_ip_filter');
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=geoview
|
||||
PKG_VERSION:=0.2.6
|
||||
PKG_RELEASE:=5
|
||||
PKG_VERSION:=0.2.7
|
||||
PKG_RELEASE:=6
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/snowie2000/geoview/tar.gz/$(PKG_VERSION)?
|
||||
|
||||
+2
-2
@@ -8,8 +8,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=go-ethereum
|
||||
PKG_VERSION:=1.17.6
|
||||
PKG_RELEASE:=10
|
||||
PKG_VERSION:=1.17.7
|
||||
PKG_RELEASE:=11
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/ethereum/go-ethereum/tar.gz/v${PKG_VERSION}?
|
||||
|
||||
+31
-15
@@ -6,9 +6,9 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=HomeRedirect
|
||||
PKG_VERSION:=1.4
|
||||
PKG_RELEASE:=1
|
||||
PKG_DATE:=20210226
|
||||
PKG_VERSION:=2.0
|
||||
PKG_RELEASE:=2
|
||||
PKG_DATE:=20260930
|
||||
|
||||
PKG_MAINTAINER:=xiaoqingfeng <xiaoqingfengatgm@gmail.com>
|
||||
PKG_LICENSE:=GPL-3.0-or-later
|
||||
@@ -20,7 +20,7 @@ define Package/$(PKG_NAME)
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=Port forwarding utility for HomeLede.
|
||||
DEPENDS:=+bash +coreutils-nohup +socat
|
||||
DEPENDS:=+socat
|
||||
PKGARCH:=all
|
||||
URL:=https://github.com/xiaoqingfengATGH/feeds-xiaoqingfeng
|
||||
endef
|
||||
@@ -43,28 +43,44 @@ endef
|
||||
define Package/$(PKG_NAME)/install
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_DIR) $(1)/etc/homeredirect
|
||||
$(INSTALL_BIN) files/etc/init.d/homeredirect $(1)/etc/init.d
|
||||
$(INSTALL_CONF) files/etc/config/homeredirect $(1)/etc/config
|
||||
$(INSTALL_DATA) files/etc/homeredirect/firewall.include $(1)/etc/homeredirect/
|
||||
$(INSTALL_DATA) files/etc/homeredirect/script.sh $(1)/etc/homeredirect/
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/postinst
|
||||
#!/bin/sh
|
||||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||
rm -f /etc/homeredirect/firewall.include
|
||||
rm -f /etc/homeredirect/script.sh
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete firewall.homeredirect
|
||||
delete ucitrack.@homeredirect[-1]
|
||||
add ucitrack homeredirect
|
||||
set ucitrack.@homeredirect[-1].init=homeredirect
|
||||
commit ucitrack
|
||||
commit firewall
|
||||
EOF
|
||||
rm -rf /tmp/luci-*cache
|
||||
}
|
||||
exit 0
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/prerm
|
||||
#!/bin/sh
|
||||
/etc/init.d/homeredirect stop
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@homeredirect[-1]
|
||||
commit ucitrack
|
||||
EOF
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete firewall.homeredirect
|
||||
EOF
|
||||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||
/etc/init.d/homeredirect stop >/dev/null 2>&1
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@homeredirect[-1]
|
||||
delete firewall.homeredirect
|
||||
commit ucitrack
|
||||
EOF
|
||||
# remove generated per-rule firewall rules (hr_ prefixed)
|
||||
for s in $$(uci -q show firewall | sed -n "s/^firewall\.\(hr_[A-Za-z0-9_]*\)=rule$$/\1/p"); do
|
||||
uci -q delete "firewall.$$s"
|
||||
done
|
||||
uci -q commit firewall
|
||||
/etc/init.d/firewall reload >/dev/null 2>&1
|
||||
}
|
||||
exit 0
|
||||
endef
|
||||
|
||||
|
||||
@@ -1,38 +1,13 @@
|
||||
config global
|
||||
option enabled '1'
|
||||
|
||||
config redirect
|
||||
option proto 'tcp4'
|
||||
option src_ip '0.0.0.0'
|
||||
option src_dport '60609'
|
||||
option dest_ip '192.168.1.100'
|
||||
option dest_port '3389'
|
||||
option name 'TCP_REDIRECT_IPV4'
|
||||
option enabled '0'
|
||||
|
||||
config redirect
|
||||
option proto 'tcp6'
|
||||
option src_ip '::'
|
||||
option src_dport '60608'
|
||||
option dest_ip 'fd5b:64cf:4ff4::1c4'
|
||||
option dest_port '3389'
|
||||
option name 'TCP_REDIRECT_IPV6'
|
||||
option enabled '0'
|
||||
|
||||
config redirect
|
||||
option proto 'udp4'
|
||||
option src_ip '0.0.0.0'
|
||||
option src_dport '64511'
|
||||
option dest_ip '192.168.1.100'
|
||||
option dest_port '500'
|
||||
option name 'UDP_REDIRECT_IPV4'
|
||||
option enabled '0'
|
||||
option cert ''
|
||||
option key ''
|
||||
|
||||
config redirect
|
||||
option proto 'udp6'
|
||||
option src_ip '::'
|
||||
option src_dport '64500'
|
||||
option dest_ip 'fd5b:64cf:4ff4::1c4'
|
||||
option dest_port '4500'
|
||||
option name 'UDP_REDIRECT_IPV6'
|
||||
option enabled '0'
|
||||
option name 'demo-cross-family'
|
||||
option proto 'tcp6'
|
||||
option src_dport '60608'
|
||||
option dest_ip '192.168.1.100'
|
||||
option dest_port '3389'
|
||||
option ipv6only '1'
|
||||
option enabled '0'
|
||||
@@ -1 +0,0 @@
|
||||
bash /etc/homeredirect/script.sh
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
del_rule() {
|
||||
count=$(iptables -n -L INPUT 2>/dev/null | grep -c "HOME_REDIRECT")
|
||||
if [ -n "$count" ]; then
|
||||
until [ "$count" = 0 ]
|
||||
do
|
||||
rules=$(iptables -n -L INPUT --line-num 2>/dev/null | grep "HOME_REDIRECT" | awk '{print $1}')
|
||||
for rule in $rules
|
||||
do
|
||||
iptables -D INPUT $rule 2>/dev/null
|
||||
break
|
||||
done
|
||||
count=$(expr $count - 1)
|
||||
done
|
||||
fi
|
||||
|
||||
iptables -F HOME_REDIRECT 2>/dev/null
|
||||
iptables -X HOME_REDIRECT 2>/dev/null
|
||||
}
|
||||
|
||||
add_rule(){
|
||||
iptables -N HOME_REDIRECT
|
||||
iptables -I INPUT -j HOME_REDIRECT
|
||||
|
||||
maxRedirctCount=$(uci show homeredirect | grep @redirect | awk -F '[' '{print $2}' | awk -F ']' '{print $1}' | sort | tail -n 1)
|
||||
|
||||
for ((i=($maxRedirctCount);i>=0;i--));
|
||||
do
|
||||
enabled=$(uci get homeredirect.@redirect[$i].enabled)
|
||||
if [ $enabled -eq 1 ]; then
|
||||
protoAll=$(uci get homeredirect.@redirect[$i].proto)
|
||||
proto=${protoAll:0:3}
|
||||
port=$(uci get homeredirect.@redirect[$i].src_dport)
|
||||
iptables -A HOME_REDIRECT -p $proto --dport $port -j ACCEPT
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
del_rule
|
||||
|
||||
enable=$(uci get homeredirect.@global[0].enabled)
|
||||
if [ $enable -eq 1 ]; then
|
||||
add_rule
|
||||
fi
|
||||
@@ -1,140 +1,157 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# HomeRedirect - CGNAT-era port forwarder (socat front-end, procd managed)
|
||||
# Copyright 2020-2026 Richard <xiaoqingfengatgm@gmail.com>
|
||||
|
||||
USE_PROCD=1
|
||||
START=99
|
||||
STOP=10
|
||||
|
||||
RUNLOG_DIR=/tmp/hr
|
||||
FW_PREFIX="hr_"
|
||||
|
||||
PROCESSED_REDIRECT=0
|
||||
|
||||
log()
|
||||
{
|
||||
logger -t homeredirect $1
|
||||
log() {
|
||||
logger -t homeredirect "$*"
|
||||
}
|
||||
|
||||
setupDefaultSrcIP() {
|
||||
if [ -z $src_ip ];then
|
||||
if [ "$1" = "ipv4" ]; then
|
||||
src_ip="0.0.0.0"
|
||||
else
|
||||
src_ip="::"
|
||||
fi
|
||||
fi
|
||||
# classify proto: addr_type (socat LISTEN address), transport, firewall
|
||||
# proto/family, is_v6, is_tls
|
||||
classify_proto() {
|
||||
case "$1" in
|
||||
tcp4) addr_type="TCP4-LISTEN"; transport="TCP"; fw_proto="tcp"; fw_family="ipv4"; is_v6=0; is_tls=0 ;;
|
||||
udp4) addr_type="UDP4-LISTEN"; transport="UDP"; fw_proto="udp"; fw_family="ipv4"; is_v6=0; is_tls=0 ;;
|
||||
tcp6) addr_type="TCP6-LISTEN"; transport="TCP"; fw_proto="tcp"; fw_family="ipv6"; is_v6=1; is_tls=0 ;;
|
||||
udp6) addr_type="UDP6-LISTEN"; transport="UDP"; fw_proto="udp"; fw_family="ipv6"; is_v6=1; is_tls=0 ;;
|
||||
tls4) addr_type="OPENSSL-LISTEN"; transport="TCP"; fw_proto="tcp"; fw_family="ipv4"; is_v6=0; is_tls=1 ;;
|
||||
tls6) addr_type="OPENSSL-LISTEN"; transport="TCP"; fw_proto="tcp"; fw_family="ipv6"; is_v6=1; is_tls=1 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
setup() {
|
||||
fw_add_rule() {
|
||||
local id="$1"
|
||||
local enabled proto src_dport
|
||||
|
||||
config_get enabled $1 enabled
|
||||
config_get enabled "$id" enabled 0
|
||||
[ "$enabled" = "1" ] || return 0
|
||||
config_get proto "$id" proto
|
||||
config_get src_dport "$id" src_dport
|
||||
classify_proto "$proto" || return 0
|
||||
|
||||
id=$1
|
||||
config_get proto $1 proto
|
||||
config_get src_ip $1 src_ip
|
||||
config_get src_dport $1 src_dport
|
||||
config_get dest_ip $1 dest_ip
|
||||
config_get dest_port $1 dest_port
|
||||
config_get name $1 name
|
||||
|
||||
terminateRedirect $id
|
||||
|
||||
[ "$enabled" != "1" ] && return 0
|
||||
|
||||
PROCESSED_REDIRECT=1
|
||||
|
||||
if [ "$proto" = "tcp4" ]; then
|
||||
src_addresstype="TCP4-LISTEN"
|
||||
dest_addresstype="TCP4"
|
||||
setupDefaultSrcIP "ipv4"
|
||||
elif [ "$proto" = "tcp6" ]; then
|
||||
src_addresstype="TCP6-LISTEN"
|
||||
dest_addresstype="TCP6"
|
||||
setupDefaultSrcIP "ipv6"
|
||||
src_ip="[$src_ip]"
|
||||
dest_ip="[$dest_ip]"
|
||||
elif [ "$proto" = "udp4" ]; then
|
||||
src_addresstype="UDP4-LISTEN"
|
||||
dest_addresstype="UDP4"
|
||||
setupDefaultSrcIP "ipv4"
|
||||
elif [ "$proto" = "udp6" ]; then
|
||||
src_addresstype="UDP6-LISTEN"
|
||||
dest_addresstype="UDP6"
|
||||
setupDefaultSrcIP "ipv6"
|
||||
src_ip="[$src_ip]"
|
||||
dest_ip="[$dest_ip]"
|
||||
fi
|
||||
|
||||
#echo "nohup socat -lf $RUNLOG_DIR/$id.log $src_addresstype:$src_dport,bind=$src_ip,fork $dest_addresstype:$dest_ip:$dest_port > $RUNLOG_DIR/$id.log 2>&1 &"
|
||||
nohup socat -lf $RUNLOG_DIR/$id.log $src_addresstype:$src_dport,bind=$src_ip,fork $dest_addresstype:$dest_ip:$dest_port > $RUNLOG_DIR/$id.log 2>&1 &
|
||||
log "[HomeRedirect] Port redirect from $proto $src_ip:$src_dport==>$dest_addresstype:$dest_ip:$dest_port started."
|
||||
uci -q set "firewall.${FW_PREFIX}${id}=rule"
|
||||
uci -q set "firewall.${FW_PREFIX}${id}.target=ACCEPT"
|
||||
uci -q set "firewall.${FW_PREFIX}${id}.src=wan"
|
||||
uci -q set "firewall.${FW_PREFIX}${id}.proto=$fw_proto"
|
||||
uci -q set "firewall.${FW_PREFIX}${id}.dest_port=$src_dport"
|
||||
uci -q set "firewall.${FW_PREFIX}${id}.family=$fw_family"
|
||||
uci -q set "firewall.${FW_PREFIX}${id}.name=homeredirect: $src_dport/$fw_proto ($fw_family)"
|
||||
}
|
||||
|
||||
# param $1 is port
|
||||
showTcpPortState() {
|
||||
local process=$(netstat -ltnp | awk -F ' ' '{if(NR>2) print $1"/"$4"/"$7}' | grep :$1)
|
||||
if [ -n "$process" ]; then
|
||||
echo $process
|
||||
else
|
||||
echo 'TCP Port $1 is Free.'
|
||||
fi
|
||||
}
|
||||
# param $1 is port
|
||||
showUdpPortState() {
|
||||
local process=$(netstat -lunp | awk -F ' ' '{if(NR>2) print $1"/"$4"/"$6}'|grep :$1)
|
||||
if [ -n "$process" ]; then
|
||||
echo $process
|
||||
else
|
||||
echo 'UDP Port $1 is Free.'
|
||||
fi
|
||||
# regenerate the UCI firewall rules owned by this service (fw3 and fw4 both
|
||||
# render "config rule" with src=wan into the wan INPUT chain); replaces the
|
||||
# old script.sh that wrote iptables rules directly
|
||||
sync_firewall() {
|
||||
local s changed=0
|
||||
|
||||
for s in $(uci -q show firewall 2>/dev/null | sed -n "s/^firewall\.\(${FW_PREFIX}[A-Za-z0-9_]*\)=rule$/\1/p"); do
|
||||
uci -q delete "firewall.$s"
|
||||
changed=1
|
||||
done
|
||||
|
||||
[ "$1" = "add" ] && {
|
||||
config_foreach fw_add_rule redirect
|
||||
changed=1
|
||||
}
|
||||
|
||||
[ "$changed" = "1" ] && {
|
||||
uci -q commit firewall
|
||||
/etc/init.d/firewall reload >/dev/null 2>&1
|
||||
}
|
||||
}
|
||||
|
||||
isRedirectRunning() {
|
||||
local runningPID=$(ps | grep socat | grep $RUNLOG_DIR/$1 | sed '/grep/d' | awk -F ' ' '{print $1}')
|
||||
if [ -n "$runningPID" ]; then
|
||||
return 1
|
||||
else
|
||||
setup_instance() {
|
||||
local id="$1"
|
||||
local enabled proto src_ip src_dport dest_ip dest_port name ipv6only
|
||||
local cert key listen_opts listen_addr
|
||||
|
||||
config_get enabled "$id" enabled 0
|
||||
config_get proto "$id" proto
|
||||
config_get src_ip "$id" src_ip
|
||||
config_get src_dport "$id" src_dport
|
||||
config_get dest_ip "$id" dest_ip
|
||||
config_get dest_port "$id" dest_port
|
||||
config_get name "$id" name
|
||||
config_get ipv6only "$id" ipv6only 1
|
||||
|
||||
[ "$enabled" = "1" ] || return 0
|
||||
|
||||
classify_proto "$proto" || {
|
||||
log "rule $name: unknown proto '$proto' - skipping"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# param $1 is redirect id
|
||||
terminateRedirect() {
|
||||
isRedirectRunning $1
|
||||
[ "$?" = "1" ] && {
|
||||
local runningPID=$(ps | grep socat | grep $RUNLOG_DIR/$1 | sed '/grep/d' | awk -F ' ' '{print $1}')
|
||||
#echo "Going to kill process $runningPID"
|
||||
kill $runningPID
|
||||
}
|
||||
}
|
||||
|
||||
terminateAll() {
|
||||
local runningPIDs=$(ps | grep socat | grep $RUNLOG_DIR | sed '/grep/d' | awk -F ' ' '{print $1}')
|
||||
[ -n "$runningPIDs" ] && {
|
||||
kill $runningPIDs
|
||||
log "Redirect process : $runningPIDs stopped."
|
||||
}
|
||||
}
|
||||
# listener bind address defaults by family
|
||||
[ -z "$src_ip" ] && { [ "$is_v6" = "1" ] && src_ip="::" || src_ip="0.0.0.0"; }
|
||||
|
||||
start() {
|
||||
local vt_enabled=$(uci -q get homeredirect.@global[0].enabled)
|
||||
if [ "$vt_enabled" = 0 ]; then
|
||||
terminateAll
|
||||
fw3 reload
|
||||
return 1
|
||||
# destination side is family neutral: bare v6 literals get bracketed,
|
||||
# v4 literals and hostnames pass through, hostnames are re-resolved by
|
||||
# socat on every forked connection
|
||||
case "$dest_ip" in
|
||||
\[*) ;; # already bracketed
|
||||
*:*) dest_ip="[$dest_ip]" ;; # bare v6 literal
|
||||
esac
|
||||
|
||||
listen_opts="fork,reuseaddr"
|
||||
# socat >= 1.8.1 resolves bind= with AF_INET unless pf=ip6 is given
|
||||
[ "$is_v6" = "1" ] && listen_opts="$listen_opts,pf=ip6"
|
||||
# v6 listeners default to ipv6only: pure v6 entry in a CGNAT world,
|
||||
# v4-mapped connections are refused unless the rule opts out
|
||||
[ "$is_v6" = "1" ] && [ "$ipv6only" = "1" ] && listen_opts="$listen_opts,ipv6only=1"
|
||||
|
||||
listen_addr="$addr_type"
|
||||
if [ "$is_tls" = "1" ]; then
|
||||
cert=$(uci -q get homeredirect.@global[0].cert)
|
||||
key=$(uci -q get homeredirect.@global[0].key)
|
||||
if [ -z "$cert" ] || [ -z "$key" ] || [ ! -f "$cert" ] || [ ! -f "$key" ]; then
|
||||
log "rule $name: TLS listener needs global cert/key - skipping"
|
||||
return 0
|
||||
fi
|
||||
listen_opts="$listen_opts,cert=$cert,key=$key,verify=0"
|
||||
fi
|
||||
|
||||
rm -rf $RUNLOG_DIR
|
||||
mkdir -p $RUNLOG_DIR
|
||||
|
||||
|
||||
log "rule $name: $proto $src_ip:$src_dport -> $transport:$dest_ip:$dest_port"
|
||||
|
||||
procd_open_instance "$id"
|
||||
procd_set_param command /usr/bin/socat -lf "$RUNLOG_DIR/$id.log" \
|
||||
"$listen_addr:$src_dport,bind=$src_ip,$listen_opts" \
|
||||
"$transport:$dest_ip:$dest_port"
|
||||
procd_set_param respawn 3600 5 5
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
start_service() {
|
||||
mkdir -p "$RUNLOG_DIR"
|
||||
|
||||
[ "$(uci -q get homeredirect.@global[0].enabled)" = "1" ] || {
|
||||
sync_firewall
|
||||
return 0
|
||||
}
|
||||
|
||||
config_load homeredirect
|
||||
|
||||
PROCESSED_REDIRECT=0
|
||||
config_foreach setup redirect
|
||||
[ "$PROCESSED_REDIRECT" == "1" ] && {
|
||||
fw3 reload
|
||||
}
|
||||
log 'HomeRedirect started.'
|
||||
config_foreach setup_instance redirect
|
||||
sync_firewall add
|
||||
}
|
||||
|
||||
stop() {
|
||||
terminateAll
|
||||
fw3 reload
|
||||
log 'HomeRedirect stopped.'
|
||||
stop_service() {
|
||||
sync_firewall
|
||||
rm -rf "$RUNLOG_DIR"
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "homeredirect"
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
restart
|
||||
}
|
||||
@@ -11,8 +11,8 @@ PKG_ARCH_LINKEASE:=$(ARCH)
|
||||
|
||||
PKG_NAME:=linkease-common-bin
|
||||
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
|
||||
PKG_SOURCE_DATE:=1.7.5
|
||||
PKG_RELEASE:=42
|
||||
PKG_SOURCE_DATE:=1.7.6
|
||||
PKG_RELEASE:=43
|
||||
|
||||
ARCH_HEXCODE:=
|
||||
ifeq ($(ARCH),x86_64)
|
||||
@@ -67,3 +67,12 @@ define Package/$(PKG_NAME)/install
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
||||
|
||||
# OpenWrt 24.10 does not expose a package-level REPLACES variable in
|
||||
# package-pack.mk. Preserve the generated control stanza and append the
|
||||
# versioned ownership hand-off required for legacy monolithic LinkEase packages.
|
||||
LINKEASE_COMMON_BIN_GENERATED_CONTROL:=$(Package/$(PKG_NAME)/CONTROL)
|
||||
define Package/$(PKG_NAME)/CONTROL
|
||||
$(LINKEASE_COMMON_BIN_GENERATED_CONTROL)
|
||||
Replaces: linkease (<< 1.7.6~)
|
||||
endef
|
||||
@@ -0,0 +1,36 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=linkease-runtime-transition
|
||||
PKG_VERSION:=1.7.6
|
||||
PKG_RELEASE:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/$(PKG_NAME)
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
SUBMENU:=Web Servers/Proxies
|
||||
TITLE:=LinkEase split-runtime transition contract
|
||||
DEPENDS:=@(arm||x86_64||aarch64) +linkease +luci-lib-linkeasefile
|
||||
EXTRA_DEPENDS:=linkease (>= 1.7.6~), luci-lib-linkeasefile (>= 2.1.70-r4)
|
||||
PKGARCH:=all
|
||||
URL:=https://www.linkease.com/
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/description
|
||||
Forces legacy LinkEase installations onto the split-safe runtime and LuCI
|
||||
ownership generation without exposing version expressions to app-meta hooks.
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/install
|
||||
$(INSTALL_DIR) $(1)/usr/share/linkease
|
||||
$(INSTALL_DATA) ./files/runtime-generation $(1)/usr/share/linkease/runtime-generation
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
||||
@@ -0,0 +1 @@
|
||||
1.7.6
|
||||
+3
-2
@@ -11,8 +11,8 @@ PKG_ARCH_LINKEASE:=$(ARCH)
|
||||
|
||||
PKG_NAME:=linkease
|
||||
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
|
||||
PKG_SOURCE_DATE:=1.7.5
|
||||
PKG_RELEASE:=45
|
||||
PKG_SOURCE_DATE:=1.7.6
|
||||
PKG_RELEASE:=46
|
||||
|
||||
ARCH_HEXCODE:=
|
||||
ifeq ($(ARCH),x86_64)
|
||||
@@ -44,6 +44,7 @@ define Package/$(PKG_NAME)
|
||||
SUBMENU:=Web Servers/Proxies
|
||||
TITLE:=LinkEase - the file cloud
|
||||
DEPENDS:=@(arm||x86_64||aarch64) +linkease-common-bin
|
||||
EXTRA_DEPENDS:=linkease-common-bin (>= 1.7.6~)
|
||||
PKGARCH:=all
|
||||
URL:=https://www.linkease.com/
|
||||
endef
|
||||
|
||||
@@ -11,7 +11,7 @@ PKG_ARCH_LINKEASE:=$(ARCH)
|
||||
PKG_NAME:=linkeasefull
|
||||
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
|
||||
PKG_SOURCE_DATE:=3.0.22
|
||||
PKG_RELEASE:=44
|
||||
PKG_RELEASE:=45
|
||||
|
||||
ARCH_HEXCODE:=
|
||||
ifeq ($(ARCH),x86_64)
|
||||
@@ -40,6 +40,7 @@ define Package/$(PKG_NAME)
|
||||
SUBMENU:=Web Servers/Proxies
|
||||
TITLE:=LinkEase Full - the local web desktop
|
||||
DEPENDS:=@(x86_64||aarch64) +linkease-app-entry +linkease-common-bin +ca-bundle +cifsmount +kmod-fs-cifs
|
||||
EXTRA_DEPENDS:=linkease-common-bin (>= 1.7.6~)
|
||||
PKGARCH:=all
|
||||
URL:=https://www.linkease.com/
|
||||
endef
|
||||
|
||||
@@ -1 +1 @@
|
||||
release
|
||||
snapshot
|
||||
@@ -1 +1 @@
|
||||
26.270.72870~a24d1f2
|
||||
26.272.65915~80de46c
|
||||
@@ -3,7 +3,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_VERSION:=1.0.1
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
|
||||
LUCI_TITLE:=LuCI Airoha SoC Status (NPU, CPU, Frame Engine)
|
||||
|
||||
@@ -71,14 +71,14 @@ var bandInfo = [
|
||||
|
||||
var psePortMap = [
|
||||
{ name: 'CDM1', label: 'CPU DMA 1', color: '#607d8b' },
|
||||
{ name: 'GDM1', label: 'Switch 1G', color: '#ff9800' },
|
||||
{ name: 'GDM1', label: _('Switch 1G'), color: '#ff9800' },
|
||||
{ name: 'GDM2', label: 'WAN 10G', color: '#4caf50' },
|
||||
{ name: 'GDM3', label: 'GDM3', color: '#607d8b' },
|
||||
{ name: 'PPE1', label: 'PPE Eng 1', color: '#2196f3' },
|
||||
{ name: 'PPE1', label: _('PPE Eng 1'), color: '#2196f3' },
|
||||
{ name: 'CDM2', label: 'CPU DMA 2', color: '#607d8b' },
|
||||
{ name: 'CDM3', label: 'CDM3', color: '#607d8b' },
|
||||
{ name: 'CDM4', label: 'WDMA WiFi', color: '#9c27b0' },
|
||||
{ name: 'PPE2', label: 'PPE Eng 2', color: '#2196f3' },
|
||||
{ name: 'PPE2', label: _('PPE Eng 2'), color: '#2196f3' },
|
||||
{ name: 'GDM4', label: 'LAN2 10G', color: '#4caf50' }
|
||||
];
|
||||
|
||||
@@ -102,7 +102,7 @@ function calcTotalMem(regions) {
|
||||
function tokenHealth(c, s) {
|
||||
if (!s) return { text: 'N/A', color: '#888' };
|
||||
var p = c/s*100;
|
||||
return p < 50 ? { text:'Healthy', color:'#4caf50' } : p < 80 ? { text:'Warning', color:'#ff9800' } : { text:'Critical', color:'#f44336' };
|
||||
return p < 50 ? { text:_('Healthy'), color:'#4caf50' } : p < 80 ? { text:_('Warning'), color:'#ff9800' } : { text:_('Critical'), color:'#f44336' };
|
||||
}
|
||||
|
||||
function getBandStats(ti, b) {
|
||||
@@ -118,10 +118,10 @@ function getTxQueue(ti, b) {
|
||||
}
|
||||
|
||||
function bandHealth(s) {
|
||||
if (!s || s.count===0) return { text:'No clients', color:'#888' };
|
||||
if (!s.tx_packets) return { text:'Idle', color:'#888' };
|
||||
if (!s || s.count===0) return { text:_('No clients'), color:'#888' };
|
||||
if (!s.tx_packets) return { text:_('Idle'), color:'#888' };
|
||||
var r = s.tx_retries/(s.tx_packets+s.tx_retries);
|
||||
return r>0.5 ? {text:'Poor',color:'#f44336'} : r>0.2 ? {text:'Fair',color:'#ff9800'} : {text:'Good',color:'#4caf50'};
|
||||
return r>0.5 ? {text:_('Poor'),color:'#f44336'} : r>0.2 ? {text:_('Fair'),color:'#ff9800'} : {text:_('Good'),color:'#4caf50'};
|
||||
}
|
||||
|
||||
function retryPct(s) {
|
||||
@@ -131,7 +131,7 @@ function retryPct(s) {
|
||||
|
||||
/* ── Mini Band Chip (compact for FE diagram) ── */
|
||||
function renderBandChip(band, txQ, stats) {
|
||||
var info = bandInfo[band] || { name: 'Band '+band, accent: '#888' };
|
||||
var info = bandInfo[band] || { name: _('Band %d').format(band), accent: '#888' };
|
||||
var id = 'band-'+band;
|
||||
var h = bandHealth(stats);
|
||||
var type = txQ ? txQ.type : '?';
|
||||
@@ -147,7 +147,7 @@ function renderBandChip(band, txQ, stats) {
|
||||
E('span', { 'style': 'width:7px;height:7px;border-radius:50%;background:'+h.color+';display:inline-block' }),
|
||||
E('span', { 'style': 'color:'+h.color+';font-weight:500' }, h.text)
|
||||
]),
|
||||
E('span', { 'id': id+'-clients', 'class': 'soc-muted' }, stats.count + ' sta'),
|
||||
E('span', { 'id': id+'-clients', 'class': 'soc-muted' }, _('%d clients').format(stats.count)),
|
||||
(stats.tx_packets > 0) ? E('span', { 'id': id+'-retries', 'class': 'soc-muted' }, rp) : E('span')
|
||||
])
|
||||
]);
|
||||
@@ -158,14 +158,14 @@ function updateBandChip(band, stats) {
|
||||
var el = document.getElementById(id+'-health');
|
||||
if (el) { el.innerHTML = ''; el.appendChild(E('span',{'style':'width:6px;height:6px;border-radius:50%;background:'+h.color+';display:inline-block'})); el.appendChild(E('span',{'style':'color:'+h.color+';font-weight:500;font-size:11px'},h.text)); }
|
||||
var cl = document.getElementById(id+'-clients');
|
||||
if (cl) cl.textContent = stats.count+'sta';
|
||||
if (cl) cl.textContent = _('%d clients').format(stats.count);
|
||||
var re = document.getElementById(id+'-retries');
|
||||
if (re) { var rp2 = retryPct(stats); re.textContent = rp2; }
|
||||
}
|
||||
|
||||
/* ── Frame Engine Diagram (with WiFi bands, NPU, PPE flows) ── */
|
||||
function renderFeDiagram(fe, ti, st) {
|
||||
if (!fe || fe.error) return E('div', { 'class': 'soc-muted' }, 'devmem not available on this build');
|
||||
if (!fe || fe.error) return E('div', { 'class': 'soc-muted' }, _('devmem not available on this build'));
|
||||
ti = ti || {}; st = st || {};
|
||||
|
||||
var ports = Array.isArray(fe.pse_ports) ? fe.pse_ports : [];
|
||||
@@ -184,9 +184,9 @@ function renderFeDiagram(fe, ti, st) {
|
||||
E('span', { 'class': 'soc-muted' }, 'TX'), E('span', { 'class': 'soc-text', 'style': 'text-align:right' }, fmtK(d.tx)),
|
||||
E('span', { 'class': 'soc-muted' }, 'RX'), E('span', { 'class': 'soc-text', 'style': 'text-align:right' }, fmtK(d.rx))
|
||||
].concat(d.tx_drop > 0 ? [
|
||||
E('span', { 'style': 'color:#f44336' }, 'TX Drop'), E('span', { 'style': 'color:#f44336;text-align:right' }, fmtK(d.tx_drop))
|
||||
E('span', { 'style': 'color:#f44336' }, _('TX Drop')), E('span', { 'style': 'color:#f44336;text-align:right' }, fmtK(d.tx_drop))
|
||||
] : []).concat(d.rx_drop > 0 ? [
|
||||
E('span', { 'style': 'color:#f44336' }, 'RX Drop'), E('span', { 'style': 'color:#f44336;text-align:right' }, fmtK(d.rx_drop))
|
||||
E('span', { 'style': 'color:#f44336' }, _('RX Drop')), E('span', { 'style': 'color:#f44336;text-align:right' }, fmtK(d.rx_drop))
|
||||
] : []))
|
||||
]);
|
||||
}
|
||||
@@ -202,7 +202,7 @@ function renderFeDiagram(fe, ti, st) {
|
||||
E('span', { 'style': 'font-weight:bold;color:#607d8b;font-size:13px' }, name+' '+pse),
|
||||
E('span', { 'class': 'soc-label' }, label)
|
||||
]),
|
||||
E('div', { 'class': 'soc-text', 'style': 'font-size:12px;margin-bottom:4px' }, 'HW Offload: '+pct+'%'),
|
||||
E('div', { 'class': 'soc-text', 'style': 'font-size:12px;margin-bottom:4px' }, _('HW Offload:')+' '+pct+'%'),
|
||||
E('div', { 'class': 'soc-bar-track', 'style': 'height:6px' }, [
|
||||
E('div', { 'style': 'background:'+barCol+';height:100%;width:'+pct+'%;transition:width .5s;border-radius:4px' })
|
||||
]),
|
||||
@@ -228,7 +228,7 @@ function renderFeDiagram(fe, ti, st) {
|
||||
E('div', { 'style': 'display:flex;gap:12px;font-size:11px;margin-bottom:8px' }, [
|
||||
E('span', { 'class': 'soc-muted' }, 'IQ '+p7.iq),
|
||||
E('span', { 'class': 'soc-muted' }, 'OQ '+p7.oq),
|
||||
p7.drops > 0 ? E('span', { 'style': 'color:#f44336' }, 'Drop '+fmtK(p7.drops)) : null
|
||||
p7.drops > 0 ? E('span', { 'style': 'color:#f44336' }, _('Drop')+' '+fmtK(p7.drops)) : null
|
||||
].filter(Boolean)),
|
||||
// WiFi bands inside
|
||||
E('div', { 'style': 'display:grid;grid-template-columns:repeat(3,1fr);gap:6px' }, bandChips)
|
||||
@@ -239,28 +239,28 @@ function renderFeDiagram(fe, ti, st) {
|
||||
var npuCard = E('div', { 'class': 'soc-card', 'style': 'border-color:'+(npuActive?'#00bcd4':'var(--soc-border)') }, [
|
||||
E('div', { 'style': 'display:flex;justify-content:space-between;align-items:center;margin-bottom:4px' }, [
|
||||
E('span', { 'style': 'font-weight:bold;color:#00bcd4;font-size:14px' }, 'NPU'),
|
||||
E('span', { 'style': 'background:'+(npuActive?'#00695c':'#666')+';color:#fff;padding:1px 7px;border-radius:3px;font-size:10px;font-weight:600' }, npuActive ? 'ACTIVE' : 'OFF')
|
||||
E('span', { 'style': 'background:'+(npuActive?'#00695c':'#666')+';color:#fff;padding:1px 7px;border-radius:3px;font-size:10px;font-weight:600' }, npuActive ? _('ACTIVE') : _('OFF'))
|
||||
]),
|
||||
E('div', { 'class': 'soc-label', 'style': 'margin-bottom:4px' }, '8x RISC-V via PCIe RAM'),
|
||||
E('div', { 'class': 'soc-label', 'style': 'margin-bottom:4px' }, _('8x RISC-V via PCIe RAM')),
|
||||
E('div', { 'style': 'font-size:11px' }, [
|
||||
E('span', { 'class': 'soc-muted' }, 'Manages: '),
|
||||
E('span', { 'class': 'soc-text', 'style': 'font-size:11px' }, 'PPE init, WDMA rings, flow stats')
|
||||
E('span', { 'class': 'soc-muted' }, _('Manages:')+' '),
|
||||
E('span', { 'class': 'soc-text', 'style': 'font-size:11px' }, _('PPE init, WDMA rings, flow stats'))
|
||||
])
|
||||
]);
|
||||
|
||||
// PPE engines with flow count
|
||||
var ppeCard = E('div', { 'class': 'soc-card', 'style': 'border-color:#2196f3' }, [
|
||||
E('div', { 'style': 'display:flex;justify-content:space-between;align-items:center;margin-bottom:4px' }, [
|
||||
E('span', { 'style': 'font-weight:bold;color:#2196f3;font-size:14px' }, 'PPE Engines'),
|
||||
E('span', { 'style': 'font-weight:bold;color:#2196f3;font-size:14px' }, _('PPE Engines')),
|
||||
E('span', { 'class': 'soc-label' }, 'P4 + P8')
|
||||
]),
|
||||
E('div', { 'style': 'display:flex;gap:16px;font-size:12px' }, [
|
||||
E('span', {}, [
|
||||
E('span', { 'class': 'soc-muted' }, 'Bound '),
|
||||
E('span', { 'class': 'soc-muted' }, _('Bound')+' '),
|
||||
E('span', { 'class': 'soc-text', 'style': 'font-weight:bold', 'id': 'fe-ppe-bound' }, (st.offload_bound||0).toString())
|
||||
]),
|
||||
E('span', {}, [
|
||||
E('span', { 'class': 'soc-muted' }, 'Total '),
|
||||
E('span', { 'class': 'soc-muted' }, _('Total')+' '),
|
||||
E('span', { 'class': 'soc-text', 'id': 'fe-ppe-total' }, (st.offload_total||0).toString())
|
||||
])
|
||||
])
|
||||
@@ -289,8 +289,8 @@ function renderFeDiagram(fe, ti, st) {
|
||||
// PSE buffer bar
|
||||
E('div', { 'class': 'soc-card', 'style': 'margin-bottom:10px' }, [
|
||||
E('div', { 'style': 'display:flex;justify-content:space-between;margin-bottom:4px' }, [
|
||||
E('span', { 'class': 'soc-text', 'style': 'font-weight:bold;font-size:13px' }, 'PSE Shared Buffer'),
|
||||
E('span', { 'class': 'soc-muted', 'style': 'font-size:12px' }, (fe.pse_used||0)+' used / '+(fe.pse_free||0)+' free ('+pseP+'%)')
|
||||
E('span', { 'class': 'soc-text', 'style': 'font-weight:bold;font-size:13px' }, _('PSE Shared Buffer')),
|
||||
E('span', { 'class': 'soc-muted', 'style': 'font-size:12px' }, _('%d used / %d free (%s%%)').format(fe.pse_used||0, fe.pse_free||0, pseP))
|
||||
]),
|
||||
E('div', { 'class': 'soc-bar-track', 'style': 'height:8px' }, [
|
||||
E('div', { 'style': 'background:'+pseCol+';height:100%;width:'+pseP+'%;border-radius:4px;transition:width .5s' })
|
||||
@@ -298,7 +298,7 @@ function renderFeDiagram(fe, ti, st) {
|
||||
]),
|
||||
// Row 1: GDM ports
|
||||
E('div', { 'class': 'soc-gdm-grid' }, [
|
||||
gdmCard('gdm1', 'GDM1', 'Internal Switch (1G LAN3/4)', '#ff9800', 'P1'),
|
||||
gdmCard('gdm1', 'GDM1', _('Internal Switch (1G LAN3/4)'), '#ff9800', 'P1'),
|
||||
gdmCard('gdm2', 'GDM2', 'WAN (USXGMII 10G)', '#4caf50', 'P2'),
|
||||
gdmCard('gdm4', 'GDM4', 'LAN2 (USXGMII 10G)', '#4caf50', 'P9')
|
||||
]),
|
||||
@@ -314,7 +314,7 @@ function renderFeDiagram(fe, ti, st) {
|
||||
npuCard
|
||||
]),
|
||||
// PSE port grid
|
||||
E('div', { 'class': 'soc-text', 'style': 'font-size:12px;font-weight:600;margin-bottom:6px' }, 'PSE Port Queue Status'),
|
||||
E('div', { 'class': 'soc-text', 'style': 'font-size:12px;font-weight:600;margin-bottom:6px' }, _('PSE Port Queue Status')),
|
||||
E('div', { 'class': 'soc-pse-grid' }, portCells)
|
||||
]);
|
||||
}
|
||||
@@ -331,7 +331,7 @@ function renderFreqBar(hw, min, max, pll, gov) {
|
||||
var pct = Math.round(((s.freq-min)/(s.max-min))*100);
|
||||
pct = Math.max(0,Math.min(100,pct));
|
||||
var bg = s.oc ? 'linear-gradient(90deg,#e65100,#ff9800)' : 'linear-gradient(90deg,#2e7d32,#66bb6a)';
|
||||
var label = s.oc ? (pll+' MHz (OC)') : fmtFreq(s.freq);
|
||||
var label = s.oc ? (_('%s MHz (OC)').format(pll)) : fmtFreq(s.freq);
|
||||
|
||||
return E('div', { 'id':'cpu-freq-bar-wrap', 'style':'display:flex;align-items:center;gap:10px' }, [
|
||||
E('span', { 'class':'soc-muted', 'style':'font-size:90%' }, fmtFreq(min)),
|
||||
@@ -346,7 +346,7 @@ function renderFreqBar(hw, min, max, pll, gov) {
|
||||
function updateFreqBar(hw, min, max, pll, gov) {
|
||||
var s = freqBarState(hw,min,max,pll,gov);
|
||||
var el = document.getElementById('cpu-freq-text'), fl = document.getElementById('cpu-freq-fill'), ml = document.getElementById('cpu-freq-max-label');
|
||||
if (el) el.textContent = s.oc ? (pll+' MHz (OC)') : fmtFreq(s.freq);
|
||||
if (el) el.textContent = s.oc ? (_('%s MHz (OC)').format(pll)) : fmtFreq(s.freq);
|
||||
if (fl && s.max>0) { var pct=Math.max(0,Math.min(100,Math.round(((s.freq-min)/(s.max-min))*100))); fl.style.width=pct+'%'; fl.style.background=s.oc?'linear-gradient(90deg,#e65100,#ff9800)':'linear-gradient(90deg,#2e7d32,#66bb6a)'; }
|
||||
if (ml) ml.textContent = fmtFreq(s.max);
|
||||
}
|
||||
@@ -356,7 +356,7 @@ function renderGovSelect(avail, active) {
|
||||
if (!gs.length) return E('span',{},'N/A');
|
||||
return E('select', { 'id':'cpu-governor-select','class':'cbi-input-select','style':'min-width:140px','change':function(ev){
|
||||
var g=ev.target.value; ev.target.disabled=true;
|
||||
callSetGovernor(g).then(function(r){ev.target.disabled=false;if(r&&r.error) ui.addNotification(null,E('p',{},_('Error: ')+r.error),'error');}).catch(function(){ev.target.disabled=false;});
|
||||
callSetGovernor(g).then(function(r){ev.target.disabled=false;if(r&&r.error) ui.addNotification(null,E('p',{},_('Error:')+' '+r.error),'error');}).catch(function(){ev.target.disabled=false;});
|
||||
}}, gs.map(function(g){return E('option',{'value':g,'selected':g===active?'':null},g);}));
|
||||
}
|
||||
|
||||
@@ -365,7 +365,7 @@ function renderMaxFreqSelect(avail, cur) {
|
||||
if (!fs.length) return E('span',{},'N/A');
|
||||
return E('select', { 'id':'cpu-maxfreq-select','class':'cbi-input-select','style':'min-width:140px','change':function(ev){
|
||||
var f=ev.target.value; ev.target.disabled=true;
|
||||
callSetMaxFreq(parseInt(f)).then(function(r){ev.target.disabled=false;if(r&&r.error) ui.addNotification(null,E('p',{},_('Error: ')+r.error),'error');}).catch(function(){ev.target.disabled=false;});
|
||||
callSetMaxFreq(parseInt(f)).then(function(r){ev.target.disabled=false;if(r&&r.error) ui.addNotification(null,E('p',{},_('Error:')+' '+r.error),'error');}).catch(function(){ev.target.disabled=false;});
|
||||
}}, fs.map(function(f){return E('option',{'value':f,'selected':parseInt(f)===parseInt(cur)?'':null},(parseInt(f)/1000).toFixed(0)+' MHz');}));
|
||||
}
|
||||
|
||||
@@ -374,11 +374,11 @@ function renderOcControls() {
|
||||
var btn = E('button',{'class':'cbi-button cbi-button-action','style':'margin-left:8px','click':function(){
|
||||
var f=parseInt(document.getElementById('oc-freq-input').value);
|
||||
if(isNaN(f)||f<500||f>1600){ui.addNotification(null,E('p',{},_('Must be 500-1600 MHz')),'error');return;}
|
||||
if(f>1400&&!confirm('Frequencies above 1400 MHz may be unstable. Continue?')) return;
|
||||
if(f>1400&&!confirm(_('Frequencies above 1400 MHz may be unstable. Continue?'))) return;
|
||||
btn.disabled=true;btn.textContent=_('Applying...');
|
||||
callSetOverclock(f).then(function(r){btn.disabled=false;btn.textContent=_('Apply');
|
||||
if(r&&r.error) ui.addNotification(null,E('p',{},_('Failed: ')+r.error),'error');
|
||||
else if(r&&r.result==='ok') ui.addNotification(null,E('p',{},_('CPU set to ')+r.actual_mhz+' MHz'),'info');
|
||||
if(r&&r.error) ui.addNotification(null,E('p',{},_('Failed:')+' '+r.error),'error');
|
||||
else if(r&&r.result==='ok') ui.addNotification(null,E('p',{},_('CPU set to')+' '+r.actual_mhz+' MHz'),'info');
|
||||
}).catch(function(e){btn.disabled=false;btn.textContent=_('Apply');});
|
||||
}},_('Apply'));
|
||||
return E('div',{'style':'display:flex;align-items:center;gap:8px;flex-wrap:wrap'},[
|
||||
@@ -434,9 +434,9 @@ return view.extend({
|
||||
E('span',{'class':'label-success'},_('Active')+(st.npu_device?' ('+st.npu_device+')':'')) :
|
||||
E('span',{'class':'label-danger'},_('Not Active'))) ]),
|
||||
E('tr',{'class':'tr'},[ E('td',{'class':'td'},E('strong',{},_('Firmware / Clock / Cores'))),
|
||||
E('td',{'class':'td','id':'npu-info'}, (st.npu_version||'N/A')+' | '+(st.npu_clock?(st.npu_clock/1e6).toFixed(0)+' MHz':'N/A')+' | '+(st.npu_cores||0)+' cores') ]),
|
||||
E('td',{'class':'td','id':'npu-info'}, (st.npu_version||'N/A')+' | '+(st.npu_clock?(st.npu_clock/1e6).toFixed(0)+' MHz':'N/A')+' | '+_('%d cores').format(st.npu_cores||0)) ]),
|
||||
E('tr',{'class':'tr'},[ E('td',{'class':'td'},E('strong',{},_('Reserved Memory'))),
|
||||
E('td',{'class':'td','id':'npu-memory'}, calcTotalMem(memR)+' ('+memR.length+' regions)') ])
|
||||
E('td',{'class':'td','id':'npu-memory'}, _('%s (%d regions)').format(calcTotalMem(memR), memR.length)) ])
|
||||
]),
|
||||
|
||||
// Frame Engine diagram (includes WiFi bands, PPE flows, NPU indicator)
|
||||
|
||||
@@ -1,73 +1,125 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:327
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:406
|
||||
msgid "Active"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:150
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:161
|
||||
msgid "%d clients"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:284
|
||||
msgid "Airoha SoC Status"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:437
|
||||
msgid "%d cores"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:224
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:233
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:237
|
||||
msgid "Apply"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:293
|
||||
msgid "%d used / %d free (%s%%)"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:221
|
||||
msgid "Applying..."
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:439
|
||||
msgid "%s (%d regions)"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:350
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:420
|
||||
msgid "Bound:"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:362
|
||||
msgid "Bytes"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:310
|
||||
msgid "CPU Cores"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:288
|
||||
msgid "CPU Frequency"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:229
|
||||
msgid "CPU set to"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:291
|
||||
msgid "Current Frequency"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:334
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:349
|
||||
msgid "%s MHz (OC)"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:244
|
||||
msgid ""
|
||||
"Direct PLL programming. Governor locked to performance. Stock max: 1200 MHz. "
|
||||
"Tested stable up to 1500 MHz."
|
||||
msgid "8x RISC-V via PCIe RAM"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:360
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:242
|
||||
msgid "ACTIVE"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:434
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:470
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:414
|
||||
msgid "Airoha SoC Status"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:379
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:382
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:383
|
||||
msgid "Apply"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:378
|
||||
msgid "Applying..."
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:134
|
||||
msgid "Band %d"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:259
|
||||
msgid "Bound"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:424
|
||||
msgid "CPU Cores"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:418
|
||||
msgid "CPU Frequency"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:381
|
||||
msgid "CPU set to"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:105
|
||||
msgid "Critical"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:420
|
||||
msgid "Current Frequency"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:386
|
||||
msgid "Direct PLL. Stock max 1200 MHz. Stable up to 1500 MHz."
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:231
|
||||
msgid "Drop"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:359
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:368
|
||||
msgid "Error:"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:453
|
||||
msgid "Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:85
|
||||
msgid "Failed to set governor:"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:380
|
||||
msgid "Failed:"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:112
|
||||
msgid "Failed to set max frequency:"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:124
|
||||
msgid "Fair"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:212
|
||||
msgid "Frequency must be 500-1600 MHz"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:436
|
||||
msgid "Firmware / Clock / Cores"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:296
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:443
|
||||
msgid "Frame Engine"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:377
|
||||
msgid "Frequencies above 1400 MHz may be unstable. Continue?"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:124
|
||||
msgid "Good"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:421
|
||||
msgid "Governor"
|
||||
msgstr ""
|
||||
|
||||
@@ -75,69 +127,108 @@ msgstr ""
|
||||
msgid "Grant access to Airoha SoC status (NPU + CPU + Overclock)"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:355
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:205
|
||||
msgid "HW Offload:"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:105
|
||||
msgid "Healthy"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:122
|
||||
msgid "Idle"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:452
|
||||
msgid "Index"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:301
|
||||
msgid "Internal Switch (1G LAN3/4)"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:246
|
||||
msgid "Manages:"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:422
|
||||
msgid "Max Frequency"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:331
|
||||
msgid "NPU Clock / Cores"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:376
|
||||
msgid "Must be 500-1600 MHz"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:321
|
||||
msgid "NPU Firmware Version"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:430
|
||||
msgid "NPU & Offload Engine"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:318
|
||||
msgid "NPU Information"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:325
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:432
|
||||
msgid "NPU Status"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:359
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:453
|
||||
msgid "New Flow"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:328
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:411
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:121
|
||||
msgid "No clients"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:435
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:470
|
||||
msgid "Not Active"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:322
|
||||
msgid "Not available"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:242
|
||||
msgid "OFF"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:339
|
||||
msgid "Offload Statistics"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:358
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:453
|
||||
msgid "Original Flow"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:306
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:423
|
||||
msgid "Overclock"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:226
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:234
|
||||
msgid "Overclock failed:"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:77
|
||||
msgid "PPE Eng 1"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:347
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:81
|
||||
msgid "PPE Eng 2"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:254
|
||||
msgid "PPE Engines"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:449
|
||||
msgid "PPE Flow Offload Entries"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:361
|
||||
msgid "Packets"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:247
|
||||
msgid "PPE init, WDMA rings, flow stats"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:335
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:317
|
||||
msgid "PSE Port Queue Status"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:292
|
||||
msgid "PSE Shared Buffer"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:124
|
||||
msgid "Poor"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:189
|
||||
msgid "RX Drop"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:438
|
||||
msgid "Reserved Memory"
|
||||
msgstr ""
|
||||
|
||||
@@ -145,20 +236,30 @@ msgstr ""
|
||||
msgid "SoC Status"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:356
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:452
|
||||
msgid "State"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:349
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:419
|
||||
msgid "Total:"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:74
|
||||
msgid "Switch 1G"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:357
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:187
|
||||
msgid "TX Drop"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:263
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:452
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:351
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:421
|
||||
msgid "Unbound:"
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:105
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
#: feeds/luci/applications/luci-app-airoha-npu/htdocs/luci-static/resources/view/airoha_npu/status.js:168
|
||||
msgid "devmem not available on this build"
|
||||
msgstr ""
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
zh_Hans
|
||||
@@ -0,0 +1,197 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Language: zh_Hans\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
msgid "%d clients"
|
||||
msgstr "%d 个客户端"
|
||||
|
||||
msgid "%d cores"
|
||||
msgstr "%d 个核心"
|
||||
|
||||
msgid "%d used / %d free (%s%%)"
|
||||
msgstr "已用 %d / 空闲 %d(%s%%)"
|
||||
|
||||
msgid "%s (%d regions)"
|
||||
msgstr "%s(%d 个区域)"
|
||||
|
||||
msgid "%s MHz (OC)"
|
||||
msgstr "%s MHz(超频)"
|
||||
|
||||
msgid "8x RISC-V via PCIe RAM"
|
||||
msgstr "8 个 RISC-V 核心,通过 PCIe RAM 通信"
|
||||
|
||||
msgid "ACTIVE"
|
||||
msgstr "运行中"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "运行中"
|
||||
|
||||
msgid "Airoha SoC Status"
|
||||
msgstr "Airoha SoC 状态"
|
||||
|
||||
msgid "Apply"
|
||||
msgstr "应用"
|
||||
|
||||
msgid "Applying..."
|
||||
msgstr "正在应用…"
|
||||
|
||||
msgid "Band %d"
|
||||
msgstr "频段 %d"
|
||||
|
||||
msgid "Bound"
|
||||
msgstr "已绑定"
|
||||
|
||||
msgid "CPU Cores"
|
||||
msgstr "CPU 核心数"
|
||||
|
||||
msgid "CPU Frequency"
|
||||
msgstr "CPU 频率"
|
||||
|
||||
msgid "CPU set to"
|
||||
msgstr "CPU 频率已设置为"
|
||||
|
||||
msgid "Critical"
|
||||
msgstr "严重"
|
||||
|
||||
msgid "Current Frequency"
|
||||
msgstr "当前频率"
|
||||
|
||||
msgid "Direct PLL. Stock max 1200 MHz. Stable up to 1500 MHz."
|
||||
msgstr "直接设置 PLL。默认最高 1200 MHz,已测试稳定至 1500 MHz。"
|
||||
|
||||
msgid "Drop"
|
||||
msgstr "丢包"
|
||||
|
||||
msgid "Error:"
|
||||
msgstr "错误:"
|
||||
|
||||
msgid "Ethernet"
|
||||
msgstr "以太网"
|
||||
|
||||
msgid "Failed:"
|
||||
msgstr "失败:"
|
||||
|
||||
msgid "Fair"
|
||||
msgstr "一般"
|
||||
|
||||
msgid "Firmware / Clock / Cores"
|
||||
msgstr "固件 / 时钟 / 核心"
|
||||
|
||||
msgid "Frame Engine"
|
||||
msgstr "帧引擎"
|
||||
|
||||
msgid "Good"
|
||||
msgstr "良好"
|
||||
|
||||
msgid "Governor"
|
||||
msgstr "调频策略"
|
||||
|
||||
msgid "Grant access to Airoha SoC status (NPU + CPU + Overclock)"
|
||||
msgstr "允许访问 Airoha SoC 状态(NPU、CPU 和超频)"
|
||||
|
||||
msgid "HW Offload:"
|
||||
msgstr "硬件卸载:"
|
||||
|
||||
msgid "Healthy"
|
||||
msgstr "正常"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "空闲"
|
||||
|
||||
msgid "Index"
|
||||
msgstr "索引"
|
||||
|
||||
msgid "Internal Switch (1G LAN3/4)"
|
||||
msgstr "内置交换机(千兆 LAN3/4)"
|
||||
|
||||
msgid "Manages:"
|
||||
msgstr "管理:"
|
||||
|
||||
msgid "Max Frequency"
|
||||
msgstr "最高频率"
|
||||
|
||||
msgid "Must be 500-1600 MHz"
|
||||
msgstr "频率必须在 500–1600 MHz 之间"
|
||||
|
||||
msgid "NPU & Offload Engine"
|
||||
msgstr "NPU 与卸载引擎"
|
||||
|
||||
msgid "NPU Status"
|
||||
msgstr "NPU 状态"
|
||||
|
||||
msgid "New Flow"
|
||||
msgstr "转换后数据流"
|
||||
|
||||
msgid "No clients"
|
||||
msgstr "无客户端"
|
||||
|
||||
msgid "Not Active"
|
||||
msgstr "未运行"
|
||||
|
||||
msgid "OFF"
|
||||
msgstr "关闭"
|
||||
|
||||
msgid "Original Flow"
|
||||
msgstr "原始数据流"
|
||||
|
||||
msgid "Overclock"
|
||||
msgstr "超频"
|
||||
|
||||
msgid "PPE Eng 1"
|
||||
msgstr "PPE 引擎 1"
|
||||
|
||||
msgid "PPE Eng 2"
|
||||
msgstr "PPE 引擎 2"
|
||||
|
||||
msgid "PPE Engines"
|
||||
msgstr "PPE 引擎"
|
||||
|
||||
msgid "PPE Flow Offload Entries"
|
||||
msgstr "PPE 流量卸载条目"
|
||||
|
||||
msgid "PPE init, WDMA rings, flow stats"
|
||||
msgstr "PPE 初始化、WDMA 环形队列、流量统计"
|
||||
|
||||
msgid "PSE Port Queue Status"
|
||||
msgstr "PSE 端口队列状态"
|
||||
|
||||
msgid "PSE Shared Buffer"
|
||||
msgstr "PSE 共享缓冲区"
|
||||
|
||||
msgid "Poor"
|
||||
msgstr "差"
|
||||
|
||||
msgid "RX Drop"
|
||||
msgstr "接收丢包"
|
||||
|
||||
msgid "Reserved Memory"
|
||||
msgstr "保留内存"
|
||||
|
||||
msgid "SoC Status"
|
||||
msgstr "SoC 状态"
|
||||
|
||||
msgid "State"
|
||||
msgstr "状态"
|
||||
|
||||
msgid "Switch 1G"
|
||||
msgstr "千兆交换机"
|
||||
|
||||
msgid "TX Drop"
|
||||
msgstr "发送丢包"
|
||||
|
||||
msgid "Total"
|
||||
msgstr "总计"
|
||||
|
||||
msgid "Type"
|
||||
msgstr "类型"
|
||||
|
||||
msgid "Warning"
|
||||
msgstr "警告"
|
||||
|
||||
msgid "devmem not available on this build"
|
||||
msgstr "当前固件不支持 devmem"
|
||||
|
||||
msgid "Frequencies above 1400 MHz may be unstable. Continue?"
|
||||
msgstr "超过 1400 MHz 的频率可能不稳定,是否继续?"
|
||||
@@ -291,6 +291,12 @@ set_overclock() {
|
||||
echo '{"error":"missing freq_mhz parameter"}'
|
||||
return
|
||||
fi
|
||||
case "$target_mhz" in
|
||||
*[!0-9]*)
|
||||
echo '{"error":"frequency must be an integer"}'
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
# Validate range (500-1600, crash likely above 1500 at stock voltage)
|
||||
if [ "$target_mhz" -lt 500 ] || [ "$target_mhz" -gt 1600 ]; then
|
||||
@@ -312,9 +318,16 @@ set_overclock() {
|
||||
posdiv=0
|
||||
pcw_int=$((target_mhz / 50))
|
||||
fi
|
||||
if [ $((pcw_int * 50 / (1 << posdiv))) -ne "$target_mhz" ]; then
|
||||
echo '{"error":"frequency must use 25 MHz steps below 1000 MHz or 50 MHz steps above"}'
|
||||
return
|
||||
fi
|
||||
|
||||
# Lock governor to performance to prevent cpufreq from fighting
|
||||
echo performance > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor 2>/dev/null
|
||||
if ! echo performance > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor 2>/dev/null; then
|
||||
echo '{"error":"failed to lock performance governor"}'
|
||||
return
|
||||
fi
|
||||
|
||||
# Read current register values
|
||||
local cur_clkmux=$(($(devmem 0x1fa201e0)))
|
||||
@@ -347,7 +360,7 @@ set_overclock() {
|
||||
fi
|
||||
|
||||
# Step 6: Wait for PLL lock
|
||||
sleep 0.02
|
||||
sleep 0.02 2>/dev/null || sleep 1
|
||||
|
||||
# Step 7: Enable ARMPLL path in CLK_MUX (set bit 0)
|
||||
local cur_clkmux2=$(($(devmem 0x1fa201e0)))
|
||||
@@ -379,6 +392,11 @@ set_overclock() {
|
||||
read_freq=$((read_pcw * 50 / (1 << read_posdiv)))
|
||||
fi
|
||||
|
||||
if [ "$read_freq" -ne "$target_mhz" ]; then
|
||||
printf '{"error":"PLL frequency verification failed","target_mhz":%d,"actual_mhz":%d}' \
|
||||
"$target_mhz" "$read_freq"
|
||||
return
|
||||
fi
|
||||
printf '{"result":"ok","target_mhz":%d,"actual_mhz":%d,"pcw":%d,"posdiv":%d}' \
|
||||
"$target_mhz" "$read_freq" "$read_pcw" "$read_posdiv"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-argon-config
|
||||
PKG_VERSION:=1.0
|
||||
PKG_RELEASE:=4
|
||||
PKG_RELEASE:=5
|
||||
|
||||
PKG_MAINTAINER:=jerrykuku <jerrykuku@qq.com>
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ config global
|
||||
option dark_primary '#483d8b'
|
||||
option blur '10'
|
||||
option blur_dark '10'
|
||||
option transparency '0.3'
|
||||
option transparency_dark '0.3'
|
||||
option transparency '0.5'
|
||||
option transparency_dark '0.5'
|
||||
option mode 'dark'
|
||||
option online_wallpaper 'default'
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-clashoo
|
||||
PKG_VERSION:=1.30.0
|
||||
PKG_RELEASE:=1
|
||||
PKG_VERSION:=1.31.0
|
||||
PKG_RELEASE:=2
|
||||
PKG_MAINTAINER:=kenzok8
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
|
||||
@@ -158,7 +158,8 @@ var callListTemplates = rpc.declare({ object: 'luci.clashoo', method: 'list_temp
|
||||
var callUploadTemplate= rpc.declare({ object: 'luci.clashoo', method: 'upload_template', params: ['name', 'content'], expect: {} });
|
||||
var callApplyRewrite = rpc.declare({ object: 'luci.clashoo', method: 'apply_rewrite', params: ['base_type','base_name','rewrite_type','rewrite_name','output_name','set_active'], expect: {} });
|
||||
var callFetchUrl = rpc.declare({ object: 'luci.clashoo', method: 'fetch_rewrite_url', params: ['url','name'], expect: {} });
|
||||
var callApplyTplUrl = rpc.declare({ object: 'luci.clashoo', method: 'apply_template_with_url', params: ['template_source','sub_url','output_name','set_active'], expect: {} });
|
||||
var callApplyTplUrl = rpc.declare({ object: 'luci.clashoo', method: 'apply_template_with_url', params: ['template_source','sub_pairs','output_name','set_active'], expect: {} });
|
||||
var callRegenerate = rpc.declare({ object: 'luci.clashoo', method: 'regenerate_output', params: ['name'], expect: {} });
|
||||
var callMigrateSbProfile = rpc.declare({ object: 'luci.clashoo', method: 'migrate_singbox_profile', params: ['name'], expect: {} });
|
||||
var callSmartFlushCache = rpc.declare({ object: 'luci.clashoo', method: 'smart_flush_cache', expect: {} });
|
||||
var callDetectPrimaryGroup = rpc.declare({ object: 'luci.clashoo', method: 'detect_primary_group', expect: {} });
|
||||
@@ -596,22 +597,24 @@ function createConfigEditor(mode) {
|
||||
return {
|
||||
el: wrap,
|
||||
textarea: ta,
|
||||
setValue: function (content) {
|
||||
setValue: function (content, readOnly) {
|
||||
content = (content == null) ? '' : String(content);
|
||||
ta.readOnly = !!readOnly;
|
||||
if (content.length > LARGE) { showTextarea(content); return; }
|
||||
if (cm) { showCM(content); return; }
|
||||
if (cm) { cm.setOption('readOnly', !!readOnly); showCM(content); return; }
|
||||
loadCodeMirror().then(function () {
|
||||
if (!cm && window.CodeMirror) {
|
||||
cm = window.CodeMirror(host, {
|
||||
value: '', mode: mode,
|
||||
lineNumbers: true, matchBrackets: true,
|
||||
lineWrapping: true, tabSize: 2, indentUnit: 2,
|
||||
viewportMargin: 60
|
||||
viewportMargin: 60,
|
||||
readOnly: !!readOnly
|
||||
});
|
||||
if (getThemeClass().indexOf('dark') >= 0)
|
||||
host.classList.add('cl-cm-dark');
|
||||
}
|
||||
if (cm) showCM(content); else showTextarea(content);
|
||||
if (cm) { cm.setOption('readOnly', !!readOnly); showCM(content); } else showTextarea(content);
|
||||
}).catch(function () { showTextarea(content); });
|
||||
},
|
||||
getValue: function () {
|
||||
@@ -945,7 +948,66 @@ return view.extend({
|
||||
});
|
||||
|
||||
var tplUrlIn = E('input', { type: 'text', 'class': 'cl-sub-url', placeholder: _("Enter remote template URL, e.g. https://raw.githubusercontent.com/…/Clash.yaml") });
|
||||
var subUrlIn = E('input', { type: 'text', 'class': 'cl-sub-url', placeholder: _("Enter subscription URL (injected into template proxy-providers)") });
|
||||
/* ── 多 provider pairs 输入 ── */
|
||||
var pairs = [];
|
||||
var pairsBox = E('div', { 'class': 'cl-pairs-box' });
|
||||
|
||||
function renderPairs() {
|
||||
pairsBox.innerHTML = '';
|
||||
pairs.forEach(function (p, idx) {
|
||||
var nameIn = E('input', {
|
||||
type: 'text', 'class': 'cl-sub-url',
|
||||
style: 'width:120px;flex-shrink:0',
|
||||
placeholder: _('Provider name'), value: p.name || ''
|
||||
});
|
||||
nameIn.addEventListener('input', function () { pairs[idx].name = nameIn.value; });
|
||||
|
||||
var urlIn = E('input', {
|
||||
type: 'text', 'class': 'cl-sub-url',
|
||||
style: 'flex:1;min-width:0',
|
||||
placeholder: _('Subscription URL'), value: p.url || ''
|
||||
});
|
||||
urlIn.addEventListener('input', function () { pairs[idx].url = urlIn.value; });
|
||||
|
||||
var children = [nameIn, urlIn];
|
||||
|
||||
if (idx === 0) {
|
||||
var addBtn = E('button', {
|
||||
'class': 'btn cbi-button cl-btn-sm',
|
||||
style: 'flex-shrink:0'
|
||||
}, '+');
|
||||
if (pairs.length >= 5) {
|
||||
addBtn.setAttribute('disabled', 'disabled');
|
||||
addBtn.style.opacity = '0.5';
|
||||
addBtn.style.cursor = 'not-allowed';
|
||||
}
|
||||
addBtn.addEventListener('click', function () {
|
||||
if (pairs.length >= 5) return;
|
||||
pairs.push({ name: '', url: '' });
|
||||
renderPairs();
|
||||
});
|
||||
children.push(addBtn);
|
||||
} else {
|
||||
var delBtn = E('button', {
|
||||
'class': 'btn cbi-button cl-btn-sm',
|
||||
style: 'flex-shrink:0'
|
||||
}, '−');
|
||||
delBtn.addEventListener('click', function () {
|
||||
pairs.splice(idx, 1);
|
||||
renderPairs();
|
||||
});
|
||||
children.push(delBtn);
|
||||
}
|
||||
|
||||
pairsBox.appendChild(E('div', {
|
||||
'class': 'cl-pair-row',
|
||||
style: 'display:flex;gap:6px;margin-bottom:6px;align-items:center'
|
||||
}, children));
|
||||
});
|
||||
}
|
||||
|
||||
pairs.push({ name: '', url: '' });
|
||||
renderPairs();
|
||||
var outNameIn = E('input', { type: 'text', 'class': 'cl-sub-url', placeholder: _("Output file name (without extension, blank to auto-fill)") });
|
||||
var rwMode = 'local';
|
||||
|
||||
@@ -990,12 +1052,13 @@ return view.extend({
|
||||
|
||||
var rwApply = function (setActive) {
|
||||
var tplSrc = rwMode === 'local' ? tplSel.value : tplUrlIn.value.trim();
|
||||
var subUrl = subUrlIn.value.trim();
|
||||
var out = outNameIn.value.trim();
|
||||
if (!tplSrc) { ui.addNotification(null, E('p', rwMode === 'local' ? _("Please select a local template file") : _("Please enter a remote template URL"))); return; }
|
||||
if (!subUrl) { ui.addNotification(null, E('p', _("Please enter a subscription URL"))); return; }
|
||||
var validPairs = pairs.filter(function (p) { return p.name.trim() && p.url.trim(); });
|
||||
if (validPairs.length === 0) { ui.addNotification(null, E('p', _("Please fill at least one name + URL pair"))); return; }
|
||||
if (!out) { ui.addNotification(null, E('p', _("Please enter an output file name"))); return; }
|
||||
L.resolveDefault(callApplyTplUrl(tplSrc, subUrl, out, setActive ? '1' : '0'), {}).then(function (r) {
|
||||
var pairsJson = JSON.stringify(validPairs);
|
||||
L.resolveDefault(callApplyTplUrl(tplSrc, pairsJson, out, setActive ? '1' : '0'), {}).then(function (r) {
|
||||
ui.addNotification(null, E('p', r && r.success ? (r.message || _("Generated: ") + r.output_name) : (_("Generate failed: ") + (r && r.message || _("Unknown error")))));
|
||||
if (r && r.success) location.reload();
|
||||
});
|
||||
@@ -1019,7 +1082,7 @@ return view.extend({
|
||||
}
|
||||
}, _("Save"));
|
||||
|
||||
var otherEditorBox = E('div', { 'class': 'cl-section cl-card cl-sb-editor' }, [
|
||||
var otherEditorBox = E('div', { 'class': 'cl-section cl-card cl-sb-editor cl-inline-editor' }, [
|
||||
otherEditorTitle,
|
||||
otherEd.el,
|
||||
E('div', { 'class': 'cl-actions cl-sb-row-actions cl-sb-editor-actions' }, [
|
||||
@@ -1027,93 +1090,194 @@ return view.extend({
|
||||
E('span', { 'class': 'cl-hint' }, _("Click Save after editing; switching configuration automatically restarts the service"))
|
||||
])
|
||||
]);
|
||||
var otherEditorHint = otherEditorBox.querySelector('.cl-hint');
|
||||
|
||||
function loadOtherEditor(name, type) {
|
||||
otherEditorTitle.textContent = _("Editing: ") + name;
|
||||
otherSaveBtn.removeAttribute('disabled');
|
||||
|
||||
function loadOtherEditor(name, type, readOnly) {
|
||||
otherEditorTitle.textContent = (readOnly ? _("Viewing: ") : _("Editing: ")) + name;
|
||||
if (readOnly) {
|
||||
otherSaveBtn.style.display = "none";
|
||||
} else {
|
||||
otherSaveBtn.style.display = "";
|
||||
otherSaveBtn.removeAttribute('disabled');
|
||||
}
|
||||
if (otherEditorHint) {
|
||||
otherEditorHint.style.display = "";
|
||||
otherEditorHint.textContent = readOnly
|
||||
? _("Read-only preview; edit the template and click Update to regenerate")
|
||||
: _("Click Save after editing; switching configuration automatically restarts the service");
|
||||
}
|
||||
otherEd.textarea.dataset.name = name;
|
||||
otherEd.textarea.dataset.type = type;
|
||||
otherEd.setValue(_("Loading…"));
|
||||
otherEd.setValue(_("Loading…"), readOnly);
|
||||
L.resolveDefault(callReadOtherConfig(name, type), {}).then(function (r) {
|
||||
otherEd.setValue(r.content || '');
|
||||
otherEd.setValue(r.content || '', readOnly);
|
||||
});
|
||||
}
|
||||
|
||||
var currentEditorCard = null;
|
||||
var toggleOtherEditor = function (f, type, cardEl) {
|
||||
if (currentEditorCard === cardEl && otherEditorBox.parentNode) {
|
||||
otherEditorBox.parentNode.removeChild(otherEditorBox);
|
||||
currentEditorCard = null;
|
||||
return;
|
||||
}
|
||||
if (otherEditorBox.parentNode) otherEditorBox.parentNode.removeChild(otherEditorBox);
|
||||
loadOtherEditor(f.name, type, f.generated === true);
|
||||
cardEl.parentNode.insertBefore(otherEditorBox, cardEl.nextSibling);
|
||||
currentEditorCard = cardEl;
|
||||
setTimeout(function(){
|
||||
var listWrap = cardEl.closest(".cl-file-list") || cardEl.parentNode;
|
||||
var section = listWrap.closest(".cl-section") || listWrap.parentNode;
|
||||
if (listWrap && section) {
|
||||
var cs = getComputedStyle(section);
|
||||
var innerW = section.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight);
|
||||
var listW = listWrap.clientWidth;
|
||||
var diff = Math.floor((innerW - listW) / 2);
|
||||
if (diff > 0 && innerW > 0) {
|
||||
otherEditorBox.style.width = innerW + "px";
|
||||
otherEditorBox.style.maxWidth = "none";
|
||||
otherEditorBox.style.marginLeft = "-" + diff + "px";
|
||||
otherEditorBox.style.marginRight = "-" + diff + "px";
|
||||
otherEditorBox.style.boxSizing = "border-box";
|
||||
otherEditorBox.style.alignSelf = "stretch";
|
||||
}
|
||||
}
|
||||
try { otherEditorBox.scrollIntoView({behavior:"smooth", block:"nearest"}); } catch(e) {}
|
||||
}, 60);
|
||||
};
|
||||
|
||||
var makeOtherCards = function (files, type) {
|
||||
return files.map(function (f) {
|
||||
var cardEl;
|
||||
var nameNodes = [];
|
||||
if (f.active) nameNodes.push(E('span', { 'class': 'cl-active-badge' }, _("Active")));
|
||||
nameNodes.push(E('span', { 'class': 'cl-file-name-text' }, safeText(f.name)));
|
||||
|
||||
return E('div', { 'class': 'cl-file-item' + (f.active ? ' is-active' : '') }, [
|
||||
var actions = [];
|
||||
|
||||
if (f.generated === true) {
|
||||
actions.push(E('button', {
|
||||
'class': 'btn cbi-button-action cl-btn-sm cl-btn-update-output',
|
||||
disabled: f.active ? 'disabled' : null,
|
||||
style: f.active ? 'opacity:.5;cursor:not-allowed' : '',
|
||||
title: f.active ? _('Active config cannot be updated; switch to another first') : '',
|
||||
click: function (ev) {
|
||||
var btn = ev.target;
|
||||
if (f.active || btn.disabled || clKernelBusy()) return;
|
||||
clKernelLock();
|
||||
btn.disabled = true;
|
||||
btn.textContent = _("Updating…");
|
||||
L.resolveDefault(callRegenerate(f.name), {}).then(function (r) {
|
||||
if (!r || !r.success) {
|
||||
ui.addNotification(null, E('p', _("Update failed: ") + ((r && (r.message || r.error)) || '')));
|
||||
btn.disabled = false;
|
||||
btn.textContent = _("Update");
|
||||
clKernelUnlock();
|
||||
return;
|
||||
}
|
||||
if (!r.sub_pairs || r.sub_pairs.length === 0) {
|
||||
ui.addNotification(null, E('p', _("Update failed: this config has no proxy-providers")));
|
||||
btn.disabled = false;
|
||||
btn.textContent = _("Update");
|
||||
clKernelUnlock();
|
||||
return;
|
||||
}
|
||||
var pairsJson = JSON.stringify(r.sub_pairs);
|
||||
L.resolveDefault(callApplyTplUrl(r.template_source, pairsJson, f.name, f.active ? '1' : '0'), {}).then(function (r2) {
|
||||
ui.addNotification(null, E('p', (r2 && r2.success) ? f.name + _(" updated") : _("Update failed")));
|
||||
location.reload();
|
||||
}).catch(function () {
|
||||
btn.disabled = false;
|
||||
btn.textContent = _("Update");
|
||||
clKernelUnlock();
|
||||
});
|
||||
}).catch(function () {
|
||||
btn.disabled = false;
|
||||
btn.textContent = _("Update");
|
||||
clKernelUnlock();
|
||||
});
|
||||
}
|
||||
}, _("Update")));
|
||||
}
|
||||
|
||||
actions.push(E('button', {
|
||||
'class': 'btn cbi-button cl-btn-sm cl-btn-edit',
|
||||
click: function (ev) {
|
||||
var btn = ev.target;
|
||||
if (btn.disabled) return;
|
||||
toggleOtherEditor(f, type, cardEl);
|
||||
}
|
||||
}, f.generated === true ? _("Show/Hide") : _("Edit")));
|
||||
|
||||
actions.push(E('button', {
|
||||
'class': 'btn cbi-button cl-btn-sm cl-btn-switch',
|
||||
click: function (ev) {
|
||||
var btn = ev.target;
|
||||
if (btn.disabled || clKernelBusy()) return;
|
||||
clKernelLock();
|
||||
btn.disabled = true;
|
||||
btn.textContent = _("Loading…");
|
||||
L.resolveDefault(callSetConfig(f.name), {}).then(function () {
|
||||
location.reload();
|
||||
}).catch(function () {
|
||||
btn.disabled = false;
|
||||
btn.textContent = _("Switch Profile");
|
||||
clKernelUnlock();
|
||||
});
|
||||
}
|
||||
}, _("Switch Profile")));
|
||||
|
||||
actions.push(E('button', {
|
||||
'class': 'btn cbi-button cl-btn-sm cl-btn-delete',
|
||||
click: function (ev) {
|
||||
var btn = ev.target;
|
||||
if (btn.disabled || clKernelBusy()) return;
|
||||
if (!confirm(_("Delete ") + f.name + '?')) return;
|
||||
clKernelLock();
|
||||
btn.disabled = true;
|
||||
btn.textContent = _("Loading…");
|
||||
L.resolveDefault(callDeleteCfg(f.name, type), {}).then(function () {
|
||||
location.reload();
|
||||
}).catch(function () {
|
||||
btn.disabled = false;
|
||||
btn.textContent = _("Delete");
|
||||
clKernelUnlock();
|
||||
});
|
||||
}
|
||||
}, _("Delete")));
|
||||
|
||||
cardEl = E('div', { 'class': 'cl-file-item' + (f.active ? ' is-active' : '') }, [
|
||||
E('div', { 'class': 'cl-file-meta' }, [
|
||||
E('div', { 'class': 'cl-file-name' }, nameNodes),
|
||||
E('div', { 'class': 'cl-file-size' }, safeText(f.size))
|
||||
]),
|
||||
E('div', { 'class': 'cl-file-actions' }, [
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cl-btn-sm cl-btn-edit',
|
||||
click: function (ev) {
|
||||
var btn = ev.target;
|
||||
if (btn.disabled) return;
|
||||
btn.disabled = true;
|
||||
var orig = btn.textContent;
|
||||
btn.textContent = _("Loading…");
|
||||
Promise.resolve(loadOtherEditor(f.name, type)).then(function () {
|
||||
btn.disabled = false;
|
||||
btn.textContent = orig;
|
||||
}).catch(function () {
|
||||
btn.disabled = false;
|
||||
btn.textContent = orig;
|
||||
});
|
||||
}
|
||||
}, _("Edit")),
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cl-btn-sm cl-btn-switch',
|
||||
click: function (ev) {
|
||||
var btn = ev.target;
|
||||
if (btn.disabled || clKernelBusy()) return;
|
||||
clKernelLock();
|
||||
btn.disabled = true;
|
||||
btn.textContent = _("Loading…");
|
||||
L.resolveDefault(callSetConfig(f.name), {}).then(function () {
|
||||
location.reload();
|
||||
}).catch(function () {
|
||||
btn.disabled = false;
|
||||
btn.textContent = _("Switch Profile");
|
||||
clKernelUnlock();
|
||||
});
|
||||
}
|
||||
}, _("Switch Profile")),
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cl-btn-sm cl-btn-delete',
|
||||
click: function (ev) {
|
||||
var btn = ev.target;
|
||||
if (btn.disabled || clKernelBusy()) return;
|
||||
if (!confirm(_("Delete ") + f.name + '?')) return;
|
||||
clKernelLock();
|
||||
btn.disabled = true;
|
||||
btn.textContent = _("Loading…");
|
||||
L.resolveDefault(callDeleteCfg(f.name, type), {}).then(function () {
|
||||
location.reload();
|
||||
}).catch(function () {
|
||||
btn.disabled = false;
|
||||
btn.textContent = _("Delete");
|
||||
clKernelUnlock();
|
||||
});
|
||||
}
|
||||
}, _("Delete"))
|
||||
])
|
||||
E('div', { 'class': 'cl-file-actions' }, actions)
|
||||
]);
|
||||
return cardEl;
|
||||
});
|
||||
};
|
||||
|
||||
var otherFiles = (upFiles || []).map(function(f){ return {f:f, t:'2'}; })
|
||||
.concat((customFiles || []).map(function(f){ return {f:f, t:'3'}; }));
|
||||
var tplOnlyFiles = (customFiles || []).filter(function(f){ return f.generated !== true; });
|
||||
var genCustomFiles = (customFiles || []).filter(function(f){ return f.generated === true; });
|
||||
|
||||
var otherCards = otherFiles.map(function(o) {
|
||||
return makeOtherCards([o.f], o.t)[0];
|
||||
});
|
||||
var tplCards = tplOnlyFiles.map(function(f){ return makeOtherCards([f], '3')[0]; });
|
||||
var genCards = (upFiles || []).map(function(f){ return makeOtherCards([f], '2')[0]; })
|
||||
.concat(genCustomFiles.map(function(f){ return makeOtherCards([f], '3')[0]; }));
|
||||
|
||||
var tplListBox = tplCards.length ? E('div', { 'class': 'cl-section cl-card' }, [
|
||||
E("h4", {}, _("Template Selection")),
|
||||
E('div', { 'class': 'cl-fixed-600' }, [
|
||||
E('div', { 'class': 'cl-file-list' }, tplCards)
|
||||
])
|
||||
]) : null;
|
||||
|
||||
var genListBox = genCards.length ? E('div', { 'class': 'cl-section cl-card' }, [
|
||||
E('h4', {}, _("Other Configuration Files (upload / overwrite output)")),
|
||||
E('div', { 'class': 'cl-fixed-600' }, [
|
||||
E('div', { 'class': 'cl-file-list' }, genCards)
|
||||
])
|
||||
]) : null;
|
||||
|
||||
var sections = [
|
||||
E('div', { 'class': 'cl-section cl-card' }, [
|
||||
@@ -1138,15 +1302,8 @@ return view.extend({
|
||||
])
|
||||
];
|
||||
|
||||
if (otherFiles.length) {
|
||||
sections.push(E('div', { 'class': 'cl-section cl-card' }, [
|
||||
E('h4', {}, _("Other Configuration Files (upload / overwrite output)")),
|
||||
E('div', { 'class': 'cl-fixed-600' }, [
|
||||
E('div', { 'class': 'cl-file-list' }, otherCards)
|
||||
])
|
||||
]));
|
||||
sections.push(otherEditorBox);
|
||||
}
|
||||
if (genListBox) sections.push(genListBox);
|
||||
if (tplListBox) sections.push(tplListBox);
|
||||
|
||||
sections.push(
|
||||
E('div', { 'class': 'cl-section cl-card' }, [
|
||||
@@ -1161,8 +1318,8 @@ return view.extend({
|
||||
E('div', { 'class': 'cl-rw-divider' }),
|
||||
E('div', { 'class': 'cl-rewrite-group cl-rewrite-group-input' }, [
|
||||
E('div', { 'class': 'cl-rewrite-group-title' }, _("Information Input")),
|
||||
subUrlIn,
|
||||
outNameIn,
|
||||
pairsBox,
|
||||
E('div', { 'class': 'cl-actions cl-rewrite-actions' }, [
|
||||
E('button', { 'class': 'btn cbi-button cl-btn-sm', click: function(){ rwApply(false); } }, _("Generate Configuration")),
|
||||
E('button', { 'class': 'btn cbi-button-action cl-btn-sm cl-btn-generate-switch', click: function(){ rwApply(true); } }, _("Apply Configuration"))
|
||||
@@ -1414,7 +1571,7 @@ return view.extend({
|
||||
|
||||
o = s.option(form.DynamicList, 'fake_ip_filter', _("Fake-IP Filter Domains"));
|
||||
o.placeholder = '+.lan / geosite:cn / RULE-SET,cn_domain,real-ip';
|
||||
o.description = _("Blocklist mode: enter domains or shorthand like <code>geosite:cn</code>. Rule mode: entries are converted to rule syntax automatically, such as <code>GEOSITE,cn,real-ip</code> / <code>RULE-SET,xxx,real-ip</code>; usually add <code>MATCH,fake-ip</code> at the end as fallback. <code>geosite:cn</code> automatically uses built-in cn.mrs acceleration and avoids loading the 10MB geosite.dat. Allowlist mode drops the shipped defaults (they mean the opposite there), so enter your own domains.");
|
||||
o.description = _("Blocklist mode: enter domains or shorthand like <code>geosite:cn</code>. Rule mode: entries are converted to rule syntax automatically, such as <code>RULE-SET,xxx,real-ip</code> / <code>DOMAIN-SUFFIX,xxx,real-ip</code>; usually add <code>MATCH,fake-ip</code> at the end as fallback. <code>geosite:cn</code> becomes <code>RULE-SET,cn_domain,real-ip</code> via built-in cn.mrs acceleration (other <code>geosite:xxx</code> becomes <code>GEOSITE,xxx,real-ip</code>). Allowlist mode drops the shipped defaults (they mean the opposite there), so enter your own domains.");
|
||||
o.depends('enhanced_mode', 'fake-ip');
|
||||
o.remove = function () {};
|
||||
o = s.option(form.DynamicList, 'default_nameserver', 'Bootstrap DNS');
|
||||
|
||||
@@ -203,7 +203,7 @@ msgstr ""
|
||||
msgid "Blocklist (listed items use real IP, default)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Blocklist mode: enter domains or shorthand like <code>geosite:cn</code>. Rule mode: entries are converted to rule syntax automatically, such as <code>GEOSITE,cn,real-ip</code> / <code>RULE-SET,xxx,real-ip</code>; usually add <code>MATCH,fake-ip</code> at the end as fallback. <code>geosite:cn</code> automatically uses built-in cn.mrs acceleration and avoids loading the 10MB geosite.dat. Allowlist mode drops the shipped defaults (they mean the opposite there), so enter your own domains."
|
||||
msgid "Blocklist mode: enter domains or shorthand like <code>geosite:cn</code>. Rule mode: entries are converted to rule syntax automatically, such as <code>RULE-SET,xxx,real-ip</code> / <code>DOMAIN-SUFFIX,xxx,real-ip</code>; usually add <code>MATCH,fake-ip</code> at the end as fallback. <code>geosite:cn</code> becomes <code>RULE-SET,cn_domain,real-ip</code> via built-in cn.mrs acceleration (other <code>geosite:xxx</code> becomes <code>GEOSITE,xxx,real-ip</code>). Allowlist mode drops the shipped defaults (they mean the opposite there), so enter your own domains."
|
||||
msgstr ""
|
||||
|
||||
msgid "Bypass China IPv4"
|
||||
|
||||
@@ -213,8 +213,8 @@ msgstr "黑名单"
|
||||
msgid "Blocklist (listed items use real IP, default)"
|
||||
msgstr "黑名单(列入走真 IP,默认)"
|
||||
|
||||
msgid "Blocklist mode: enter domains or shorthand like <code>geosite:cn</code>. Rule mode: entries are converted to rule syntax automatically, such as <code>GEOSITE,cn,real-ip</code> / <code>RULE-SET,xxx,real-ip</code>; usually add <code>MATCH,fake-ip</code> at the end as fallback. <code>geosite:cn</code> automatically uses built-in cn.mrs acceleration and avoids loading the 10MB geosite.dat. Allowlist mode drops the shipped defaults (they mean the opposite there), so enter your own domains."
|
||||
msgstr "黑名单模式:填域名或 <code>geosite:cn</code> 简写。规则模式:条目会自动转成 <code>GEOSITE,cn,real-ip</code> / <code>RULE-SET,xxx,real-ip</code> 这种与 rules 同语法的写法,末尾通常加一条 <code>MATCH,fake-ip</code> 兜底。填 <code>geosite:cn</code> 会自动改用内置 cn.mrs 加速,免加载 10MB geosite.dat。白名单模式下随包自带的默认项含义相反,会被跳过,请自行填写需要 Fake-IP 的域名。"
|
||||
msgid "Blocklist mode: enter domains or shorthand like <code>geosite:cn</code>. Rule mode: entries are converted to rule syntax automatically, such as <code>RULE-SET,xxx,real-ip</code> / <code>DOMAIN-SUFFIX,xxx,real-ip</code>; usually add <code>MATCH,fake-ip</code> at the end as fallback. <code>geosite:cn</code> becomes <code>RULE-SET,cn_domain,real-ip</code> via built-in cn.mrs acceleration (other <code>geosite:xxx</code> becomes <code>GEOSITE,xxx,real-ip</code>). Allowlist mode drops the shipped defaults (they mean the opposite there), so enter your own domains."
|
||||
msgstr "黑名单模式:填域名或 <code>geosite:cn</code> 简写。规则模式:条目会自动转成 <code>RULE-SET,xxx,real-ip</code> / <code>DOMAIN-SUFFIX,xxx,real-ip</code> 这种与 rules 同语法的写法,末尾通常加一条 <code>MATCH,fake-ip</code> 兜底。<code>geosite:cn</code> 会转成 <code>RULE-SET,cn_domain,real-ip</code>,走内置 cn.mrs 加速(其它 <code>geosite:xxx</code> 则转成 <code>GEOSITE,xxx,real-ip</code>)。白名单模式下随包自带的默认项含义相反,会被跳过,请自行填写需要 Fake-IP 的域名。"
|
||||
|
||||
msgid "Bypass China IPv4"
|
||||
msgstr "大陆 IPv4 绕过"
|
||||
@@ -1577,3 +1577,21 @@ msgstr "✗ 启动失败: "
|
||||
|
||||
msgid "✗ Submission failed"
|
||||
msgstr "✗ 提交失败"
|
||||
|
||||
msgid "Please fill at least one name + URL pair"
|
||||
msgstr "请至少填写一组「名称 + 订阅链接」"
|
||||
|
||||
msgid "Provider name"
|
||||
msgstr "订阅源名称"
|
||||
|
||||
msgid "Update failed: this config has no proxy-providers"
|
||||
msgstr "更新失败:该配置没有 proxy-providers"
|
||||
|
||||
msgid "Viewing: "
|
||||
msgstr "查看:"
|
||||
|
||||
msgid "Read-only preview; edit the template and click Update to regenerate"
|
||||
msgstr "只读预览;修改请编辑模板后点「更新」重新生成"
|
||||
|
||||
msgid "Active config cannot be updated; switch to another first"
|
||||
msgstr "活跃配置无法更新;请先切换到其他配置"
|
||||
@@ -3042,30 +3042,71 @@ if (!dir) return { files: [] };
|
||||
let active = uci_get('clashoo', 'config', 'use_config');
|
||||
let active_name = replace(active, /^.*\//, '');
|
||||
let files = [];
|
||||
for (let f in (glob(dir + '/*.yaml') || [])) {
|
||||
|
||||
let need_check = (req.args?.type == '3');
|
||||
let collect = function(ext) {
|
||||
for (let f in (glob(dir + '/*' + ext) || [])) {
|
||||
let name = replace(f, dir + '/', '');
|
||||
let fi = stat(f);
|
||||
let generated = false;
|
||||
if (need_check && (!fi || fi.size <= 524288)) {
|
||||
let content = readfile(f) || '';
|
||||
for (let ln in split(content, '\n')) {
|
||||
if (match(ln, /^x-clashoo:/)) { generated = true; break; }
|
||||
}
|
||||
}
|
||||
push(files, {
|
||||
name,
|
||||
mtime: fi ? ('' + fi.mtime) : null,
|
||||
size: fi ? (int(fi.size / 1024) + ' KB') : null,
|
||||
active: name == active_name
|
||||
});
|
||||
}
|
||||
for (let f in (glob(dir + '/*.yml') || [])) {
|
||||
let name = replace(f, dir + '/', '');
|
||||
let fi = stat(f);
|
||||
push(files, {
|
||||
name,
|
||||
mtime: fi ? ('' + fi.mtime) : null,
|
||||
size: fi ? (int(fi.size / 1024) + ' KB') : null,
|
||||
active: name == active_name
|
||||
active: name == active_name,
|
||||
generated: generated
|
||||
});
|
||||
}
|
||||
};
|
||||
collect('.yaml');
|
||||
collect('.yml');
|
||||
return { files, active: active_name };
|
||||
}
|
||||
},
|
||||
|
||||
regenerate_output: {
|
||||
args: { name: 'name' },
|
||||
call: function(req) {
|
||||
let name = ensure_yaml_name(req.args?.name || '');
|
||||
if (!name)
|
||||
return { success: false, error: 'invalid_name', message: '文件名无效' };
|
||||
let path = TEMPLATE_DIR + '/' + name;
|
||||
if (!access(path, 'r'))
|
||||
return { success: false, error: 'not_found', message: '文件不存在' };
|
||||
|
||||
let p = popen("yq -M -o=json '{\"template\": .\"x-clashoo\".template // \"\", \"pairs\": [.[\"proxy-providers\"] | to_entries[] | {\"name\": .key, \"url\": .value.url}]}' " + shell_quote(path) + " 2>/dev/null");
|
||||
let out = '';
|
||||
if (p) { out = trim(p.read('all')); p.close(); }
|
||||
|
||||
let template = '';
|
||||
let pairs = [];
|
||||
try {
|
||||
let data = json(out || '{}');
|
||||
template = data.template || '';
|
||||
if (type(data.pairs) == 'array') {
|
||||
for (let item in data.pairs) {
|
||||
if (item && item.name && item.url) push(pairs, item);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (!template)
|
||||
return { success: false, error: 'no_meta', message: '该文件不是模板生成的配置' };
|
||||
|
||||
return {
|
||||
success: true,
|
||||
template_source: template,
|
||||
sub_pairs: pairs
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
delete_config: {
|
||||
args: { name: 'name', type: 'type' },
|
||||
call: function(req) {
|
||||
@@ -3370,25 +3411,38 @@ return { success: true, enabled: enabled, interval: interval };
|
||||
apply_template_with_url: {
|
||||
args: {
|
||||
template_source: 'template_source',
|
||||
sub_url: 'sub_url',
|
||||
sub_pairs: 'sub_pairs',
|
||||
output_name: 'output_name',
|
||||
set_active: 'set_active'
|
||||
},
|
||||
call: function(req) {
|
||||
let tpl_src = trim(req.args?.template_source || '');
|
||||
let sub_url = trim(req.args?.sub_url || '');
|
||||
let pairs_raw = trim(req.args?.sub_pairs || '');
|
||||
let output_name = ensure_yaml_name(req.args?.output_name || '');
|
||||
if (!output_name) output_name = 'tpl-rewrite.yaml';
|
||||
let uniq_name = replace(output_name, /\.(yaml|yml)$/, '');
|
||||
let set_active = (req.args?.set_active || '') == '1';
|
||||
|
||||
if (!tpl_src)
|
||||
return { success: false, error: 'invalid_template', message: '模板来源不能为空' };
|
||||
if (!sub_url || !match(sub_url, /^https?:\/\//))
|
||||
return { success: false, error: 'invalid_sub_url', message: '订阅 URL 无效' };
|
||||
|
||||
let pairs = [];
|
||||
try {
|
||||
let parsed = json(pairs_raw || '[]');
|
||||
if (type(parsed) == 'array') {
|
||||
for (let p in parsed) {
|
||||
if (p && p.name && p.url && match(p.url, /^https?:\/\//))
|
||||
push(pairs, { name: trim(p.name), url: trim(p.url) });
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
return { success: false, error: 'invalid_pairs', message: '订阅参数格式错误' };
|
||||
}
|
||||
if (length(pairs) == 0)
|
||||
return { success: false, error: 'empty_pairs', message: '请至少填一行有效的 名字+URL' };
|
||||
|
||||
let tmp_tpl = '/tmp/clashoo_tpl_in.yaml';
|
||||
let tmp_out = '/tmp/clashoo_tpl_out.yaml';
|
||||
let tmp_pairs = '/tmp/clashoo_tpl_pairs.json';
|
||||
let out_dir = '/usr/share/clashoo/config/custom';
|
||||
system('mkdir -p ' + shell_quote(out_dir));
|
||||
|
||||
@@ -3413,7 +3467,6 @@ if (system('cp -f ' + shell_quote(local_path) + ' ' + shell_quote(tmp_tpl)) != 0
|
||||
return { success: false, error: 'copy_failed', message: '读取本地模板失败' };
|
||||
}
|
||||
|
||||
/* 用 yq 把所有 proxy-providers 条目的 url 替换为订阅链接 */
|
||||
if (system('command -v yq >/dev/null 2>&1') != 0)
|
||||
return { success: false, error: 'missing_yq', message: '缺少 yq,无法注入订阅 URL' };
|
||||
|
||||
@@ -3423,15 +3476,29 @@ return { success: false, error: 'missing_yq', message: '缺少 yq,无法注入
|
||||
if (!access(exploded, "r")) {
|
||||
system("cp -f " + shell_quote(tmp_tpl) + " " + shell_quote(exploded));
|
||||
}
|
||||
/* 替换 proxy-providers.url 并把 provider 名改成唯一名(同步 proxy-groups 的 use)*/
|
||||
let inject_cmd = "URL=" + shell_quote(sub_url) + " NAME=" + shell_quote(uniq_name)
|
||||
+ " yq e '.[\"proxy-providers\"][].url = env(URL) | (.[\"proxy-providers\"] | keys | map({\"key\": ., \"value\": strenv(NAME) + \"-\" + .}) | from_entries) as $rename | .[\"proxy-providers\"] |= with_entries(.key = $rename[.key]) | (.[\"proxy-groups\"][] | select(has(\"use\")) | .use) |= map($rename[.] // .)' "
|
||||
|
||||
/* pairs 写到临时 JSON 文件 */
|
||||
writefile(tmp_pairs, sprintf('%.J', pairs));
|
||||
|
||||
let tpl_label = match(tpl_src, /^https?:\/\//) ? tpl_src : replace(tpl_src, /^.*\//, "");
|
||||
|
||||
let yq_expr = '(load("' + tmp_pairs + '")) as $pairs | '
|
||||
+ '(.["proxy-providers"] | keys) as $oldkeys | '
|
||||
+ '($oldkeys | to_entries | map(.key as $i | .value as $k | {"key": $k, "value": ($pairs[$i].name // $k)}) | from_entries) as $ren | '
|
||||
+ '($oldkeys | to_entries | map(select(.key < ($pairs | length)) | .key as $i | .value as $k | {"key": $k, "value": $pairs[$i].url}) | from_entries) as $reurl | '
|
||||
+ '.["proxy-providers"] |= with_entries(.key as $old | .key = ($ren[$old] // $old) | .value.url = ($reurl[$old] // .value.url)) | '
|
||||
+ '(.["proxy-groups"][] | select(has("use")) | .use) |= map($ren[.] // .) | '
|
||||
+ '."x-clashoo" = {"template": strenv(TPL_LABEL)}';
|
||||
|
||||
let inject_cmd = "TPL_LABEL=" + shell_quote(tpl_label)
|
||||
+ " yq -M e '" + yq_expr + "' "
|
||||
+ shell_quote(exploded) + " > " + shell_quote(tmp_out);
|
||||
|
||||
if (system(inject_cmd) != 0 || !access(tmp_out, "r")) {
|
||||
system("rm -f " + shell_quote(exploded));
|
||||
system("rm -f " + shell_quote(exploded) + " " + shell_quote(tmp_pairs));
|
||||
return { success: false, error: "inject_failed", message: "订阅 URL 注入失败" };
|
||||
}
|
||||
system("rm -f " + shell_quote(exploded));
|
||||
system("rm -f " + shell_quote(exploded) + " " + shell_quote(tmp_pairs));
|
||||
|
||||
let out_path = out_dir + '/' + output_name;
|
||||
if (system('mv -f ' + shell_quote(tmp_out) + ' ' + shell_quote(out_path)) != 0)
|
||||
@@ -3443,20 +3510,20 @@ system('rm -f ' + shell_quote(tmp_tpl));
|
||||
/* 只把独立引用项"直连"转成 DIRECT,组名里的"直连"不动 */
|
||||
system("sed -i 's/^\\( *- *\\)直连$/\\1DIRECT/' " + shell_quote(out_path) + " 2>/dev/null");
|
||||
system("yq e '(.proxy-groups[] | select(has(\"proxies\")) | .proxies) |= map(sub(\"^直连$\", \"DIRECT\"))' " + shell_quote(out_path) + " -i 2>/dev/null");
|
||||
|
||||
/* 用 mixin.uc + yq merge 叠加 UCI 覆盖(端口、routing-mark、dns 等) */
|
||||
let mixin_script = "/usr/share/clashoo/runtime/mixin.uc";
|
||||
if (access(mixin_script, "r") && system("command -v yq >/dev/null 2>&1") == 0) {
|
||||
let mixin_yaml = "/tmp/_clashoo_mixin.yaml";
|
||||
let merged_out = out_path + ".merged";
|
||||
system("ucode " + shell_quote(mixin_script) + " 2>/dev/null | yq -M -p json -o yaml > " + shell_quote(mixin_yaml) + " 2>/dev/null");
|
||||
system("yq -M eval-all '(. as $item ireduce ({}; . * $item)) as $m | [\"port\",\"socks-port\",\"redir-port\",\"tproxy-port\",\"mixed-port\",\"allow-lan\",\"bind-address\",\"mode\",\"log-level\",\"ipv6\",\"interface-name\",\"routing-mark\",\"external-controller\",\"external-ui\",\"secret\",\"tun\",\"listeners\",\"tunnels\",\"dns\",\"hosts\",\"profile\",\"geodata-mode\",\"geodata-loader\",\"geox-url\",\"proxy-providers\",\"proxies\",\"proxy-groups\",\"rule-providers\",\"rules\",\"sub-rules\",\"ntp\",\"authentication\",\"sniffer\",\"experimental\"] as $order | ($order | to_entries | map({\"key\": .value, \"value\": .key}) | from_entries) as $rank | $m | to_entries | sort_by(.key as $k | $rank[$k] // 999) | from_entries' " + shell_quote(out_path) + " " + shell_quote(mixin_yaml) + " > " + shell_quote(merged_out) + " 2>/dev/null");
|
||||
system("yq -M eval-all '(. as $item ireduce ({}; . * $item)) as $m | [\"x-clashoo\",\"port\",\"socks-port\",\"redir-port\",\"tproxy-port\",\"mixed-port\",\"allow-lan\",\"bind-address\",\"mode\",\"log-level\",\"ipv6\",\"interface-name\",\"routing-mark\",\"external-controller\",\"external-ui\",\"secret\",\"tun\",\"listeners\",\"tunnels\",\"dns\",\"hosts\",\"profile\",\"geodata-mode\",\"geodata-loader\",\"geox-url\",\"proxy-providers\",\"proxies\",\"proxy-groups\",\"rule-providers\",\"rules\",\"sub-rules\",\"ntp\",\"authentication\",\"sniffer\",\"experimental\"] as $order | ($order | to_entries | map({\"key\": .value, \"value\": .key}) | from_entries) as $rank | $m | to_entries | sort_by(.key as $k | $rank[$k] // 999) | from_entries' " + shell_quote(out_path) + " " + shell_quote(mixin_yaml) + " > " + shell_quote(merged_out) + " 2>/dev/null");
|
||||
if (access(merged_out, "r")) {
|
||||
system("mv -f " + shell_quote(merged_out) + " " + shell_quote(out_path));
|
||||
}
|
||||
system("rm -f " + shell_quote(mixin_yaml));
|
||||
}
|
||||
|
||||
|
||||
/* ── mihomo -t 预校验(搜所有 mihomo 变体)── */
|
||||
let _core_bin = '';
|
||||
for (let _cm in ['mihomo', 'clash-meta', 'clash']) {
|
||||
@@ -3488,7 +3555,6 @@ system('service ' + get_service_name() + ' restart >/dev/null 2>&1');
|
||||
return { success: true, output_name, output_path: out_path, message: '模板已应用: ' + output_name };
|
||||
}
|
||||
},
|
||||
|
||||
apply_rewrite: {
|
||||
args: {
|
||||
base_type: 'base_type',
|
||||
|
||||
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-daede
|
||||
PKG_VERSION:=1.15
|
||||
PKG_RELEASE:=46
|
||||
PKG_RELEASE:=47
|
||||
PKG_MAINTAINER:=kenzok8
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
|
||||
@@ -102,18 +102,21 @@ const CSS = [
|
||||
'.dd-adv:not(.dd-closed) .dd-adv-chevron{transform:rotate(90deg)}',
|
||||
'.dd-adv-body{margin-top:8px;padding:2px 4px 4px}',
|
||||
'.dd-adv.dd-closed .dd-adv-body{display:none}',
|
||||
'.dd-editor{width:100%;min-height:460px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;font-size:12px;line-height:1.5;box-sizing:border-box;resize:vertical;border-radius:6px 6px 0 0}',
|
||||
/* display:block kills the ~5px inline-block baseline gap that made the
|
||||
overlay pre (inset:0) ~5px taller than the textarea — the two layers'
|
||||
scrollbars and glyphs would otherwise drift apart on mobile */
|
||||
'.dd-editor{display:block;width:100%;min-height:460px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;font-size:12px;line-height:1.5;box-sizing:border-box;resize:vertical;border-radius:6px 6px 0 0}',
|
||||
/* syntax-highlight overlay: a <pre> sits behind a transparent <textarea>.
|
||||
both share identical box metrics so glyphs line up; the textarea stays the
|
||||
real editor (caret, selection, insert-at-cursor, jump-to-line all native) */
|
||||
'.dd-edit-wrap{position:relative}',
|
||||
'.dd-edit-wrap .dd-editor,.dd-edit-wrap .dd-hl{margin:0;padding:10px 12px;border-width:1px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;font-size:12px;line-height:1.5;letter-spacing:0;tab-size:4;white-space:pre;word-break:normal;overflow-x:auto;box-sizing:border-box}',
|
||||
'.dd-edit-wrap .dd-hl{position:absolute;inset:0;margin:0;overflow:hidden;border:1px solid transparent;border-radius:6px 6px 0 0;pointer-events:none;background:#f6f8fa;color:#3b4252;z-index:1}',
|
||||
'.dd-edit-wrap .dd-editor,.dd-edit-wrap .dd-hl{margin:0;padding:10px 12px;border-width:1px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;font-size:12px;line-height:1.5;letter-spacing:0;tab-size:4;white-space:pre;word-break:normal;overflow:auto;box-sizing:border-box}',
|
||||
'.dd-edit-wrap .dd-hl{position:absolute;inset:0;margin:0;border:1px solid transparent;border-radius:6px 6px 0 0;pointer-events:none;background:#f6f8fa;color:#3b4252;z-index:1}',
|
||||
/* reset Argon's code{background:var(--lighter)} so the overlay inherits the
|
||||
pre background uniformly — otherwise a dark pre shows as side bars.
|
||||
color:inherit so plain text follows .dd-hl (light in dark mode) instead of
|
||||
the theme's own code{color}, which is dark and vanishes on a dark pre */
|
||||
'.dd-edit-wrap .dd-hl code{font:inherit;white-space:inherit;word-break:inherit;display:block;color:inherit !important;background:transparent !important}',
|
||||
'.dd-edit-wrap .dd-hl code{font:inherit;white-space:inherit;word-break:inherit;display:block;color:inherit !important;background:transparent !important;padding: 0px}',
|
||||
'.dd-edit-wrap .dd-editor-hl{position:relative;z-index:2;color:transparent !important;background:transparent !important;caret-color:#2f7288;border:1px solid rgba(128,128,128,.28)}',
|
||||
'.dd-edit-wrap .dd-editor-hl::placeholder{color:rgba(128,128,128,.55)}',
|
||||
/* keep selected text transparent too — else the browser force-colors it and
|
||||
|
||||
@@ -12,7 +12,7 @@ LUCI_DEPENDS:=+luci-base +logd +jsonfilter +coreutils-timeout
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
PKG_VERSION:=0.1.47
|
||||
PKG_RELEASE:=52
|
||||
PKG_RELEASE:=53
|
||||
|
||||
# Reproducible build: honor SOURCE_DATE_EPOCH from the build environment (set by docker-sdk.sh / CI).
|
||||
ifdef SOURCE_DATE_EPOCH
|
||||
|
||||
@@ -9,7 +9,11 @@
|
||||
*
|
||||
* While paused, ingest grows up to fetchLinesMax. Live mode caps at rowLimit.
|
||||
* On resume, merge (do not replace) so pause-accumulated rows survive the first
|
||||
* live poll.
|
||||
* live poll. In live mode, an empty normalized poll preserves the current rows:
|
||||
* the buffer cannot tell inactivity from a cleared server log. The view reports
|
||||
* how long ago it last received a non-empty batch after its stale threshold.
|
||||
* A repeated non-empty window resets that receipt clock even if all events are
|
||||
* old; the hint measures received batches, not the age of the last new event.
|
||||
*/
|
||||
|
||||
function ingestCap(paused, rowLimit, fetchLinesMax) {
|
||||
|
||||
@@ -23,7 +23,7 @@ function chipFieldLabel(spec) {
|
||||
}
|
||||
|
||||
function chipValueNodes(spec, val) {
|
||||
const key = spec.key;
|
||||
const contains = log.isSubstringFilterField(spec.key);
|
||||
const label = chipFieldLabel(spec);
|
||||
const p = log.parseFilterValue(val);
|
||||
if (!p.value) return [''];
|
||||
@@ -31,7 +31,7 @@ function chipValueNodes(spec, val) {
|
||||
const valueNode = p.negate ? E('span', { 'class': 'fwlive-chip-strike' }, [p.value]) : p.value;
|
||||
|
||||
if (!p.negate) {
|
||||
if (key === 'q' || key === 'src' || key === 'dst')
|
||||
if (contains)
|
||||
return [
|
||||
E('span', { 'class': 'fwlive-chip-polarity' }, [_('contains')]),
|
||||
' ',
|
||||
@@ -44,7 +44,7 @@ function chipValueNodes(spec, val) {
|
||||
];
|
||||
}
|
||||
|
||||
if (key === 'q' || key === 'src' || key === 'dst')
|
||||
if (contains)
|
||||
return [
|
||||
label + ': ',
|
||||
E('strong', { 'class': 'fwlive-chip-not' }, [_('does not contain')]),
|
||||
|
||||
@@ -28,9 +28,19 @@ return baseclass.extend({
|
||||
POLL_CADENCE_FAST_S: 1,
|
||||
POLL_CADENCE_MID_S: 2,
|
||||
POLL_CADENCE_SLOW_S: 5,
|
||||
/* Three slow polls; keep empty-poll status quiet through adaptive cadence changes. */
|
||||
EMPTY_POLL_STALE_AFTER_MS: 15000,
|
||||
POLL_RTT_FAST_MS: 300,
|
||||
POLL_RTT_SLOW_MS: 1500,
|
||||
POLL_RTT_STREAK: 3,
|
||||
/* Rules-map retry backoff; attempts include the initial read, a reload starts fresh. */
|
||||
RULES_RETRY_BASE_MS: 5000,
|
||||
RULES_RETRY_MAX_DELAY_MS: 60000,
|
||||
RULES_RETRY_MAX_ATTEMPTS: 6,
|
||||
/* Addresses per fwlive.resolve call; must equal rpcd RESOLVE_MAX. */
|
||||
RESOLVE_BATCH_MAX: 32,
|
||||
RESOLVE_SHED_COOLDOWN_MS: 60000,
|
||||
FILTER_INPUT_DEBOUNCE_MS: 100,
|
||||
VIEW_MODES: ['simple', 'detailed'],
|
||||
COLUMN_SETS: {
|
||||
simple: ['action', 'time', 'iface', 'flow', 'proto', 'rule'],
|
||||
|
||||
@@ -11,5 +11,5 @@
|
||||
* GENERATED — do not edit. Edit fwlive.css and run: node scripts/embed-fwlive-css.js
|
||||
*/
|
||||
return baseclass.extend({
|
||||
styleText: "\n/* SPDX-License-Identifier: Apache-2.0 */\n.fwlive-map {\n\tmax-width: none;\n\twidth: 100%;\n\t--fwlive-pass-color: var(--success-color-high, var(--success-color, #46a546));\n\t--fwlive-deny-color: var(--error-color-high, var(--error-color, #ca3c3c));\n\t--fwlive-bg-medium: var(--background-color-medium, var(--white-color-low, #f9f9f9));\n\t--fwlive-paused-color: #b45309;\n}\n/* Wide page in Detail only — Simple keeps LuCI’s 940px column. */\n#maincontent.container:has(.fwlive-map[data-view=\"detailed\"]) {\n\tmax-width: none;\n\tpadding-left: 16px;\n\tpadding-right: 16px;\n}\n.fwlive-map[data-row-tint=\"accessible\"] {\n\t--fwlive-pass-color: #0d9488;\n\t--fwlive-deny-color: #c2410c;\n}\n.fwlive-map.fwlive-watch-paused .fwlive-title-row,\n.fwlive-map.fwlive-watch-paused .fwlive-watch-strip {\n\tbackground: rgba(180, 83, 9, 0.08);\n\tbackground: color-mix(in srgb, var(--fwlive-paused-color) 8%, transparent);\n}\n.fwlive-map.fwlive-watch-paused .fwlive-title-row {\n\tmargin: 0 -8px;\n\tpadding: 6px 8px 0;\n\tborder-radius: 3px 3px 0 0;\n}\n.fwlive-map.fwlive-watch-paused .fwlive-watch-strip {\n\tmargin: 0 -8px 10px;\n\tpadding: 8px;\n\tborder-radius: 0 0 3px 3px;\n\tborder-bottom-color: transparent;\n}\n.fwlive-title-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tjustify-content: space-between;\n\tgap: 8px 16px;\n\tmargin: 0 0 4px;\n}\n.fwlive-title-row h2 {\n\tmargin: 0;\n\tflex: 0 1 auto;\n}\n.fwlive-title-status {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n\tmargin-left: auto;\n}\n.fwlive-watch-strip {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: stretch;\n\tjustify-content: flex-start;\n\tgap: 0;\n\tmin-height: 40px;\n\tpadding: 8px 0 10px;\n\tborder-bottom: 1px solid var(--border-color-medium);\n\tmargin-bottom: 10px;\n}\n.fwlive-watch-group {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tmin-height: 28px;\n\tpadding: 0 10px;\n\tborder-left: 1px solid var(--border-color-medium);\n\tflex-wrap: wrap;\n}\n.fwlive-watch-group:last-child {\n\tpadding-right: 0;\n}\n.fwlive-watch-group-label {\n\tmargin-right: 2px;\n\tcolor: var(--text-color-medium);\n\tfont-size: 0.72em;\n\tfont-weight: 700;\n\tletter-spacing: 0.08em;\n\ttext-transform: uppercase;\n\twhite-space: nowrap;\n}\n.fwlive-watch-seg {\n\tdisplay: inline-flex;\n\talign-items: stretch;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\toverflow: hidden;\n}\n.fwlive-watch-seg .fwlive-seg-btn {\n\tmargin: 0;\n\tborder: 0;\n\tborder-radius: 0;\n\tborder-right: 1px solid var(--border-color-medium);\n\tbackground: transparent;\n\tpadding: 4px 10px;\n\tfont-size: 0.88em;\n\tline-height: 1.25;\n\tmin-height: 28px;\n}\n.fwlive-watch-seg .fwlive-seg-btn:last-child {\n\tborder-right: 0;\n}\n.fwlive-watch-seg .fwlive-seg-btn[aria-pressed=\"true\"] {\n\tbackground: rgba(26, 111, 156, 0.12);\n\tbackground: color-mix(in srgb, var(--primary-color-high) 12%, transparent);\n\tcolor: var(--primary-color-high);\n\tfont-weight: 600;\n}\n.fwlive-watch-label { font-weight: 600; }\n.fwlive-watch-paused .fwlive-watch-label { color: var(--fwlive-paused-color); }\n.fwlive-map.fwlive-watch-paused .fwlive-title-status .fwlive-watch-label { color: var(--fwlive-paused-color); }\n.fwlive-dot {\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 50%;\n\tbackground: var(--text-color-low, var(--border-color-high));\n\tdisplay: inline-block;\n\tflex-shrink: 0;\n}\n.fwlive-dot.fwlive-dot-on {\n\tbackground: var(--fwlive-pass-color);\n\tbox-shadow: 0 0 0 3px color-mix(in srgb, var(--fwlive-pass-color) 22%, transparent);\n}\n.fwlive-btn-ghost {\n\tbackground: transparent;\n\tborder-color: var(--border-color-medium);\n}\n.fwlive-btn-quiet {\n\tbackground: transparent;\n\tborder-color: var(--border-color-medium);\n\tcolor: var(--text-color-medium);\n\tfont-weight: 500;\n}\n.fwlive-log-merged {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 10px;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\tbackground: var(--background-color-medium, var(--white-color-low, var(--background-color-high)));\n\tcolor: var(--text-color-high);\n\tfont-weight: 500;\n\tfont-size: 0.88em;\n\tline-height: 1.25;\n\tmin-height: 28px;\n\tcursor: pointer;\n}\n.fwlive-log-merged:hover {\n\tbackground: var(--background-color-low, var(--background-color-medium));\n}\n.fwlive-log-merged:disabled {\n\topacity: 0.65;\n\tcursor: default;\n}\n.fwlive-log-on-dot {\n\twidth: 6px;\n\theight: 6px;\n\tborder-radius: 50%;\n\tbackground: var(--fwlive-pass-color);\n\tflex-shrink: 0;\n}\n.fwlive-log-rate {\n\tcolor: var(--text-color-medium);\n\tfont-weight: 400;\n}\n.fwlive-display-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px 14px;\n\tmargin: 0 0 12px;\n\tpadding: 8px 12px;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\tbackground: var(--background-color-high);\n}\n.fwlive-dLine truncated
|
||||
styleText: "\n/* SPDX-License-Identifier: Apache-2.0 */\n.fwlive-map {\n\tmax-width: none;\n\twidth: 100%;\n\t--fwlive-pass-color: var(--success-color-high, var(--success-color, #46a546));\n\t--fwlive-deny-color: var(--error-color-high, var(--error-color, #ca3c3c));\n\t--fwlive-bg-medium: var(--background-color-medium, var(--white-color-low, #f9f9f9));\n\t--fwlive-paused-color: #b45309;\n}\n/* Wide page in Detail only — Simple keeps LuCI’s 940px column. */\n#maincontent.container:has(.fwlive-map[data-view=\"detailed\"]) {\n\tmax-width: none;\n\tpadding-left: 16px;\n\tpadding-right: 16px;\n}\n.fwlive-map[data-row-tint=\"accessible\"] {\n\t--fwlive-pass-color: #0d9488;\n\t--fwlive-deny-color: #c2410c;\n}\n.fwlive-map.fwlive-watch-paused .fwlive-title-row,\n.fwlive-map.fwlive-watch-paused .fwlive-watch-strip {\n\tbackground: rgba(180, 83, 9, 0.08);\n\tbackground: color-mix(in srgb, var(--fwlive-paused-color) 8%, transparent);\n}\n.fwlive-map.fwlive-watch-paused .fwlive-title-row {\n\tmargin: 0 -8px;\n\tpadding: 6px 8px 0;\n\tborder-radius: 3px 3px 0 0;\n}\n.fwlive-map.fwlive-watch-paused .fwlive-watch-strip {\n\tmargin: 0 -8px 10px;\n\tpadding: 8px;\n\tborder-radius: 0 0 3px 3px;\n\tborder-bottom-color: transparent;\n}\n.fwlive-title-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tjustify-content: space-between;\n\tgap: 8px 16px;\n\tmargin: 0 0 4px;\n}\n.fwlive-title-row h2 {\n\tmargin: 0;\n\tflex: 0 1 auto;\n}\n.fwlive-title-status {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n\tmargin-left: auto;\n}\n.fwlive-watch-strip {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: stretch;\n\tjustify-content: flex-start;\n\tgap: 0;\n\tmin-height: 40px;\n\tpadding: 8px 0 10px;\n\tborder-bottom: 1px solid var(--border-color-medium);\n\tmargin-bottom: 10px;\n}\n.fwlive-watch-group {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tmin-height: 28px;\n\tpadding: 0 10px;\n\tborder-left: 1px solid var(--border-color-medium);\n\tflex-wrap: wrap;\n}\n.fwlive-watch-group:last-child {\n\tpadding-right: 0;\n}\n.fwlive-watch-group-label {\n\tmargin-right: 2px;\n\tcolor: var(--text-color-medium);\n\tfont-size: 0.72em;\n\tfont-weight: 700;\n\tletter-spacing: 0.08em;\n\ttext-transform: uppercase;\n\twhite-space: nowrap;\n}\n.fwlive-watch-seg {\n\tdisplay: inline-flex;\n\talign-items: stretch;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\toverflow: hidden;\n}\n.fwlive-watch-seg .fwlive-seg-btn {\n\tmargin: 0;\n\tborder: 0;\n\tborder-radius: 0;\n\tborder-right: 1px solid var(--border-color-medium);\n\tbackground: transparent;\n\tpadding: 4px 10px;\n\tfont-size: 0.88em;\n\tline-height: 1.25;\n\tmin-height: 28px;\n}\n.fwlive-watch-seg .fwlive-seg-btn:last-child {\n\tborder-right: 0;\n}\n.fwlive-watch-seg .fwlive-seg-btn[aria-pressed=\"true\"] {\n\tbackground: rgba(26, 111, 156, 0.12);\n\tbackground: color-mix(in srgb, var(--primary-color-high) 12%, transparent);\n\tcolor: var(--primary-color-high);\n\tfont-weight: 600;\n}\n.fwlive-watch-label { font-weight: 600; }\n.fwlive-watch-paused .fwlive-watch-label { color: var(--fwlive-paused-color); }\n.fwlive-map.fwlive-watch-paused .fwlive-title-status .fwlive-watch-label { color: var(--fwlive-paused-color); }\n.fwlive-dot {\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 50%;\n\tbackground: var(--text-color-low, var(--border-color-high));\n\tdisplay: inline-block;\n\tflex-shrink: 0;\n}\n.fwlive-dot.fwlive-dot-on {\n\tbackground: var(--fwlive-pass-color);\n\tbox-shadow: 0 0 0 3px color-mix(in srgb, var(--fwlive-pass-color) 22%, transparent);\n}\n.fwlive-btn-ghost {\n\tbackground: transparent;\n\tborder-color: var(--border-color-medium);\n}\n.fwlive-btn-quiet {\n\tbackground: transparent;\n\tborder-color: var(--border-color-medium);\n\tcolor: var(--text-color-medium);\n\tfont-weight: 500;\n}\n.fwlive-log-merged {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 10px;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\tbackground: var(--background-color-medium, var(--white-color-low, var(--background-color-high)));\n\tcolor: var(--text-color-high);\n\tfont-weight: 500;\n\tfont-size: 0.88em;\n\tline-height: 1.25;\n\tmin-height: 28px;\n\tcursor: pointer;\n}\n.fwlive-log-merged:hover {\n\tbackground: var(--background-color-low, var(--background-color-medium));\n}\n.fwlive-log-merged:disabled {\n\topacity: 0.65;\n\tcursor: default;\n}\n.fwlive-log-on-dot {\n\twidth: 6px;\n\theight: 6px;\n\tborder-radius: 50%;\n\tbackground: var(--fwlive-pass-color);\n\tflex-shrink: 0;\n}\n.fwlive-log-rate {\n\tcolor: var(--text-color-medium);\n\tfont-weight: 400;\n}\n.fwlive-display-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px 14px;\n\tmargin: 0 0 12px;\n\tpadding: 8px 12px;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\tbackground: var(--background-color-high);\n}\n.fwlive-dLine truncated
|
||||
});
|
||||
@@ -216,19 +216,23 @@
|
||||
}
|
||||
/* Draw our own disclosure arrow — themes that restyle summary drop the native marker. */
|
||||
.fwlive-more-filters > summary,
|
||||
.fwlive-help > summary {
|
||||
.fwlive-help > summary,
|
||||
.fwlive-rules-details > summary {
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
}
|
||||
.fwlive-more-filters > summary::-webkit-details-marker,
|
||||
.fwlive-help > summary::-webkit-details-marker { display: none; }
|
||||
.fwlive-help > summary::-webkit-details-marker,
|
||||
.fwlive-rules-details > summary::-webkit-details-marker { display: none; }
|
||||
.fwlive-more-filters > summary::before,
|
||||
.fwlive-help > summary::before {
|
||||
.fwlive-help > summary::before,
|
||||
.fwlive-rules-details > summary::before {
|
||||
content: "▸ ";
|
||||
color: var(--text-color-medium);
|
||||
}
|
||||
.fwlive-more-filters[open] > summary::before,
|
||||
.fwlive-help[open] > summary::before { content: "▾ "; }
|
||||
.fwlive-help[open] > summary::before,
|
||||
.fwlive-rules-details[open] > summary::before { content: "▾ "; }
|
||||
.fwlive-ctl {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -754,6 +758,15 @@
|
||||
color: var(--warn-color-high);
|
||||
font-weight: 600;
|
||||
}
|
||||
.fwlive-rules-details {
|
||||
margin: 4px 0 8px;
|
||||
color: var(--text-color-high);
|
||||
}
|
||||
#fwlive-rules-details-body {
|
||||
margin: 6px 0;
|
||||
white-space: pre-line;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.fwlive-filter-panel { margin-bottom: 12px; }
|
||||
.fwlive-map[data-view="simple"] .fwlive-grid-core {
|
||||
display: grid;
|
||||
|
||||
@@ -32,6 +32,20 @@ return baseclass.extend({
|
||||
return value;
|
||||
},
|
||||
|
||||
/* Scoped IPv6 (`fe80::1%eth0`) resolves and caches under the bare address. */
|
||||
stripZone: function (addr) {
|
||||
if (typeof addr !== 'string') return addr;
|
||||
const zone = addr.lastIndexOf('%');
|
||||
return zone === -1 ? addr : addr.slice(0, zone);
|
||||
},
|
||||
|
||||
/* Display reads refresh recency so visible names stay warm in the LRU. */
|
||||
cachedName: function (map, addr) {
|
||||
if (!map || !addr) return null;
|
||||
const value = this.lruGet(map, this.stripZone(addr));
|
||||
return value == null ? null : String(value);
|
||||
},
|
||||
|
||||
failIsHot: function (failedMap, ip, nowMs, ttlMs) {
|
||||
if (!failedMap || !failedMap.has(ip)) return false;
|
||||
const at = failedMap.get(ip);
|
||||
|
||||
@@ -79,19 +79,7 @@ function filterLink(field, value, label, onFilterClick) {
|
||||
function addrFilterLink(field, ip, showHostnames, hostnameCache, onFilterClick) {
|
||||
if (!ip) return log.formatCell(ip);
|
||||
|
||||
let name = null;
|
||||
if (showHostnames && hostnameCache) {
|
||||
/* Resolve stores the bare address; scoped rows still look up that key. */
|
||||
const cacheKey =
|
||||
typeof ip === 'string' && ip.lastIndexOf('%') !== -1
|
||||
? ip.slice(0, ip.lastIndexOf('%'))
|
||||
: ip;
|
||||
/* Display reads refresh recency so visible names remain warm in the LRU. */
|
||||
name =
|
||||
hostname && typeof hostname.lruGet === 'function'
|
||||
? hostname.lruGet(hostnameCache, cacheKey)
|
||||
: hostnameCache.get(cacheKey);
|
||||
}
|
||||
const name = showHostnames ? hostname.cachedName(hostnameCache, ip) : null;
|
||||
const display = name || ip;
|
||||
const title = name ? ip : _('Filter by %s').format(log.filterFieldLabel(field));
|
||||
|
||||
|
||||
@@ -593,6 +593,11 @@ return baseclass.extend({
|
||||
return p.negate ? !hit : hit;
|
||||
},
|
||||
|
||||
/* Fields matchesFilter compares by substring ("contains"); the rest match exactly. */
|
||||
isSubstringFilterField: function (key) {
|
||||
return key === 'q' || key === 'src' || key === 'dst';
|
||||
},
|
||||
|
||||
matchesFilter: function (row, filters) {
|
||||
if (filters.q && !this.matchesQueryField(row, filters.q)) return false;
|
||||
if (filters.action && !this.matchesActionField(row, filters.action)) return false;
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
* state - loggingState + { showConsent }
|
||||
* callbacks - { onEnable(), onDismissConsent(persist) }
|
||||
*
|
||||
* toggleFailureNotice(code, fallback) → string
|
||||
* rpcd enable/disable error code → notice; unknown codes return fallback.
|
||||
*
|
||||
* Modules must not mutate state. host is cleared then rebuilt (idempotent replace).
|
||||
*/
|
||||
|
||||
@@ -46,18 +49,51 @@ function persistConsentDismissed() {
|
||||
}
|
||||
}
|
||||
|
||||
/* Shared by enable and disable; codes a toggle cannot emit fall through. */
|
||||
function toggleFailureNotice(code, fallback) {
|
||||
switch (code) {
|
||||
case 'nf_log_missing':
|
||||
return _('Cannot enable logging until kernel log modules are installed.');
|
||||
case 'firewall_changes_pending':
|
||||
return _('Another change is staged for the firewall; apply or revert it first.');
|
||||
case 'no_wan_zone':
|
||||
return _('No WAN zone found; cannot toggle logging without one.');
|
||||
case 'lock_failed':
|
||||
return _('Could not acquire the logging lock.');
|
||||
case 'rollback_tracking_failed':
|
||||
return _('Could not track the logging change safely; logging was not changed.');
|
||||
case 'baseline_snapshot_failed':
|
||||
return _('Could not snapshot the current logging state.');
|
||||
case 'firewall_reload_failed':
|
||||
return _('The firewall did not reload; saved and live logging may differ.');
|
||||
case 'uci_set_failed':
|
||||
return _('Could not write the WAN zone log option.');
|
||||
case 'uci_delete_failed':
|
||||
return _('Could not clear the WAN zone log option.');
|
||||
case 'uci_commit_failed':
|
||||
return _('Could not save the firewall configuration.');
|
||||
case 'firewall_commit_raced':
|
||||
return _(
|
||||
'Another change overwrote WAN logging after it was saved; check the current state.'
|
||||
);
|
||||
default:
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
function enableLoggingButton(state, callbacks) {
|
||||
return E(
|
||||
'button',
|
||||
{
|
||||
'class': 'cbi-button cbi-button-action',
|
||||
'type': 'button',
|
||||
'title': _('Enable WAN zone drop/reject logging (same as Network → Firewall).'),
|
||||
'disabled': state.loggingBusy ? '' : null,
|
||||
'click': function () {
|
||||
callbacks.onEnable();
|
||||
}
|
||||
},
|
||||
[state.loggingBusy ? _('Enabling…') : _('Enable WAN drop/reject logging')]
|
||||
[state.loggingBusy ? _('Enabling…') : _('Enable logging')]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -180,21 +216,7 @@ function renderToolbar(host, state, callbacks) {
|
||||
return;
|
||||
}
|
||||
|
||||
host.appendChild(
|
||||
E(
|
||||
'button',
|
||||
{
|
||||
'class': 'cbi-button cbi-button-action',
|
||||
'type': 'button',
|
||||
'title': _('Enable WAN zone drop/reject logging (same as Network → Firewall).'),
|
||||
'disabled': state.loggingBusy ? '' : null,
|
||||
'click': function () {
|
||||
callbacks.onEnable();
|
||||
}
|
||||
},
|
||||
[state.loggingBusy ? _('Enabling…') : _('Enable logging')]
|
||||
)
|
||||
);
|
||||
host.appendChild(enableLoggingButton(state, callbacks));
|
||||
appendLoggingNotice(host, state);
|
||||
}
|
||||
|
||||
@@ -359,7 +381,9 @@ function buildEmptyStateNodes(state, callbacks) {
|
||||
])
|
||||
);
|
||||
nodes.push(
|
||||
E('p', { 'class': 'fwlive-empty-muted' }, [_('Nothing changes until you click Enable.')])
|
||||
E('p', { 'class': 'fwlive-empty-muted' }, [
|
||||
_('Nothing changes until you click Enable logging.')
|
||||
])
|
||||
);
|
||||
nodes.push(
|
||||
E('p', {}, [
|
||||
@@ -399,6 +423,7 @@ return baseclass.extend({
|
||||
CONSENT_STORAGE_KEY: CONSENT_STORAGE_KEY,
|
||||
consentDismissedPermanent: consentDismissedPermanent,
|
||||
persistConsentDismissed: persistConsentDismissed,
|
||||
toggleFailureNotice: toggleFailureNotice,
|
||||
renderToolbar: renderToolbar,
|
||||
buildEmptyStateNodes: buildEmptyStateNodes,
|
||||
renderEmptyState: renderEmptyState,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
'require baseclass';
|
||||
'require fwlive.log as log';
|
||||
'require fwlive.links as links';
|
||||
'require fwlive.hostname as hostname';
|
||||
|
||||
/**
|
||||
* Table thead/rows DOM renderer for luci-app-fwlive.
|
||||
@@ -271,13 +272,8 @@ function renderThead(host, state, _callbacks) {
|
||||
}
|
||||
|
||||
function hostnameCacheValue(ip, state) {
|
||||
if (!state.showHostnames || !state.hostnameCache || !ip) return '';
|
||||
const key =
|
||||
typeof ip === 'string' && ip.lastIndexOf('%') !== -1
|
||||
? ip.slice(0, ip.lastIndexOf('%'))
|
||||
: ip;
|
||||
const value = state.hostnameCache.get ? state.hostnameCache.get(key) : undefined;
|
||||
return value == null ? '' : String(value);
|
||||
if (!state.showHostnames) return '';
|
||||
return hostname.cachedName(state.hostnameCache, ip) || '';
|
||||
}
|
||||
|
||||
function rowRenderKey(row, state, columns) {
|
||||
@@ -363,21 +359,11 @@ function renderAllRows(host, rows, state, columns, callbacks) {
|
||||
}
|
||||
}
|
||||
|
||||
function canReuseRows(host) {
|
||||
return (
|
||||
host &&
|
||||
host.childNodes &&
|
||||
typeof host.childNodes.length === 'number' &&
|
||||
typeof host.insertBefore === 'function' &&
|
||||
typeof host.removeChild === 'function'
|
||||
);
|
||||
}
|
||||
|
||||
function renderRows(host, state, callbacks) {
|
||||
const rows = state.rows || [];
|
||||
const columns = state.columns || [];
|
||||
|
||||
if (state.forceRender || !canReuseRows(host)) {
|
||||
if (state.forceRender) {
|
||||
renderAllRows(host, rows, state, columns, callbacks);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -23,9 +23,8 @@
|
||||
'require fwlive.render-policy as renderPolicy';
|
||||
'require fwlive.render-scheduler as renderScheduler';
|
||||
|
||||
const RULES_RETRY_BASE_MS = 5000;
|
||||
/* Includes the initial read; a page reload starts a fresh retry budget. */
|
||||
const RULES_RETRY_MAX_ATTEMPTS = 6;
|
||||
/* Poll error codes that only a reinstall fixes; retrying cannot help. */
|
||||
const INSTALL_POLL_ERRORS = ['timeout_missing', 'jsonfilter_missing', 'classifier_missing'];
|
||||
|
||||
const callFwlivePoll = rpc.declare({
|
||||
object: 'fwlive',
|
||||
@@ -112,12 +111,6 @@ function isIpv4Address(addr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Scoped IPv6 (`fe80::1%eth0`) still resolves as the bare address. */
|
||||
function stripIpZone(addr) {
|
||||
const zone = addr.lastIndexOf('%');
|
||||
return zone === -1 ? addr : addr.slice(0, zone);
|
||||
}
|
||||
|
||||
return view.extend({
|
||||
rowLimit: constants.DEFAULT_ROW_LIMIT,
|
||||
fetchMode: constants.DEFAULT_FETCH_MODE,
|
||||
@@ -159,6 +152,9 @@ return view.extend({
|
||||
messageLayout: 'wrap',
|
||||
/* Session-new IDs from the last applied batch; this is not buffer growth. */
|
||||
lastBatchNewIdCount: 0,
|
||||
/* Monotonic time for age hints after successful empty poll batches. */
|
||||
lastNonEmptyBatchAt: null,
|
||||
lastSuccessfulBatchEmpty: false,
|
||||
showHostnames: false,
|
||||
rowTint: constants.DEFAULT_ROW_TINT,
|
||||
/* Last non-off palette so toggling tint back on restores Classic/Accessible. */
|
||||
@@ -172,6 +168,8 @@ return view.extend({
|
||||
lastPollError: false,
|
||||
lastPollErrorCode: null,
|
||||
lastRulesError: null,
|
||||
rulesMapTruncated: false,
|
||||
rulesMapLoaded: false,
|
||||
rulesRetryAttempt: 0,
|
||||
nextRulesRetryAt: 0,
|
||||
followLive: true,
|
||||
@@ -599,7 +597,7 @@ return view.extend({
|
||||
|
||||
isLikelyIp(addr) {
|
||||
if (typeof addr !== 'string' || !addr) return false;
|
||||
addr = stripIpZone(addr);
|
||||
addr = hostname.stripZone(addr);
|
||||
if (!addr) return false;
|
||||
if (isIpv4Address(addr)) return true;
|
||||
if (!addr.includes(':') || !/^[\da-f:.]+$/i.test(addr) || addr.includes(':::'))
|
||||
@@ -708,17 +706,16 @@ return view.extend({
|
||||
const res = await callFwliveRules();
|
||||
if (!this.isCurrentPollEpoch(epoch)) return;
|
||||
this.rulesMap = (res && res.rules) || {};
|
||||
this.rulesMapTruncated = !!(res && res.truncated === true);
|
||||
this.rulesMapLoaded = true;
|
||||
this.firewallBackend = (res && res.backend) || 'nft';
|
||||
/* Bounds / mktemp failures are reply.error — same idea as poll. */
|
||||
/* Truncation belongs to this map; error describes its lookup failure. */
|
||||
this.noteRulesMapOutcome((res && res.error) || null);
|
||||
if (this.lastRulesError) console.warn('fwlive rules map error:', this.lastRulesError);
|
||||
this.refreshBufferedRuleLabels();
|
||||
} catch (_e) {
|
||||
if (!this.isCurrentPollEpoch(epoch)) return;
|
||||
if (!(this.rulesMap && Object.keys(this.rulesMap).length)) {
|
||||
this.rulesMap = {};
|
||||
this.firewallBackend = 'nft';
|
||||
}
|
||||
/* Retain the entire last snapshot, including an empty truncated map. */
|
||||
this.noteRulesMapOutcome('rules_unavailable');
|
||||
}
|
||||
this.updateBackendUi();
|
||||
@@ -735,15 +732,15 @@ return view.extend({
|
||||
/* Back off consecutive failures, then stop after a bounded retry budget. */
|
||||
this.rulesRetryAttempt = Math.min(
|
||||
(this.rulesRetryAttempt || 0) + 1,
|
||||
RULES_RETRY_MAX_ATTEMPTS
|
||||
constants.RULES_RETRY_MAX_ATTEMPTS
|
||||
);
|
||||
if (this.rulesRetryAttempt >= RULES_RETRY_MAX_ATTEMPTS) {
|
||||
if (this.rulesRetryAttempt >= constants.RULES_RETRY_MAX_ATTEMPTS) {
|
||||
this.nextRulesRetryAt = 0;
|
||||
return;
|
||||
}
|
||||
const delay = Math.min(
|
||||
RULES_RETRY_BASE_MS * Math.pow(2, this.rulesRetryAttempt - 1),
|
||||
60000
|
||||
constants.RULES_RETRY_BASE_MS * Math.pow(2, this.rulesRetryAttempt - 1),
|
||||
constants.RULES_RETRY_MAX_DELAY_MS
|
||||
);
|
||||
this.nextRulesRetryAt = this.nowMs() + delay;
|
||||
},
|
||||
@@ -753,6 +750,56 @@ return view.extend({
|
||||
return '';
|
||||
},
|
||||
|
||||
rulesDiagnosticCause(error) {
|
||||
switch (error) {
|
||||
case 'mktemp_failed':
|
||||
return _('Could not create a temporary file for rule names.');
|
||||
case 'tsv_failed':
|
||||
return _('Could not process firewall rule names.');
|
||||
case 'no_backend':
|
||||
return _('Could not read the active firewall rules.');
|
||||
case 'timeout_missing':
|
||||
return _('The required timeout utility is unavailable.');
|
||||
case 'rules_unavailable':
|
||||
if (!this.rulesMapLoaded) return _('Could not load rule names.');
|
||||
if (this.rulesMap && Object.keys(this.rulesMap).length)
|
||||
return _(
|
||||
'Could not refresh rule names; previously loaded names are still shown.'
|
||||
);
|
||||
return _('Could not refresh rule names.');
|
||||
default:
|
||||
return _('Rule-name lookup failed.');
|
||||
}
|
||||
},
|
||||
|
||||
rulesDiagnosticLines() {
|
||||
const lines = [];
|
||||
if (this.rulesMapTruncated)
|
||||
lines.push(_('Rule-name lookup reached a safety limit.') + ' (truncated=true)');
|
||||
if (this.lastRulesError) {
|
||||
const cause = this.rulesDiagnosticCause(this.lastRulesError);
|
||||
/* Unknown RPC codes are bounded diagnostic text, never HTML. */
|
||||
const code =
|
||||
typeof this.lastRulesError === 'string' ? this.lastRulesError.slice(0, 80) : '';
|
||||
lines.push(cause + (code ? ' (' + code + ')' : ''));
|
||||
}
|
||||
lines.push(_('Rule-name lookup does not change your firewall rules.'));
|
||||
lines.push(
|
||||
_(
|
||||
'Some entries may show names derived from their log prefixes. Searching by a friendly rule name may miss those entries.'
|
||||
)
|
||||
);
|
||||
return lines;
|
||||
},
|
||||
|
||||
/* timeout_missing is an install problem shown elsewhere, not a rules-map gap. */
|
||||
rulesMapDegraded() {
|
||||
return !!(
|
||||
this.rulesMapTruncated ||
|
||||
(this.lastRulesError && this.lastRulesError !== 'timeout_missing')
|
||||
);
|
||||
},
|
||||
|
||||
updateBackendUi() {
|
||||
const map = document.querySelector('.fwlive-map');
|
||||
if (map) map.setAttribute('data-backend', this.firewallBackend || 'unknown');
|
||||
@@ -762,13 +809,8 @@ return view.extend({
|
||||
const warnings = (this.loggingStatus && this.loggingStatus.warnings) || [];
|
||||
let text = this.backendDisplayLabel();
|
||||
let degraded = false;
|
||||
if (this.lastRulesError && this.lastRulesError !== 'timeout_missing') {
|
||||
let err = '';
|
||||
if (this.lastRulesError === 'rules_truncated')
|
||||
err = _('Rule labels incomplete — map truncated');
|
||||
else if (this.lastRulesError === 'mktemp_failed')
|
||||
err = _('Rule labels unavailable — temp file failed');
|
||||
else err = _('Rule labels unavailable');
|
||||
if (this.rulesMapDegraded()) {
|
||||
const err = _('Some rule names may be missing');
|
||||
text = text ? text + ' \u00b7 ' + err : err;
|
||||
degraded = true;
|
||||
}
|
||||
@@ -782,6 +824,14 @@ return view.extend({
|
||||
label.textContent = text;
|
||||
label.classList.toggle('fwlive-backend-warn', degraded);
|
||||
}
|
||||
const details = document.getElementById('fwlive-rules-details');
|
||||
const body = document.getElementById('fwlive-rules-details-body');
|
||||
if (details && body) {
|
||||
const degraded = this.rulesMapDegraded();
|
||||
details.style.display = degraded ? '' : 'none';
|
||||
body.textContent = degraded ? this.rulesDiagnosticLines().join('\n\n') : '';
|
||||
if (!degraded) details.open = false;
|
||||
}
|
||||
|
||||
this.updateEmptyStateUi();
|
||||
},
|
||||
@@ -820,6 +870,7 @@ return view.extend({
|
||||
this.updateLoggingToolbarUi();
|
||||
this.updateEmptyStateUi();
|
||||
this.updateStatus();
|
||||
if (wasWeakDevice !== this.weakDevice) this.updateAdaptiveBanner();
|
||||
if (wasWeakDevice !== this.weakDevice && document.getElementById('fwlive-table'))
|
||||
this.renderRows(true);
|
||||
},
|
||||
@@ -876,35 +927,8 @@ return view.extend({
|
||||
this.updateEmptyStateUi();
|
||||
this.updateLoggingToolbarUi();
|
||||
},
|
||||
failureNotice: (res) => {
|
||||
if (res && res.error === 'nf_log_missing')
|
||||
return _('Cannot enable logging until kernel log modules are installed.');
|
||||
if (res && res.error === 'firewall_changes_pending')
|
||||
return _(
|
||||
'Another change is staged for the firewall; apply or revert it first.'
|
||||
);
|
||||
if (res && res.error === 'no_wan_zone')
|
||||
return _('No WAN zone found; cannot toggle logging without one.');
|
||||
if (res && res.error === 'lock_failed')
|
||||
return _('Could not acquire the logging lock.');
|
||||
if (res && res.error === 'rollback_tracking_failed')
|
||||
return _('Could not track the logging change safely; logging was not changed.');
|
||||
if (res && res.error === 'baseline_snapshot_failed')
|
||||
return _('Could not snapshot the current logging state.');
|
||||
if (res && res.error === 'firewall_reload_failed')
|
||||
return _('The firewall did not reload; saved and live logging may differ.');
|
||||
if (res && res.error === 'uci_set_failed')
|
||||
return _('Could not write the WAN zone log option.');
|
||||
if (res && res.error === 'uci_delete_failed')
|
||||
return _('Could not clear the WAN zone log option.');
|
||||
if (res && res.error === 'uci_commit_failed')
|
||||
return _('Could not save the firewall configuration.');
|
||||
if (res && res.error === 'firewall_commit_raced')
|
||||
return _(
|
||||
'Another change overwrote WAN logging after it was saved; check the current state.'
|
||||
);
|
||||
return _('Could not enable logging.');
|
||||
},
|
||||
failureNotice: (res) =>
|
||||
logging.toggleFailureNotice(res && res.error, _('Could not enable logging.')),
|
||||
successNotice: (res) =>
|
||||
res.changed
|
||||
? _(
|
||||
@@ -921,31 +945,8 @@ return view.extend({
|
||||
wanLog: false,
|
||||
call: () => callFwliveDisableLogging(),
|
||||
initialUi: () => this.updateLoggingToolbarUi(),
|
||||
failureNotice: (res) => {
|
||||
if (res && res.error === 'firewall_changes_pending')
|
||||
return _(
|
||||
'Another change is staged for the firewall; apply or revert it first.'
|
||||
);
|
||||
if (res && res.error === 'no_wan_zone')
|
||||
return _('No WAN zone found; cannot toggle logging without one.');
|
||||
if (res && res.error === 'lock_failed')
|
||||
return _('Could not acquire the logging lock.');
|
||||
if (res && res.error === 'rollback_tracking_failed')
|
||||
return _('Could not track the logging change safely; logging was not changed.');
|
||||
if (res && res.error === 'firewall_reload_failed')
|
||||
return _('The firewall did not reload; saved and live logging may differ.');
|
||||
if (res && res.error === 'uci_set_failed')
|
||||
return _('Could not write the WAN zone log option.');
|
||||
if (res && res.error === 'uci_delete_failed')
|
||||
return _('Could not clear the WAN zone log option.');
|
||||
if (res && res.error === 'uci_commit_failed')
|
||||
return _('Could not save the firewall configuration.');
|
||||
if (res && res.error === 'firewall_commit_raced')
|
||||
return _(
|
||||
'Another change overwrote WAN logging after it was saved; check the current state.'
|
||||
);
|
||||
return _('Could not disable logging.');
|
||||
},
|
||||
failureNotice: (res) =>
|
||||
logging.toggleFailureNotice(res && res.error, _('Could not disable logging.')),
|
||||
successNotice: (res) => (res.changed ? _('WAN drop/reject logging is off.') : ''),
|
||||
catchNotice: () => _('Administrator access is required to disable logging.')
|
||||
});
|
||||
@@ -1174,6 +1175,8 @@ return view.extend({
|
||||
|
||||
const batch = this.normalizePollBatch(raw);
|
||||
this.lastBatchNewIdCount = batch.pollNew;
|
||||
this.lastSuccessfulBatchEmpty = batch.rows.length === 0;
|
||||
if (batch.rows.length) this.lastNonEmptyBatchAt = this.nowMs();
|
||||
|
||||
/* Oldest-first ring buffer; filteredRows() reverses for newest-first display. */
|
||||
this.entries = buffer.applyFetchedEntries(this.entries, batch.rows, {
|
||||
@@ -1224,7 +1227,7 @@ return view.extend({
|
||||
}
|
||||
} else if (
|
||||
this.lastRulesError === 'rules_unavailable' &&
|
||||
this.rulesRetryAttempt < RULES_RETRY_MAX_ATTEMPTS &&
|
||||
this.rulesRetryAttempt < constants.RULES_RETRY_MAX_ATTEMPTS &&
|
||||
!this.tablePaused &&
|
||||
!this.lastPollError &&
|
||||
this.nowMs() >= (this.nextRulesRetryAt || 0)
|
||||
@@ -1269,16 +1272,14 @@ return view.extend({
|
||||
const cap = this.ingestCap();
|
||||
if (this.entries.length >= cap && cap > 0) bits.push(_('buffer full'));
|
||||
if (this.ensureRenderScheduler().isFloodSuppressed())
|
||||
bits.push(_('render paused (high rate)'));
|
||||
bits.push(_('table refresh throttled'));
|
||||
if (this.weakDevice && this.rowLimit > constants.WEAK_DEVICE_DISPLAY_ROW_CAP)
|
||||
bits.push(
|
||||
_('Display limited to %d rows on this device').format(
|
||||
constants.WEAK_DEVICE_DISPLAY_ROW_CAP
|
||||
)
|
||||
_('display limited to %d rows').format(constants.WEAK_DEVICE_DISPLAY_ROW_CAP)
|
||||
);
|
||||
if (this.degradedSampling) bits.push(_('Degraded — sampling'));
|
||||
if (this.serverTruncated) bits.push(_('truncated'));
|
||||
if (this.resolveLoadShed) bits.push(_('resolve paused (load)'));
|
||||
if (this.degradedSampling) bits.push(_('polling slowed'));
|
||||
if (this.serverTruncated) bits.push(_('server limited fetch'));
|
||||
if (this.resolveLoadShed) bits.push(_('hostname lookup paused'));
|
||||
if (!this.tablePaused && !this.followLive)
|
||||
bits.push(_('scroll frozen — scroll to top to follow live'));
|
||||
return bits.length ? ' — ' + bits.join(', ') : '';
|
||||
@@ -1445,21 +1446,33 @@ return view.extend({
|
||||
else if (this.serverAdaptive === 0)
|
||||
parts.push(_('Server adaptive protection is disabled.'));
|
||||
if (this.degradedSampling)
|
||||
parts.push(_('Degraded — sampling (slow poll RTT; cadence reduced).'));
|
||||
parts.push(
|
||||
_('Polling slowed: the router is responding slowly, so polls run less often.')
|
||||
);
|
||||
if (this.serverShed && this.serverShed.limit)
|
||||
parts.push(
|
||||
_('Server shedding — at most %d log lines per poll.').format(this.serverShed.limit)
|
||||
_(
|
||||
'Server limited fetch: the router is under load; at most %d log lines per poll.'
|
||||
).format(this.serverShed.limit)
|
||||
);
|
||||
else if (this.serverTruncated)
|
||||
parts.push(
|
||||
_('Server limited fetch: this poll returned fewer lines to protect the router.')
|
||||
);
|
||||
else if (this.serverTruncated) parts.push(_('Server truncated this poll (adaptive cap).'));
|
||||
if (this.resolveLoadShed)
|
||||
parts.push(_('Hostname resolve paused while the router is under load.'));
|
||||
parts.push(_('Hostname lookup paused while the router is under load.'));
|
||||
if (this.weakDevice && this.rowLimit > constants.WEAK_DEVICE_DISPLAY_ROW_CAP)
|
||||
parts.push(
|
||||
_(
|
||||
'Display limited to %d rows on this device; the larger Limit still buffers rows.'
|
||||
).format(constants.WEAK_DEVICE_DISPLAY_ROW_CAP)
|
||||
);
|
||||
return parts;
|
||||
},
|
||||
|
||||
updateAdaptiveBanner() {
|
||||
const el = document.getElementById('fwlive-adaptive');
|
||||
if (!el) return;
|
||||
if (!el.style) el.style = { display: '' };
|
||||
|
||||
const parts = this.adaptiveBannerParts();
|
||||
|
||||
@@ -1534,11 +1547,9 @@ return view.extend({
|
||||
const scroll = document.getElementById('fwlive-scroll');
|
||||
const empty = document.getElementById('fwlive-empty');
|
||||
if (scroll) {
|
||||
if (!scroll.style) scroll.style = { display: '' };
|
||||
scroll.style.display = hideTable ? 'none' : '';
|
||||
}
|
||||
if (empty) {
|
||||
if (!empty.style) empty.style = { display: '' };
|
||||
empty.style.display = hideTable ? 'none' : rowCount ? 'none' : 'block';
|
||||
}
|
||||
},
|
||||
@@ -1547,7 +1558,6 @@ return view.extend({
|
||||
const card = document.getElementById('fwlive-summary');
|
||||
const toggle = document.getElementById('fwlive-summary-rows');
|
||||
if (card) {
|
||||
if (!card.style) card.style = { display: '' };
|
||||
card.style.display = this.summaryMode ? 'block' : 'none';
|
||||
}
|
||||
this.syncEmptyScrollVisibility(this.filteredRowsState().rows.length);
|
||||
@@ -1602,12 +1612,11 @@ return view.extend({
|
||||
updateFloodBanner() {
|
||||
const el = document.getElementById('fwlive-flood');
|
||||
if (!el) return;
|
||||
if (!el.style) el.style = { display: '' };
|
||||
|
||||
if (this.ensureRenderScheduler().isFloodSuppressed()) {
|
||||
el.style.display = 'block';
|
||||
el.textContent = _(
|
||||
'High event rate — table refresh is throttled to protect the browser. The buffer still updates; refresh will resume automatically.'
|
||||
'Table refresh throttled: the event rate is high, so the table repaints less often to protect the browser. The buffer still updates; refresh resumes automatically.'
|
||||
);
|
||||
} else {
|
||||
el.style.display = 'none';
|
||||
@@ -1659,12 +1668,37 @@ return view.extend({
|
||||
return this.filteredRowsState().rows.slice();
|
||||
},
|
||||
|
||||
formatAgeShort(seconds) {
|
||||
if (seconds < 60) return _('%ds').format(seconds);
|
||||
if (seconds < 3600) return _('%dm').format(Math.floor(seconds / 60));
|
||||
if (seconds < 86400) return _('%dh').format(Math.floor(seconds / 3600));
|
||||
return _('%dd').format(Math.floor(seconds / 86400));
|
||||
},
|
||||
|
||||
stalenessHint() {
|
||||
if (
|
||||
!this.entries.length ||
|
||||
!this.lastSuccessfulBatchEmpty ||
|
||||
!Number.isFinite(this.lastNonEmptyBatchAt)
|
||||
)
|
||||
return '';
|
||||
|
||||
const elapsed = Math.max(0, this.nowMs() - this.lastNonEmptyBatchAt);
|
||||
if (elapsed < constants.EMPTY_POLL_STALE_AFTER_MS) return '';
|
||||
|
||||
const age = this.formatAgeShort(Math.floor(elapsed / 1000));
|
||||
return _('Firewall log has no current entries; showing rows last received %s ago.').format(
|
||||
age
|
||||
);
|
||||
},
|
||||
|
||||
compactCountText(filtered) {
|
||||
const stored = this.entries.length;
|
||||
/* Keep the stored-buffer denominator tied to the user's Limit. A weak
|
||||
* device's rendered-row cap is called out separately in statusSuffix(). */
|
||||
const limit = this.rowLimit;
|
||||
const suffix = this.statusSuffix();
|
||||
const stale = this.stalenessHint();
|
||||
const suffix = this.statusSuffix() + (stale ? ' — ' + stale : '');
|
||||
/* The filter state contains both visible rows and the full match count, so
|
||||
* paused status can report matches beyond the display cap without rescanning. */
|
||||
const state =
|
||||
@@ -1680,6 +1714,15 @@ return view.extend({
|
||||
return '';
|
||||
},
|
||||
|
||||
/* No reply is a transport failure; a typed code means rpcd answered. */
|
||||
pollErrorText(suffix) {
|
||||
const code = this.lastPollErrorCode;
|
||||
if (INSTALL_POLL_ERRORS.indexOf(code) >= 0)
|
||||
return _('Installation is incomplete. Reinstall luci-app-fwlive.');
|
||||
if (code) return _('The router could not read the firewall log — retrying…') + suffix;
|
||||
return _('Connection lost — retrying…') + suffix;
|
||||
},
|
||||
|
||||
updateStatus(filtered) {
|
||||
const status = document.getElementById('fwlive-status');
|
||||
if (!status) return;
|
||||
@@ -1690,10 +1733,7 @@ return view.extend({
|
||||
|
||||
if (this.lastPollError) {
|
||||
status.className = 'fwlive-status fwlive-status-error';
|
||||
status.textContent =
|
||||
this.lastPollErrorCode === 'timeout_missing'
|
||||
? _('Installation is incomplete. Reinstall luci-app-fwlive.')
|
||||
: _('Connection lost — retrying…') + suffix;
|
||||
status.textContent = this.pollErrorText(suffix);
|
||||
this.updateAdaptiveBanner();
|
||||
return;
|
||||
}
|
||||
@@ -1834,6 +1874,7 @@ return view.extend({
|
||||
this.applyRowLimit(n);
|
||||
this.saveRowLimit();
|
||||
this.updateHash(this.readFilters());
|
||||
this.updateAdaptiveBanner();
|
||||
/* Reset flood throttle so Limit changes paint even during ping -A. */
|
||||
this.ensureRenderScheduler().resetBudget();
|
||||
const cancelForce = this.ensureRenderScheduler().forceNextRender();
|
||||
@@ -1903,8 +1944,8 @@ return view.extend({
|
||||
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
const r = entries[i];
|
||||
if (r.src && this.isLikelyIp(r.src)) ips.add(stripIpZone(r.src));
|
||||
if (r.dst && this.isLikelyIp(r.dst)) ips.add(stripIpZone(r.dst));
|
||||
if (r.src && this.isLikelyIp(r.src)) ips.add(hostname.stripZone(r.src));
|
||||
if (r.dst && this.isLikelyIp(r.dst)) ips.add(hostname.stripZone(r.dst));
|
||||
}
|
||||
|
||||
return Array.from(ips);
|
||||
@@ -1934,12 +1975,12 @@ return view.extend({
|
||||
|
||||
const ips = this.collectIpsFromEntries(entries);
|
||||
const need = [];
|
||||
const now = Date.now();
|
||||
const now = this.nowMs();
|
||||
/* While the router sheds resolve load, hold the paused banner without
|
||||
* re-asking every poll — retry after the cooldown expires. */
|
||||
if (this.resolveLoadShed && now < (this.resolveShedUntil || 0)) return;
|
||||
|
||||
for (let i = 0; i < ips.length && need.length < 32; i++) {
|
||||
for (let i = 0; i < ips.length && need.length < constants.RESOLVE_BATCH_MAX; i++) {
|
||||
const ip = ips[i];
|
||||
if (hostname.lruGet(this.hostnameCache, ip) !== undefined) continue;
|
||||
if (hostname.failIsHot(this.hostnameFailed, ip, now)) continue;
|
||||
@@ -1958,7 +1999,7 @@ return view.extend({
|
||||
|
||||
if (this.isLoadShedReply(res)) {
|
||||
this.resolveLoadShed = true;
|
||||
this.resolveShedUntil = Date.now() + 60000;
|
||||
this.resolveShedUntil = this.nowMs() + constants.RESOLVE_SHED_COOLDOWN_MS;
|
||||
this.updateAdaptiveBanner();
|
||||
return;
|
||||
}
|
||||
@@ -2115,7 +2156,6 @@ return view.extend({
|
||||
|
||||
const body = el.querySelector('tbody');
|
||||
const scroll = document.getElementById('fwlive-scroll');
|
||||
this.updateHash(this.readFilters());
|
||||
|
||||
const filtered = this.filteredRowsState();
|
||||
const rows = filtered.rows.slice();
|
||||
@@ -2184,6 +2224,7 @@ return view.extend({
|
||||
},
|
||||
|
||||
onFilterInput() {
|
||||
this.updateHash(this.readFilters());
|
||||
this.renderRows(true);
|
||||
},
|
||||
|
||||
@@ -2194,7 +2235,7 @@ return view.extend({
|
||||
this.filterInputTimer = null;
|
||||
this.onFilterInput();
|
||||
}.bind(this),
|
||||
100
|
||||
constants.FILTER_INPUT_DEBOUNCE_MS
|
||||
);
|
||||
},
|
||||
|
||||
@@ -2281,10 +2322,7 @@ return view.extend({
|
||||
/* fetchEntries already accounts the poll RTT for every rpc
|
||||
* outcome; a throw here is a local normalize/buffer bug, not
|
||||
* network slowness, so count nothing further. */
|
||||
if (epoch === this.currentPollEpoch()) {
|
||||
this.lastPollError = true;
|
||||
this.lastPollErrorCode = null;
|
||||
}
|
||||
this.markLocalPollFailure(epoch);
|
||||
}
|
||||
|
||||
if (epoch !== this.currentPollEpoch()) return;
|
||||
@@ -2317,13 +2355,17 @@ return view.extend({
|
||||
} catch (_e) {
|
||||
/* Keep the coordinator promise settling so a queued refresh cannot
|
||||
* be stranded by an unexpected local rendering failure. */
|
||||
if (epoch === this.currentPollEpoch()) {
|
||||
this.lastPollError = true;
|
||||
this.lastPollErrorCode = null;
|
||||
}
|
||||
this.markLocalPollFailure(epoch);
|
||||
}
|
||||
},
|
||||
|
||||
/* No error code: the status line reports it as a lost connection. */
|
||||
markLocalPollFailure(epoch) {
|
||||
if (epoch !== this.currentPollEpoch()) return;
|
||||
this.lastPollError = true;
|
||||
this.lastPollErrorCode = null;
|
||||
},
|
||||
|
||||
load() {
|
||||
/* A late LuCI lifecycle callback may re-enter load() after pagehide has
|
||||
* made disposal terminal; do not restore state or re-register polling. */
|
||||
@@ -2442,7 +2484,14 @@ return view.extend({
|
||||
)
|
||||
]),
|
||||
E('li', {}, [
|
||||
_('Display options on the bar set Limit, row tint, palette, and hostnames.')
|
||||
_(
|
||||
'Display options set Limit, Fetch budget, Maximum raw lines, row tint, palette, and hostnames.'
|
||||
)
|
||||
]),
|
||||
E('li', {}, [
|
||||
_(
|
||||
'Summary mode: when the router responds slowly, a compact summary replaces the table. Use Show rows to see the table; it returns automatically after three fast polls.'
|
||||
)
|
||||
]),
|
||||
E('li', {}, [
|
||||
_(
|
||||
@@ -2550,6 +2599,18 @@ return view.extend({
|
||||
)
|
||||
])
|
||||
]),
|
||||
E(
|
||||
'details',
|
||||
{
|
||||
'id': 'fwlive-rules-details',
|
||||
'class': 'fwlive-rules-details',
|
||||
'style': 'display:none'
|
||||
},
|
||||
[
|
||||
E('summary', { 'aria-label': _('Rule name details') }, [_('Details')]),
|
||||
E('div', { 'id': 'fwlive-rules-details-body' }, [])
|
||||
]
|
||||
),
|
||||
E('div', { 'id': 'fwlive-watch-strip', 'class': 'fwlive-watch-strip' }, [
|
||||
E('div', { 'class': 'fwlive-watch-group' }, [
|
||||
E(
|
||||
@@ -2797,6 +2858,7 @@ return view.extend({
|
||||
this.updateEmptyStateUi();
|
||||
this.updateBackendUi();
|
||||
this.updateTintWarnUi();
|
||||
this.updateHash(this.readFilters());
|
||||
this.renderRows(true);
|
||||
const testLi = document.getElementById('fwlive-manual-test');
|
||||
if (testLi)
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -12,15 +12,16 @@
|
||||
# Lock: sibling ${FWLIVE_ADAPTIVE_LOCK_FILE:-$STATE.lock} — never the JSON
|
||||
# inode (atomic mv replaces that inode; locking it would not serialize writers).
|
||||
# Lock covers only short update — never held across ubus/filter work.
|
||||
# Hot-path budget: ≤1 flock exec and 2 find execs per successful update
|
||||
# (directory safety checked before lock open and before the state write).
|
||||
# Hot-path budget: ≤1 flock exec and ≤1 find exec per record
|
||||
# (directory safety checked once before the lock is opened; the state write
|
||||
# relies on that check).
|
||||
# Release flock by closing the fd when the subshell exits (no flock -u).
|
||||
# /proc/uptime + state I/O use shell builtins/redirects (no sed/cat/jsonfilter
|
||||
# on the adaptive path). Fail-open on missing
|
||||
# flock, lock busy, or corrupt state. Fail-closed if the lock file cannot be
|
||||
# opened (skip the write; do not record unlocked). Lock-busy ⇒ unlocked
|
||||
# last-writer-wins is acceptable (state stays one valid JSON line; ordering
|
||||
# is not guaranteed).
|
||||
# on the adaptive path). Fail-open on missing flock, a busy lock, or corrupt
|
||||
# state. Fail-closed when the state directory check fails, or when the lock
|
||||
# file cannot be created, opened, or is not a regular writable file (skip the
|
||||
# write; do not record unlocked). Lock-busy ⇒ unlocked last-writer-wins is
|
||||
# acceptable (state stays one valid JSON line; ordering is not guaranteed).
|
||||
# Failed ubus log.read must NOT call record() — a ~0 ms failure is not "cold"
|
||||
# health and must not clear an existing hot/shed cap.
|
||||
# Outside the measured duration interval: plan (pre), record/merge (post).
|
||||
@@ -213,7 +214,6 @@ fwlive_adaptive_write_state() {
|
||||
_w=$4
|
||||
_s=$5
|
||||
_c=$6
|
||||
fwlive_adaptive_state_dir_ok || return 0
|
||||
# Refuse to follow a symlinked state path (same discipline as logging.lock).
|
||||
[ -L "$FWLIVE_ADAPTIVE_STATE_FILE" ] && return 0
|
||||
_tmp="${FWLIVE_ADAPTIVE_STATE_FILE}.tmp.$$"
|
||||
@@ -229,36 +229,32 @@ fwlive_adaptive_write_state() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# One non-blocking flock on the persistent sibling lock file; fail-open if
|
||||
# missing/busy. Release by exiting the subshell (closes fd 9) — no flock -u.
|
||||
# Busy ⇒ run unlocked: last-writer-wins is acceptable (valid one-line JSON;
|
||||
# ordering under contention is not guaranteed).
|
||||
# Lock-open failure (redirection): fail-closed — skip the write; do not run
|
||||
# record() unlocked. Probe fd 9 first so a set -eu caller does not abort.
|
||||
# One non-blocking flock on the persistent sibling lock file.
|
||||
# Fail-open only when flock is missing or the lock is busy (unlocked
|
||||
# last-writer-wins: valid one-line JSON; ordering is not guaranteed).
|
||||
# Fail-closed — skip the body — when the state directory is unsafe, or the
|
||||
# lock cannot be created, opened, or is not a regular writable file.
|
||||
# Release by exiting the subshell (closes fd 9) — no flock -u.
|
||||
# Probe fd 9 first so a set -eu caller does not abort.
|
||||
fwlive_adaptive_with_lock() {
|
||||
fwlive_adaptive_state_dir_ok || return 0
|
||||
if ! command -v flock >/dev/null 2>&1; then
|
||||
"$@"
|
||||
return $?
|
||||
fi
|
||||
fwlive_adaptive_state_dir_ok || {
|
||||
"$@"
|
||||
return $?
|
||||
}
|
||||
_lock=$(fwlive_adaptive_lock_path)
|
||||
# Symlinked or non-file lock path: do not create/follow; fail open unlocked.
|
||||
if [ -L "$_lock" ] || [ -d "$_lock" ]; then
|
||||
"$@"
|
||||
return $?
|
||||
if [ -L "$_lock" ]; then
|
||||
return 0
|
||||
fi
|
||||
# Create lock at 0600 (world-readable fd can take LOCK_EX).
|
||||
if [ ! -e "$_lock" ]; then
|
||||
if ! ( umask 077; : >"$_lock" ) 2>/dev/null; then
|
||||
"$@"
|
||||
return $?
|
||||
return 0
|
||||
fi
|
||||
elif [ ! -w "$_lock" ]; then
|
||||
"$@"
|
||||
return $?
|
||||
fi
|
||||
# Only a regular file: a writable FIFO would block the fd-9 open below.
|
||||
if [ ! -f "$_lock" ] || [ ! -w "$_lock" ]; then
|
||||
return 0
|
||||
fi
|
||||
# Probe in a subshell first: a failed fd-9 redirection aborts a POSIX
|
||||
# non-interactive shell (set -eu) before any fallback can run.
|
||||
@@ -270,7 +266,6 @@ fwlive_adaptive_with_lock() {
|
||||
"$@"
|
||||
exit $?
|
||||
fi
|
||||
# Lock busy — fail open (unlocked).
|
||||
"$@"
|
||||
) 9>>"$_lock"
|
||||
return $?
|
||||
@@ -290,6 +285,22 @@ fwlive_adaptive_bucket_for_ms() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Clamp $_limit into [1, min($1, $2)].
|
||||
fwlive_adaptive_clamp() {
|
||||
[ "$_limit" -gt "$1" ] && _limit=$1
|
||||
[ "$_limit" -gt "$2" ] && _limit=$2
|
||||
[ "$_limit" -lt 1 ] && _limit=1
|
||||
return 0
|
||||
}
|
||||
|
||||
# Double $_limit. A base below 1 becomes $1; the result is capped at $1.
|
||||
fwlive_adaptive_double() {
|
||||
[ "$_limit" -lt 1 ] && _limit=$1
|
||||
_limit=$((_limit * 2))
|
||||
[ "$_limit" -gt "$1" ] && _limit=$1
|
||||
return 0
|
||||
}
|
||||
|
||||
# Args: requested_limit duration_ms prev_limit prev_bucket prev_warm
|
||||
# prev_completed_cs planning
|
||||
# Prints next limit. A full-sized cold sample may retain one upward probe
|
||||
@@ -307,6 +318,7 @@ fwlive_adaptive_compute_limit() {
|
||||
_bucket=$(fwlive_adaptive_bucket_for_ms "$_ms")
|
||||
_limit=$_max
|
||||
_cd=0
|
||||
_probe=0
|
||||
|
||||
case "$_prev_b" in
|
||||
hot) _cd=$FWLIVE_ADAPTIVE_COOLDOWN_HOT_CS ;;
|
||||
@@ -316,44 +328,30 @@ fwlive_adaptive_compute_limit() {
|
||||
|
||||
if [ "$_cd" -gt 0 ] && [ "$_prev_c" -gt 0 ] && \
|
||||
[ "$_elapsed" -lt "$_cd" ]; then
|
||||
if [ "$_ms" -le "$FWLIVE_ADAPTIVE_HOT_EXIT_MS" ] && \
|
||||
[ "$_bucket" != hot ]; then
|
||||
:
|
||||
else
|
||||
if [ "$_ms" -gt "$FWLIVE_ADAPTIVE_HOT_EXIT_MS" ] || \
|
||||
[ "$_bucket" = hot ]; then
|
||||
_limit=$_prev_l
|
||||
[ "$_limit" -gt "$_req" ] && _limit=$_req
|
||||
[ "$_limit" -gt "$_max" ] && _limit=$_max
|
||||
[ "$_limit" -lt 1 ] && _limit=1
|
||||
fwlive_adaptive_clamp "$_req" "$_max"
|
||||
printf '%s\n' "$_limit"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Once a hot/warm cooldown expires, deliberately test a larger request.
|
||||
# Planning and recording use the same pure helper: planning raises the next
|
||||
# request, while recording raises the retained limit only when that probe
|
||||
# completed below the hot-exit threshold. A still-hot probe therefore falls
|
||||
# through to the hot floor below.
|
||||
# Planning raises the next request. Recording raises the retained limit
|
||||
# only when that probe completed below the hot-exit threshold. A still-hot
|
||||
# probe falls through to the hot floor below.
|
||||
if [ "$_cd" -gt 0 ] && [ "$_prev_c" -gt 0 ] && \
|
||||
[ "$_elapsed" -ge "$_cd" ]; then
|
||||
if [ "$_planning" = 1 ]; then
|
||||
_limit=$_prev_l
|
||||
[ "$_limit" -lt 1 ] && _limit=$_max
|
||||
_limit=$((_limit * 2))
|
||||
[ "$_limit" -gt "$_max" ] && _limit=$_max
|
||||
[ "$_limit" -gt "$_req" ] && _limit=$_req
|
||||
[ "$_limit" -lt 1 ] && _limit=1
|
||||
printf '%s\n' "$_limit"
|
||||
return 0
|
||||
fi
|
||||
_healthy=0
|
||||
if [ "$_ms" -le "$FWLIVE_ADAPTIVE_HOT_EXIT_MS" ] && \
|
||||
[ "$_bucket" != hot ]; then
|
||||
_healthy=1
|
||||
fi
|
||||
if [ "$_planning" = 1 ] || [ "$_healthy" = 1 ]; then
|
||||
_limit=$_prev_l
|
||||
[ "$_limit" -lt 1 ] && _limit=$_max
|
||||
_limit=$((_limit * 2))
|
||||
[ "$_limit" -gt "$_max" ] && _limit=$_max
|
||||
[ "$_limit" -gt "$_req" ] && _limit=$_req
|
||||
[ "$_limit" -lt 1 ] && _limit=1
|
||||
fwlive_adaptive_double "$_max"
|
||||
fwlive_adaptive_clamp "$_req" "$_max"
|
||||
printf '%s\n' "$_limit"
|
||||
return 0
|
||||
fi
|
||||
@@ -369,7 +367,9 @@ fwlive_adaptive_compute_limit() {
|
||||
elif [ "$_req" -ge "$_base" ]; then
|
||||
# A full-sized cold sample earns one doubling, not a jump
|
||||
# from the 250-line floor straight to the maximum.
|
||||
_limit=$((_base * 2))
|
||||
_limit=$_base
|
||||
fwlive_adaptive_double "$_max"
|
||||
[ "$_prev_l" -ge 1 ] && _probe=1
|
||||
else
|
||||
# A short cold sample does not prove the larger request is safe.
|
||||
_limit=$_base
|
||||
@@ -381,7 +381,7 @@ fwlive_adaptive_compute_limit() {
|
||||
# 250-line cap.
|
||||
if [ "$_prev_l" -gt "$FWLIVE_ADAPTIVE_COOL_CAP" ] && \
|
||||
[ "$_prev_c" -gt 0 ] && \
|
||||
[ "$((_now - _prev_c))" -lt "$FWLIVE_ADAPTIVE_COOLDOWN_PROBE_CS" ]; then
|
||||
[ "$_elapsed" -lt "$FWLIVE_ADAPTIVE_COOLDOWN_PROBE_CS" ]; then
|
||||
_limit=$_prev_l
|
||||
else
|
||||
_limit=$FWLIVE_ADAPTIVE_COOL_CAP
|
||||
@@ -401,12 +401,11 @@ fwlive_adaptive_compute_limit() {
|
||||
hot) _limit=$FWLIVE_ADAPTIVE_HOT_FLOOR ;;
|
||||
esac
|
||||
|
||||
if [ "$_planning" = 1 ] || [ "$_bucket" != cold ] || \
|
||||
[ "$_prev_l" -lt 1 ] || [ "$_req" -lt "$_prev_l" ]; then
|
||||
[ "$_limit" -gt "$_req" ] && _limit=$_req
|
||||
if [ "$_probe" = 1 ]; then
|
||||
fwlive_adaptive_clamp "$_max" "$_max"
|
||||
else
|
||||
fwlive_adaptive_clamp "$_req" "$_max"
|
||||
fi
|
||||
[ "$_limit" -gt "$_max" ] && _limit=$_max
|
||||
[ "$_limit" -lt 1 ] && _limit=1
|
||||
printf '%s\n' "$_limit"
|
||||
}
|
||||
|
||||
@@ -498,34 +497,19 @@ fwlive_adaptive_merge_reply() {
|
||||
*) printf '%s' "$_body"; return 0 ;;
|
||||
esac
|
||||
_base=${_body%\}}
|
||||
_effective=
|
||||
[ "$_success" = 1 ] && _effective=",\"effective_limit\":$_limit"
|
||||
_has_msgs=0
|
||||
_tail="\"adaptive\":$_adapt"
|
||||
case "$_body" in
|
||||
*',"messages_received":'*) _has_msgs=1 ;;
|
||||
*',"messages_received":'*) ;;
|
||||
*) _tail="${_tail},\"messages_received\":$_msgs" ;;
|
||||
esac
|
||||
if [ "$_adapt" = 0 ]; then
|
||||
if [ "$_has_msgs" = 1 ]; then
|
||||
printf '%s%s"adaptive":0}' "$_base" "$_sep"
|
||||
else
|
||||
printf '%s%s"adaptive":0,"messages_received":%s}' "$_base" "$_sep" "$_msgs"
|
||||
if [ "$_adapt" = 1 ]; then
|
||||
if [ "$_success" = 1 ]; then
|
||||
_tail="${_tail},\"effective_limit\":$_limit"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
if [ "$_shed" = 1 ]; then
|
||||
if [ "$_has_msgs" = 1 ]; then
|
||||
printf '%s%s"adaptive":1%s,"truncated":%s,"shed":{"level":"hot","limit":%s}}' \
|
||||
"$_base" "$_sep" "$_effective" "$_trunc" "$_limit"
|
||||
else
|
||||
printf '%s%s"adaptive":1,"messages_received":%s%s,"truncated":%s,"shed":{"level":"hot","limit":%s}}' \
|
||||
"$_base" "$_sep" "$_msgs" "$_effective" "$_trunc" "$_limit"
|
||||
fi
|
||||
else
|
||||
if [ "$_has_msgs" = 1 ]; then
|
||||
printf '%s%s"adaptive":1%s,"truncated":%s}' "$_base" "$_sep" "$_effective" "$_trunc"
|
||||
else
|
||||
printf '%s%s"adaptive":1,"messages_received":%s%s,"truncated":%s}' \
|
||||
"$_base" "$_sep" "$_msgs" "$_effective" "$_trunc"
|
||||
_tail="${_tail},\"truncated\":$_trunc"
|
||||
if [ "$_shed" = 1 ]; then
|
||||
_tail="${_tail},\"shed\":{\"level\":\"hot\",\"limit\":$_limit}"
|
||||
fi
|
||||
fi
|
||||
printf '%s%s%s}' "$_base" "$_sep" "$_tail"
|
||||
}
|
||||
@@ -268,10 +268,14 @@ wan_log_generation_bump() {
|
||||
printf '%s' "$_generation_next"
|
||||
}
|
||||
|
||||
wan_log_error_json() {
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"%s"}' "$1" "$2"
|
||||
}
|
||||
|
||||
wan_log_tracking_failed_json() {
|
||||
_zone_json="$1"
|
||||
logger -t fwlive "WAN log toggle aborted: commit generation unavailable" 2>/dev/null || true
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"rollback_tracking_failed"}' "$_zone_json"
|
||||
wan_log_error_json "$_zone_json" rollback_tracking_failed
|
||||
}
|
||||
|
||||
find_wan_zone_section_state() {
|
||||
@@ -940,7 +944,7 @@ commit_wan_log_change() {
|
||||
# non-empty changes list here can only be a foreign writer's race.
|
||||
if firewall_changes_pending; then
|
||||
logger -t fwlive "WAN log toggle aborted at commit gate: firewall changes staged by another writer" 2>/dev/null || true
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"firewall_changes_pending"}' "$zone_json"
|
||||
wan_log_error_json "$zone_json" firewall_changes_pending
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -960,12 +964,12 @@ commit_wan_log_change() {
|
||||
|
||||
if [ -n "$target" ]; then
|
||||
if ! uci set "firewall.${zone}.log=${target}"; then
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"uci_set_failed"}' "$zone_json"
|
||||
wan_log_error_json "$zone_json" uci_set_failed
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
if ! uci delete "firewall.${zone}.log"; then
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"uci_delete_failed"}' "$zone_json"
|
||||
wan_log_error_json "$zone_json" uci_delete_failed
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
@@ -982,7 +986,7 @@ commit_wan_log_change() {
|
||||
uci set "firewall.${zone}.log=${previous}" 2>/dev/null || true
|
||||
fi
|
||||
logger -t fwlive "WAN log toggle aborted after stage: firewall changes staged by another writer" 2>/dev/null || true
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"firewall_changes_pending"}' "$zone_json"
|
||||
wan_log_error_json "$zone_json" firewall_changes_pending
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -1001,7 +1005,7 @@ commit_wan_log_change() {
|
||||
else
|
||||
logger -t fwlive "WAN log commit failed with foreign changes staged — not reverting (uci_commit_failed)" 2>/dev/null || true
|
||||
fi
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"uci_commit_failed"}' "$zone_json"
|
||||
wan_log_error_json "$zone_json" uci_commit_failed
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -1036,14 +1040,14 @@ report_wan_log_after_commit() {
|
||||
if [ "$_rc" -eq 2 ]; then
|
||||
if ! reload_firewall; then
|
||||
logger -t fwlive "Firewall reload failed after raced WAN log commit" 2>/dev/null || true
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"firewall_reload_failed"}' "$zone_json"
|
||||
wan_log_error_json "$zone_json" firewall_reload_failed
|
||||
return 0
|
||||
fi
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"firewall_commit_raced"}' "$zone_json"
|
||||
wan_log_error_json "$zone_json" firewall_commit_raced
|
||||
return 0
|
||||
fi
|
||||
shift 2
|
||||
reload_and_report_wan_log "$@" "$WAN_LOG_COMMIT_GENERATION"
|
||||
reload_and_report_wan_log "$@" "$zone_json" "$WAN_LOG_COMMIT_GENERATION"
|
||||
}
|
||||
|
||||
# Firewall reload + best-effort UCI rollback on reload failure. The reload
|
||||
@@ -1095,7 +1099,7 @@ reload_and_report_wan_log() {
|
||||
# reload failure. The next toggle self-corrects the state.
|
||||
logger -t fwlive "Firewall reload failed; rollback lock unavailable — skipped" 2>/dev/null || true
|
||||
fi
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"firewall_reload_failed"}' "$zone_json"
|
||||
wan_log_error_json "$zone_json" firewall_reload_failed
|
||||
return 0
|
||||
fi
|
||||
logger -t fwlive "$success_msg" 2>/dev/null || true
|
||||
@@ -1103,40 +1107,44 @@ reload_and_report_wan_log() {
|
||||
return 0
|
||||
}
|
||||
|
||||
enable_wan_logging() {
|
||||
# $1=enable checks nf_log before the lock. Success leaves the lock held
|
||||
# and zone / zone_json set. Failure prints JSON and returns non-zero.
|
||||
wan_log_toggle_preamble() {
|
||||
find_wan_zone_section_state
|
||||
zone=$WAN_ZONE_FOUND
|
||||
if [ -z "$zone" ]; then
|
||||
no_wan_zone_error_json
|
||||
return 0
|
||||
return 1
|
||||
fi
|
||||
|
||||
zone_json=$(json_null_or_string "$zone")
|
||||
|
||||
NF_LOG_STATE_COMPUTED=0
|
||||
compute_nf_log_state
|
||||
if [ "$NF_LOG_IPV4_READY" != true ] || [ "$NF_LOG_IPV6_READY" != true ]; then
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"nf_log_missing"}' "$zone_json"
|
||||
return 0
|
||||
if [ "${1-}" = enable ]; then
|
||||
NF_LOG_STATE_COMPUTED=0
|
||||
compute_nf_log_state
|
||||
if [ "$NF_LOG_IPV4_READY" != true ] || [ "$NF_LOG_IPV6_READY" != true ]; then
|
||||
wan_log_error_json "$zone_json" nf_log_missing
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Locked critical section: read->compute->stage->commit for firewall.<zone>.log.
|
||||
# The log bit is re-read AFTER acquiring the lock so the target is computed
|
||||
# from the latest committed value; a concurrent toggle cannot interleave.
|
||||
# Staging + commit live inside commit_wan_log_change behind its last-moment
|
||||
# firewall_changes_pending re-check: a foreign writer racing between
|
||||
# the early check above and the commit aborts the toggle instead of having
|
||||
# the pending check below and the commit aborts the toggle instead of having
|
||||
# its half-finished delta published with our log bit.
|
||||
if ! acquire_wan_log_lock; then
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"lock_failed"}' "$zone_json"
|
||||
return 0
|
||||
wan_log_error_json "$zone_json" lock_failed
|
||||
return 1
|
||||
fi
|
||||
|
||||
if firewall_changes_pending; then
|
||||
release_wan_log_lock
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"firewall_changes_pending"}' "$zone_json"
|
||||
return 0
|
||||
wan_log_error_json "$zone_json" firewall_changes_pending
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
enable_wan_logging() {
|
||||
wan_log_toggle_preamble enable || return 0
|
||||
|
||||
current=$(wan_zone_log_value "$zone")
|
||||
if wan_filter_log_enabled "$current"; then
|
||||
@@ -1157,7 +1165,7 @@ enable_wan_logging() {
|
||||
|
||||
if ! maybe_snapshot_wan_log_baseline "$zone"; then
|
||||
release_wan_log_lock
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"baseline_snapshot_failed"}' "$zone_json"
|
||||
wan_log_error_json "$zone_json" baseline_snapshot_failed
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -1168,38 +1176,12 @@ enable_wan_logging() {
|
||||
report_wan_log_after_commit "$_commit_rc" "$zone_json" \
|
||||
"$zone" "$current" "$target" \
|
||||
'Firewall reload failed after enable; reverted UCI WAN log' \
|
||||
'WAN zone logging enabled' \
|
||||
"$zone_json"
|
||||
'WAN zone logging enabled'
|
||||
return 0
|
||||
}
|
||||
|
||||
disable_wan_logging() {
|
||||
find_wan_zone_section_state
|
||||
zone=$WAN_ZONE_FOUND
|
||||
if [ -z "$zone" ]; then
|
||||
no_wan_zone_error_json
|
||||
return 0
|
||||
fi
|
||||
|
||||
zone_json=$(json_null_or_string "$zone")
|
||||
|
||||
# Locked critical section: read->compute->stage->commit for firewall.<zone>.log.
|
||||
# The log bit is re-read AFTER acquiring the lock so the target is computed
|
||||
# from the latest committed value; a concurrent toggle cannot interleave.
|
||||
# Staging + commit live inside commit_wan_log_change behind its last-moment
|
||||
# firewall_changes_pending re-check: a foreign writer racing between
|
||||
# the early check above and the commit aborts the toggle instead of having
|
||||
# its half-finished delta published with our log bit.
|
||||
if ! acquire_wan_log_lock; then
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"lock_failed"}' "$zone_json"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if firewall_changes_pending; then
|
||||
release_wan_log_lock
|
||||
printf '{"ok":false,"changed":false,"wan_zone":%s,"error":"firewall_changes_pending"}' "$zone_json"
|
||||
return 0
|
||||
fi
|
||||
wan_log_toggle_preamble || return 0
|
||||
|
||||
current=$(wan_zone_log_value "$zone")
|
||||
if [ -z "$current" ] || ! wan_filter_log_enabled "$current"; then
|
||||
@@ -1224,8 +1206,7 @@ disable_wan_logging() {
|
||||
report_wan_log_after_commit "$_commit_rc" "$zone_json" \
|
||||
"$zone" "$current" "$target" \
|
||||
'Firewall reload failed after disable; reverted UCI WAN log' \
|
||||
'WAN zone logging disabled' \
|
||||
"$zone_json"
|
||||
'WAN zone logging disabled'
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ LOGGING_SH="$LIBEXEC_DIR/fwlive-logging.sh"
|
||||
ADAPTIVE_SH="$LIBEXEC_DIR/fwlive-adaptive-cap.sh"
|
||||
# Max reverse-DNS lookups per resolve call (~32 names keeps nslookup load bounded on small routers).
|
||||
RESOLVE_MAX=32
|
||||
# DNS names are at most 253 octets; a longer PTR answer is treated as no name.
|
||||
RESOLVE_NAME_MAX=253
|
||||
# Per-lookup nslookup timeout (integer seconds — BusyBox `timeout` truncates
|
||||
# fractional values to 0 on OpenWrt 23.05/1.36, so 0.5 would silently
|
||||
# degrade to no timeout; luna fold 2026-08-10). The wall-clock budget
|
||||
@@ -70,6 +72,15 @@ RULES_MAP_MAX_BYTES=65536
|
||||
# the whole dump. Bound map_prefix_with_label calls independently.
|
||||
RULES_MAP_MAX_LINES=512
|
||||
|
||||
# Append one already-escaped "key":"value" to OUT. Value may be empty.
|
||||
# No first-wins dedupe and no RULES_MAP_MAX_* caps.
|
||||
json_object_append() {
|
||||
if [ -n "$OUT" ]; then
|
||||
OUT="${OUT},"
|
||||
fi
|
||||
OUT="${OUT}\"$1\":\"$2\""
|
||||
}
|
||||
|
||||
map_add() {
|
||||
key="$1"
|
||||
val="$2"
|
||||
@@ -105,10 +116,7 @@ map_add() {
|
||||
return 0
|
||||
fi
|
||||
_map_keys=$(( ${_map_keys:-0} + 1 ))
|
||||
if [ -n "$OUT" ]; then
|
||||
OUT="${OUT},"
|
||||
fi
|
||||
OUT="${OUT}\"${esc_key}\":\"${esc_val}\""
|
||||
json_object_append "$esc_key" "$esc_val"
|
||||
}
|
||||
|
||||
uci_rule_names() {
|
||||
@@ -581,10 +589,12 @@ build_rules_map() {
|
||||
_enrich_error='no_backend'
|
||||
fi
|
||||
_rules_json="{\"backend\":\"$backend\",\"rules\":{$OUT}"
|
||||
# Map limits and enrichment failures are independent outcomes.
|
||||
_truncated=false
|
||||
[ -n "$_map_overflow" ] && _truncated=true
|
||||
_rules_json="${_rules_json},\"truncated\":${_truncated}"
|
||||
if [ -n "$_enrich_error" ]; then
|
||||
_rules_json="${_rules_json},\"error\":\"${_enrich_error}\""
|
||||
elif [ -n "$_map_overflow" ]; then
|
||||
_rules_json="${_rules_json},\"error\":\"rules_truncated\""
|
||||
fi
|
||||
printf '%s}' "$_rules_json"
|
||||
}
|
||||
@@ -617,6 +627,22 @@ poll_clamp_lines() {
|
||||
fi
|
||||
}
|
||||
|
||||
# jshn_load_input JSON
|
||||
# Status 0: JSON loaded (json_* available). Status 2: library missing
|
||||
# (FWLIVE_JSHN_SH or json_init). Status 1: parse failure.
|
||||
# Caller checks command -v jshn (jshn_missing) and runs with nounset off.
|
||||
# jshn uses intentionally unset state variables.
|
||||
jshn_load_input() {
|
||||
# shellcheck disable=SC1090,SC1091
|
||||
. "${FWLIVE_JSHN_SH:-/usr/share/libubox/jshn.sh}" 2>/dev/null || return 2
|
||||
json_init >/dev/null 2>&1 || return 2
|
||||
# json_load masks a failing jshn exit through eval. Check the real
|
||||
# parser once, then evaluate only its generated shell assignments.
|
||||
_json_no_warning=1
|
||||
_json_code=$(jshn -r "$1" 2>/dev/null) || return 1
|
||||
eval "$_json_code" || return 1
|
||||
}
|
||||
|
||||
# Failed jshn reads still default to 50 (silent numeric contract; syslog named cause only).
|
||||
poll_lines_from_input() {
|
||||
input="$1"
|
||||
@@ -627,20 +653,12 @@ poll_lines_from_input() {
|
||||
_cause=jshn_missing
|
||||
else
|
||||
_rc=0
|
||||
# jshn uses intentionally unset state variables. Keep nounset disabled in
|
||||
# this subshell so strict mode is restored automatically on every exit.
|
||||
# exit 2: library missing or source failed; exit 1: JSON parse failed.
|
||||
# Keep nounset disabled in this subshell so strict mode is restored
|
||||
# on every exit. Status 2: library missing; status 1: parse failure.
|
||||
# Missing addresses[0] is an intentional silent default, not a parse error.
|
||||
_first=$( (
|
||||
set +u
|
||||
# shellcheck disable=SC1090,SC1091
|
||||
. "${FWLIVE_JSHN_SH:-/usr/share/libubox/jshn.sh}" 2>/dev/null || exit 2
|
||||
json_init >/dev/null 2>&1 || exit 2
|
||||
# json_load masks a failing jshn exit through eval. Check the real
|
||||
# parser once, then evaluate only its generated shell assignments.
|
||||
_json_no_warning=1
|
||||
_json_code=$(jshn -r "$input" 2>/dev/null) || exit 1
|
||||
eval "$_json_code" || exit 1
|
||||
jshn_load_input "$input" || exit $?
|
||||
first=
|
||||
if json_select addresses 2>/dev/null; then
|
||||
json_get_var first 1 || first=
|
||||
@@ -928,15 +946,10 @@ resolve_addresses() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
_rc=0
|
||||
_addresses=$( (
|
||||
set +u
|
||||
# shellcheck disable=SC1090,SC1091
|
||||
. "${FWLIVE_JSHN_SH:-/usr/share/libubox/jshn.sh}"
|
||||
# json_load masks a failing jshn exit through eval. Check the real
|
||||
# parser once, then evaluate only its generated shell assignments.
|
||||
_json_no_warning=1
|
||||
_json_code=$(jshn -r "$input" 2>/dev/null) || exit 1
|
||||
eval "$_json_code" || exit 1
|
||||
jshn_load_input "$input" || exit $?
|
||||
if ! json_select addresses 2>/dev/null; then exit 0; fi
|
||||
idx=1
|
||||
# json_get_type false ends the array. A non-string element is skipped
|
||||
@@ -955,49 +968,44 @@ resolve_addresses() {
|
||||
fi
|
||||
idx=$((idx + 1))
|
||||
done
|
||||
) ) || {
|
||||
) ) || _rc=$?
|
||||
if [ "$_rc" -eq 2 ]; then
|
||||
printf '{"names":{},"error":"jshn_lib_missing"}'
|
||||
return 0
|
||||
fi
|
||||
if [ "$_rc" -ne 0 ]; then
|
||||
printf '{"names":{},"error":"invalid_input"}'
|
||||
return 0
|
||||
}
|
||||
fi
|
||||
while IFS= read -r ip; do
|
||||
[ -n "${ip:-}" ] || continue
|
||||
# Producer already validated; skip repeats before they cost a slot.
|
||||
case "$OUT" in
|
||||
*"\"$ip\":"*) continue ;;
|
||||
esac
|
||||
if [ "$lookups" -ge "$RESOLVE_MAX" ]; then
|
||||
truncated=1
|
||||
break
|
||||
fi
|
||||
# Abort cleanly once the lookup-loop wall-clock budget is spent;
|
||||
# never START a lookup past the budget.
|
||||
now=$(fwlive_adaptive_clock_cs)
|
||||
if [ $((now - start)) -ge $((RESOLVE_BUDGET * 100)) ]; then
|
||||
truncated=1
|
||||
break
|
||||
fi
|
||||
lookups=$((lookups + 1))
|
||||
# NXDOMAIN / timeout: resolve_hostname returns 1. set -e
|
||||
# cannot apply to this assignment.
|
||||
name=$(resolve_hostname "$ip") || name=
|
||||
if [ -n "$name" ]; then
|
||||
map_add "$ip" "$name"
|
||||
else
|
||||
# Record a completed miss so the view can fail-mark NXDOMAIN
|
||||
# without treating the unprocessed truncated tail as tried.
|
||||
# map_add skips empty values (rules-map labels); resolve needs them.
|
||||
esc_key=$(printf '%s' "$ip" | json_escape)
|
||||
case "$OUT" in
|
||||
*"\"$esc_key\":"*) ;;
|
||||
*)
|
||||
if [ -n "$OUT" ]; then
|
||||
OUT="${OUT},"
|
||||
fi
|
||||
OUT="${OUT}\"${esc_key}\":\"\""
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
done <<EOF
|
||||
[ -n "${ip:-}" ] || continue
|
||||
# Producer already validated; skip repeats before they cost a slot.
|
||||
case "$OUT" in
|
||||
*"\"$ip\":"*) continue ;;
|
||||
esac
|
||||
if [ "$lookups" -ge "$RESOLVE_MAX" ]; then
|
||||
truncated=1
|
||||
break
|
||||
fi
|
||||
# Abort cleanly once the lookup-loop wall-clock budget is spent;
|
||||
# never START a lookup past the budget.
|
||||
now=$(fwlive_adaptive_clock_cs)
|
||||
if [ $((now - start)) -ge $((RESOLVE_BUDGET * 100)) ]; then
|
||||
truncated=1
|
||||
break
|
||||
fi
|
||||
lookups=$((lookups + 1))
|
||||
# NXDOMAIN / timeout: resolve_hostname returns 1. set -e
|
||||
# cannot apply to this assignment.
|
||||
name=$(resolve_hostname "$ip") || name=
|
||||
[ "${#name}" -le "$RESOLVE_NAME_MAX" ] || name=
|
||||
esc_key=$(printf '%s' "$ip" | json_escape)
|
||||
esc_val=
|
||||
if [ -n "$name" ]; then
|
||||
esc_val=$(printf '%s' "$name" | json_escape)
|
||||
fi
|
||||
json_object_append "$esc_key" "$esc_val"
|
||||
done <<EOF
|
||||
$_addresses
|
||||
EOF
|
||||
|
||||
@@ -1420,6 +1428,12 @@ case "${1:-}" in
|
||||
run_selftest
|
||||
exit $?
|
||||
;;
|
||||
__limits)
|
||||
printf '%s %s %s %s %s\n' \
|
||||
"$POLL_TIMEOUT" "$TIMEOUT_KILL_GRACE" "$NFT_TIMEOUT" \
|
||||
"$RESOLVE_TIMEOUT" "$RESOLVE_BUDGET"
|
||||
exit 0
|
||||
;;
|
||||
__poll_clamp)
|
||||
poll_clamp_lines "${2:-}"
|
||||
exit $?
|
||||
|
||||
@@ -23,7 +23,7 @@ LUCI_DEPENDS:= \
|
||||
|
||||
PKG_NAME:=luci-app-homeproxy-pro
|
||||
PKG_VERSION:=28.9.1.14
|
||||
PKG_RELEASE:=10
|
||||
PKG_RELEASE:=11
|
||||
|
||||
# Only files the package actually ships belong here. The previous list named
|
||||
# four paths that exist nowhere in the tree - certs/ and ruleset/ are created at
|
||||
|
||||
+12
-24
@@ -121,24 +121,26 @@ function renderDnsCache(ctx) {
|
||||
|
||||
s.tab('dns_cache', _('DNS Settings'));
|
||||
|
||||
o = s.taboption('dns_cache', form.Value, 'dns_server', _('DNS server'),
|
||||
/* The name says overseas because that is the only thing that belongs
|
||||
* here: every query this field answers goes to a domain that is not on
|
||||
* the China path, and a domestic resolver answers those with polluted or
|
||||
* NXDOMAIN results. The Chinese public resolvers that used to be listed
|
||||
* below a divider were therefore a footgun with a helpful-looking label -
|
||||
* the one combination that reliably breaks a working proxy. Only the
|
||||
* overseas public resolvers are offered now. */
|
||||
o = s.taboption('dns_cache', form.Value, 'dns_server', _('Overseas DNS server'),
|
||||
_('Resolves every domain that is not on the China DNS path, through the selected proxy node. ' +
|
||||
'Pick an overseas service: a domestic resolver answers these queries with polluted or ' +
|
||||
'NXDOMAIN results, which is what makes a foreign site fail to resolve while the proxy itself works. ' +
|
||||
'Support UDP, TCP, DoH, DoQ, DoT. TCP protocol will be used if not specified.'));
|
||||
o.value('wan', _('WAN DNS (read from interface)'));
|
||||
'A domestic resolver answers these queries with polluted or NXDOMAIN results, which is what ' +
|
||||
'makes a foreign site fail to resolve while the proxy itself works - so only overseas services ' +
|
||||
'are offered here. Support UDP, TCP, DoH, DoQ, DoT. TCP protocol will be used if not specified.'));
|
||||
o.value('1.1.1.1', _('CloudFlare Public DNS (1.1.1.1)'));
|
||||
o.value('208.67.222.222', _('Cisco Public DNS (208.67.222.222)'));
|
||||
o.value('8.8.8.8', _('Google Public DNS (8.8.8.8)'));
|
||||
o.value('', '---');
|
||||
o.value('223.5.5.5', _('Aliyun Public DNS (223.5.5.5)'));
|
||||
o.value('119.29.29.29', _('Tencent Public DNS (119.29.29.29)'));
|
||||
o.value('117.50.10.10', _('ThreatBook Public DNS (117.50.10.10)'));
|
||||
o.default = '8.8.8.8';
|
||||
o.rmempty = false;
|
||||
o.depends({'routing_mode': 'custom', '!reverse': true});
|
||||
o.validate = function(section_id, value) {
|
||||
if (section_id && !['wan'].includes(value)) {
|
||||
if (section_id) {
|
||||
if (!value)
|
||||
return _('Expecting: %s').format(_('non-empty value'));
|
||||
|
||||
@@ -204,20 +206,6 @@ function renderDnsCache(ctx) {
|
||||
o.depends('routing_mode', 'bypass_mainland_china');
|
||||
o.rmempty = false;
|
||||
|
||||
/* The DNS server above is the DoH/DoT endpoint, and it is the one server
|
||||
* in the generated configuration whose address is a hostname: it has to
|
||||
* be resolved before it can answer anything. Left empty, that lookup
|
||||
* goes through the WAN resolver (the pre-1.14 behaviour); naming a
|
||||
* resolver here decouples it from the ISP/upstream one. Only one is
|
||||
* used - sing-box resolves a hostname through exactly one server. */
|
||||
o = s.taboption('dns_cache', form.DynamicList, 'bootstrap_dns', _('Bootstrap DNS server'),
|
||||
_('Resolver used to look up the DNS server\'s own hostname - only relevant when that address ' +
|
||||
'is a domain, as with a DoH/DoT endpoint. Leave empty to use the WAN resolver. ' +
|
||||
'Only the first entry is used.'));
|
||||
o.datatype = 'ipaddr';
|
||||
o.depends({'routing_mode': 'custom', '!reverse': true});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('dns_cache', form.SectionValue, '_dns_cache', form.NamedSection, 'dns', 'homeproxy-pro');
|
||||
o.depends({'routing_mode': 'custom', '!reverse': true});
|
||||
ss = o.subsection;
|
||||
|
||||
@@ -152,8 +152,7 @@ msgstr ""
|
||||
msgid "Alibaba Cloud DNS"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:134
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:171
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:173
|
||||
msgid "Aliyun Public DNS (223.5.5.5)"
|
||||
msgstr ""
|
||||
|
||||
@@ -316,10 +315,6 @@ msgstr ""
|
||||
msgid "Block"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:213
|
||||
msgid "Bootstrap DNS server"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/common.js:84
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/common.js:108
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/server.js:624
|
||||
@@ -342,11 +337,11 @@ msgstr ""
|
||||
msgid "CA provider"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:202
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:204
|
||||
msgid "CN-IP DNS fallback (sing-box 1.14)"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:172
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:174
|
||||
msgid "CNNIC Public DNS (210.2.4.8)"
|
||||
msgstr ""
|
||||
|
||||
@@ -371,7 +366,7 @@ msgstr ""
|
||||
msgid "Check update"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:165
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:167
|
||||
msgid "China DNS server"
|
||||
msgstr ""
|
||||
|
||||
@@ -395,7 +390,7 @@ msgstr ""
|
||||
msgid "Cipher suites"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:131
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:137
|
||||
msgid "Cisco Public DNS (208.67.222.222)"
|
||||
msgstr ""
|
||||
|
||||
@@ -415,7 +410,7 @@ msgstr ""
|
||||
msgid "Client version"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:130
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:136
|
||||
msgid "CloudFlare Public DNS (1.1.1.1)"
|
||||
msgstr ""
|
||||
|
||||
@@ -487,7 +482,6 @@ msgid "DNS rule"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/common.js:410
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:124
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/nodes.js:221
|
||||
msgid "DNS server"
|
||||
msgstr ""
|
||||
@@ -885,12 +879,12 @@ msgstr ""
|
||||
#: htdocs/luci-static/resources/homeproxy-pro.js:1156
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/access.js:158
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/access.js:203
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:143
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:155
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:159
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:181
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:192
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:196
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:145
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:157
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:161
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:183
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:194
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:198
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/nodes.js:141
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/nodes.js:155
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/nodes.js:158
|
||||
@@ -1067,7 +1061,7 @@ msgstr ""
|
||||
msgid "Google"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:132
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:138
|
||||
msgid "Google Public DNS (8.8.8.8)"
|
||||
msgstr ""
|
||||
|
||||
@@ -1882,6 +1876,10 @@ msgstr ""
|
||||
msgid "Override the connection destination port."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:131
|
||||
msgid "Overseas DNS server"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/server.js:376
|
||||
msgid "PEM-encoded private key of an existing ACME account (1.14)."
|
||||
msgstr ""
|
||||
@@ -2201,23 +2199,16 @@ msgstr ""
|
||||
msgid "Resolve strategy"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:214
|
||||
msgid ""
|
||||
"Resolver used to look up the DNS server's own hostname - only relevant when "
|
||||
"that address is a domain, as with a DoH/DoT endpoint. Leave empty to use the "
|
||||
"WAN resolver. Only the first entry is used."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:125
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:132
|
||||
msgid ""
|
||||
"Resolves every domain that is not on the China DNS path, through the "
|
||||
"selected proxy node. Pick an overseas service: a domestic resolver answers "
|
||||
"these queries with polluted or NXDOMAIN results, which is what makes a "
|
||||
"foreign site fail to resolve while the proxy itself works. Support UDP, TCP, "
|
||||
"DoH, DoQ, DoT. TCP protocol will be used if not specified."
|
||||
"selected proxy node. A domestic resolver answers these queries with polluted "
|
||||
"or NXDOMAIN results, which is what makes a foreign site fail to resolve "
|
||||
"while the proxy itself works - so only overseas services are offered here. "
|
||||
"Support UDP, TCP, DoH, DoQ, DoT. TCP protocol will be used if not specified."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:166
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:168
|
||||
msgid ""
|
||||
"Resolves the domains on the China path, so it has to be a domestic service "
|
||||
"to get the correct local CDN answers. Keep the default; the upstream may "
|
||||
@@ -2677,8 +2668,7 @@ msgid ""
|
||||
"Tell the client to use the BBR flow control algorithm instead of Hysteria CC."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:135
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:173
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:175
|
||||
msgid "Tencent Public DNS (119.29.29.29)"
|
||||
msgstr ""
|
||||
|
||||
@@ -2884,8 +2874,7 @@ msgid ""
|
||||
"QUIC stream based UDP relay mode that TUIC does not provide."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:136
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:174
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:176
|
||||
msgid "ThreatBook Public DNS (117.50.10.10)"
|
||||
msgstr ""
|
||||
|
||||
@@ -3127,8 +3116,7 @@ msgstr ""
|
||||
msgid "VMess"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:129
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:170
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:172
|
||||
msgid "WAN DNS (read from interface)"
|
||||
msgstr ""
|
||||
|
||||
@@ -3144,7 +3132,7 @@ msgstr ""
|
||||
msgid "WebSocket"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:203
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:205
|
||||
msgid ""
|
||||
"When the main DNS returns a mainland China IP, re-resolve via China DNS "
|
||||
"using evaluate/match_response."
|
||||
@@ -3229,8 +3217,8 @@ msgstr ""
|
||||
#: htdocs/luci-static/resources/homeproxy-pro.js:220
|
||||
#: htdocs/luci-static/resources/homeproxy-pro.js:1134
|
||||
#: htdocs/luci-static/resources/homeproxy-pro.js:1154
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:143
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:181
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:145
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:183
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/nodes.js:141
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/subscription.js:72
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/node.js:484
|
||||
@@ -3343,10 +3331,10 @@ msgstr ""
|
||||
msgid "v6"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:155
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:159
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:192
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:196
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:157
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:161
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:194
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:198
|
||||
msgid "valid DNS server address"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -162,8 +162,7 @@ msgstr "激进"
|
||||
msgid "Alibaba Cloud DNS"
|
||||
msgstr "阿里云 DNS"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:134
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:171
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:173
|
||||
msgid "Aliyun Public DNS (223.5.5.5)"
|
||||
msgstr "阿里云公共 DNS(223.5.5.5)"
|
||||
|
||||
@@ -329,10 +328,6 @@ msgstr "黑名单模式"
|
||||
msgid "Block"
|
||||
msgstr "封锁"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:213
|
||||
msgid "Bootstrap DNS server"
|
||||
msgstr "引导 DNS 服务器"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/common.js:84
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/common.js:108
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/server.js:624
|
||||
@@ -355,11 +350,11 @@ msgstr "默认使用防火墙规则绕过中国大陆流量。"
|
||||
msgid "CA provider"
|
||||
msgstr "CA 颁发机构"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:202
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:204
|
||||
msgid "CN-IP DNS fallback (sing-box 1.14)"
|
||||
msgstr "大陆 IP DNS 兜底(sing-box 1.14)"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:172
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:174
|
||||
msgid "CNNIC Public DNS (210.2.4.8)"
|
||||
msgstr "CNNIC 公共 DNS(210.2.4.8)"
|
||||
|
||||
@@ -384,7 +379,7 @@ msgstr "检查"
|
||||
msgid "Check update"
|
||||
msgstr "检查更新"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:165
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:167
|
||||
msgid "China DNS server"
|
||||
msgstr "国内 DNS 服务器"
|
||||
|
||||
@@ -408,7 +403,7 @@ msgstr "Chromium / Cronet"
|
||||
msgid "Cipher suites"
|
||||
msgstr "密码套件"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:131
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:137
|
||||
msgid "Cisco Public DNS (208.67.222.222)"
|
||||
msgstr "思科公共 DNS(208.67.222.222)"
|
||||
|
||||
@@ -428,7 +423,7 @@ msgstr "客户端设置"
|
||||
msgid "Client version"
|
||||
msgstr "客户端版本"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:130
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:136
|
||||
msgid "CloudFlare Public DNS (1.1.1.1)"
|
||||
msgstr "CloudFlare 公共 DNS(1.1.1.1)"
|
||||
|
||||
@@ -500,7 +495,6 @@ msgid "DNS rule"
|
||||
msgstr "DNS 规则"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/common.js:410
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:124
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/nodes.js:221
|
||||
msgid "DNS server"
|
||||
msgstr "DNS 服务器"
|
||||
@@ -913,12 +907,12 @@ msgstr "Evaluate 标签"
|
||||
#: htdocs/luci-static/resources/homeproxy-pro.js:1156
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/access.js:158
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/access.js:203
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:143
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:155
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:159
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:181
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:192
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:196
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:145
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:157
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:161
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:183
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:194
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:198
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/nodes.js:141
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/nodes.js:155
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/nodes.js:158
|
||||
@@ -1096,7 +1090,7 @@ msgstr "全局设置"
|
||||
msgid "Google"
|
||||
msgstr "谷歌"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:132
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:138
|
||||
msgid "Google Public DNS (8.8.8.8)"
|
||||
msgstr "谷歌公共 DNS(8.8.8.8)"
|
||||
|
||||
@@ -1927,6 +1921,10 @@ msgstr "覆盖目标连接地址。"
|
||||
msgid "Override the connection destination port."
|
||||
msgstr "覆盖目标连接端口。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:131
|
||||
msgid "Overseas DNS server"
|
||||
msgstr "国外 DNS 服务器"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/server.js:376
|
||||
msgid "PEM-encoded private key of an existing ACME account (1.14)."
|
||||
msgstr "已有 ACME 账户的 PEM 编码私钥(1.14)。"
|
||||
@@ -2246,29 +2244,28 @@ msgstr "解析"
|
||||
msgid "Resolve strategy"
|
||||
msgstr "解析策略"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:214
|
||||
msgid ""
|
||||
"Resolver used to look up the DNS server's own hostname - only relevant when "
|
||||
"that address is a domain, as with a DoH/DoT endpoint. Leave empty to use the "
|
||||
"WAN resolver. Only the first entry is used."
|
||||
msgstr "用于解析 DNS 服务器自身主机名的解析器,仅当该地址是域名时(如 DoH/DoT 端点)才有意义。留空则使用 WAN 解析器,仅第一项生效。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:125
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:132
|
||||
msgid ""
|
||||
"Resolves every domain that is not on the China DNS path, through the "
|
||||
"selected proxy node. Pick an overseas service: a domestic resolver answers "
|
||||
"these queries with polluted or NXDOMAIN results, which is what makes a "
|
||||
"foreign site fail to resolve while the proxy itself works. Support UDP, TCP, "
|
||||
"DoH, DoQ, DoT. TCP protocol will be used if not specified."
|
||||
msgstr "解析所有不在中国解析路径上的域名,并通过所选代理节点发出查询。请选择境外服务:国内解析器会返回被污染或 NXDOMAIN 的结果,这正是代理本身正常、境外网站却解析失败的原因。支持 UDP、TCP、DoH、DoQ、DoT,未指定协议时使用 TCP。"
|
||||
"selected proxy node. A domestic resolver answers these queries with polluted "
|
||||
"or NXDOMAIN results, which is what makes a foreign site fail to resolve "
|
||||
"while the proxy itself works - so only overseas services are offered here. "
|
||||
"Support UDP, TCP, DoH, DoQ, DoT. TCP protocol will be used if not specified."
|
||||
msgstr ""
|
||||
"解析所有不在中国解析路径上的域名,并通过所选代理节点发出查询。国内解析器会返"
|
||||
"回被污染或 NXDOMAIN 的结果,这正是代理本身正常、境外网站却解析失败的原因,因"
|
||||
"此这里只提供境外服务。支持 UDP、TCP、DoH、DoQ、DoT,未指定协议时使用 TCP。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:166
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:168
|
||||
msgid ""
|
||||
"Resolves the domains on the China path, so it has to be a domestic service "
|
||||
"to get the correct local CDN answers. Keep the default; the upstream may "
|
||||
"block UDP/53, in which case a DoH address (https://dns.alidns.com/dns-query, "
|
||||
"https://doh.pub/dns-query) also works. Support UDP, TCP, DoH, DoQ, DoT."
|
||||
msgstr "解析中国路径上的域名,必须是国内服务才能获得正确的本地 CDN 结果。建议保持默认值;若上游封禁 UDP/53,也可使用 DoH 地址(https://dns.alidns.com/dns-query、https://doh.pub/dns-query)。支持 UDP、TCP、DoH、DoQ、DoT。"
|
||||
msgstr ""
|
||||
"解析中国路径上的域名,必须是国内服务才能获得正确的本地 CDN 结果。建议保持默认"
|
||||
"值;若上游封禁 UDP/53,也可使用 DoH 地址(https://dns.alidns.com/dns-query、"
|
||||
"https://doh.pub/dns-query)。支持 UDP、TCP、DoH、DoQ、DoT。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/status.js:258
|
||||
msgid "Resources management"
|
||||
@@ -2740,8 +2737,7 @@ msgid ""
|
||||
"Tell the client to use the BBR flow control algorithm instead of Hysteria CC."
|
||||
msgstr "让客户端使用 BBR 流控算法。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:135
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:173
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:175
|
||||
msgid "Tencent Public DNS (119.29.29.29)"
|
||||
msgstr "腾讯公共 DNS(119.29.29.29)"
|
||||
|
||||
@@ -2970,8 +2966,7 @@ msgstr ""
|
||||
"这是 UDP over TCP 协议的 TUIC 版本,旨在提供 TUIC 本身不具备的基于 QUIC 流的 "
|
||||
"UDP 中继模式。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:136
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:174
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:176
|
||||
msgid "ThreatBook Public DNS (117.50.10.10)"
|
||||
msgstr "微步在线公共 DNS(117.50.10.10)"
|
||||
|
||||
@@ -3217,8 +3212,7 @@ msgstr "VLESS"
|
||||
msgid "VMess"
|
||||
msgstr "VMess"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:129
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:170
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:172
|
||||
msgid "WAN DNS (read from interface)"
|
||||
msgstr "WAN DNS(从接口获取)"
|
||||
|
||||
@@ -3234,7 +3228,7 @@ msgstr "警告"
|
||||
msgid "WebSocket"
|
||||
msgstr "WebSocket"
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:203
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:205
|
||||
msgid ""
|
||||
"When the main DNS returns a mainland China IP, re-resolve via China DNS "
|
||||
"using evaluate/match_response."
|
||||
@@ -3320,8 +3314,8 @@ msgstr ""
|
||||
#: htdocs/luci-static/resources/homeproxy-pro.js:220
|
||||
#: htdocs/luci-static/resources/homeproxy-pro.js:1134
|
||||
#: htdocs/luci-static/resources/homeproxy-pro.js:1154
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:143
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:181
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:145
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:183
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/nodes.js:141
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/subscription.js:72
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/node.js:484
|
||||
@@ -3442,10 +3436,10 @@ msgstr ""
|
||||
msgid "v6"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:155
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:159
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:192
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:196
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:157
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:161
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:194
|
||||
#: htdocs/luci-static/resources/view/homeproxy-pro/client/dns.js:198
|
||||
msgid "valid DNS server address"
|
||||
msgstr "有效 DNS 服务器地址"
|
||||
|
||||
@@ -3508,6 +3502,29 @@ msgstr "使用额外标签时 URL 需包含 {tag}"
|
||||
msgid "{tag} in initial path when extra tags are used"
|
||||
msgstr "使用额外标签时初始路径需包含 {tag}"
|
||||
|
||||
#~ msgid "Bootstrap DNS server"
|
||||
#~ msgstr "引导 DNS 服务器"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Resolver used to look up the DNS server's own hostname - only relevant "
|
||||
#~ "when that address is a domain, as with a DoH/DoT endpoint. Leave empty to "
|
||||
#~ "use the WAN resolver. Only the first entry is used."
|
||||
#~ msgstr ""
|
||||
#~ "用于解析 DNS 服务器自身主机名的解析器,仅当该地址是域名时(如 DoH/DoT 端"
|
||||
#~ "点)才有意义。留空则使用 WAN 解析器,仅第一项生效。"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Resolves every domain that is not on the China DNS path, through the "
|
||||
#~ "selected proxy node. Pick an overseas service: a domestic resolver "
|
||||
#~ "answers these queries with polluted or NXDOMAIN results, which is what "
|
||||
#~ "makes a foreign site fail to resolve while the proxy itself works. "
|
||||
#~ "Support UDP, TCP, DoH, DoQ, DoT. TCP protocol will be used if not "
|
||||
#~ "specified."
|
||||
#~ msgstr ""
|
||||
#~ "解析所有不在中国解析路径上的域名,并通过所选代理节点发出查询。请选择境外服"
|
||||
#~ "务:国内解析器会返回被污染或 NXDOMAIN 的结果,这正是代理本身正常、境外网站"
|
||||
#~ "却解析失败的原因。支持 UDP、TCP、DoH、DoQ、DoT,未指定协议时使用 TCP。"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Support UDP, TCP, DoH, DoQ, DoT. TCP protocol will be used if not "
|
||||
#~ "specified."
|
||||
|
||||
@@ -26,15 +26,6 @@ config homeproxy-pro 'config'
|
||||
option main_udp_node 'same'
|
||||
option dns_server '8.8.8.8'
|
||||
option china_dns_server '223.5.5.5'
|
||||
# Bootstrap resolver for the DoH/DoT endpoint's own hostname. Without
|
||||
# it `main-dns` borrows the WAN resolver, so the one lookup that decides
|
||||
# where every proxied name goes is answered by the ISP: poisoning that
|
||||
# single answer is enough to break the whole DNS split, and it is the
|
||||
# only query that was still leaving through the ISP after the split
|
||||
# itself was configured correctly. This is a conffile, so upgrading
|
||||
# never rewrites an existing /etc/config/homeproxy-pro - the value below
|
||||
# only reaches fresh installs.
|
||||
list bootstrap_dns '223.5.5.5'
|
||||
option routing_mode 'bypass_mainland_china'
|
||||
option routing_port 'common'
|
||||
option proxy_mode 'redirect_tproxy'
|
||||
|
||||
@@ -385,7 +385,6 @@ export const Loader = {
|
||||
/* A2.1: scalar + list fields on the `config` section. */
|
||||
dns_server: opt(uci, 'main', 'dns_server'),
|
||||
china_dns_server: opt(uci, 'main', 'china_dns_server'),
|
||||
bootstrap_dns: opt(uci, 'main', 'bootstrap_dns') || [],
|
||||
log_level: opt(uci, 'main', 'log_level') || 'warn',
|
||||
tun_dns_mode: opt(uci, 'main', 'tun_dns_mode'),
|
||||
tun_dns_address: opt(uci, 'main', 'tun_dns_address'),
|
||||
|
||||
@@ -94,26 +94,6 @@ export function build_context(dm, env) {
|
||||
? env.wan_dns
|
||||
: ((routing_mode in ['proxy_mainland_china', 'global']) ? '8.8.8.8' : '223.5.5.5');
|
||||
|
||||
/* Bootstrap resolvers: the servers the proxy path uses to look up a DNS
|
||||
* server's *own* hostname. `main-dns` is the user's DoH/DoT endpoint
|
||||
* and the only server whose address may be a name, so this lookup has to
|
||||
* work before any configured resolver can answer.
|
||||
*
|
||||
* It used to be borrowed from default-dns (the WAN/ISP resolver), which
|
||||
* is the one resolver a polluted or unreachable WAN takes down; the
|
||||
* option lets the user name a resolver that still answers. Empty means
|
||||
* "keep using the WAN resolver", so an untouched configuration
|
||||
* generates exactly the same bytes as before. */
|
||||
const bootstrap_dns = [];
|
||||
if (type(dm.general.bootstrap_dns) === 'array') {
|
||||
for (let server in dm.general.bootstrap_dns)
|
||||
if (!isEmpty(server))
|
||||
push(bootstrap_dns, server);
|
||||
} else if (!isEmpty(dm.general.bootstrap_dns)) {
|
||||
/* UCI hands back a bare string for a list with a single value. */
|
||||
push(bootstrap_dns, dm.general.bootstrap_dns);
|
||||
}
|
||||
|
||||
/* dns/routing fields used by both sections */
|
||||
const dns_optimistic_cache = (dm.dns.settings || {}).optimistic_cache || '0';
|
||||
const dns_optimistic_timeout = (dm.dns.settings || {}).optimistic_timeout;
|
||||
@@ -157,7 +137,7 @@ export function build_context(dm, env) {
|
||||
tcpip_stack, endpoint_independent_nat,
|
||||
udp_timeout, udp_mapping, udp_filtering, udp_nat_max,
|
||||
tun_dns_mode, tun_dns_address,
|
||||
wan_dns, bootstrap_dns, dns_optimistic_cache, dns_optimistic_timeout,
|
||||
wan_dns, dns_optimistic_cache, dns_optimistic_timeout,
|
||||
dns_query_timeout, dns_store_dns,
|
||||
default_interface: (dm.access_control.control || {}).bind_interface,
|
||||
|
||||
|
||||
@@ -92,15 +92,69 @@ const NAPTR_BYPASS_SUFFIXES = [
|
||||
'pub.3gppnetwork.org'
|
||||
];
|
||||
|
||||
/* The address of the bootstrap resolver, or null when there is none.
|
||||
*
|
||||
* Every DNS server whose address is a *hostname* needs a domain_resolver
|
||||
* before sing-box will start it, and that lookup is the one step nothing
|
||||
* else can bootstrap: it has to work before any of the configured servers
|
||||
* can answer. `main-dns` is exactly that case - it is the user's DoH/DoT
|
||||
* endpoint - and it used to borrow default-dns (the WAN/ISP resolver) for
|
||||
* it, which is the single resolver a polluted or unreachable WAN takes down.
|
||||
*
|
||||
* It used to be a field of its own in the form, which made no sense to read:
|
||||
* a second DNS address next to the China DNS server, both of them a bare
|
||||
* public IP, for a lookup that happens once at startup. It is derived now,
|
||||
* from the China DNS server, which is the one address this router already
|
||||
* knows it can reach directly. That answer is only usable when it is a bare
|
||||
* IP: the option also accepts the literal 'wan' and a DoH/DoT URL, and both
|
||||
* of those are hostnames - a hostname cannot resolve the hostname it would be
|
||||
* needed to resolve. For those, and only for those, this returns null and
|
||||
* main-dns keeps borrowing the WAN resolver, exactly as it did before any of
|
||||
* this existed.
|
||||
*/
|
||||
function bootstrap_addr(ctx) {
|
||||
const addr = ctx.china_dns_server;
|
||||
if (isEmpty(addr))
|
||||
return null;
|
||||
|
||||
return (match(addr, /^[0-9]+(\.[0-9]+){3}$/) != null
|
||||
|| match(addr, /^[0-9a-fA-F:]+$/) != null) ? addr : null;
|
||||
}
|
||||
|
||||
/* Append the bootstrap resolver, when there is a usable address for it.
|
||||
*
|
||||
* The bootstrap server carries a plain IP, has no domain_resolver of its own
|
||||
* and is never referenced by a DNS rule: it exists only as the target of the
|
||||
* domain_resolver pointer, so there is no cycle for sing-box to reject.
|
||||
* Nothing is emitted when there is no such address ("resolve through the WAN
|
||||
* resolver"), which keeps a configuration whose China DNS server is a
|
||||
* hostname byte-identical to one that never had this.
|
||||
*
|
||||
* It is emitted only alongside main-dns: without a node there is no DoH/DoT
|
||||
* endpoint to bootstrap, and a server nothing points at is just noise. */
|
||||
function append_bootstrap_dns(config, ctx) {
|
||||
const addr = bootstrap_addr(ctx);
|
||||
if (isEmpty(addr) || isEmpty(ctx.main_node))
|
||||
return;
|
||||
|
||||
push(config.dns.servers, {
|
||||
tag: 'bootstrap-dns',
|
||||
type: 'udp',
|
||||
server: addr,
|
||||
detour: ctx.self_mark ? 'direct-out' : null
|
||||
});
|
||||
}
|
||||
|
||||
function append_proxy_dns(config, dm, ctx) {
|
||||
if (isEmpty(ctx.main_node))
|
||||
return;
|
||||
|
||||
/* The user's DoH/DoT endpoint is the one server in this block whose
|
||||
* address is a hostname, so it is the one that needs the bootstrap
|
||||
* resolver; without a configured one it keeps resolving through
|
||||
* default-dns (the WAN resolver), exactly as before. */
|
||||
const main_resolver = isEmpty(ctx.bootstrap_dns) ? 'default-dns' : 'bootstrap-dns';
|
||||
* resolver. Which resolver that is follows the China DNS server - the
|
||||
* one direct-routable address already configured for this router - and
|
||||
* only when it is a bare IP; see bootstrap_addr(). */
|
||||
const main_resolver = isEmpty(bootstrap_addr(ctx)) ? 'default-dns' : 'bootstrap-dns';
|
||||
|
||||
/* Main DNS */
|
||||
push(config.dns.servers, {
|
||||
@@ -484,39 +538,6 @@ function initDns(config, ctx) {
|
||||
};
|
||||
}
|
||||
|
||||
/* Append the bootstrap resolver, if the user configured one.
|
||||
*
|
||||
* Every DNS server whose address is a *hostname* needs a domain_resolver
|
||||
* before sing-box will start it, and that lookup is the one step nothing
|
||||
* else can bootstrap: it has to work before any of the configured servers
|
||||
* can answer. `main-dns` is exactly that case - it is the user's DoH/DoT
|
||||
* endpoint - and it used to borrow default-dns (the WAN/ISP resolver) for
|
||||
* it, which is the single resolver a polluted or unreachable WAN takes down.
|
||||
*
|
||||
* The bootstrap server carries a plain IP, has no domain_resolver of its own
|
||||
* and is never referenced by a DNS rule: it exists only as the target of the
|
||||
* domain_resolver pointer, so there is no cycle for sing-box to reject.
|
||||
* Nothing is emitted when the list is empty ("resolve through the WAN
|
||||
* resolver"), which keeps an untouched configuration byte-identical.
|
||||
*
|
||||
* Only the first entry is used. sing-box resolves a hostname through
|
||||
* exactly one transport (`DomainResolveOptions.Server` is a single tag), and
|
||||
* registering extra servers would not make them a fallback chain - it would
|
||||
* only leave unused servers in the config. The list form is kept because
|
||||
* the option is a DynamicList in the UI and a value with several entries
|
||||
* must not produce an unparseable address. */
|
||||
function append_bootstrap_dns(config, ctx) {
|
||||
if (isEmpty(ctx.bootstrap_dns))
|
||||
return;
|
||||
|
||||
push(config.dns.servers, {
|
||||
tag: 'bootstrap-dns',
|
||||
type: 'udp',
|
||||
server: ctx.bootstrap_dns[0],
|
||||
detour: ctx.self_mark ? 'direct-out' : null
|
||||
});
|
||||
}
|
||||
|
||||
/* Build the sing-box `dns` block. Mutates `config` and returns it for
|
||||
* chaining. Routing mode is determined by ctx.routing_mode: any non-
|
||||
* 'custom' mode follows the proxy path (the proxy-mode split inside the
|
||||
|
||||
@@ -282,7 +282,7 @@ Two further host differences are bridged so the remaining checks still run:
|
||||
| `tests/ucode/test_parser_flatten.uc` | Round-trip invariant for the canonical-Node pipeline: `flatten(normalize(parse_uri(uri)))` must equal the parser's flat UCI dict field-for-field for every supported scheme. This is what stops the parser, the Loader's `PROTOCOL_OPTIONS` (now derived from `parser/mapping.uc`) and the Repository's flatten from drifting apart. |
|
||||
| `tests/ucode/test_subscription_repository.uc` | Integration test for `subscription/repository.uc`: stages a sandboxed UCI file with a user node, a kept subscription node, and a dropped subscription node, then runs `Repository.apply_nodes` and asserts (a) the user node is untouched, (b) the kept node has the new fields and no stale fields, (c) the dropped node is gone, (d) a brand-new node is added under `md5(group+label)`. PR-03 added the `apply_main_node_refs` paths (urltest prune + missing-target switch + reset-to-nil) and the `scrub_stale_urltest_refs` pass to the same test. |
|
||||
| `tests/ucode/test_generators.sh` | Runs `generate_client.uc`/`generate_server.uc` against the UCI fixtures in `tests/fixtures/generators/` inside a scratch directory (the `uci` cursor and `HP_DIR`/`RUN_DIR` are redirected) and validates each result with `sing-box check`. The `redirect` case is the product's default `proxy_mode` and asserts, from the emitted JSON, that every dialling outbound carries the runtime `routing_mark`. |
|
||||
| `tests/ucode/test_dns_proxy_list.sh` | The `proxy_list.txt` → `dns.rules` plumbing and the bootstrap resolver, neither of which `run_case()` in the generator suite can see (it truncates both resource lists before every case and the fixture has no `bootstrap_dns` option). Patches the client fixture to each of the four proxy modes with both lists populated, and asserts the DNS rule order (`direct-domain` < `proxy-domain` via `main-dns` < the SVCB/HTTPS reject, `geosite-cn` last when the mode emits it) plus the routing half's `"tag": "proxy-domain"` and `route.final: main-out`. Then, separately: with `bootstrap_dns` set, `main-dns` must resolve its own hostname through `bootstrap-dns` and that server must carry no `domain_resolver`; with it unset, no `bootstrap-dns` server may be emitted at all. |
|
||||
| `tests/ucode/test_dns_proxy_list.sh` | The `proxy_list.txt` → `dns.rules` plumbing and the bootstrap resolver, neither of which `run_case()` in the generator suite can see (it truncates both resource lists before every case and the fixture has no `china_dns_server` option). Patches the client fixture to each of the four proxy modes with both lists populated, and asserts the DNS rule order (`direct-domain` < `proxy-domain` via `main-dns` < the SVCB/HTTPS reject, `geosite-cn` last when the mode emits it) plus the routing half's `"tag": "proxy-domain"` and `route.final: main-out`. Then, separately, the bootstrap resolver: it is derived from `china_dns_server`, so a bare IP there must make `main-dns` resolve its own hostname through `bootstrap-dns` with no `domain_resolver` of its own, and a DoH URL there (a hostname, which cannot resolve a hostname) must emit no `bootstrap-dns` server at all and leave `main-dns` on `default-dns`. |
|
||||
| `tests/toolchain/build-ucode-linux.sh` | Builds the local ucode toolchain described above; not part of `tests/run.sh`. |
|
||||
| `tests/toolchain/validate-data.sh` | Off-target stand-in for `/sbin/validate_data`, used through `HP_VALIDATE_DATA`; not part of `tests/run.sh`. |
|
||||
| `tests/ucode/test_ucode_grammar.sh` | Pins the ucode dialect: the toolchain must reject `export function ... }` without `;` and object/array destructuring, and must accept the constructs the package uses (`?.`/`??`, object spread, computed keys, template literals). |
|
||||
|
||||
@@ -2065,31 +2065,48 @@ rm -rf "$SNAP_TMP"
|
||||
trap - EXIT INT TERM
|
||||
|
||||
echo
|
||||
echo "== guard 45: a fresh install bootstraps main-dns, an untouched config still does not =="
|
||||
echo "== guard 45: the bootstrap resolver is derived, not configured =="
|
||||
|
||||
# E3. With no bootstrap_dns, `main-dns` (the DoH/DoT endpoint) falls back to
|
||||
# the WAN resolver, so the ISP answers the one lookup that decides where every
|
||||
# proxied name goes. The package default below closes that for fresh
|
||||
# installs; this guard exists so neither half drifts silently:
|
||||
# (a) an explicitly empty list must still emit NO bootstrap-dns server, so
|
||||
# a user who clears the field gets the old behaviour back rather than a
|
||||
# resolver the generator invents for them;
|
||||
# (b) the package-shipped default is what makes the fix reach a new install
|
||||
# at all - the field is read from the 'config' section, and the file is
|
||||
# a conffile, so this line only lands on fresh installs.
|
||||
if grep -q "if (isEmpty(ctx.bootstrap_dns))" "$SCRIPTS/generator/dns.uc"; then
|
||||
pass "an empty bootstrap_dns still emits no bootstrap-dns server"
|
||||
# main-dns is the user's DoH/DoT endpoint and the one server in the config
|
||||
# whose address is a hostname, so it needs a domain_resolver before it can
|
||||
# answer. It used to borrow default-dns - the WAN/ISP resolver - which makes
|
||||
# the ISP the answerer of the single query that decides where every proxied
|
||||
# name goes. It used to be a form field for that; it is derived now, from the
|
||||
# China DNS server. Both halves are pinned:
|
||||
# (a) the generator must read the China DNS server, never a separate option
|
||||
# - a second DNS address next to the China one made no sense to read;
|
||||
# (b) a bare IP is the only usable value, because the option also accepts
|
||||
# 'wan' and a DoH/DoT URL, and a hostname cannot resolve a hostname.
|
||||
if grep -q "const addr = ctx.china_dns_server;" "$SCRIPTS/generator/dns.uc"; then
|
||||
pass "the bootstrap address is taken from the China DNS server"
|
||||
else
|
||||
fail "append_bootstrap_dns no longer short-circuits on an empty bootstrap_dns - a"
|
||||
fail "user who cleared the field would get a resolver they did not ask for"
|
||||
fail "bootstrap_addr() no longer reads ctx.china_dns_server - if it reads a"
|
||||
fail "separate option again, main-dns may fall back to the WAN resolver"
|
||||
fi
|
||||
|
||||
if grep -q "^ list bootstrap_dns '223.5.5.5'" "$ROOT/root/etc/config/homeproxy-pro"; then
|
||||
pass "a fresh install ships a bootstrap_dns, so main-dns never asks the ISP"
|
||||
if grep -qE "match\(addr, /\^\[0-9\]\+" "$SCRIPTS/generator/dns.uc" &&
|
||||
grep -qE "match\(addr, /\^\[0-9a-fA-F:\]\+" "$SCRIPTS/generator/dns.uc"; then
|
||||
pass "only a bare IP is accepted as the bootstrap address"
|
||||
else
|
||||
fail "the package-shipped /etc/config/homeproxy-pro no longer ships a bootstrap_dns -"
|
||||
fail "a new install would resolve its DoH endpoint's hostname through the WAN"
|
||||
fail "resolver, which is the last query that still leaves via the ISP"
|
||||
fail "bootstrap_addr() no longer rejects a non-IP value - a DoH URL or the"
|
||||
fail "literal 'wan' is a hostname, and using one to resolve a hostname is a cycle"
|
||||
fi
|
||||
|
||||
# The option is gone from the form and from the shipped config; leaving either
|
||||
# would mean a value nothing reads, which is how the confusing second field
|
||||
# came to exist in the first place.
|
||||
if grep -q "bootstrap_dns" "$ROOT/root/etc/config/homeproxy-pro"; then
|
||||
fail "the package-shipped /etc/config/homeproxy-pro still carries a bootstrap_dns -"
|
||||
fail "the generator derives it now, so this option is read by nothing"
|
||||
else
|
||||
pass "the package-shipped /etc/config/homeproxy-pro carries no bootstrap_dns"
|
||||
fi
|
||||
|
||||
if grep -rq "bootstrap_dns" "$ROOT/htdocs/luci-static/resources/view/homeproxy-pro/"; then
|
||||
fail "a view still renders a bootstrap_dns field - the value is derived from"
|
||||
fail "the China DNS server, and a second DNS address only reads as a mistake"
|
||||
else
|
||||
pass "no view offers a bootstrap_dns field any more"
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
@@ -3281,8 +3281,8 @@
|
||||
{
|
||||
"kind": "Value",
|
||||
"name": "dns_server",
|
||||
"title": "DNS server",
|
||||
"description": "Resolves every domain that is not on the China DNS path, through the selected proxy node. Pick an overseas service: a domestic resolver answers these queries with polluted or NXDOMAIN results, which is what makes a foreign site fail to resolve while the proxy itself works. Support UDP, TCP, DoH, DoQ, DoT. TCP protocol will be used if not specified.",
|
||||
"title": "Overseas DNS server",
|
||||
"description": "Resolves every domain that is not on the China DNS path, through the selected proxy node. A domestic resolver answers these queries with polluted or NXDOMAIN results, which is what makes a foreign site fail to resolve while the proxy itself works - so only overseas services are offered here. Support UDP, TCP, DoH, DoQ, DoT. TCP protocol will be used if not specified.",
|
||||
"depends": [
|
||||
{
|
||||
"routing_mode": "custom",
|
||||
@@ -3290,10 +3290,6 @@
|
||||
}
|
||||
],
|
||||
"values": [
|
||||
[
|
||||
"wan",
|
||||
"WAN DNS (read from interface)"
|
||||
],
|
||||
[
|
||||
"1.1.1.1",
|
||||
"CloudFlare Public DNS (1.1.1.1)"
|
||||
@@ -3305,29 +3301,13 @@
|
||||
[
|
||||
"8.8.8.8",
|
||||
"Google Public DNS (8.8.8.8)"
|
||||
],
|
||||
[
|
||||
"",
|
||||
"---"
|
||||
],
|
||||
[
|
||||
"223.5.5.5",
|
||||
"Aliyun Public DNS (223.5.5.5)"
|
||||
],
|
||||
[
|
||||
"119.29.29.29",
|
||||
"Tencent Public DNS (119.29.29.29)"
|
||||
],
|
||||
[
|
||||
"117.50.10.10",
|
||||
"ThreatBook Public DNS (117.50.10.10)"
|
||||
]
|
||||
],
|
||||
"subsection": null,
|
||||
"props": {
|
||||
"default": "8.8.8.8",
|
||||
"rmempty": false,
|
||||
"validate": "fn(758:77dbe8107e5c)"
|
||||
"validate": "fn(730:48f7f360fbd2)"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -3387,24 +3367,6 @@
|
||||
"rmempty": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "DynamicList",
|
||||
"name": "bootstrap_dns",
|
||||
"title": "Bootstrap DNS server",
|
||||
"description": "Resolver used to look up the DNS server's own hostname - only relevant when that address is a domain, as with a DoH/DoT endpoint. Leave empty to use the WAN resolver. Only the first entry is used.",
|
||||
"depends": [
|
||||
{
|
||||
"routing_mode": "custom",
|
||||
"!reverse": true
|
||||
}
|
||||
],
|
||||
"values": [],
|
||||
"subsection": null,
|
||||
"props": {
|
||||
"datatype": "ipaddr",
|
||||
"modalonly": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "SectionValue",
|
||||
"name": "_dns_cache",
|
||||
|
||||
@@ -20,10 +20,13 @@
|
||||
#
|
||||
# 2. The bootstrap resolver: the DoH/DoT endpoint (main-dns) is the only
|
||||
# server whose address is a hostname, and it used to borrow default-dns
|
||||
# (the WAN/ISP resolver) for that lookup. When the user configures a
|
||||
# bootstrap resolver, main-dns must point at it instead, and that server
|
||||
# must stay at the bottom of the chain (no domain_resolver of its own,
|
||||
# no DNS rule routing to it) or the lookup depends on itself.
|
||||
# (the WAN/ISP resolver) for that lookup, which makes the ISP the
|
||||
# answerer of the one query that decides where every proxied name goes.
|
||||
# The resolver is derived from the China DNS server now, so both halves
|
||||
# of that rule are asserted: a bare IP there yields a bootstrap-dns that
|
||||
# main-dns points at and which carries no domain_resolver of its own,
|
||||
# and a hostname there yields no bootstrap server at all (a hostname
|
||||
# cannot resolve the hostname it would be needed to resolve).
|
||||
#
|
||||
# Usage: sh tests/ucode/test_dns_proxy_list.sh <repo-root> [work-dir]
|
||||
|
||||
@@ -34,7 +37,8 @@ ROOT="$(cd "$ROOT" && pwd)"
|
||||
FIXTURE="$ROOT/tests/fixtures/generators/client.uci"
|
||||
DIRECT_DOMAIN="direct.example.cn"
|
||||
PROXY_DOMAIN="play.example.cn"
|
||||
BOOTSTRAP_DNS="223.5.5.5"
|
||||
CHINA_DNS_IP="223.5.5.5"
|
||||
CHINA_DNS_DOH="https://dns.alidns.com/dns-query"
|
||||
FAILED=0
|
||||
|
||||
rm -rf "$WORK"
|
||||
@@ -42,12 +46,14 @@ mkdir -p "$WORK"
|
||||
|
||||
# Stage the checkout the way test_generators.sh does: HP_DIR/RUN_DIR/UCICONFIG_DIR
|
||||
# are rewritten into the work dir and the fixture is copied in as the UCI
|
||||
# config. The extra bootstrap line is appended to the `config` section here
|
||||
# (the section's first named section), which is how the Loader reads it.
|
||||
# config. The fixture carries no china_dns_server (the generator then falls
|
||||
# back to the Aliyun public resolver), so the line is inserted into the
|
||||
# `config` section here - the section the Loader reads it from. It has to be
|
||||
# inserted rather than substituted for that reason.
|
||||
stage_case() {
|
||||
dir="$1"
|
||||
label="$2"
|
||||
bootstrap="$3"
|
||||
china_dns="$3"
|
||||
fixture="$4"
|
||||
|
||||
rm -rf "$dir"
|
||||
@@ -55,9 +61,9 @@ stage_case() {
|
||||
"$dir/scripts/parser" "$dir/resources"
|
||||
|
||||
cp "$fixture" "$dir/config/homeproxy-pro"
|
||||
if [ -n "$bootstrap" ]; then
|
||||
if [ -n "$china_dns" ]; then
|
||||
sed -i "/^\toption routing_mode /i\\
|
||||
\toption bootstrap_dns '$bootstrap'
|
||||
\toption china_dns_server '$china_dns'
|
||||
" "$dir/config/homeproxy-pro"
|
||||
fi
|
||||
|
||||
@@ -237,18 +243,18 @@ check_proxy_list() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# --- 1. bootstrap resolver -------------------------------------------------
|
||||
# --- 1. bootstrap resolver, derived from a bare-IP China DNS server ---------
|
||||
|
||||
dir="$WORK/bootstrap"
|
||||
if stage_case "$dir" "bootstrap" "$BOOTSTRAP_DNS" "$FIXTURE"; then
|
||||
if stage_case "$dir" "bootstrap" "$CHINA_DNS_IP" "$FIXTURE"; then
|
||||
json="$dir/run/sing-box-c.json"
|
||||
|
||||
bootstrap_line="$(grep -nF '"tag": "bootstrap-dns"' "$json" | head -1 | cut -d: -f1)"
|
||||
if [ -z "$bootstrap_line" ]; then
|
||||
echo "FAIL: bootstrap: no bootstrap-dns server was emitted"
|
||||
echo "FAIL: bootstrap: a bare-IP China DNS server produced no bootstrap-dns server"
|
||||
FAILED=1
|
||||
elif ! sed -n "$bootstrap_line,$((bootstrap_line + 4))p" "$json" | grep -qF "\"$BOOTSTRAP_DNS\""; then
|
||||
echo "FAIL: bootstrap: bootstrap-dns does not carry $BOOTSTRAP_DNS"
|
||||
elif ! sed -n "$bootstrap_line,$((bootstrap_line + 4))p" "$json" | grep -qF "\"$CHINA_DNS_IP\""; then
|
||||
echo "FAIL: bootstrap: bootstrap-dns does not carry the China DNS server ($CHINA_DNS_IP)"
|
||||
FAILED=1
|
||||
elif sed -n "$bootstrap_line,$((bootstrap_line + 4))p" "$json" | grep -qF '"domain_resolver"'; then
|
||||
echo "FAIL: bootstrap: the bootstrap resolver has a domain_resolver of its own"
|
||||
@@ -264,26 +270,30 @@ if stage_case "$dir" "bootstrap" "$BOOTSTRAP_DNS" "$FIXTURE"; then
|
||||
echo "FAIL: bootstrap: main-dns still resolves through the WAN resolver"
|
||||
FAILED=1
|
||||
else
|
||||
echo "PASS: bootstrap: main-dns resolves its own hostname through bootstrap-dns ($BOOTSTRAP_DNS)"
|
||||
echo "PASS: bootstrap: main-dns resolves its own hostname through bootstrap-dns ($CHINA_DNS_IP)"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
# --- 2. the default (no bootstrap configured) ------------------------------
|
||||
# --- 2. a hostname China DNS server is not a usable bootstrap --------------
|
||||
# The option also accepts a DoH/DoT URL, and a URL is a hostname: using one to
|
||||
# resolve the hostname it would be needed to resolve is the cycle this whole
|
||||
# mechanism exists to avoid. It must fall back to the WAN resolver, loudly
|
||||
# enough to be visible here, rather than to a broken bootstrap.
|
||||
|
||||
dir="$WORK/default"
|
||||
if stage_case "$dir" "default" "" "$FIXTURE"; then
|
||||
dir="$WORK/hostname"
|
||||
if stage_case "$dir" "hostname" "$CHINA_DNS_DOH" "$FIXTURE"; then
|
||||
json="$dir/run/sing-box-c.json"
|
||||
if grep -qF '"tag": "bootstrap-dns"' "$json"; then
|
||||
echo "FAIL: default: an unconfigured bootstrap resolver was emitted"
|
||||
echo "FAIL: hostname: a DoH China DNS server was used as the bootstrap resolver"
|
||||
FAILED=1
|
||||
elif ! grep -qF '"server": "default-dns"' "$json"; then
|
||||
echo "FAIL: default: main-dns no longer resolves through the WAN resolver"
|
||||
echo "FAIL: hostname: no bootstrap server and main-dns does not use default-dns either"
|
||||
FAILED=1
|
||||
else
|
||||
echo "PASS: default: no bootstrap server, main-dns still resolves through default-dns"
|
||||
echo "PASS: hostname: a DoH China DNS server yields no bootstrap server, main-dns uses default-dns"
|
||||
fi
|
||||
else
|
||||
FAILED=1
|
||||
|
||||
@@ -9,8 +9,8 @@ LUCI_TITLE:=LuCI for HomeRedirect
|
||||
LUCI_DEPENDS:=+HomeRedirect
|
||||
LUCI_PKGARCH:=all
|
||||
PKG_NAME:=luci-app-homeredirect
|
||||
PKG_VERSION:=1.0
|
||||
PKG_RELEASE:=1
|
||||
PKG_VERSION:=2.0
|
||||
PKG_RELEASE:=2
|
||||
PKG_MAINTAINER:=Richard Yu <xiaoqingfengatgm@gmail.com>
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
-- Copyright 2020 Richard <xiaoqingfengatgm@gmail.com>
|
||||
-- Copyright 2020-2026 Richard <xiaoqingfengatgm@gmail.com>
|
||||
-- feed site : https://github.com/xiaoqingfengATGH/feeds-xiaoqingfeng
|
||||
module("luci.controller.homeredirect", package.seeall)
|
||||
local appname = "homeredirect"
|
||||
local RUNLOG_DIR = "/tmp/hr"
|
||||
local ucic = luci.model.uci.cursor()
|
||||
local http = require "luci.http"
|
||||
|
||||
function index()
|
||||
|
||||
entry({"admin", "services", "homeredirect", "show"}, call("show_menu")).leaf = true
|
||||
entry({"admin", "services", "homeredirect", "hide"}, call("hide_menu")).leaf = true
|
||||
|
||||
if nixio.fs.access("/etc/config/homeredirect") and
|
||||
nixio.fs.access("/etc/config/homeredirect_show") then
|
||||
entry({"admin", "services", "homeredirect"},
|
||||
entry({"admin", "services", "homeredirect", "hide"}, call("hide_menu")).leaf = true
|
||||
|
||||
if nixio.fs.access("/etc/config/homeredirect") and
|
||||
nixio.fs.access("/etc/config/homeredirect_show") then
|
||||
entry({"admin", "services", "homeredirect"},
|
||||
alias("admin", "services", "homeredirect", "settings"),
|
||||
_("Home Redirect"), 50).dependent = true
|
||||
end
|
||||
|
||||
entry({"admin", "services", "homeredirect", "settings"},
|
||||
cbi("homeredirect/settings")).leaf = true
|
||||
entry({"admin", "services", "homeredirect", "status"}, call("status")).leaf =
|
||||
true
|
||||
end
|
||||
|
||||
entry({"admin", "services", "homeredirect", "settings"},
|
||||
cbi("homeredirect/settings")).leaf = true
|
||||
entry({"admin", "services", "homeredirect", "status"}, call("status")).leaf = true
|
||||
end
|
||||
|
||||
local function http_write_json(content)
|
||||
@@ -30,33 +27,39 @@ local function http_write_json(content)
|
||||
end
|
||||
|
||||
function status()
|
||||
local e = {}
|
||||
-- per-rule running state via procd service instances: each redirect runs
|
||||
-- as its own procd instance named after the uci section id
|
||||
local e = {}
|
||||
local running = {}
|
||||
local stats = luci.util.ubus("service", "list", {name = appname, verbose = true}) or {}
|
||||
local instances = (stats[appname] or {}).instances or {}
|
||||
for _, inst in pairs(instances) do
|
||||
if inst.running == true then
|
||||
-- instance command carries the log path /tmp/hr/<id>.log
|
||||
local cmd = table.concat(inst.command or {}, " ")
|
||||
local id = cmd:match("/tmp/hr/([%w_]+)%.log")
|
||||
if id then running[id] = 1 end
|
||||
end
|
||||
end
|
||||
|
||||
e.enabled = ucic:get(appname, "@global[0]", "enabled")
|
||||
ucic:foreach(appname, "redirect", function(redirect)
|
||||
local state = -1
|
||||
local id = redirect['.name']
|
||||
local enabled = redirect['enabled']
|
||||
if enabled == "1" then
|
||||
local pid = luci.sys.exec("ps | grep socat | grep " .. RUNLOG_DIR .. "/" .. id .. " | sed '/grep/d' | awk -F ' ' '{print $1}'")
|
||||
if pid == "" then
|
||||
state = 0
|
||||
else
|
||||
state = tonumber(pid)
|
||||
end
|
||||
local state = -1
|
||||
if redirect['enabled'] == "1" then
|
||||
state = running[id] and 1 or 0
|
||||
end
|
||||
e[id] = state
|
||||
end)
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
http_write_json(e)
|
||||
end
|
||||
|
||||
function show_menu()
|
||||
luci.sys.call("touch /etc/config/homeredirect_show")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "homeredirect"))
|
||||
luci.sys.call("touch /etc/config/homeredirect_show")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "homeredirect"))
|
||||
end
|
||||
|
||||
function hide_menu()
|
||||
luci.sys.call("rm -rf /etc/config/homeredirect_show")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin", "status", "overview"))
|
||||
luci.sys.call("rm -rf /etc/config/homeredirect_show")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin", "status", "overview"))
|
||||
end
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
local s = require "luci.sys"
|
||||
local m, s, o
|
||||
local sys = require "luci.sys"
|
||||
local fs = require "nixio.fs"
|
||||
|
||||
mp = Map("homeredirect", translate("Home Redirect - Port forwarding utility"))
|
||||
mp.description = translate("HomeRedirect is a customized port forwarding utility for HomeLede. It supports TCP / UDP protocol, IPv4 and IPv6.")
|
||||
mp.description = translate("HomeLede port forwarding application - fills the gaps left by firewall port forwarding, mainly used for cross-family forwarding under CGNAT.")
|
||||
mp:section(SimpleSection).template = "homeredirect/index"
|
||||
|
||||
s = mp:section(TypedSection, "global")
|
||||
@@ -11,11 +13,64 @@ enabled = s:option(Flag, "enabled", translate("Master switch"))
|
||||
enabled.default = 0
|
||||
enabled.rmempty = false
|
||||
|
||||
-- TLS certificate pair: configure both or neither; files must exist
|
||||
cert = s:option(Value, "cert", translate("TLS certificate"),
|
||||
translate("Required by TLS rules. PEM certificate path, e.g. /etc/acme/your.domain/fullchain.cer. Configure together with the private key."))
|
||||
cert.optional = true
|
||||
cert.rmempty = true
|
||||
|
||||
key = s:option(Value, "key", translate("TLS private key"),
|
||||
translate("PEM private key path matching the certificate above, e.g. /etc/acme/your.domain/your.domain.key. With a combined cert+key file, set both fields to the same path."))
|
||||
key.optional = true
|
||||
key.rmempty = true
|
||||
|
||||
cert.validate = function(self, value, section)
|
||||
if value and #value > 0 then
|
||||
local kv = key:formvalue(section)
|
||||
if not kv or #kv == 0 then
|
||||
return nil, translate("Private key is missing - certificate and key must be configured as a pair")
|
||||
end
|
||||
if not fs.access(value) then
|
||||
return nil, translate("Certificate file not found")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
key.validate = function(self, value, section)
|
||||
if value and #value > 0 then
|
||||
local cv = cert:formvalue(section)
|
||||
if not cv or #cv == 0 then
|
||||
return nil, translate("Certificate is missing - certificate and key must be configured as a pair")
|
||||
end
|
||||
if not fs.access(value) then
|
||||
return nil, translate("Key file not found")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "_tls_status", translate("TLS status"))
|
||||
o.rawhtml = true
|
||||
o.cfgvalue = function(self, section)
|
||||
local c = cert:cfgvalue(section)
|
||||
local k = key:cfgvalue(section)
|
||||
if c and #c > 0 and k and #k > 0 then
|
||||
if fs.access(c) and fs.access(k) then
|
||||
return '<font color="green"><b>' .. translate("Ready") .. '</b></font>'
|
||||
else
|
||||
return '<font color="red"><b>' .. translate("File missing") .. '</b></font>'
|
||||
end
|
||||
end
|
||||
return '<font color="gray">' .. translate("Not configured") .. '</font>'
|
||||
end
|
||||
|
||||
s = mp:section(TypedSection, "redirect", translate("Redirect Configuration"))
|
||||
s.addremove = true
|
||||
s.anonymous = true
|
||||
s.template = "cbi/tblsection"
|
||||
s.sortable = true
|
||||
s.description = translate("Typical scenarios: 1) CGNAT, only public IPv6 - forward a public v6 port to an internal IPv4 service (cross-family). 2) Moving target - use a domain name as destination, re-resolved on every connection. 3) TLS frontend - terminate TLS on the router, backend stays plain.")
|
||||
|
||||
enabled = s:option(Flag, "enabled", translate("Enabled"))
|
||||
enabled.rmempty = false
|
||||
@@ -25,16 +80,13 @@ name.optional = false
|
||||
name.rmempty = false
|
||||
|
||||
proto = s:option(ListValue, "proto", translate("Transport Protocol"))
|
||||
proto.default = "tcp4"
|
||||
proto.default = "tcp6"
|
||||
proto:value("tcp4", "TCP/IPv4")
|
||||
proto:value("udp4", "UDP/IPv4")
|
||||
proto:value("tcp6", "TCP/IPv6")
|
||||
proto:value("udp6", "UDP/IPv6")
|
||||
|
||||
-- src_ip = s:option(Value, "src_ip", translate("Source IP"))
|
||||
-- src_ip.datatype = "ipaddr"
|
||||
-- src_ip.optional = false
|
||||
-- src_ip.rmempty = false
|
||||
proto:value("tls4", "TLS/IPv4")
|
||||
proto:value("tls6", "TLS/IPv6")
|
||||
|
||||
src_dport = s:option(Value, "src_dport", translate("Source Port"))
|
||||
src_dport.datatype = "port"
|
||||
@@ -42,7 +94,6 @@ src_dport.optional = false
|
||||
src_dport.rmempty = false
|
||||
|
||||
dest_ip = s:option(Value, "dest_ip", translate("Destination Address"))
|
||||
dest_ip.datatype = "ipaddr"
|
||||
dest_ip.optional = false
|
||||
dest_ip.rmempty = false
|
||||
|
||||
@@ -51,12 +102,11 @@ dest_port.datatype = "port"
|
||||
dest_port.optional = false
|
||||
dest_port.rmempty = false
|
||||
|
||||
o = s:option(DummyValue, "rs", translate("Status"))
|
||||
o.default = "检测中..."
|
||||
ipv6only = s:option(Flag, "ipv6only", translate("IPv6 only"))
|
||||
ipv6only.default = ipv6only.enabled
|
||||
ipv6only.rmempty = false
|
||||
|
||||
local apply=luci.http.formvalue("cbi.apply")
|
||||
if apply then
|
||||
io.popen("/etc/init.d/homeredirect restart")
|
||||
end
|
||||
o = s:option(DummyValue, "rs", translate("Status"))
|
||||
o.default = "…"
|
||||
|
||||
return mp
|
||||
@@ -1,38 +1,23 @@
|
||||
<% include("cbi/map") %>
|
||||
<%# rendered as a SimpleSection child of the cbi() map; only injects the
|
||||
status poller. Never include("cbi/map") here: the nested template scope
|
||||
has no "readable" var and would render a bogus permission warning. %>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
if(window.jQuery == undefined)
|
||||
{
|
||||
|
||||
/*! jQuery v3.5.0 | (c) 2005, 2020 jQuery Foundation, Inc. | jquery.org/license */
|
||||
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.3",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b="length"in a&&a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|readonly|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^Line truncated
|
||||
|
||||
return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function aa(){return!0}function ba(){return!1}function ca(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var Line truncated
|
||||
return new Za.prototype.init(a,b,c,d,e)}m.Tween=Za,Za.prototype={constructor:Za,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")},cur:function(){var a=Za.propHooks[this.prop];return a&&a.get?a.get(this):Za.propHooks._default.get(this)},run:function(a){var b,c=Za.propHooks[this.prop];return this.options.duration?this.pos=b=m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Za.propHooks._default.set(this),this}},Za.prototype.init.prototype=Za.prototype,Za.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Za.propHooks.scrollTop=Za.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Za.prototype.init,m.fx.step={};var $a,_a,ab=/^(?:toggle|show|hide)$/,bb=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cb=/queueHooks$/,db=[ib],eb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bb.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bb.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fb(){return setTimeout(function(){$a=void 0}),$a=m.now()}function gb(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hb(a,b,c){for(var d,e=(eb[b]||[]).concat(eb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fa(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fa(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ab.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fa(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hb(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=db.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$a||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$a||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);g>f;f++)if(d=db[f].call(j,a,k,j.opts))return d;return m.map(k,hb,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kb,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],eb[cLine truncated
|
||||
|
||||
}
|
||||
|
||||
XHR.poll(3, '<%=luci.dispatcher.build_url("admin", "services", "homeredirect", "status")%>', null,
|
||||
function(x, result)
|
||||
{
|
||||
// cbi-homeredirect-cfg023837-rs
|
||||
$("div[id^=cbi-homeredirect-][id$=-rs]").each(function(idx,ele){
|
||||
var idstr = $(ele).attr("id")
|
||||
var id=idstr.split("-")[2];
|
||||
var els = document.querySelectorAll('div[id^=cbi-homeredirect-][id$=-rs]');
|
||||
for (var i = 0; i < els.length; i++) {
|
||||
var id = els[i].id.split('-')[2];
|
||||
var state = result[id];
|
||||
if(state==-1)
|
||||
{
|
||||
$(ele).html("<%=translate("Disabled")%>");
|
||||
if (state == -1) {
|
||||
els[i].innerHTML = '<%:Disabled%>';
|
||||
} else if (state == 0) {
|
||||
els[i].innerHTML = '<font color="red"><%:Not running%></font>';
|
||||
} else {
|
||||
els[i].innerHTML = '<font color="green"><b><%:Running%></b></font>';
|
||||
}
|
||||
else if(state==0)
|
||||
{
|
||||
$(ele).html("<font color='red'><%=translate("Not running")%></font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
$(ele).html("<font color='green'><b><%=translate("Running")%></b></font>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
)
|
||||
//]]>
|
||||
</script>
|
||||
</script>
|
||||
@@ -1,12 +1,15 @@
|
||||
msgid "Home Redirect"
|
||||
msgstr "端口转发"
|
||||
|
||||
msgid "HomeRedirect is a customized port forwarding utility for HomeLede. It supports TCP / UDP protocol, IPv4 and IPv6."
|
||||
msgstr "HomeRedirect是一款为HomeLede定制的端口转发工具,可以将路由上端口访问转发至任意位置,支持TCP/UDP协议,IPv4和IPv6。"
|
||||
|
||||
msgid "Home Redirect - Port forwarding utility"
|
||||
msgstr "Home Redirect 端口转发"
|
||||
|
||||
msgid "HomeLede port forwarding application - fills the gaps left by firewall port forwarding, mainly used for cross-family forwarding under CGNAT."
|
||||
msgstr "Homelede的端口转发应用,用于填补系统防火墙端口转发缺口,主要应用于CGNAT环境下跨协议栈转发。"
|
||||
|
||||
msgid "Typical scenarios: 1) CGNAT, only public IPv6 - forward a public v6 port to an internal IPv4 service (cross-family). 2) Moving target - use a domain name as destination, re-resolved on every connection. 3) TLS frontend - terminate TLS on the router, backend stays plain."
|
||||
msgstr "典型场景:① CGNAT 仅有公网 IPv6——将公网 v6 端口转发至内网 IPv4 服务(跨族);② 目标地址不固定——目标填域名,每次连接重新解析;③ TLS 前置——路由器终结 TLS,后端保持明文。"
|
||||
|
||||
msgid "Redirect Configuration"
|
||||
msgstr "转发设置"
|
||||
|
||||
@@ -25,9 +28,6 @@ msgstr "转发目标端口"
|
||||
msgid "Name"
|
||||
msgstr "名称"
|
||||
|
||||
msgid "Source IP"
|
||||
msgstr "路由器IP"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
@@ -42,3 +42,66 @@ msgstr "未运行"
|
||||
|
||||
msgid "Running"
|
||||
msgstr "运行中"
|
||||
|
||||
msgid "TLS certificate"
|
||||
msgstr "TLS证书"
|
||||
|
||||
msgid "PEM certificate path, e.g. /etc/acme/your.domain/fullchain.cer"
|
||||
msgstr "PEM 证书路径,如 /etc/acme/你的域名/fullchain.cer"
|
||||
|
||||
msgid "TLS private key"
|
||||
msgstr "TLS私钥"
|
||||
|
||||
msgid "Required by TLS rules. PEM certificate path, e.g. /etc/acme/your.domain/fullchain.cer. Configure together with the private key."
|
||||
msgstr "TLS 规则必填。PEM 证书路径,如 /etc/acme/你的域名/fullchain.cer。须与私钥同时配置。"
|
||||
|
||||
msgid "PEM private key path matching the certificate above, e.g. /etc/acme/your.domain/your.domain.key. With a combined cert+key file, set both fields to the same path."
|
||||
msgstr "与上方证书配对的 PEM 私钥路径,如 /etc/acme/你的域名/你的域名.key。若为证书私钥合一文件,两栏填同一路径即可。"
|
||||
|
||||
msgid "TLS status"
|
||||
msgstr "TLS 状态"
|
||||
|
||||
msgid "Private key is missing - certificate and key must be configured as a pair"
|
||||
msgstr "缺少私钥——证书与私钥必须成对配置"
|
||||
|
||||
msgid "Certificate is missing - certificate and key must be configured as a pair"
|
||||
msgstr "缺少证书——证书与私钥必须成对配置"
|
||||
|
||||
msgid "Certificate file not found"
|
||||
msgstr "证书文件不存在"
|
||||
|
||||
msgid "Key file not found"
|
||||
msgstr "私钥文件不存在"
|
||||
|
||||
msgid "Ready"
|
||||
msgstr "就绪"
|
||||
|
||||
msgid "File missing"
|
||||
msgstr "文件缺失"
|
||||
|
||||
msgid "Not configured"
|
||||
msgstr "未配置"
|
||||
|
||||
msgid "IPv6 only"
|
||||
msgstr "仅IPv6"
|
||||
|
||||
msgid "Enabled"
|
||||
msgstr "启用"
|
||||
|
||||
msgid "TCP/IPv4"
|
||||
msgstr "TCP/IPv4"
|
||||
|
||||
msgid "UDP/IPv4"
|
||||
msgstr "UDP/IPv4"
|
||||
|
||||
msgid "TCP/IPv6"
|
||||
msgstr "TCP/IPv6"
|
||||
|
||||
msgid "UDP/IPv6"
|
||||
msgstr "UDP/IPv6"
|
||||
|
||||
msgid "TLS/IPv4"
|
||||
msgstr "TLS/IPv4"
|
||||
|
||||
msgid "TLS/IPv6"
|
||||
msgstr "TLS/IPv6"
|
||||
@@ -7,13 +7,15 @@
|
||||
}
|
||||
EEOF
|
||||
}
|
||||
# homeredirect uci-defaults: ucitrack registration + legacy cleanup
|
||||
# (rules are regenerated by the init script itself via UCI, no firewall
|
||||
# include script or bash direct-write is needed anymore)
|
||||
|
||||
[ -f /etc/config/homeredirect ] || exit 0
|
||||
|
||||
# migrate away from the 1.x firewall include
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete firewall.homeredirect
|
||||
set firewall.homeredirect=include
|
||||
set firewall.homeredirect.type=script
|
||||
set firewall.homeredirect.path=/etc/homeredirect/firewall.include
|
||||
set firewall.homeredirect.reload=1
|
||||
EOF
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
@@ -23,5 +25,8 @@ uci -q batch <<-EOF >/dev/null
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /etc/homeredirect/firewall.include
|
||||
rm -f /etc/homeredirect/script.sh
|
||||
|
||||
rm -rf /tmp/luci-*cache
|
||||
exit 0
|
||||
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-honk
|
||||
PKG_VERSION:=1.1.4
|
||||
PKG_RELEASE:=9
|
||||
PKG_RELEASE:=10
|
||||
|
||||
LUCI_TITLE:=LuCI support for honk
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{j as e}from"./vendor-react-Bf71BWbF.js";import{u as c,ec as o,eW as x,B as p,ed as u,ee as m,eX as d,c as j}from"./index-Bw0aJc9a.js";const a=({action:n})=>e.jsxs(p,{isDisabled:n.isDisabled,isPending:n.isPending,tip:n.reason,onPress:n.onAction,children:[n.icon,n.label]});function $({actions:n,overflowMode:i="collapse"}){if(i==="wrap")return e.jsx(e.Fragment,{children:n.map(l=>e.jsx(a,{action:l},l.id))});const[s,...r]=n;return s?e.jsxs(e.Fragment,{children:[e.jsx(a,{action:s}),r.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"rp-wide-only",children:r.map(l=>e.jsx(a,{action:l},l.id))}),e.jsx("span",{className:"rp-narrow-only",children:e.jsx(b,{actions:r})})]})]}):null}function f({actions:n,label:i}){return e.jsx(u,{"aria-label":i,disabledKeys:n.filter(s=>s.isDisabled||s.isPending).map(s=>s.id),onAction:s=>n.find(r=>r.id===s)?.onAction(),children:n.map(s=>e.jsx(m,{id:s.id,className:j("rp-item plain",s.negative&&"negative"),textValue:s.label,children:e.jsxs("span",{className:"rp-item-text",children:[e.jsx(d,{slot:"label",children:s.label}),s.isDisabled&&s.reason&&e.jsx(d,{slot:"description",className:"desc reason",children:s.reason})]})},s.id))})}function b({actions:n,label:i,small:s,quiet:r}){const l=c(),t=i??l("ui.moreActions");return n.length===0?null:e.jsx(o,{chevron:!1,small:s,quiet:r,label:t,content:e.jsx(f,{actions:n,label:t}),children:e.jsx(x,{})})}export{$ as A,b as M};
|
||||
import{j as e}from"./vendor-react-Bf71BWbF.js";import{u as c,ec as o,eW as x,B as p,ed as u,ee as m,eX as d,c as j}from"./index-BOpK0UVB.js";const a=({action:n})=>e.jsxs(p,{isDisabled:n.isDisabled,isPending:n.isPending,tip:n.reason,onPress:n.onAction,children:[n.icon,n.label]});function $({actions:n,overflowMode:i="collapse"}){if(i==="wrap")return e.jsx(e.Fragment,{children:n.map(l=>e.jsx(a,{action:l},l.id))});const[s,...r]=n;return s?e.jsxs(e.Fragment,{children:[e.jsx(a,{action:s}),r.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"rp-wide-only",children:r.map(l=>e.jsx(a,{action:l},l.id))}),e.jsx("span",{className:"rp-narrow-only",children:e.jsx(b,{actions:r})})]})]}):null}function f({actions:n,label:i}){return e.jsx(u,{"aria-label":i,disabledKeys:n.filter(s=>s.isDisabled||s.isPending).map(s=>s.id),onAction:s=>n.find(r=>r.id===s)?.onAction(),children:n.map(s=>e.jsx(m,{id:s.id,className:j("rp-item plain",s.negative&&"negative"),textValue:s.label,children:e.jsxs("span",{className:"rp-item-text",children:[e.jsx(d,{slot:"label",children:s.label}),s.isDisabled&&s.reason&&e.jsx(d,{slot:"description",className:"desc reason",children:s.reason})]})},s.id))})}function b({actions:n,label:i,small:s,quiet:r}){const l=c(),t=i??l("ui.moreActions");return n.length===0?null:e.jsx(o,{chevron:!1,small:s,quiet:r,label:t,content:e.jsx(f,{actions:n,label:t}),children:e.jsx(x,{})})}export{$ as A,b as M};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{j as r}from"./vendor-react-Bf71BWbF.js";import{c as t}from"./index-Bw0aJc9a.js";function o({className:a,...s}){return r.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:20,height:20,viewBox:"0 0 20 20","aria-hidden":"true",focusable:"false",className:t("rp-icon",a),...s,children:r.jsx("path",{fill:"currentColor",d:"M10 1.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17m0 15.5a7 7 0 1 1 0-14 7 7 0 0 1 0 14m3.75-7.75h-3v-3a.75.75 0 0 0-1.5 0v3h-3a.75.75 0 0 0 0 1.5h3v3a.75.75 0 0 0 1.5 0v-3h3a.75.75 0 0 0 0-1.5"})})}export{o as A};
|
||||
import{j as r}from"./vendor-react-Bf71BWbF.js";import{c as t}from"./index-BOpK0UVB.js";function o({className:a,...s}){return r.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:20,height:20,viewBox:"0 0 20 20","aria-hidden":"true",focusable:"false",className:t("rp-icon",a),...s,children:r.jsx("path",{fill:"currentColor",d:"M10 1.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17m0 15.5a7 7 0 1 1 0-14 7 7 0 0 1 0 14m3.75-7.75h-3v-3a.75.75 0 0 0-1.5 0v3h-3a.75.75 0 0 0 0 1.5h3v3a.75.75 0 0 0 1.5 0v-3h3a.75.75 0 0 0 0-1.5"})})}export{o as A};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{r as u,j as a}from"./vendor-react-Bf71BWbF.js";import{u as ct,aI as it,fx as rt,fy as ut}from"./index-Bw0aJc9a.js";import{u as ht,e as dt,v as H,C as xt,f as pt,n as ft,g as J}from"./layout-BWzq8YqC.js";import{G as mt,C as yt}from"./AreaCurve-BriPYJva.js";import"./array-C0P64tl-.js";const Mt=l=>{const o=Math.pow(10,Math.floor(Math.log10(l))),e=l/o;return([1,1.2,1.5,2,2.5,3,4,5,6,8,10].find(h=>e<=h)??10)*o},gt=l=>{const o=Math.pow(10,Math.floor(Math.log10(Math.max(l,1e-9)))),e=l/o;return(e<=1?.2:e<=2?.5:e<=5?1:2)*o},I=[30,60,120,300,600,900,1800,3600,7200,21600,43200,86400].map(l=>l*1e3);function kt(l,o){const e=o-l,s=I.find(c=>e/c<=6)??I[I.length-1],h=s>=864e5?new Date(o).getTimezoneOffset()*6e4:0,y=Math.ceil((l-h)/s)*s+h,x=[];for(let c=y;c<=o;c+=s)c-l>=e*.04&&o-c>=e*.04&&x.push(c);return{ticks:x,step:s}}function Q(l){const[o,e]=u.useState([]);return u.useLayoutEffect(()=>{const s=document.createElement("span");Object.assign(s.style,{position:"absolute",top:"-20000px",whiteSpace:"pre",fontSize:"11px"}),document.body.appendChild(s),e(l.map(y=>{s.textContent=y;const{width:x,height:c}=s.getBoundingClientRect();return{width:x,height:c}})),s.remove()},[l]),o}function wt({label:l,series:o,timestamps:e,fmt:s,locale:h,height:y=150,baseline:x="zero",window:c,fill:U}){const X=ct(),C=it(),N=u.useId(),[Y,E]=rt(Math.round,120),{tip:Z,showAt:_,hide:F}=ht(),[z,$]=u.useState(null),i=z&&z.index<e.length?z.index:null,A=c?c.until-c.since:e.length?e[e.length-1]-e[0]:0,M=c?.since,g=c?.until,p=u.useMemo(()=>M!==void 0&&g!==void 0?kt(M,g):void 0,[M,g]),D=p?p.step<6e4:A<180*1e3,B=p?p.step>=864e5:A>2160*60*1e3,G=u.useMemo(()=>new Intl.DateTimeFormat(h,B?{month:"numeric",day:"numeric"}:D?{hour:"2-digit",minute:"2-digit",second:"2-digit",hourCycle:"h23"}:{hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),[h,D,B]),{yDomain:K,yTicks:j}=u.useMemo(()=>{const t=o.flatMap(d=>d.values.filter(w=>w!==null));let n=0,r=Mt(Math.max(1,...t)*1.08);if(x==="auto"&&t.length){const d=Math.min(...t),w=Math.max(...t),b=gt(Math.max(w-d,w*.02,1));n=Math.max(0,Math.floor(d/b)*b-b),r=Math.ceil(w/b)*b+b}return{yDomain:[n,r],yTicks:x==="auto"?[n,(n+r)/2,r]:[r/2,r]}},[o,x]),P=u.useMemo(()=>{const t=e.length-1;return p?p.ticks:[...new Set((D?[0,Math.round(t/2),t]:[0,Math.round(t/3),Math.round(2*t/3),t]).map(n=>e[n]))]},[p,D,e]),O=u.useMemo(()=>M!==void 0&&g!==void 0?[M,g]:[Math.min(...e),Math.max(...e)],[M,g,e]),k=E?.width??0,S=E?.height??y,m=S-30,v=k-64,tt=[Math.min(O[0],...e),Math.max(O[1],...e)],f=t=>J(t,tt,[20,v]),T=t=>J(t,K,[m,8]),et={x:20,y:8,width:v-20,height:m-8},R=(t,n)=>$({index:t,y:n}),W=()=>{$(null),F()};u.useLayoutEffect(()=>{if(i===null){F();return}if(!o.some(t=>t.values[i]!=null)){F();return}_({x:f(e[i]),y:z?.y??(8+m)/2,width:k,bounds:et,label:ut(h).format(e[i]),lines:o.filter(t=>t.values[i]!=null).sort((t,n)=>t.label<n.label?-1:t.label>n.label?1:0).map(t=>X("ui.valuePair",{label:t.label,value:s(t.values[i])}))})});const L=dt(e.length,R,W),V=u.useMemo(()=>P.map(t=>G.format(t)),[P,G]),nt=u.useMemo(()=>j.map(s),[j,s]),ot=Q(V),st=Q(nt),at=p?H(P.map(f),ot.map(t=>t.width),0,k,16,!0):P.map((t,n)=>({index:n,position:f(t)})),q=H(j.map(T),st.map(t=>t.height),0,S,5,!1),lt=[...new Set([...q.map(t=>T(j[t.index])),8,m])];return a.jsx("div",{ref:Y,style:{height:y,width:"100%",flex:U?"1 1 auto":void 0,position:"relative"},onPointerLeave:L.onPointerLeave,children:e.length>0&&E&&a.jsxs(a.Fragment,{children:[a.jsx(xt,{tip:Z}),a.jsxs("svg",{className:"rp-activity-surface",width:k,height:S,viewBox:`0 0 ${k} ${S}`,style:{display:"block"},role:"application","aria-label":l,tabIndex:0,onFocus:L.onFocus,onBlur:L.onBlur,onKeyDown:L.onKeyDown,onPointerMove:t=>{const{x:n,y:r}=pt(t,t.currentTarget,{width:k,height:S});if(n<20||n>v||r<8||r>m){W();return}const d=ft(e.map(f),n);R(d,r)},children:[a.jsx("g",{className:"rp-area-grid",children:lt.map(t=>a.jsx("line",{x1:20,x2:v,y1:t,y2:t,stroke:C["hl-med"],strokeDasharray:"2 4",fill:"none"},t))}),a.jsx("defs",{children:o.map((t,n)=>a.jsx(mt,{id:N+n,color:t.color},t.label))}),o.map((t,n)=>a.jsx(yt,{points:e.map((r,d)=>t.values[d]==null?null:{x:f(r),y:T(t.values[d])}),baseline:T(Math.max(0,K[0])),color:t.color,id:N+n,strokeWidth:2},t.label)),i!==null&&a.jsx("path",{d:`M${f(e[i])},8L${f(e[i])},${m}`,stroke:C.subtle,strokeDasharray:"3 3",fill:"none",pointerEvents:"none"}),a.jsx("g",{children:at.map(({index:t,position:n})=>a.jsx("text",{x:n,y:m+8,className:"rp-area-tick",fill:C.subtle,textAnchor:"middle",children:a.jsx("tspan",{x:n,dy:"0.71em",children:V[t]})},t))}),a.jsx("g",{className:"rp-area-y-ticks",children:q.map(({index:t,position:n})=>a.jsx("text",{x:v+8,y:n,className:"rp-area-tick",fill:C.subtle,textAnchor:"start",children:a.jsx("tspan",{x:v+8,dy:"0.355em",children:s(j[t])})},t))}),i!==null&&o.map(t=>t.values[i]==null?null:a.jsx("circle",{cx:f(e[i]),cy:T(t.values[i]),r:4,fill:t.color,stroke:"#fff",strokeWidth:2},t.label))]})]})})}export{wt as AreaPlot};
|
||||
import{r as u,j as a}from"./vendor-react-Bf71BWbF.js";import{u as ct,aI as it,fx as rt,fy as ut}from"./index-BOpK0UVB.js";import{u as ht,e as dt,v as H,C as xt,f as pt,n as ft,g as J}from"./layout-Bzzn7HLw.js";import{G as mt,C as yt}from"./AreaCurve-BriPYJva.js";import"./array-C0P64tl-.js";const Mt=l=>{const o=Math.pow(10,Math.floor(Math.log10(l))),e=l/o;return([1,1.2,1.5,2,2.5,3,4,5,6,8,10].find(h=>e<=h)??10)*o},gt=l=>{const o=Math.pow(10,Math.floor(Math.log10(Math.max(l,1e-9)))),e=l/o;return(e<=1?.2:e<=2?.5:e<=5?1:2)*o},I=[30,60,120,300,600,900,1800,3600,7200,21600,43200,86400].map(l=>l*1e3);function kt(l,o){const e=o-l,s=I.find(c=>e/c<=6)??I[I.length-1],h=s>=864e5?new Date(o).getTimezoneOffset()*6e4:0,y=Math.ceil((l-h)/s)*s+h,x=[];for(let c=y;c<=o;c+=s)c-l>=e*.04&&o-c>=e*.04&&x.push(c);return{ticks:x,step:s}}function Q(l){const[o,e]=u.useState([]);return u.useLayoutEffect(()=>{const s=document.createElement("span");Object.assign(s.style,{position:"absolute",top:"-20000px",whiteSpace:"pre",fontSize:"11px"}),document.body.appendChild(s),e(l.map(y=>{s.textContent=y;const{width:x,height:c}=s.getBoundingClientRect();return{width:x,height:c}})),s.remove()},[l]),o}function wt({label:l,series:o,timestamps:e,fmt:s,locale:h,height:y=150,baseline:x="zero",window:c,fill:U}){const X=ct(),C=it(),N=u.useId(),[Y,E]=rt(Math.round,120),{tip:Z,showAt:_,hide:F}=ht(),[z,$]=u.useState(null),i=z&&z.index<e.length?z.index:null,A=c?c.until-c.since:e.length?e[e.length-1]-e[0]:0,M=c?.since,g=c?.until,p=u.useMemo(()=>M!==void 0&&g!==void 0?kt(M,g):void 0,[M,g]),D=p?p.step<6e4:A<180*1e3,B=p?p.step>=864e5:A>2160*60*1e3,G=u.useMemo(()=>new Intl.DateTimeFormat(h,B?{month:"numeric",day:"numeric"}:D?{hour:"2-digit",minute:"2-digit",second:"2-digit",hourCycle:"h23"}:{hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),[h,D,B]),{yDomain:K,yTicks:j}=u.useMemo(()=>{const t=o.flatMap(d=>d.values.filter(w=>w!==null));let n=0,r=Mt(Math.max(1,...t)*1.08);if(x==="auto"&&t.length){const d=Math.min(...t),w=Math.max(...t),b=gt(Math.max(w-d,w*.02,1));n=Math.max(0,Math.floor(d/b)*b-b),r=Math.ceil(w/b)*b+b}return{yDomain:[n,r],yTicks:x==="auto"?[n,(n+r)/2,r]:[r/2,r]}},[o,x]),P=u.useMemo(()=>{const t=e.length-1;return p?p.ticks:[...new Set((D?[0,Math.round(t/2),t]:[0,Math.round(t/3),Math.round(2*t/3),t]).map(n=>e[n]))]},[p,D,e]),O=u.useMemo(()=>M!==void 0&&g!==void 0?[M,g]:[Math.min(...e),Math.max(...e)],[M,g,e]),k=E?.width??0,S=E?.height??y,m=S-30,v=k-64,tt=[Math.min(O[0],...e),Math.max(O[1],...e)],f=t=>J(t,tt,[20,v]),T=t=>J(t,K,[m,8]),et={x:20,y:8,width:v-20,height:m-8},R=(t,n)=>$({index:t,y:n}),W=()=>{$(null),F()};u.useLayoutEffect(()=>{if(i===null){F();return}if(!o.some(t=>t.values[i]!=null)){F();return}_({x:f(e[i]),y:z?.y??(8+m)/2,width:k,bounds:et,label:ut(h).format(e[i]),lines:o.filter(t=>t.values[i]!=null).sort((t,n)=>t.label<n.label?-1:t.label>n.label?1:0).map(t=>X("ui.valuePair",{label:t.label,value:s(t.values[i])}))})});const L=dt(e.length,R,W),V=u.useMemo(()=>P.map(t=>G.format(t)),[P,G]),nt=u.useMemo(()=>j.map(s),[j,s]),ot=Q(V),st=Q(nt),at=p?H(P.map(f),ot.map(t=>t.width),0,k,16,!0):P.map((t,n)=>({index:n,position:f(t)})),q=H(j.map(T),st.map(t=>t.height),0,S,5,!1),lt=[...new Set([...q.map(t=>T(j[t.index])),8,m])];return a.jsx("div",{ref:Y,style:{height:y,width:"100%",flex:U?"1 1 auto":void 0,position:"relative"},onPointerLeave:L.onPointerLeave,children:e.length>0&&E&&a.jsxs(a.Fragment,{children:[a.jsx(xt,{tip:Z}),a.jsxs("svg",{className:"rp-activity-surface",width:k,height:S,viewBox:`0 0 ${k} ${S}`,style:{display:"block"},role:"application","aria-label":l,tabIndex:0,onFocus:L.onFocus,onBlur:L.onBlur,onKeyDown:L.onKeyDown,onPointerMove:t=>{const{x:n,y:r}=pt(t,t.currentTarget,{width:k,height:S});if(n<20||n>v||r<8||r>m){W();return}const d=ft(e.map(f),n);R(d,r)},children:[a.jsx("g",{className:"rp-area-grid",children:lt.map(t=>a.jsx("line",{x1:20,x2:v,y1:t,y2:t,stroke:C["hl-med"],strokeDasharray:"2 4",fill:"none"},t))}),a.jsx("defs",{children:o.map((t,n)=>a.jsx(mt,{id:N+n,color:t.color},t.label))}),o.map((t,n)=>a.jsx(yt,{points:e.map((r,d)=>t.values[d]==null?null:{x:f(r),y:T(t.values[d])}),baseline:T(Math.max(0,K[0])),color:t.color,id:N+n,strokeWidth:2},t.label)),i!==null&&a.jsx("path",{d:`M${f(e[i])},8L${f(e[i])},${m}`,stroke:C.subtle,strokeDasharray:"3 3",fill:"none",pointerEvents:"none"}),a.jsx("g",{children:at.map(({index:t,position:n})=>a.jsx("text",{x:n,y:m+8,className:"rp-area-tick",fill:C.subtle,textAnchor:"middle",children:a.jsx("tspan",{x:n,dy:"0.71em",children:V[t]})},t))}),a.jsx("g",{className:"rp-area-y-ticks",children:q.map(({index:t,position:n})=>a.jsx("text",{x:v+8,y:n,className:"rp-area-tick",fill:C.subtle,textAnchor:"start",children:a.jsx("tspan",{x:v+8,dy:"0.355em",children:s(j[t])})},t))}),i!==null&&o.map(t=>t.values[i]==null?null:a.jsx("circle",{cx:f(e[i]),cy:T(t.values[i]),r:4,fill:t.color,stroke:"#fff",strokeWidth:2},t.label))]})]})})}export{wt as AreaPlot};
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{r as E,$ as W,a as Pt,j as f}from"./vendor-react-Bf71BWbF.js";import{fk as Bt,fE as It,fe as ie,ca as H,c8 as M,fF as et,fG as tt,fH as At,c2 as Le,fb as S,fc as ae,fd as Ie,eZ as R,fq as rt,fI as Ot,fJ as Mt,fK as jt,b$ as Nt,cb as Rt,ci as Lt,fL as Vt,ck as Gt,cl as Ht,bZ as zt,fi as Yt,cn as Ut,bW as Xt,cp as qt,cr as _t,co as Wt,fM as Jt,fN as Zt,bX as Ke,aQ as Qt,fu as er,fr as tr,c7 as rr,fO as nt,fP as at,fQ as le,bY as nr,bU as ot,eY as ar,c as Ae,M as Ce,dR as Ve,dY as it,fR as Ge,fS as He,e6 as lt,u as J,aa as or,ad as ir,ac as ze,af as lr,cS as sr,et as ur,b as dr,bm as Ye,E as cr,j as pr,I as te,ak as st,B as V,dT as Ue,ah as ut,T as dt,a as ct,aO as Xe,aJ as fr,bQ as gr,a3 as pe,L as yr,h as mr,bR as hr,aN as Dr,bs as br,fv as $r,fw as vr,fT as Er,aL as xr,br as wr,aj as pt,cY as Tr}from"./index-Bw0aJc9a.js";import{$ as kr,a as Kr}from"./Policies-Dgwc4tfn.js";import{d as Cr}from"./Virtualizer-DCY9HC9Z.js";import{$ as Sr}from"./ListLayout-_fDlx5XY.js";import{D as ft}from"./DaeCode-B8yPDjSE.js";import{b as Fr,g as Pr}from"./policyText-CltaDVEo.js";import{P as Br}from"./openGroup-Dk9B33qx.js";import{$ as Ir}from"./useFilter-Tjznm3lB.js";import"./ActionGroup-DLxTuKht.js";import"./useGridSelectionCheckbox-COXIVEmS.js";import"./nav-BASDWt23.js";var P=(function(e){return e[e.none=0]="none",e[e.cancel=0]="cancel",e[e.move=1]="move",e[e.copy=2]="copy",e[e.link=4]="link",e[e.all=7]="all",e})({});const gt={...P,copyMove:3,copyLink:6,linkMove:5,all:7,uninitialized:7},yt=mt(gt);yt[7]="all";const re={none:"cancel",link:"link",copy:"copy",move:"move"},be=mt(re);function mt(e){let t={};for(let r in e)t[e[r]]=r;return t}const Ar=new Set(["text/plain","text/uri-list","text/html"]),ye="application/vnd.react-aria.items+json",me="application/octet-stream",Oe=new WeakMap,ht=Symbol();function Or(e){let{id:t}=Oe.get(e)||{};if(!t)throw new Error("Droppable item outside a droppable collection");return t}function Mr(e){let{ref:t}=Oe.get(e)||{};if(!t)throw new Error("Droppable item outside a droppable collection");return t}function z(e){let t=new Set;for(let r of e)for(let n of Object.keys(r))t.add(n);return t}function Dt(e){return e||(e="virtual"),e==="pointer"&&(e="virtual"),e==="virtual"&&typeof window<"u"&&typeof window.matchMedia=="function"&&window.matchMedia("(pointer: coarse)").matches&&(e="touch"),e}function Me(){return Dt(Bt())}function bt(){return Dt(It())}function Se(e,t){let r=new Map,n=!1,a=[];for(let o of t){let g=Object.keys(o);g.length>1&&(n=!0);let c={};for(let y of g){let $=r.get(y);$?n=!0:($=[],r.set(y,$));let m=o[y];c[y]=m,$.push(m)}a.push(c)}for(let[o,g]of r)if(Ar.has(o)){let c=g.join(`
|
||||
import{r as E,$ as W,a as Pt,j as f}from"./vendor-react-Bf71BWbF.js";import{fk as Bt,fE as It,fe as ie,ca as H,c8 as M,fF as et,fG as tt,fH as At,c2 as Le,fb as S,fc as ae,fd as Ie,eZ as R,fq as rt,fI as Ot,fJ as Mt,fK as jt,b$ as Nt,cb as Rt,ci as Lt,fL as Vt,ck as Gt,cl as Ht,bZ as zt,fi as Yt,cn as Ut,bW as Xt,cp as qt,cr as _t,co as Wt,fM as Jt,fN as Zt,bX as Ke,aQ as Qt,fu as er,fr as tr,c7 as rr,fO as nt,fP as at,fQ as le,bY as nr,bU as ot,eY as ar,c as Ae,M as Ce,dR as Ve,dY as it,fR as Ge,fS as He,e6 as lt,u as J,aa as or,ad as ir,ac as ze,af as lr,cS as sr,et as ur,b as dr,bm as Ye,E as cr,j as pr,I as te,ak as st,B as V,dT as Ue,ah as ut,T as dt,a as ct,aO as Xe,aJ as fr,bQ as gr,a3 as pe,L as yr,h as mr,bR as hr,aN as Dr,bs as br,fv as $r,fw as vr,fT as Er,aL as xr,br as wr,aj as pt,cY as Tr}from"./index-BOpK0UVB.js";import{$ as kr,a as Kr}from"./Policies-DZOKUNEx.js";import{d as Cr}from"./Virtualizer-BIsXGNLZ.js";import{$ as Sr}from"./ListLayout-CkBMjK9o.js";import{D as ft}from"./DaeCode-B8yPDjSE.js";import{b as Fr,g as Pr}from"./policyText-y7dbn7hu.js";import{P as Br}from"./openGroup-B1VdMhOs.js";import{$ as Ir}from"./useFilter-6_o4NyOf.js";import"./ActionGroup-BU73NzbX.js";import"./useGridSelectionCheckbox-C4VxQajJ.js";import"./nav-BASDWt23.js";var P=(function(e){return e[e.none=0]="none",e[e.cancel=0]="cancel",e[e.move=1]="move",e[e.copy=2]="copy",e[e.link=4]="link",e[e.all=7]="all",e})({});const gt={...P,copyMove:3,copyLink:6,linkMove:5,all:7,uninitialized:7},yt=mt(gt);yt[7]="all";const re={none:"cancel",link:"link",copy:"copy",move:"move"},be=mt(re);function mt(e){let t={};for(let r in e)t[e[r]]=r;return t}const Ar=new Set(["text/plain","text/uri-list","text/html"]),ye="application/vnd.react-aria.items+json",me="application/octet-stream",Oe=new WeakMap,ht=Symbol();function Or(e){let{id:t}=Oe.get(e)||{};if(!t)throw new Error("Droppable item outside a droppable collection");return t}function Mr(e){let{ref:t}=Oe.get(e)||{};if(!t)throw new Error("Droppable item outside a droppable collection");return t}function z(e){let t=new Set;for(let r of e)for(let n of Object.keys(r))t.add(n);return t}function Dt(e){return e||(e="virtual"),e==="pointer"&&(e="virtual"),e==="virtual"&&typeof window<"u"&&typeof window.matchMedia=="function"&&window.matchMedia("(pointer: coarse)").matches&&(e="touch"),e}function Me(){return Dt(Bt())}function bt(){return Dt(It())}function Se(e,t){let r=new Map,n=!1,a=[];for(let o of t){let g=Object.keys(o);g.length>1&&(n=!0);let c={};for(let y of g){let $=r.get(y);$?n=!0:($=[],r.set(y,$));let m=o[y];c[y]=m,$.push(m)}a.push(c)}for(let[o,g]of r)if(Ar.has(o)){let c=g.join(`
|
||||
`);e.items.add(c,o)}else e.items.add(g[0],o);if(n){let o=JSON.stringify(a);e.items.add(o,ye)}}class se{constructor(t){this.types=new Set;let r=!1;for(let n of t.items)n.type!==ye&&(n.kind==="file"&&(r=!0),n.type?this.types.add(n.type):this.types.add(me));this.includesUnknownTypes=!r&&t.types.includes("Files")}has(t){if(Array.isArray(t))return t.some(r=>this.has(r));if(this.includesUnknownTypes||t===ht&&this.types.has(me)||t==="*/*")return!0;if(typeof t=="string"){if(t.endsWith("/*")){for(let r of this.types)if(r.startsWith(t.slice(0,-2)))return!0;return!1}return this.types.has(t)}return!1}}function $t(e){let t=[];if(!e)return t;let r=!1;if(e.types.includes(ye))try{let n=e.getData(ye),a=JSON.parse(n);for(let o of a)t.push({kind:"text",types:new Set(Object.keys(o)),getText:g=>Promise.resolve(o[g])});r=!0}catch{}if(!r){let n=new Map;for(let a of e.items)if(a.kind==="string")n.set(a.type||me,e.getData(a.type));else if(a.kind==="file")if(typeof a.webkitGetAsEntry=="function"){let o=a.webkitGetAsEntry();if(!o)continue;o.isFile?t.push(Fe(a.getAsFile())):o.isDirectory&&t.push(vt(o))}else t.push(Fe(a.getAsFile()));n.size>0&&t.push({kind:"text",types:new Set(n.keys()),getText:a=>Promise.resolve(n.get(a))})}return t}function jr(e){return typeof e.text=="function"?e.text():new Promise((t,r)=>{let n=new FileReader;n.onload=()=>{t(n.result)},n.onerror=r,n.readAsText(e)})}function Fe(e){if(!e)throw new Error("No file provided");return{kind:"file",type:e.type||me,name:e.name,getText:()=>jr(e),getFile:()=>Promise.resolve(e)}}function vt(e){return{kind:"directory",name:e.name,getEntries:()=>Nr(e)}}async function*Nr(e){let t=e.createReader(),r;do{r=await new Promise((n,a)=>{t.readEntries(n,a)});for(let n of r)if(n.isFile){let a=await Rr(n);yield Fe(a)}else n.isDirectory&&(yield vt(n))}while(r.length>0)}function Rr(e){return new Promise((t,r)=>e.file(t,r))}function Lr(e){return e.kind==="text"}let B={draggingKeys:new Set};function Vr(e){B.draggingCollectionRef=e}function Gr(e){B.draggingKeys=e}function q(e){B.dropCollectionRef=e}function Et(){B={draggingKeys:new Set}}function Hr(e){B=e}function G(e){let{draggingCollectionRef:t,dropCollectionRef:r}=B;return t?.current!=null&&t.current===(e?.current||r?.current)}let fe;function he(e){fe=e}let Pe=P.none;function $e(e){Pe=e}let Be=new Map,ne=new Map,L=null,De=new Set;function xt(e){return Be.set(e.element,e),L?.updateValidDropTargets(),()=>{Be.delete(e.element),L?.updateValidDropTargets()}}function zr(e){return ne.set(e.element,e),()=>{ne.delete(e.element)}}function Yr(e,t){if(L)throw new Error("Cannot begin dragging while already dragging");L=new Wr(e,t),requestAnimationFrame(()=>{L&&(L.setup(),bt()==="keyboard"&&L.next())});for(let r of De)r()}function je(){let[e,t]=E.useState(L);return E.useEffect(()=>{let r=()=>t(L);return De.add(r),()=>{De.delete(r)}},[]),e}function Ur(){return!!L}function Xr(){L=null;for(let e of De)e()}const qe=["pointerdown","pointermove","pointerenter","pointerleave","pointerover","pointerout","pointerup","mousedown","mousemove","mouseenter","mouseleave","mouseover","mouseout","mouseup","touchstart","touchmove","touchend","focusin","focusout"],qr=["pointerup","mouseup","touchend"],_r={keyboard:"dragStartedKeyboard",touch:"dragStartedTouch",virtual:"dragStartedVirtual"};class Wr{constructor(t,r){this.validDropTargets=[],this.currentDropTarget=null,this.currentDropItem=null,this.dropOperation=null,this.mutationObserver=null,this.restoreAriaHidden=null,this.isVirtualClick=!1,this.dragTarget=t,this.stringFormatter=r,this.onKeyDown=this.onKeyDown.bind(this),this.onKeyUp=this.onKeyUp.bind(this),this.onFocus=this.onFocus.bind(this),this.onBlur=this.onBlur.bind(this),this.onClick=this.onClick.bind(this),this.onPointerDown=this.onPointerDown.bind(this),this.cancelEvent=this.cancelEvent.bind(this),this.initialFocused=!1}setup(){document.addEventListener("keydown",this.onKeyDown,!0),document.addEventListener("keyup",this.onKeyUp,!0),window.addEventListener("focus",this.onFocus,!0),window.addEventListener("blur",this.onBlur,!0),document.addEventListener("click",this.onClick,!0),document.addEventListener("pointerdown",this.onPointerDown,!0);for(let t of qe)document.addEventListener(t,this.cancelEvent,!0);this.mutationObserver=new MutationObserver(()=>this.updateValidDropTargets()),this.updateValidDropTargets(),ie(this.stringFormatter.format(_r[bt()]))}teardown(){document.removeEventListener("keydown",this.onKeyDown,!0),document.removeEventListener("keyup",this.onKeyUp,!0),window.removeEventListener("focus",this.onFocus,!0),window.removeEventListener("blur",this.onBlur,!0),document.removeEventListener("click",this.onClick,!0),document.removeEventListener("pointerdown",this.onPointerDown,!0);for(let t of qe)document.removeEventListener(t,this.cancelEvent,!0);this.mutationObserver?.disconnect(),this.restoreAriaHidden?.()}onKeyDown(t){if(this.cancelEvent(t),t.key==="Escape"){this.cancel();return}t.key==="Tab"&&!(t.metaKey||t.altKey||t.ctrlKey)&&(t.shiftKey?this.previous(
Line truncated
|
||||
`),O=new Set(y.map(A=>A.group));return Ce(d.stagedText).filter(A=>O.has(A.name)).map(A=>({group:A.name,text:K.slice(A.from,A.to+1).join(`
|
||||
`)}))},[d.stagedText,y]);return{groups:d.groups,unknown:d.unknown,byGroup:p,subscriptions:s,nodes:i,search:h,setSearch:x,loading:n.loading&&!n.data||o.loading&&!c||g.loading&&!g.data,error:[n,o,g].find(K=>K.error&&!K.data)?.error??(e.main?null:e.error),retry:E.useCallback(()=>void ur(),[]),blocked:I?r(I):null,busy:e.busy||w,applying:w,failure:C,changes:y,changeLines:y.map(K=>Fn(K,l,r)),pendingText:r("arrange.pending",{n:y.length}),place:N,unplace:Y,drop:K=>j(O=>Pn(O,K)),discard:()=>j(()=>[]),nameProblem:Q,create:(K,O)=>j(A=>ke(A,{kind:"createGroup",group:K,policy:O})),reviewing:u&&y.length>0,setReviewing:K=>{w||D(K)},preview:X,canApply:y.length>0&&d.emptyNew.length===0&&!I&&!w,applyNote:Cn(I?r(I):null,d.emptyNew,r),apply:U}}function _n({source:e,groups:t,viewGroup:r}){const n=J(),a=Bn(e,r),o=E.useMemo(()=>new Map((t??[]).map(g=>[g.name,g])),[t]);return a.error?f.jsx(cr,{error:a.error,onRetry:a.retry}):a.loading?f.jsx(pr,{}):f.jsxs("div",{className:"rp-arrange",children:[f.jsxs("div",{className:"rp-row",children:[f.jsxs("p",{className:"rp-note rp-grow",children:[f.jsx("span",{className:"rp-wide-only",children:n("arrange.note")}),f.jsx("span",{className:"rp-narrow-only",children:n("arrange.selectHint")})]}),f.jsx(On,{m:a})]}),a.blocked&&f.jsx(te,{tone:"informative",children:a.blocked}),f.jsxs("div",{className:"rp-arrange-grid",children:[f.jsx("div",{className:"rp-col",children:a.groups.length?a.groups.map(g=>f.jsx(In,{group:g,live:o.get(g.name),m:a},g.name)):f.jsx(st,{children:n("policy.empty")})}),f.jsx(An,{m:a})]}),a.changes.length>0&&f.jsxs(xn,{label:n("arrange.pendingRegion"),message:a.pendingText,children:[f.jsx(V,{quiet:!0,onPress:a.discard,isDisabled:a.busy,children:n("arrange.discard")}),f.jsx(V,{accent:!0,onPress:()=>a.setReviewing(!0),children:n("arrange.review")})]}),f.jsx(Mn,{m:a})]})}function In({group:e,live:t,m:r}){const n=J(),a=ct(),o=E.useId(),g=!!r.blocked,c=t?Pr(t.policy,n):null,y=async v=>{const l=await Promise.all(v.filter(Lr).filter(d=>d.types.has(ge)).map(d=>d.getText(ge)));r.place(e.name,l.flatMap(d=>Sn(d)??[]))},$=(v,l,d)=>f.jsx(V,{quiet:!0,icon:!0,small:!0,label:n("arrange.remove",{name:v,group:e.name}),isDisabled:g||r.applying||!!d,onPress:()=>r.unplace(e.name,l),children:f.jsx(pt,{})}),m=(v,l)=>f.jsx(V,{quiet:!0,small:!0,label:n("arrange.undoRemove",{name:v}),isDisabled:r.applying,onPress:()=>r.place(e.name,[l]),children:n("arrange.undoShort")});return f.jsx(an,{className:hr("rp-drop"),"aria-label":n("arrange.dropInto",{group:e.name}),isDisabled:g||r.applying,getDropOperation:v=>v.has(ge)?"copy":"cancel",onDrop:v=>void y(v.items),children:({isDropTarget:v})=>f.jsxs(f.Fragment,{children:[f.jsx("div",{className:"rp-row",children:f.jsxs("span",{className:"rp-cluster",children:[f.jsx("h3",{className:"rp-h3",id:o,children:e.name}),c&&f.jsx(Xe,{tip:c.id,children:c.label}),t&&f.jsx(fr,{small:!0,tone:"neutral",children:n("arrange.memberCount",{n:t.member_count})}),e.isNew&&f.jsx(Xe,{children:n("arrange.new")})]})}),e.holdsAll&&f.jsx("p",{className:"rp-note",children:n("arrange.holdsAll")}),f.jsxs(gr,{reason:Kn(e,g||r.applying),children:[(e.names.length>0||e.removedNames.length>0)&&f.jsxs(Ze,{label:n("arrange.byName"),children:[f.jsx("span",{className:"rp-label rp-tags-title",children:n("arrange.byName")}),e.names.map(l=>f.jsx(ce,{tone:l.isNew?"new":void 0,action:$(l.name,{kind:"node",value:l.name},l.blocked),children:l.name},l.name)),e.removedNames.map(l=>f.jsx(ce,{tone:"removed",action:m(l,{kind:"node",value:l}),children:l},l))]}),(e.subscriptions.length>0||e.removedSubscriptions.length>0)&&f.jsxs(Ze,{label:n("arrange.bySubscription"),children:[f.jsx("span",{className:"rp-label rp-tags-title",children:n("arrange.bySubscription")}),e.subscriptions.map(l=>f.jsx(ce,{tone:l.isNew?"new":void 0,action:$(l.label,{kind:"subscription",value:l.tag},l.blocked),children:l.count===null?l.label:n("arrange.subscriptionCount",{name:l.label,n:l.count})},l.tag)),e.removedSubscriptions.map(l=>f.jsx(ce,{tone:"removed",action:m(l.label,{kind:"subscription",value:l.tag}),children:l.label},l.tag))]})]}),e.rules.length>0&&f.jsxs("div",{className:"rp-arrange-rules",children:[f.jsx("span",{className:"rp-label",children:n("arrange.byRule")}),e.rules.map(l=>f.jsx(ft,{as:"code",text:l},l)),e.ruleNodes.length>0&&f.jsx("span",{children:e.ruleMore?n("arrange.ruleSelectsMore",{names:pe(a,e.ruleNodes),n:e.ruleMore}):n("arrange.ruleSelects",{names:pe(a,e.ruleNodes)})}),f.jsxs("span",{className:"rp-label",children:[e.ruleNote," ",f.jsx(yr,{appearance:"link",href:mr("config",{tab:"source"}),children:n("arrange.editSource")})]})]}),e.stillIn.length>0&&f.jsx(te,{tone:"informative",children:n("arrange.stillIn",{names:pe(a,e.stillIn)})}),v&&f.jsx("div",{className:"rp-drop-hint","aria-hidden":"true",children:n("arrange.dropHint")})]})})}function An({m:e}){const t=J(),r=E.useId(),n=!!e.blocked||e.applying,[a,o]=E.useState("all"),[g,c]=E.useState(new Set),y=E.useMemo(()=>[...a==="node"?[]:e.subscriptions.map(d=>({id:"subscription:
Line truncated
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{r as b,j as o}from"./vendor-react-Bf71BWbF.js";import{a4 as Oe,aw as Ae,av as sn,e4 as tn,d9 as Y,e5 as de,a5 as je,dX as He,e6 as on,a3 as $e,y as _e,h as I,Q as re,O as rn,e7 as an,df as Be,u as F,a6 as ne,a as se,aa as ln,ag as cn,ac as Se,cP as ue,aF as Ie,ap as Ve,bk as dn,bj as un,A as fn,e8 as pn,bm as $,de as Ke,a0 as ae,bg as Z,cS as fe,e9 as We,ea as gn,D as mn,eb as bn,C as hn,B as T,ec as vn,ed as xn,ee as wn,I as ce,aN as pe,bQ as ee,aO as ge,L as Ue,aJ as B,ef as yn,eg as jn,eh as Sn,ei as kn,cR as Nn,ej as Dn,J as Cn,ek as Mn,b as Pn,ah as Rn,bt as me,T as K,bS as Tn,bs as En,aL as Ge,el as zn,bq as Ln,aj as Fn,em as On,aM as An,E as Hn,j as $n,aK as _n,bx as Bn}from"./index-Bw0aJc9a.js";import{d as In}from"./files-BxEOxSF8.js";import{r as Vn,d as Kn,a as Wn,t as ke,b as Un,w as Ne,v as Gn,c as qn,n as Jn}from"./setup-DLvQ_6ZI.js";import{g as Qn}from"./policyText-CltaDVEo.js";import{a as Xn,s as Yn,c as Zn}from"./nav-BFiTWnsa.js";import{S as es,a as ns,E as _,C as te,b as be,l as ss,h as ts,c as De,r as os,d as rs,e as as,f as is,i as ls,g as cs,s as ds,k as us,t as qe,j as Ce,m as fs,n as ps,o as gs,p as ms,q as bs,u as hs,v as vs,w as xs,x as ws,y as Je,D as q,R as ys,z as js,A as Ss,B as ks,F as Ns,G as Ds,H as Qe,I as Cs,J as V,K as Ms}from"./vendor-editor-2EGeBPxF.js";import{d as Ps,s as Rs,D as Xe}from"./DaeCode-B8yPDjSE.js";import{A as Ts}from"./AddCircle-D11CyK2n.js";import{D as Es}from"./Table-Km6Zv-S8.js";import"./useGridSelectionCheckbox-COXIVEmS.js";import"./Virtualizer-DCY9HC9Z.js";import"./ListLayout-_fDlx5XY.js";const zs=["global","subscription","node","group","dns","routing"],Ls=(s,t,e)=>s?e("config.moduleEditBlocked"):t?e("ui.changeApplying"):void 0;function Me(s,t){return`${Y(s)}:${t.line+1}-${t.endLine+1}`}function Fs(s,t,e){return s.slice(0,t.from)+e+s.slice(t.to)}function Os(s,t){const{section:e,text:n}=s,a=t.find(f=>f.id===e.id);if(a?.source?.content_sha256===e.source.content_sha256)return{next:null,conflict:!1};if(!a?.source?.content||!a.block)return{next:null,conflict:!0};const r=a.source.content.slice(a.block.from,a.block.to),l=e.source.content.slice(e.block.from,e.block.to);return{next:{section:{...a,source:a.source,block:a.block},text:n===l?r:n},conflict:r!==l&&n!==l&&r!==n}}function As(s,t,e,n,a){const r=e.line+n.split(`
|
||||
import{r as b,j as o}from"./vendor-react-Bf71BWbF.js";import{a4 as Oe,aw as Ae,av as sn,e4 as tn,d9 as Y,e5 as de,a5 as je,dX as He,e6 as on,a3 as $e,y as _e,h as I,Q as re,O as rn,e7 as an,df as Be,u as F,a6 as ne,a as se,aa as ln,ag as cn,ac as Se,cP as ue,aF as Ie,ap as Ve,bk as dn,bj as un,A as fn,e8 as pn,bm as $,de as Ke,a0 as ae,bg as Z,cS as fe,e9 as We,ea as gn,D as mn,eb as bn,C as hn,B as T,ec as vn,ed as xn,ee as wn,I as ce,aN as pe,bQ as ee,aO as ge,L as Ue,aJ as B,ef as yn,eg as jn,eh as Sn,ei as kn,cR as Nn,ej as Dn,J as Cn,ek as Mn,b as Pn,ah as Rn,bt as me,T as K,bS as Tn,bs as En,aL as Ge,el as zn,bq as Ln,aj as Fn,em as On,aM as An,E as Hn,j as $n,aK as _n,bx as Bn}from"./index-BOpK0UVB.js";import{d as In}from"./files-BxEOxSF8.js";import{r as Vn,d as Kn,a as Wn,t as ke,b as Un,w as Ne,v as Gn,c as qn,n as Jn}from"./setup-V0SWKTBk.js";import{g as Qn}from"./policyText-y7dbn7hu.js";import{a as Xn,s as Yn,c as Zn}from"./nav-BFiTWnsa.js";import{S as es,a as ns,E as _,C as te,b as be,l as ss,h as ts,c as De,r as os,d as rs,e as as,f as is,i as ls,g as cs,s as ds,k as us,t as qe,j as Ce,m as fs,n as ps,o as gs,p as ms,q as bs,u as hs,v as vs,w as xs,x as ws,y as Je,D as q,R as ys,z as js,A as Ss,B as ks,F as Ns,G as Ds,H as Qe,I as Cs,J as V,K as Ms}from"./vendor-editor-2EGeBPxF.js";import{d as Ps,s as Rs,D as Xe}from"./DaeCode-B8yPDjSE.js";import{A as Ts}from"./AddCircle-0OKZjQ6F.js";import{D as Es}from"./Table-BkehX7fw.js";import"./useGridSelectionCheckbox-C4VxQajJ.js";import"./Virtualizer-BIsXGNLZ.js";import"./ListLayout-CkBMjK9o.js";const zs=["global","subscription","node","group","dns","routing"],Ls=(s,t,e)=>s?e("config.moduleEditBlocked"):t?e("ui.changeApplying"):void 0;function Me(s,t){return`${Y(s)}:${t.line+1}-${t.endLine+1}`}function Fs(s,t,e){return s.slice(0,t.from)+e+s.slice(t.to)}function Os(s,t){const{section:e,text:n}=s,a=t.find(f=>f.id===e.id);if(a?.source?.content_sha256===e.source.content_sha256)return{next:null,conflict:!1};if(!a?.source?.content||!a.block)return{next:null,conflict:!0};const r=a.source.content.slice(a.block.from,a.block.to),l=e.source.content.slice(e.block.from,e.block.to);return{next:{section:{...a,source:a.source,block:a.block},text:n===l?r:n},conflict:r!==l&&n!==l&&r!==n}}function As(s,t,e,n,a){const r=e.line+n.split(`
|
||||
`).length;return s.filter(l=>l.source_id===t&&l.line!==null&&l.line>e.line&&l.line<=r).map(l=>({line:l.line-e.line,column:l.column,level:l.level,message:he(de(l,a),a)}))}function Hs(s,t,e){return s.filter(n=>n.source_id===t&&n.line!==null).map(n=>({line:n.line,column:n.column,level:n.level,message:he(de(n,e),e)}))}function he({summary:s,detail:t},e,n=s){return t?e("config.backendDetail",{text:n,message:t}):n}function ie(s,t,e){return e.filter(n=>n.from>t.open&&n.to<=t.close&&n.depth===t.depth+1&&n.parens===0&&n.kind==="text"&&s.slice(n.from,n.to)==="->").length}function Pe(s,t,e){const n=t.filter(a=>a.from>s.open&&a.to<=s.close&&a.depth===s.depth+1&&a.parens===0&&(a.kind==="quoted"||a.kind==="text")&&!e.some(r=>a.from>=r.from&&a.to<=r.to));return e.length+n.length}function $s(s,t,e,n,a,r){const l=re(t,e,n);switch(s){case"global":return r("config.moduleSettings",{n:l.length});case"subscription":return r("config.moduleSubscriptions",{n:Pe(e,n,l)});case"node":return r("config.moduleNodes",{n:Pe(e,n,l)});case"group":return r("config.moduleGroups",{n:e.children.length,policies:$e(a,e.children.map(c=>{const f=re(t,c,n).find(p=>p.name==="policy")?.value;if(!f)return c.name;const i=rn(f);return r("ui.valuePair",{label:c.name,value:i?Qn({kind:i,native:f},r).label:f})}))});case"dns":{const c=e.children.filter(i=>i.name==="upstream"),f=e.children.filter(i=>i.name==="routing").flatMap(i=>i.children);return[r("config.moduleDnsUpstreams",{n:c.reduce((i,p)=>i+re(t,p,n).length,0)}),r("config.moduleDnsRequests",{n:f.filter(i=>i.name==="request").reduce((i,p)=>i+ie(t,p,n),0)}),r("config.moduleDnsResponses",{n:f.filter(i=>i.name==="response").reduce((i,p)=>i+ie(t,p,n),0)})].join(r("ui.listSeparator"))}case"routing":{const c=r("config.moduleRules",{n:ie(t,e,n)}),f=l.find(i=>i.name==="fallback")?.value;return f?c+r("ui.separator")+r("ui.valuePair",{label:"fallback",value:f}):c}}}const _s={global:null,subscription:I("nodes"),node:I("nodes"),group:I("policies"),dns:I("rules",{tab:"dns"}),routing:I("rules",{tab:"list"})};function Bs(s,t,e,n){const r=s.filter(i=>i.kind==="main"||i.kind==="include").map(i=>({source:i,..._e(i.content)})),l=s.find(i=>i.kind==="main")??null,c=zs.flatMap(i=>{const p=_s[i],g=r.flatMap(({source:u,blocks:v,tokens:N})=>v.filter(x=>x.name===i).map((x,w)=>({id:`${u.id}:${i}:${w}`,kind:i,source:u,block:x,href:p,range:Me(u,x),summary:$s(i,u.content,x,N,e,n),note:null})));return g.length?g:[{id:i,kind:i,source:l,block:null,href:p,range:l?Y(l):"config.dae",summary:l?.writable?n("config.moduleAbsent",{file:Y(l)}):n("config.moduleAbsentReadOnly"),note:null}]}),f=r.flatMap(({source:i,blocks:p})=>t.redactedSections(p).map(({block:g,name:u},v)=>({id:`${i.id}:${g.name}:${v}`,kind:u,source:i,block:null,href:null,range:Me(i,g),summary:"",note:n("config.incomplete")})));return[...c,...f]}function J(s,t,e){const n=Oe(Xn,s.kind,e);return{id:s.id,label:tn(s)?`${n} ${s.id.slice(0,8)}`:s.path,kind:n,facts:e("config.sourceFacts",{n:s.line_count,size:sn(String(s.bytes),t)}),loaded:e("config.loadedAt",{time:Ae(s.loaded_at,t)})}}const Is={generated:{label:"config.kind.generated",note:"config.generatedNote"},subscription:{label:"config.kind.subscription",note:"config.subscriptionNote"},disabled:{label:"config.readOnly",note:"config.readOnlyNote",help:"config.readOnlyHelp"},secret:{label:"config.secretSource",note:"config.secretNote"},refused:{label:"config.readOnly",note:"config.refusedNote"},redacted:{label:"config.redactedSource",note:"config.redactedNote"}};function Vs(s,t,e,n,a){const r=s.kind==="generated"||s.kind==="subscription"?s.kind:t?s.writable?e===!1?"redacted":null:n.holdsCredentials(s)?"secret":"refused":"disabled";if(!r)return null;const l=Is[r],c=a(l.label);return{reason:r,label:c,note:a(l.note),...l.help&&{help:{title:c,text:a(l.help)}}}}const Ks={error:"err",warning:"warn",info:"info"},Ws={error:"config.level.error",warning:"config.level.warning",info:"config.level.info"};function oe(s,t,e,n){const a=new Map(t.map(l=>[l.id,Y(l)])),r=new Map;for(const l of s){const c=JSON.stringify([l.level,l.source_id,l.line,l.column,l.code,l.message,l.params]),f=r.get(c);f?f.count++:r.set(c,{item:l,count:1})}return[...r].map(([l,{item:c,count:f}])=>{const i=a.get(c.source_id)??c.source_id,p=de(c,n),g=p.summary,u=f>1?n("config.repeated",{text:g,n:je(f,e)}):g,v=he(p,n,u);return{id:l,level:c.level,tone:Ks[c.level],levelText:Oe(Ws,c.level,n),sourceId:c.source_id,line:c.line,where:c.line===null?i:`${i}:${c.line}`,message:u,code:c.code,detail:c.line===null?v:n("config.atFile",{file:i,line:je(c.line,e),message:v}),count:f}})}function le(s){return{...Vn(s),rules:s.trim()?"keep":Kn}}function Us(s,t,e){return t.content_sha256===e.content_sha256?null:s?"conflict":"follow"}function Gs(s,t,e){return{groupUsedText:s.rules==="keep"?null:ke[s.rules].groups.length?e("config.wizardNamedGroups",{names:$e(t,ke[s.rules].groups.map(n=>n.name))}):e("config.wizardGroupUsed",{name:s.group??Un}),rows:s.subscriptions.flatMap((n,a)=>n.raw!==void 0&&!n.raw.
Line truncated
|
||||
|
||||
}`;v.dispatch({changes:{from:x,to:w,insert:h},selection:{anchor:x+u.label.length+4}})}}));else if(p==="routing"||p==="dns")g=[...rt,...lt];else if(p==="global")g=ot;else if(p==="group")g=/\bpolicy\s*:\s*[\w.-]*$/.test(a)?Re:[...Re.map(u=>({...u,apply:"policy: "+u.label})),{label:"filter",type:"property",apply:"filter: "}];else return null;return{from:e.from,options:g,validFor:/^[\w.-]*$/}}function dt(s){return ns({override:[t=>ct(t,s)]})}function ut(s,t){return t.filter(e=>e.line>=1&&e.line<=s.doc.lines).map(e=>{const n=s.doc.line(e.line),a=Math.max(0,(e.column??1)-1),r=new TextEncoder().encode(n.text);let l=0;for(let f=0;f<Math.min(a,r.length);){const i=r[f]<128?1:r[f]<224?2:r[f]<240?3:4;if(f+i>a)break;f+=i,l+=i===4?2:1}return{from:n.from+l,to:n.to,severity:e.level,message:e.message}})}function ft(s){return s.key==="Backspace"||s.key==="Delete"||s.key==="Enter"?!0:[...s.key].length===1&&!s.ctrlKey&&!s.metaKey}function pt(s){let t=!1;const e=n=>(n.state.readOnly&&s(),!1);return _.domEventHandlers({keydown:(n,a)=>ft(n)&&e(a),paste:(n,a)=>e(a),cut:(n,a)=>e(a),pointerdown:n=>(t=n.pointerType==="touch",!1),click:(n,a)=>t&&e(a)})}const gt=[["Completions","cm.completions"],["Find","cm.find"],["Replace","cm.replace"],["next","cm.next"],["previous","cm.previous"],["all","cm.all"],["match case","cm.matchCase"],["regexp","cm.regexp"],["by word","cm.byWord"],["replace","cm.replaceOne"],["replace all","cm.replaceAll"],["close","ui.close"],["Go to line","cm.gotoLine"],["go","cm.go"],["current match","cm.currentMatch"],["replaced $ matches","cm.replacedMatches"],["replaced match on line $","cm.replacedOnLine"],["on line","cm.onLine"],["Selection deleted","cm.selectionDeleted"],["Control character","cm.controlCharacter"]],Te=s=>be.phrases.of(Object.fromEntries(gt.map(([t,e])=>[t,s(e)]))),mt=_.theme({"&":{backgroundColor:"var(--rp-base)",color:"var(--rp-text)",border:"1px solid var(--rp-hl-high)",borderRadius:"var(--rp-r-md)",fontSize:"var(--rp-text-sm)"},"&.cm-focused":{outline:"none",borderColor:"var(--rp-accent)",boxShadow:"0 0 0 1px var(--rp-accent)"},".cm-scroller":{fontFamily:"ui-monospace, 'SF Mono', Menlo, Consolas, 'JetBrains Mono', 'Fira Code', 'DejaVu Sans Mono', 'Liberation Mono', 'Noto Sans Mono', monospace",lineHeight:"20px",maxHeight:"70vh",fontVariantLigatures:"none",borderRadius:"calc(var(--rp-r-md) - 1px)"},".cm-content":{padding:"8px 0",caretColor:"var(--rp-text)"},".cm-line":{padding:"0 12px"},".cm-gutters":{backgroundColor:"var(--rp-base)",color:"var(--rp-muted)",border:"none"},".cm-lineNumbers .cm-gutterElement":{padding:"0 8px 0 12px",minWidth:"40px"},".cm-activeLine, .cm-focusLine":{backgroundColor:"color-mix(in srgb, var(--rp-hl-med) 60%, transparent)"},".cm-activeLineGutter":{backgroundColor:"transparent",color:"var(--rp-text)"},".cm-selectionBackground, &.cm-focused .cm-selectionBackground, ::selection":{backgroundColor:"var(--rp-hl-high)"},".cm-cursor":{borderLeftColor:"var(--rp-text)"},".cm-matchingBracket":{backgroundColor:"color-mix(in srgb, var(--rp-accent) 20%, transparent)",outline:"none"},".cm-selectionMatch":{backgroundColor:"color-mix(in srgb, var(--rp-notice) 25%, transparent)"},".cm-tooltip.cm-tooltip-lint":{backgroundColor:"var(--rp-text)",color:"var(--rp-on-text)",border:"none",borderRadius:"var(--rp-r-sm)",padding:"2px 0"},".cm-tooltip-lint .cm-diagnostic":{border:"none",padding:"2px 8px",fontSize:"var(--rp-text-xs)",lineHeight:"16px",fontFamily:"inherit"},".cm-tooltip-lint .cm-diagnosticText":{color:"inherit"},".cm-diag-line-error":{backgroundColor:"color-mix(in srgb, var(--rp-negative) 14%, transparent)"},".cm-diag-line-warning":{backgroundColor:"color-mix(in srgb, var(--rp-notice) 16%, transparent)"},".cm-diag-line-info":{backgroundColor:"color-mix(in srgb, var(--rp-foam) 14%, transparent)"},".cm-lintRange-error":{backgroundImage:"none",textDecoration:"underline wavy var(--rp-negative)",textUnderlineOffset:"3px"},".cm-lintRange-warning":{backgroundImage:"none",textDecoration:"underline wavy var(--rp-notice)",textUnderlineOffset:"3px"},".cm-lintRange-info":{backgroundImage:"none",textDecoration:"underline dotted var(--rp-foam)",textUnderlineOffset:"3px"},".cm-tooltip":{backgroundColor:"var(--rp-surface)",border:"1px solid var(--rp-hl-high)",borderRadius:"var(--rp-r-md)",color:"var(--rp-text)"},".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]":{backgroundColor:"var(--rp-selected)",color:"var(--rp-text)"},".cm-tooltip.cm-tooltip-autocomplete > ul":{fontFamily:"ui-monospace, 'SF Mono', Menlo, Consolas, 'JetBrains Mono', 'Fira Code', 'DejaVu Sans Mono', 'Liberation Mono', 'Noto Sans Mono', monospace"},".cm-panels":{backgroundColor:"var(--rp-surface)",color:"var(--rp-text)"},".cm-panels-bottom":{borderTop:"1px solid var(--rp-hl-med)"},".cm-textfield":{border:"1px solid var(--rp-hl-high)",borderRadius:"var(--rp-r-sm)",backgroundColor:"var(--rp-base)",color:"var(--rp-text)"},".cm-button":{border:"1px solid var(--rp-hl-high)",borderRadius:"var(--rp-r-sm)",backgroundImage:"n
Line truncated
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
import{j as o,r as x}from"./vendor-react-Bf71BWbF.js";import{aT as hn,aU as fn,aV as ue,aW as le,u as J,aI as Ue,a6 as he,a as fe,av as X,aX as K,aY as gn,aM as Ve,aZ as xn,aN as pe,E as Qe,a5 as se,a_ as wn,a$ as vn,Z as F,b0 as Q,b1 as yn,b2 as Ce,a0 as ae,b3 as Ke,a2 as jn,a4 as ge,b4 as xe,b5 as Je,b6 as me,aw as _n,b7 as kn,b8 as Cn,b9 as An,aB as Ae,ba as Nn,bb as Ge,aO as be,aL as oe,bc as Mn,bd as Ln,aa as Ye,ac as E,ag as Sn,be as Tn,bf as Rn,f as Ne,bg as Pn,Y as Fn,ab as Dn,bh as Wn,bi as In,a1 as On,ad as En,bj as Bn,bk as Ze,bl as Hn,bm as te,bn as Un,b as Vn,bo as Qn,bp as Kn,A as Jn,bq as Gn,T as Me,br as re,bs as Yn,bt as Le,B as Z,bu as Zn,bv as qn,bw as Xn,aJ as $n,aK as Se,bx as zn}from"./index-Bw0aJc9a.js";import{M as et}from"./ActionGroup-DLxTuKht.js";import{F as nt}from"./FactStrip-DtkOGBRy.js";import{B as tt,r as ot}from"./ranked-SM2ov7Tw.js";import{u as st,C as at,s as Te,a as lt,p as Re}from"./layout-BWzq8YqC.js";import{D as it}from"./Table-Km6Zv-S8.js";import{T as ct}from"./TimeCell-DKHUJpad.js";import{w as Pe}from"./labels-Bgu_ZhL8.js";import{c as Fe,d as rt,e as dt}from"./files-BxEOxSF8.js";import{u as ut,R as pt}from"./useQuickRule-BmFeKwTA.js";import{u as mt}from"./outbounds-DMhWS-9H.js";import{u as bt}from"./flows-D3eabARZ.js";import{c as qe}from"./nav-Wiib71Wo.js";import"./useGridSelectionCheckbox-COXIVEmS.js";import"./Virtualizer-DCY9HC9Z.js";import"./ListLayout-_fDlx5XY.js";import"./DaeCode-B8yPDjSE.js";const O=64,ht=22,V=8,ft=28;function gt({label:n,series:t,fmt:e,onSelect:s,regions:r,height:d=260}){const l=hn(),[a,c]=fn(),{ref:u,tip:b,show:g,hide:p}=st(),w=Math.max(1,...t.flatMap(h=>h.points.flatMap(S=>[S.x,S.y]))),{end:_,ticks:v}=lt(w),m=Math.max((c??0)-O-ft,1),C=d-V-ht,y=h=>O+Te(h,_)*m,j=h=>V+(1-Te(h,_))*C,N=new Map,G=t.flatMap(h=>h.points.map(S=>{const A=y(S.x),k=j(S.y),M=A+","+k,D=N.get(M)??0;return N.set(M,D+1),{point:S,color:h.color,cx:A,cy:k,nth:D,spot:M}})).map(h=>({...h,twins:N.get(h.spot)}));return o.jsx("div",{className:"rp-scatter",ref:a,children:o.jsxs("div",{className:"rp-chart-hover",ref:u,onPointerLeave:p,children:[c!==null&&o.jsxs("svg",{width:c,height:d,role:"img","aria-label":n,"aria-describedby":l,children:[v.map(h=>o.jsxs("g",{children:[o.jsx("line",{className:"grid",x1:y(h),x2:y(h),y1:V,y2:V+C}),o.jsx("line",{className:"grid",x1:O,x2:O+m,y1:j(h),y2:j(h)}),o.jsx("text",{className:"tick",x:y(h),y:d-6,textAnchor:"middle",children:e(h)}),o.jsx("text",{className:"tick",x:O-8,y:j(h)+4,textAnchor:"end",children:e(h)})]},h)),r&&o.jsxs("g",{className:"diagonal",children:[o.jsx("line",{x1:y(0),y1:j(0),x2:y(_),y2:j(_)}),o.jsx("text",{x:O+8,y:V+14,children:r.above}),o.jsx("text",{x:O+m-8,y:V+C-8,textAnchor:"end",children:r.below})]}),G.map(({point:h,color:S,cx:A,cy:k,nth:M,twins:D})=>{const W=2*Math.PI*M/D,Y=D>1?6:0;return o.jsx("circle",{className:s?"pick":void 0,cx:A+Y*Math.cos(W),cy:k+Y*Math.sin(W),r:5,fill:S,onClick:s?()=>s(h.id):void 0,onPointerMove:R=>g(R,[h.name,h.detail])},h.id)})]}),o.jsx(at,{tip:b})]})})}function xt({series:n}){return o.jsx("div",{className:"rp-legend",children:n.map(t=>o.jsx(ue,{swatch:t.color,label:t.label,value:String(t.points.length)},t.id))})}function wt(n,t){const e=new Map;let s=0;for(const a of n){if(a.upload_bytes===null||a.download_bytes===null){s++;continue}const c={id:a.id,up:Number(a.upload_bytes),down:Number(a.download_bytes),name:a.domain||a.dst||a.id},u=e.get(a.outbound);u?u.push(c):e.set(a.outbound,[c])}const r=[...e].map(([a,c])=>({outbound:a,points:c})).sort((a,c)=>le(t)(a.outbound??"",c.outbound??""));let d,l=-1n;for(const a of n){if(a.upload_bytes===null||a.download_bytes===null)continue;const c=BigInt(a.upload_bytes)+BigInt(a.download_bytes);c>l&&(l=c,d={id:a.id,up:Number(a.upload_bytes),down:Number(a.download_bytes),name:a.domain||a.dst||a.id,outbound:a.outbound})}return{series:r,unknown:s,heaviest:d,placed:n.length-s}}const De=[0,2,3,1,4,5,6,7],vt=x.memo(function({records:t,outbounds:e,latency:s,latencyError:r,retryLatency:d,truncated:l,onSelect:a}){const c=J(),u=Ue(),b=he[fe()],g=x.useCallback(m=>X(m,b),[b]),p=x.useMemo(()=>wt(t,b),[t,b]),w=x.useMemo(()=>{const m=e.filter(y=>y!=="block"),C=y=>y==="block"?u.negative:u.cat[De[Math.max(0,m.indexOf(y))%De.length]];return p.series.map(y=>({id:y.outbound??"",label:K(y.outbound,c),color:C(y.outbound),points:y.points.map(j=>({id:j.id,x:j.up,y:j.down,name:j.name,detail:c("conn.chart.point",{download:g(j.down),upload:g(j.up)})}))}))},[p,e,u,c,g]),_=p.heaviest?[{label:c("conn.chart.busiest"),icon:o.jsx(gn,{}),tint:"c3",value:p.heaviest.name,caption:K(p.heaviest.outbound,c)},{label:c("conn.chart.down"),value:g(p.heaviest.down),icon:o.jsx(Ve,{}),tint:"c1"},{label:c("conn.chart.up"),value:g(p.heaviest.up),icon:o.jsx(xn,{}),tint:"c4"}]:[],v=p.unknown?c("conn.chart.sampleUnknown",{n:t.length,unknown:p.unknown}):c("conn.chart.sample",{n:t.length});return o.jsxs("div",{className:"rp-chart-page",children:[o.jsx(nt,{facts:_,lead:!0}),o.jsxs(pe,{title:c("conn.chart.title"),note:v,Line truncated
|
||||
import{j as o,r as x}from"./vendor-react-Bf71BWbF.js";import{aT as hn,aU as fn,aV as ue,aW as le,u as J,aI as Ue,a6 as he,a as fe,av as X,aX as K,aY as gn,aM as Ve,aZ as xn,aN as pe,E as Qe,a5 as se,a_ as wn,a$ as vn,Z as F,b0 as Q,b1 as yn,b2 as Ce,a0 as ae,b3 as Ke,a2 as jn,a4 as ge,b4 as xe,b5 as Je,b6 as me,aw as _n,b7 as kn,b8 as Cn,b9 as An,aB as Ae,ba as Nn,bb as Ge,aO as be,aL as oe,bc as Mn,bd as Ln,aa as Ye,ac as E,ag as Sn,be as Tn,bf as Rn,f as Ne,bg as Pn,Y as Fn,ab as Dn,bh as Wn,bi as In,a1 as On,ad as En,bj as Bn,bk as Ze,bl as Hn,bm as te,bn as Un,b as Vn,bo as Qn,bp as Kn,A as Jn,bq as Gn,T as Me,br as re,bs as Yn,bt as Le,B as Z,bu as Zn,bv as qn,bw as Xn,aJ as $n,aK as Se,bx as zn}from"./index-BOpK0UVB.js";import{M as et}from"./ActionGroup-BU73NzbX.js";import{F as nt}from"./FactStrip-CPXeRki4.js";import{B as tt,r as ot}from"./ranked-DDCHUGeL.js";import{u as st,C as at,s as Te,a as lt,p as Re}from"./layout-Bzzn7HLw.js";import{D as it}from"./Table-BkehX7fw.js";import{T as ct}from"./TimeCell-COfj2dEh.js";import{w as Pe}from"./labels-Bgu_ZhL8.js";import{c as Fe,d as rt,e as dt}from"./files-BxEOxSF8.js";import{u as ut,R as pt}from"./useQuickRule-qFvcUoSC.js";import{u as mt}from"./outbounds-BVwoUbXQ.js";import{u as bt}from"./flows-BW6GjUpE.js";import{c as qe}from"./nav-Wiib71Wo.js";import"./useGridSelectionCheckbox-C4VxQajJ.js";import"./Virtualizer-BIsXGNLZ.js";import"./ListLayout-CkBMjK9o.js";import"./DaeCode-B8yPDjSE.js";const O=64,ht=22,V=8,ft=28;function gt({label:n,series:t,fmt:e,onSelect:s,regions:r,height:d=260}){const l=hn(),[a,c]=fn(),{ref:u,tip:b,show:g,hide:p}=st(),w=Math.max(1,...t.flatMap(h=>h.points.flatMap(S=>[S.x,S.y]))),{end:_,ticks:v}=lt(w),m=Math.max((c??0)-O-ft,1),C=d-V-ht,y=h=>O+Te(h,_)*m,j=h=>V+(1-Te(h,_))*C,N=new Map,G=t.flatMap(h=>h.points.map(S=>{const A=y(S.x),k=j(S.y),M=A+","+k,D=N.get(M)??0;return N.set(M,D+1),{point:S,color:h.color,cx:A,cy:k,nth:D,spot:M}})).map(h=>({...h,twins:N.get(h.spot)}));return o.jsx("div",{className:"rp-scatter",ref:a,children:o.jsxs("div",{className:"rp-chart-hover",ref:u,onPointerLeave:p,children:[c!==null&&o.jsxs("svg",{width:c,height:d,role:"img","aria-label":n,"aria-describedby":l,children:[v.map(h=>o.jsxs("g",{children:[o.jsx("line",{className:"grid",x1:y(h),x2:y(h),y1:V,y2:V+C}),o.jsx("line",{className:"grid",x1:O,x2:O+m,y1:j(h),y2:j(h)}),o.jsx("text",{className:"tick",x:y(h),y:d-6,textAnchor:"middle",children:e(h)}),o.jsx("text",{className:"tick",x:O-8,y:j(h)+4,textAnchor:"end",children:e(h)})]},h)),r&&o.jsxs("g",{className:"diagonal",children:[o.jsx("line",{x1:y(0),y1:j(0),x2:y(_),y2:j(_)}),o.jsx("text",{x:O+8,y:V+14,children:r.above}),o.jsx("text",{x:O+m-8,y:V+C-8,textAnchor:"end",children:r.below})]}),G.map(({point:h,color:S,cx:A,cy:k,nth:M,twins:D})=>{const W=2*Math.PI*M/D,Y=D>1?6:0;return o.jsx("circle",{className:s?"pick":void 0,cx:A+Y*Math.cos(W),cy:k+Y*Math.sin(W),r:5,fill:S,onClick:s?()=>s(h.id):void 0,onPointerMove:R=>g(R,[h.name,h.detail])},h.id)})]}),o.jsx(at,{tip:b})]})})}function xt({series:n}){return o.jsx("div",{className:"rp-legend",children:n.map(t=>o.jsx(ue,{swatch:t.color,label:t.label,value:String(t.points.length)},t.id))})}function wt(n,t){const e=new Map;let s=0;for(const a of n){if(a.upload_bytes===null||a.download_bytes===null){s++;continue}const c={id:a.id,up:Number(a.upload_bytes),down:Number(a.download_bytes),name:a.domain||a.dst||a.id},u=e.get(a.outbound);u?u.push(c):e.set(a.outbound,[c])}const r=[...e].map(([a,c])=>({outbound:a,points:c})).sort((a,c)=>le(t)(a.outbound??"",c.outbound??""));let d,l=-1n;for(const a of n){if(a.upload_bytes===null||a.download_bytes===null)continue;const c=BigInt(a.upload_bytes)+BigInt(a.download_bytes);c>l&&(l=c,d={id:a.id,up:Number(a.upload_bytes),down:Number(a.download_bytes),name:a.domain||a.dst||a.id,outbound:a.outbound})}return{series:r,unknown:s,heaviest:d,placed:n.length-s}}const De=[0,2,3,1,4,5,6,7],vt=x.memo(function({records:t,outbounds:e,latency:s,latencyError:r,retryLatency:d,truncated:l,onSelect:a}){const c=J(),u=Ue(),b=he[fe()],g=x.useCallback(m=>X(m,b),[b]),p=x.useMemo(()=>wt(t,b),[t,b]),w=x.useMemo(()=>{const m=e.filter(y=>y!=="block"),C=y=>y==="block"?u.negative:u.cat[De[Math.max(0,m.indexOf(y))%De.length]];return p.series.map(y=>({id:y.outbound??"",label:K(y.outbound,c),color:C(y.outbound),points:y.points.map(j=>({id:j.id,x:j.up,y:j.down,name:j.name,detail:c("conn.chart.point",{download:g(j.down),upload:g(j.up)})}))}))},[p,e,u,c,g]),_=p.heaviest?[{label:c("conn.chart.busiest"),icon:o.jsx(gn,{}),tint:"c3",value:p.heaviest.name,caption:K(p.heaviest.outbound,c)},{label:c("conn.chart.down"),value:g(p.heaviest.down),icon:o.jsx(Ve,{}),tint:"c1"},{label:c("conn.chart.up"),value:g(p.heaviest.up),icon:o.jsx(xn,{}),tint:"c4"}]:[],v=p.unknown?c("conn.chart.sampleUnknown",{n:t.length,unknown:p.unknown}):c("conn.chart.sample",{n:t.length});return o.jsxs("div",{className:"rp-chart-page",children:[o.jsx(nt,{facts:_,lead:!0}),o.jsxs(pe,{title:c("conn.chart.title"),note:v,Line truncated
|
||||
`)+`
|
||||
`}function Wt(n,t){const e=n.map(r=>r.id),s=t.bulkLimit!=null&&e.length>t.bulkLimit;return t.narrowed||t.truncated||s?{ids:e}:{ids:e,query:{type:t.network,src:t.src,all:!0}}}const It=n=>n.target;function Ot({collection:n,view:t,collapse:e,onToggleGroup:s,loading:r,selected:d,onSelect:l,selectOnFocus:a,onSort:c}){const u=J(),[b,g]=Nn(442),p=x.useMemo(()=>{const v={dst:m=>o.jsx(oe,{children:m.target}),src:m=>o.jsx(oe,{className:"rp-code",children:m.source}),node:m=>o.jsx(oe,{className:"rp-chain",text:m.path??void 0,children:m.node}),rule:m=>o.jsxs("span",{className:"rp-rule",children:[o.jsx(Ge,{...m.rule}),m.recomputed&&o.jsx(be,{children:m.recomputed})]}),state:m=>m.state,down:m=>m.download,downRate:m=>m.downloadRate,age:m=>o.jsx(ct,{at:m.startedAt})};return B.filter(m=>!t.hidden.includes(m.id)).map(m=>({...m,label:u(m.label),grow:1,render:v[m.id]}))},[t.hidden,u]),w=x.useMemo(()=>n.map(v=>"connection"in v?v.connection:v),[n]),_=x.useMemo(()=>({grouped:t.group!=="none",collapsed:v=>Xe(e,v),onToggle:s}),[t.group,e,s]);return o.jsx("div",{ref:b,children:o.jsx(it,{label:u("nav.connections"),rowDetail:!0,cols:p,rows:w,height:g,selected:d&&we(d),onSelect:l&&(v=>l(v&&At(v))),selectOnFocus:a,reveal:!0,empty:u("conn.empty"),loading:r,sort:t.sort&&{column:String(t.sort.column),direction:t.sort.direction},onSort:c,getTextValue:It,stream:!0,tree:_})})}function Et(n,t,e){if(!t.some(p=>p.health?.length))return null;const s=[];let r=0;for(const p of t){const w=Mn(Ln(p.health??[]));w===void 0?r++:s.push({node:p.id,name:p.name,value:w,connections:0})}s.sort((p,w)=>p.value-w.value||le(e)(p.name,w.name));const d=new Map(s.map(p=>[p.node,p])),l=n.some(p=>p.chain?.length);let a=0;for(const p of n){const w=p.chain?.at(-1);if(w===void 0)continue;const _=d.get(w);_?_.connections++:a++}const c=s.reduce((p,w)=>p+w.connections,0);let u=0;const b=s.find(p=>(u+=p.connections)>=Math.max(1,Math.ceil(c/2))),g=s.map(p=>p.value);return{samples:s,chains:l,missing:r,unplaced:a,used:s.filter(p=>p.connections).length,p50:Re(g,50),p90:Re(g,90),weightedP50:c?b.value:null}}const Bt=n=>({domain:n.domain??null,dip:F(n.dst)??null,sip:F(n.src)??null,outbound:n.outbound,matched:n.rule_id&&n.rule_source!=="unknown"?{id:n.rule_id,expression:n.rule_expression}:null});function Ht(n,t){const e=J(),s=Ye().data?.resources,r=ut(t),l=E(s,"rules",{whileLoading:!1})&&E(s,"config",{whileLoading:!1})&&s?.config.writable===!0?n?.rule_id??null:null,a=bt(!!l),c=Sn(!!l),u=n&&Bt(n);return{canAdd:!!u&&r.canAdd(u),addTip:u?Rn(u).length?void 0:e("conn.ruleNoTarget"):e("ui.selectRow"),canShow:E(s,"rules",{whileLoading:!1})&&!!n?.rule_id,canEdit:!!l&&Tn(a.data?.rules.find(b=>b.rule_id===l),c.data?.sources??[]),openAdd:()=>{u&&r.open(u)},dialog:r.dialog}}const en=qe().map(n=>n.id),nn=n=>["id","src","network","out","rule","q"].some(t=>new URLSearchParams(n).has(t))?"list":"traffic",q=(n,t)=>ae(n,nn(n)==="list"?{tab:Ze(n,en,"list"),...t}:t);function Ut({go:n,query:t}){const e=J(),s=he[fe()],[r,d]=x.useState(()=>{try{return Ee(localStorage.getItem(Oe))}catch{return Ee(null)}}),l=Ne(Kn),a=Ne(Qn),[c,u]=x.useState(()=>de(!1)),b=x.useCallback(i=>u(f=>$e(f,i)),[]),g=i=>{const f={...r,...i};f.group!==r.group&&u(de(!1)),d(f);try{localStorage.setItem(Oe,JSON.stringify(f))}catch{}},p=x.useMemo(()=>new URLSearchParams(t),[t]),[w,_]=x.useState(p.get("q")??""),v=p.get("network")??"all",m=p.get("out")??"all",C=p.get("rule")??"all",y=(i,f)=>n("connections",q(t,{[i]:f==="all"?null:f})),j=p.get("id"),[N,ve]=x.useState(null);Pn(p.get("q"),i=>_(i??""));const G=x.useRef(t);x.useEffect(()=>{G.current=t});const h=i=>n("connections",q(G.current,{id:i})),S=x.useDeferredValue(w),A=Fn(p.get("src")??""),k=Dn(A),M=Ye(),D=M.data?.resources.connections.can_close===!0,W=E(M.data?.resources,"rules",{whileLoading:!1}),Y=E(M.data?.resources,"flows",{whileLoading:!1});Wn(M.data?.resources);const R=mt(),I=In(k.refetch),T=x.useMemo(()=>On(k.data),[k.data]),$=E(M.data?.resources,"nodes",{whileLoading:!1}),H=En($),tn=x.useMemo(()=>$&&H.data?Et(T,H.data,s):null,[$,H.data,T,s]),on=$&&!H.data?H.error:null,sn=x.useMemo(()=>[...new Set(T.map(i=>i.outbound))].sort((i,f)=>le(s)(i??"",f??"")),[T,s]),z=S.trim().toLowerCase(),U=x.useMemo(()=>T.filter(i=>(v==="all"||i.network===v)&&(m==="all"||i.outbound===m)&&(C==="all"||i.rule_expression===C)&&(!z||[i.dst,i.domain,i.src,i.pname,K(i.outbound,e),Je(i.chain,R).join(" "),i.rule_expression].join(" ").toLowerCase().includes(z))),[T,v,m,C,z,R,e]),P=j?T.find(i=>i.id===j):void 0,[ye,je]=x.useState(null);!j&&ye!==null&&je(null);const ee=Nt(P,r.group);ee&&ye!==ee.token&&(je(ee.token),u(_t(c,ee.group)));const an=Ht(P,n),_e=x.useMemo(()=>Tt(T,k.data,A,C,m,s,e),[T,k.data,A,C,m,s,e]),ln=x.useMemo(()=>Ft(P,s,e,R,W),[P,s,e,R,W]),L={..._e,detail:ln},cn=x.useMemo(()=>St(U,r,s,R,W,e),[U,r,s,R,W,e]),rn=async()=>{if(!L.detail)return;const{id:i}=L.detail;try{if(!await I.close(i))return;new URLSearchParams(G.current).get("id")===i&&h(null),te("positive",e("conn.closed",{name:L.detail.title}))}catc
Line truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{aB as u,a3 as d,a4 as t,u as f,aL as m,aJ as c}from"./index-Bw0aJc9a.js";import{j as s}from"./vendor-react-Bf71BWbF.js";const g={userspace_tcp:"flow.userspaceTcp",userspace_udp:"flow.userspaceUdp",kernel_direct:"flow.kernelDirect",kernel_block:"flow.kernelBlock",dns_intercept:"flow.dnsIntercept",kernel_bypass:"flow.kernelBypass"},w={full:"flow.full",partial:"flow.partialVisibility",none:"ui.none"};function h(e,r,p){const l=Object.entries(e.coverage).filter(([,a])=>a!=="full"),o=u(e.dropped_records),n=o?r("flow.dropped",{n:o}):null;return!l.length&&!n?null:{summary:l.length?r("flow.coverageSummary",{n:l.length}):null,detail:d(p,l.map(([a,i])=>r("ui.valuePair",{label:t(g,a,r),value:t(w,i,r)}))),dropped:n}}function k({view:e}){const r=f();return s.jsxs("div",{className:"rp-cluster",role:"group","aria-label":r("flow.coverage"),children:[e.summary&&s.jsx(m,{text:e.detail,children:s.jsx(c,{small:!0,tone:"warn",children:e.summary})}),e.dropped&&s.jsx(c,{small:!0,tone:"warn",children:e.dropped})]})}export{k as C,h as c};
|
||||
import{aB as u,a3 as d,a4 as t,u as f,aL as m,aJ as c}from"./index-BOpK0UVB.js";import{j as s}from"./vendor-react-Bf71BWbF.js";const g={userspace_tcp:"flow.userspaceTcp",userspace_udp:"flow.userspaceUdp",kernel_direct:"flow.kernelDirect",kernel_block:"flow.kernelBlock",dns_intercept:"flow.dnsIntercept",kernel_bypass:"flow.kernelBypass"},w={full:"flow.full",partial:"flow.partialVisibility",none:"ui.none"};function h(e,r,p){const l=Object.entries(e.coverage).filter(([,a])=>a!=="full"),o=u(e.dropped_records),n=o?r("flow.dropped",{n:o}):null;return!l.length&&!n?null:{summary:l.length?r("flow.coverageSummary",{n:l.length}):null,detail:d(p,l.map(([a,i])=>r("ui.valuePair",{label:t(g,a,r),value:t(w,i,r)}))),dropped:n}}function k({view:e}){const r=f();return s.jsxs("div",{className:"rp-cluster",role:"group","aria-label":r("flow.coverage"),children:[e.summary&&s.jsx(m,{text:e.detail,children:s.jsx(c,{small:!0,tone:"warn",children:e.summary})}),e.dropped&&s.jsx(c,{small:!0,tone:"warn",children:e.dropped})]})}export{k as C,h as c};
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
import{r as h,j as s}from"./vendor-react-Bf71BWbF.js";import{u as v,aT as De,bE as Re,c as Ae,bF as me,Z as qe,a4 as ke,a_ as S,aw as Ee,a5 as fe,aq as Fe,A as ge,aB as Oe,bG as xe,aa as Y,bg as E,bH as be,ac as B,a0 as W,h as ce,bk as Pe,bj as Me,a6 as V,a as I,bI as de,Y as He,f as We,bp as Ue,bJ as Be,bm as U,bq as Ve,ag as Ie,bK as Qe,W as Ke,b as $e,bL as ze,aW as Je,ak as R,j as ve,E as O,aI as Z,bM as Ge,bN as Xe,bO as Ye,bP as Ze,aN as F,aV as oe,L as ee,aP as je,aL as A,bs as es,bQ as J,T as G,bt as ye,B as _,bR as ss,aO as we,aK as se,bx as as,aJ as ue,bw as ns,bS as ts,aM as rs,bv as ls,bu as is}from"./index-Bw0aJc9a.js";import{D as Ne}from"./Table-Km6Zv-S8.js";import{T as X}from"./TimeCell-DKHUJpad.js";import{A as cs}from"./ActionGroup-DLxTuKht.js";import{q as ds,u as Ce,a as os,b as us}from"./dns-BCg5F0Tv.js";import{c as pe,d as ps,e as hs}from"./files-BxEOxSF8.js";import{d as ms}from"./nav-CdRBQuvD.js";import{u as fs,R as gs}from"./useQuickRule-BmFeKwTA.js";import{F as xs}from"./FactStrip-DtkOGBRy.js";import{r as he,B as bs}from"./ranked-SM2ov7Tw.js";import{u as vs,w as js,C as ys,p as $}from"./layout-BWzq8YqC.js";import"./useGridSelectionCheckbox-COXIVEmS.js";import"./Virtualizer-DCY9HC9Z.js";import"./ListLayout-_fDlx5XY.js";import"./DaeCode-B8yPDjSE.js";import"./flows-D3eabARZ.js";function ws({label:t,shares:n}){const a=v(),r=De(),{ref:c,tip:e,show:l,hide:o}=vs(),i=h.useMemo(()=>{const d=js(n.map(m=>m.count));return n.flatMap((m,f)=>Array.from({length:d[f]},()=>m))},[n]);return s.jsxs("div",{className:"rp-waffle rp-chart-hover",ref:c,onPointerLeave:o,children:[s.jsx("div",{className:"grid",role:"img","aria-describedby":r,"aria-label":Re(t,n,a),children:i.map((d,m)=>s.jsx("span",{style:{background:d.color},onPointerMove:f=>l(f,[d.label,d.text])},m))}),s.jsx("ul",{className:"legend",children:n.map(d=>s.jsxs("li",{children:[s.jsx("i",{className:"sw",style:{background:d.color}}),s.jsx("span",{children:d.label}),s.jsx("b",{children:d.text})]},d.id))}),s.jsx(ys,{tip:e})]})}function Ns({className:t,...n}){return s.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:20,height:20,viewBox:"0 0 20 20","aria-hidden":"true",focusable:"false",className:Ae("rp-icon",t),...n,children:[s.jsx("path",{fill:"currentColor",d:"M8.249 15.021c-.4 0-.733-.317-.748-.72l-.25-6.5c-.017-.414.307-.763.72-.779H8c.4 0 .733.317.748.72l.25 6.5c.017.414-.307.763-.72.778zM11.751 15.021h-.03c-.413-.016-.737-.365-.72-.779l.25-6.5c.015-.403.348-.72.748-.72h.03c.413.016.737.365.72.779l-.25 6.5c-.015.403-.348.72-.748.72"}),s.jsx("path",{fill:"currentColor",d:"M17 4h-3.5v-.75C13.5 2.01 12.49 1 11.25 1h-2.5C7.51 1 6.5 2.01 6.5 3.25V4H3c-.414 0-.75.336-.75.75s.336.75.75.75h.52l.422 10.342C3.99 17.052 4.98 18 6.19 18h7.62c1.211 0 2.2-.948 2.248-2.158L16.48 5.5H17c.414 0 .75-.336.75-.75S17.414 4 17 4m-9-.75c0-.413.337-.75.75-.75h2.5c.413 0 .75.337.75.75V4H8zm6.56 12.531c-.017.404-.346.719-.75.719H6.19c-.404 0-.733-.315-.75-.719L5.02 5.5h9.96z"})]})}function ae(t,n,a,r,c){return{domain:t,dip:null,sip:(c&&qe(c))??null,outbound:null,matched:null,dns:{type:n,answers:me(a),upstream:r,query:{name:t,type:n}}}}const Cs=(t,n,a)=>({domain:null,dip:t,sip:null,outbound:null,matched:null,dns:{type:a,answers:[t],upstream:null,query:{name:n,type:a}}}),Ss={forced:"dns.route.forced","dns.routing":"dns.route.rules",default:"dns.route.default"};function Se(t,n){return{fields:[[n("ui.state"),t.status],[n("ui.upstream"),t.upstream??"—"],[n("dns.routeSource"),ke(Ss,t.route.source,n)],[n("dns.routeRule"),t.route.rule??"—"],[n("ui.elapsed"),S(t.elapsed_ms,n)]],answers:(t.answers??[]).map(a=>n("dns.answer",{name:a.name,type:a.type,ttl:a.ttl,data:a.data})),cacheText:n(t.cached?"dns.hit":"dns.miss"),cacheTone:t.cached?void 0:"warn"}}function _s(t,n,a,r,c,e){const l=n?.dns_query.record_types??[],o=a==="all"?l.length>0:l.includes(a);return{types:l,choices:[...l.map(i=>({id:i,label:i})),{id:"all",label:e("dns.allTypes")}],disabled:c||!n?.dns_query.available||!o||!r.trim(),reason:!n||c?null:n.dns_query.available?o?null:e(a==="all"?"dns.noTypes":"dns.typeUnsupported"):e("dns.queryUnavailable"),showCache:!!n?.dns_cache.available,cards:t?.results.map(i=>({id:i.type,title:`${t.domain} ${i.type}`,...Se(i,e),seed:ae(t.domain,i.type,i.answers??[],i.upstream,null),answerSeeds:(i.answers??[]).map(d=>me([d]).length?{address:d.data,seed:Cs(d.data,t.domain,i.type)}:null)}))??[],tabs:ms(n).map(i=>({id:i.id,label:e(i.titleKey)}))}}function Ts(t,n,a,r,c,e){const l=a.toLowerCase(),o=n?.dns_cache,i=(t?.entries??[]).filter(d=>!l||d.domain.toLowerCase().includes(l));return{fields:[[e("dns.entries"),t?fe(t.total,c):"—"]],coverage:t?["positive","negative","persistent"].filter(d=>!t.coverage[d]).map(d=>({id:d,text:e("ui.valuePair",{label:e({positive:"dns.positive",negative:"dns.negative",persistent:"dns.persistent"}[d]),value:e(d==="persistent"?"dns.chart.memoryOnly":"dns.notCovered")})})):[],filterText:l?e("dns.cacheFilter",{domain:a}):"",confirmationText:t?e("dns.flushConfirm",{Line truncated
|
||||
import{r as h,j as s}from"./vendor-react-Bf71BWbF.js";import{u as v,aT as De,bE as Re,c as Ae,bF as me,Z as qe,a4 as ke,a_ as S,aw as Ee,a5 as fe,aq as Fe,A as ge,aB as Oe,bG as xe,aa as Y,bg as E,bH as be,ac as B,a0 as W,h as ce,bk as Pe,bj as Me,a6 as V,a as I,bI as de,Y as He,f as We,bp as Ue,bJ as Be,bm as U,bq as Ve,ag as Ie,bK as Qe,W as Ke,b as $e,bL as ze,aW as Je,ak as R,j as ve,E as O,aI as Z,bM as Ge,bN as Xe,bO as Ye,bP as Ze,aN as F,aV as oe,L as ee,aP as je,aL as A,bs as es,bQ as J,T as G,bt as ye,B as _,bR as ss,aO as we,aK as se,bx as as,aJ as ue,bw as ns,bS as ts,aM as rs,bv as ls,bu as is}from"./index-BOpK0UVB.js";import{D as Ne}from"./Table-BkehX7fw.js";import{T as X}from"./TimeCell-COfj2dEh.js";import{A as cs}from"./ActionGroup-BU73NzbX.js";import{q as ds,u as Ce,a as os,b as us}from"./dns-BY6DX1P3.js";import{c as pe,d as ps,e as hs}from"./files-BxEOxSF8.js";import{d as ms}from"./nav-B9ea5ZPQ.js";import{u as fs,R as gs}from"./useQuickRule-qFvcUoSC.js";import{F as xs}from"./FactStrip-CPXeRki4.js";import{r as he,B as bs}from"./ranked-DDCHUGeL.js";import{u as vs,w as js,C as ys,p as $}from"./layout-Bzzn7HLw.js";import"./useGridSelectionCheckbox-C4VxQajJ.js";import"./Virtualizer-BIsXGNLZ.js";import"./ListLayout-CkBMjK9o.js";import"./DaeCode-B8yPDjSE.js";import"./flows-BW6GjUpE.js";function ws({label:t,shares:n}){const a=v(),r=De(),{ref:c,tip:e,show:l,hide:o}=vs(),i=h.useMemo(()=>{const d=js(n.map(m=>m.count));return n.flatMap((m,f)=>Array.from({length:d[f]},()=>m))},[n]);return s.jsxs("div",{className:"rp-waffle rp-chart-hover",ref:c,onPointerLeave:o,children:[s.jsx("div",{className:"grid",role:"img","aria-describedby":r,"aria-label":Re(t,n,a),children:i.map((d,m)=>s.jsx("span",{style:{background:d.color},onPointerMove:f=>l(f,[d.label,d.text])},m))}),s.jsx("ul",{className:"legend",children:n.map(d=>s.jsxs("li",{children:[s.jsx("i",{className:"sw",style:{background:d.color}}),s.jsx("span",{children:d.label}),s.jsx("b",{children:d.text})]},d.id))}),s.jsx(ys,{tip:e})]})}function Ns({className:t,...n}){return s.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:20,height:20,viewBox:"0 0 20 20","aria-hidden":"true",focusable:"false",className:Ae("rp-icon",t),...n,children:[s.jsx("path",{fill:"currentColor",d:"M8.249 15.021c-.4 0-.733-.317-.748-.72l-.25-6.5c-.017-.414.307-.763.72-.779H8c.4 0 .733.317.748.72l.25 6.5c.017.414-.307.763-.72.778zM11.751 15.021h-.03c-.413-.016-.737-.365-.72-.779l.25-6.5c.015-.403.348-.72.748-.72h.03c.413.016.737.365.72.779l-.25 6.5c-.015.403-.348.72-.748.72"}),s.jsx("path",{fill:"currentColor",d:"M17 4h-3.5v-.75C13.5 2.01 12.49 1 11.25 1h-2.5C7.51 1 6.5 2.01 6.5 3.25V4H3c-.414 0-.75.336-.75.75s.336.75.75.75h.52l.422 10.342C3.99 17.052 4.98 18 6.19 18h7.62c1.211 0 2.2-.948 2.248-2.158L16.48 5.5H17c.414 0 .75-.336.75-.75S17.414 4 17 4m-9-.75c0-.413.337-.75.75-.75h2.5c.413 0 .75.337.75.75V4H8zm6.56 12.531c-.017.404-.346.719-.75.719H6.19c-.404 0-.733-.315-.75-.719L5.02 5.5h9.96z"})]})}function ae(t,n,a,r,c){return{domain:t,dip:null,sip:(c&&qe(c))??null,outbound:null,matched:null,dns:{type:n,answers:me(a),upstream:r,query:{name:t,type:n}}}}const Cs=(t,n,a)=>({domain:null,dip:t,sip:null,outbound:null,matched:null,dns:{type:a,answers:[t],upstream:null,query:{name:n,type:a}}}),Ss={forced:"dns.route.forced","dns.routing":"dns.route.rules",default:"dns.route.default"};function Se(t,n){return{fields:[[n("ui.state"),t.status],[n("ui.upstream"),t.upstream??"—"],[n("dns.routeSource"),ke(Ss,t.route.source,n)],[n("dns.routeRule"),t.route.rule??"—"],[n("ui.elapsed"),S(t.elapsed_ms,n)]],answers:(t.answers??[]).map(a=>n("dns.answer",{name:a.name,type:a.type,ttl:a.ttl,data:a.data})),cacheText:n(t.cached?"dns.hit":"dns.miss"),cacheTone:t.cached?void 0:"warn"}}function _s(t,n,a,r,c,e){const l=n?.dns_query.record_types??[],o=a==="all"?l.length>0:l.includes(a);return{types:l,choices:[...l.map(i=>({id:i,label:i})),{id:"all",label:e("dns.allTypes")}],disabled:c||!n?.dns_query.available||!o||!r.trim(),reason:!n||c?null:n.dns_query.available?o?null:e(a==="all"?"dns.noTypes":"dns.typeUnsupported"):e("dns.queryUnavailable"),showCache:!!n?.dns_cache.available,cards:t?.results.map(i=>({id:i.type,title:`${t.domain} ${i.type}`,...Se(i,e),seed:ae(t.domain,i.type,i.answers??[],i.upstream,null),answerSeeds:(i.answers??[]).map(d=>me([d]).length?{address:d.data,seed:Cs(d.data,t.domain,i.type)}:null)}))??[],tabs:ms(n).map(i=>({id:i.id,label:e(i.titleKey)}))}}function Ts(t,n,a,r,c,e){const l=a.toLowerCase(),o=n?.dns_cache,i=(t?.entries??[]).filter(d=>!l||d.domain.toLowerCase().includes(l));return{fields:[[e("dns.entries"),t?fe(t.total,c):"—"]],coverage:t?["positive","negative","persistent"].filter(d=>!t.coverage[d]).map(d=>({id:d,text:e("ui.valuePair",{label:e({positive:"dns.positive",negative:"dns.negative",persistent:"dns.persistent"}[d]),value:e(d==="persistent"?"dns.chart.memoryOnly":"dns.notCovered")})})):[],filterText:l?e("dns.cacheFilter",{domain:a}):"",confirmationText:t?e("dns.flushConfirm",{Line truncated
|
||||
`)+`
|
||||
`}function As(t,n){const a=new Set(t.records.map(r=>r.id));return{...t,records:[...t.records,...n.records.filter(r=>!a.has(r.id))],next_cursor:n.next_cursor}}function qs(t,n){const a=n&&new Set(n.records.map(r=>r.id));return{data:n??t,newerWaiting:!!a&&!!t?.records.some(r=>!a.has(r.id))}}function ks(t,n,a){if(!t)return null;const{usage:r,coverage:c}=t,e=i=>{const d=Oe(i);return d===null?"—":fe(d,n)},l=r?.entry_capacity??null,o=r&&l!==null?Fe(r.entries,l):null;return{note:r?l===null?a("dns.chart.usageFacts",{entries:e(r.entries)}):void 0:a("dns.chart.cacheNote",{n:t.total}),usage:r&&l!==null&&o!==null?{pct:o,value:o>0&&o<.5?"<"+a("ui.percent",{n:1}):a("ui.percent",{n:Math.round(o)}),facts:a("dns.chart.usageFacts",{entries:a("ui.fraction",{part:e(r.entries),whole:e(l)})})}:null,coverage:a("dns.chart.coverage",{kinds:[c.positive&&a("dns.chart.positive"),c.negative&&a("dns.chart.negative")].filter(Boolean).join(a("ui.listSeparator")),persistent:a(c.persistent?"dns.chart.persistent":"dns.chart.memoryOnly")})}}function Es(t,n,a){return t?a instanceof ge&&a.status===503?"unavailable":n?"ready":a?"error":"loading":"unlisted"}function Fs({go:t,query:n}){const a=v(),r=xe(),c=Y(),e=h.useMemo(()=>new URLSearchParams(n),[n]),[l,o]=h.useState(e.get("domain")??""),[i,d]=h.useState(e.get("type")??"A");E(e.get("domain"),p=>o(p??"")),E(e.get("type"),p=>d(p??"A"));const[m,f]=h.useState(null),{busy:x,error:y,run:C}=be({rethrow:!0}),u=c.data?.resources,b=h.useMemo(()=>_s(m,u,i,l,!!x,a),[m,u,i,l,x,a]),w=b.tabs.map(p=>p.id),T=e.has("domain")||e.has("device"),q=w.includes("log")?T?"log":"stats":w.includes("query")?"query":w[0]??"query",N=async(p={domain:l,type:i})=>{try{await C("query",async g=>{const H=await ds(r.dnsQuery,p.domain.trim(),p.type==="all"?b.types:[p.type],u?.dns_query.limits?.max_types_per_request??1,g);return g.aborted||f(H),H})}catch{}},P=B(u,"dns_query",{whileLoading:!1})&&b.types.length>0,L=fs(t,{queryAgain:P?p=>{const g=b.types.includes(p.type)?p.type:"all";t("dns",W("",{tab:"query",domain:p.name.replace(/\.$/,""),type:g,run:"1"}))}:void 0}),k=e.has("run")&&u?n:null,M=h.useEffectEvent(p=>{const g=new URLSearchParams(p);t("dns",W(p,{run:null}),{replace:!0}),N({domain:g.get("domain")??"",type:g.get("type")??"A"})});return h.useEffect(()=>{k!==null&&M(k)},[k]),{...b,rule:L,domain:l,setDomain:o,type:i,setType:d,pending:x==="query",queryError:y,submit:()=>void N(),setTab:p=>t("dns",Me(n,p,u&&!T?q:null)),tab:Pe(n,b.tabs.map(p=>p.id),q),filterDomain:e.get("domain")??"",filterDevice:e.get("device")??"",cacheHref:w.includes("cache")?ce("dns",{tab:"cache"}):null,logHref:(p,g)=>ce("dns",{tab:"log",[p]:g}),logLinks:[...B(u,"dns_rules",{whileLoading:!1})?[{id:"rules",label:a("rule.dnsTitle"),onAction:()=>t("rules","tab=dns")}]:[],...u?.runtime_settings.available?[{id:"recording",label:a("ui.recordingSettings"),onAction:()=>t("settings","card=runtime")}]:[]],logEnabled:u?.dns_log.available,viewCache:()=>t("dns",W(n,{tab:"cache",domain:m?.domain??""})),clearCacheFilter:()=>t("dns",W(n,{tab:"cache",domain:null}))}}function Os(t){const n=v(),a=V[I()],r=os(!Be()),c=h.useMemo(()=>Ts(r.cache.data,r.capabilities.data?.resources,t,r.busy,a,n),[r.cache.data,r.capabilities.data,t,r.busy,a,n]),[e,l]=h.useState(null),o=c.rows.find(f=>f.id===e),{remove:i}=r,d=h.useCallback(f=>void i(f).then(x=>x&&U("positive",n("dns.deleted",{n:x.deleted})),x=>U("negative",n("dns.deleteFailed"),Ve(x,n))),[i,n]),m=async()=>{try{const f=await r.flush();f&&U("positive",n("dns.flushed",{matched:f.matched,deleted:f.deleted}))}catch(f){return n("dns.flushFailed",{error:$e(f,n)})}};return{...c,selected:o?e:null,setSelected:l,seed:o?.seed??null,error:r.cache.error,retry:r.cache.refetch,loading:(r.cache.loading||r.capabilities.loading)&&!r.cache.data,flushPending:r.busy==="flush",remove:d,flush:m,abortFlush:()=>{r.cancel(),r.cache.refetch()}}}function Ps(t){const n=Ce({},t===!0),a=Y().data?.resources,r=B(a,"config",{whileLoading:!1}),e=Ie(t===!0&&r).data?.sources,l=h.useMemo(()=>r&&e?Qe(e,"dns"):null,[r,e]);return{log:n,cacheListed:B(a,"dns_cache",{whileLoading:!1})&&a?.dns_cache.read===!0,configHref:l}}function Ms(t){const n=v(),a=V[I()],[r,c]=ze(),[e,l]=h.useState(!1),o=us(t,!c&&e);o.data&&!e&&l(!0);const i=h.useMemo(()=>ks(o.data,a,n),[o.data,a,n]);return{ref:r,card:i,state:Es(t,!!i,o.error),error:o.error,retry:o.refetch}}function Hs(t,n,a){const r=v(),c=V[I()],[e,l]=h.useState(n);E(n,l);const[o,i]=h.useState("all"),[d,m]=h.useState(a);E(a,m);const f=xe(),x=Y(),y=de(d),C=He(y),u=y.trim()!==""&&!C,[b,w]=h.useState(C);!u&&C!==b&&w(C);const T={name:de(e),type:o,src:u?b:C},q=JSON.stringify(T),N=Ce(T,t===!0),[P,L]=h.useState(null),[k,M]=h.useState(!1),p=be({scope:q});E(q,()=>L(null));const{data:g,newerWaiting:H}=h.useMemo(()=>qs(N.data,P),[N.data,P]),ne=()=>void p.run("older",async D=>{if(!g?.next_cursor)return;L(g);let le;try{le=await f.dnsLog({name:T.name.trim()||void 0,type:o==="all"?void 0:o,src:T.src,cursor:g.next_cursor,limit:N.limit},D)}catch(j){if(!(j in
Line truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{r as an,j as K}from"./vendor-react-Bf71BWbF.js";import{u as cn,fx as fn}from"./index-Bw0aJc9a.js";import{u as gn,i as hn,e as pn,C as yn}from"./layout-BWzq8YqC.js";import{w as dn,c as T,a as mn}from"./array-C0P64tl-.js";const on=Math.abs,P=Math.atan2,k=Math.cos,vn=Math.max,rn=Math.min,C=Math.sin,F=Math.sqrt,S=1e-12,V=Math.PI,X=V/2,W=2*V;function xn(t){return t>1?0:t<-1?V:Math.acos(t)}function ln(t){return t>=1?X:t<=-1?-X:Math.asin(t)}function An(t){return t.innerRadius}function Mn(t){return t.outerRadius}function Rn(t){return t.startAngle}function Pn(t){return t.endAngle}function wn(t){return t&&t.padAngle}function Tn(t,h,x,w,v,A,p,n){var f=x-t,u=w-h,e=p-v,y=n-A,r=y*f-e*u;if(!(r*r<S))return r=(e*(h-A)-y*(t-v))/r,[t+r*f,h+r*u]}function U(t,h,x,w,v,A,p){var n=t-x,f=h-w,u=(p?A:-A)/F(n*n+f*f),e=u*f,y=-u*n,r=t+e,a=h+y,g=x+e,d=w+y,j=(r+g)/2,c=(a+d)/2,m=g-r,i=d-a,l=m*m+i*i,M=v-A,R=r*d-g*a,I=(i<0?-1:1)*F(vn(0,M*M*l-R*R)),$=(R*i-m*I)/l,B=(-R*m-i*I)/l,b=(R*i+m*I)/l,E=(-R*m+i*I)/l,L=$-j,s=B-c,o=b-j,N=E-c;return L*L+s*s>o*o+N*N&&($=b,B=E),{cx:$,cy:B,x01:-e,y01:-y,x11:$*(v/M-1),y11:B*(v/M-1)}}function jn(){var t=An,h=Mn,x=T(0),w=null,v=Rn,A=Pn,p=wn,n=null,f=dn(u);function u(){var e,y,r=+t.apply(this,arguments),a=+h.apply(this,arguments),g=v.apply(this,arguments)-X,d=A.apply(this,arguments)-X,j=on(d-g),c=d>g;if(n||(n=e=f()),a<r&&(y=a,a=r,r=y),!(a>S))n.moveTo(0,0);else if(j>W-S)n.moveTo(a*k(g),a*C(g)),n.arc(0,0,a,g,d,!c),r>S&&(n.moveTo(r*k(d),r*C(d)),n.arc(0,0,r,d,g,c));else{var m=g,i=d,l=g,M=d,R=j,I=j,$=p.apply(this,arguments)/2,B=$>S&&(w?+w.apply(this,arguments):F(r*r+a*a)),b=rn(on(a-r)/2,+x.apply(this,arguments)),E=b,L=b,s,o;if(B>S){var N=ln(B/r*C($)),O=ln(B/a*C($));(R-=N*2)>S?(N*=c?1:-1,l+=N,M-=N):(R=0,l=M=(g+d)/2),(I-=O*2)>S?(O*=c?1:-1,m+=O,i-=O):(I=0,m=i=(g+d)/2)}var q=a*k(m),z=a*C(m),G=r*k(M),H=r*C(M);if(b>S){var J=a*k(i),Q=a*C(i),Y=r*k(l),Z=r*C(l),D;if(j<V)if(D=Tn(q,z,Y,Z,J,Q,G,H)){var _=q-D[0],nn=z-D[1],en=J-D[0],tn=Q-D[1],sn=1/C(xn((_*en+nn*tn)/(F(_*_+nn*nn)*F(en*en+tn*tn)))/2),un=F(D[0]*D[0]+D[1]*D[1]);E=rn(b,(r-un)/(sn-1)),L=rn(b,(a-un)/(sn+1))}else E=L=0}I>S?L>S?(s=U(Y,Z,q,z,a,L,c),o=U(J,Q,G,H,a,L,c),n.moveTo(s.cx+s.x01,s.cy+s.y01),L<b?n.arc(s.cx,s.cy,L,P(s.y01,s.x01),P(o.y01,o.x01),!c):(n.arc(s.cx,s.cy,L,P(s.y01,s.x01),P(s.y11,s.x11),!c),n.arc(0,0,a,P(s.cy+s.y11,s.cx+s.x11),P(o.cy+o.y11,o.cx+o.x11),!c),n.arc(o.cx,o.cy,L,P(o.y11,o.x11),P(o.y01,o.x01),!c))):(n.moveTo(q,z),n.arc(0,0,a,m,i,!c)):n.moveTo(q,z),!(r>S)||!(R>S)?n.lineTo(G,H):E>S?(s=U(G,H,J,Q,r,-E,c),o=U(q,z,Y,Z,r,-E,c),n.lineTo(s.cx+s.x01,s.cy+s.y01),E<b?n.arc(s.cx,s.cy,E,P(s.y01,s.x01),P(o.y01,o.x01),!c):(n.arc(s.cx,s.cy,E,P(s.y01,s.x01),P(s.y11,s.x11),!c),n.arc(0,0,r,P(s.cy+s.y11,s.cx+s.x11),P(o.cy+o.y11,o.cx+o.x11),c),n.arc(o.cx,o.cy,E,P(o.y11,o.x11),P(o.y01,o.x01),!c))):n.arc(0,0,r,M,l,c)}if(n.closePath(),e)return n=null,e+""||null}return u.centroid=function(){var e=(+t.apply(this,arguments)+ +h.apply(this,arguments))/2,y=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-V/2;return[k(y)*e,C(y)*e]},u.innerRadius=function(e){return arguments.length?(t=typeof e=="function"?e:T(+e),u):t},u.outerRadius=function(e){return arguments.length?(h=typeof e=="function"?e:T(+e),u):h},u.cornerRadius=function(e){return arguments.length?(x=typeof e=="function"?e:T(+e),u):x},u.padRadius=function(e){return arguments.length?(w=e==null?null:typeof e=="function"?e:T(+e),u):w},u.startAngle=function(e){return arguments.length?(v=typeof e=="function"?e:T(+e),u):v},u.endAngle=function(e){return arguments.length?(A=typeof e=="function"?e:T(+e),u):A},u.padAngle=function(e){return arguments.length?(p=typeof e=="function"?e:T(+e),u):p},u.context=function(e){return arguments.length?(n=e??null,u):n},u}function Sn(t,h){return h<t?-1:h>t?1:h>=t?0:NaN}function En(t){return t}function Ln(){var t=En,h=Sn,x=null,w=T(0),v=T(W),A=T(0);function p(n){var f,u=(n=mn(n)).length,e,y,r=0,a=new Array(u),g=new Array(u),d=+w.apply(this,arguments),j=Math.min(W,Math.max(-W,v.apply(this,arguments)-d)),c,m=Math.min(Math.abs(j)/u,A.apply(this,arguments)),i=m*(j<0?-1:1),l;for(f=0;f<u;++f)(l=g[a[f]=f]=+t(n[f],f,n))>0&&(r+=l);for(h!=null?a.sort(function(M,R){return h(g[M],g[R])}):x!=null&&a.sort(function(M,R){return x(n[M],n[R])}),f=0,y=r?(j-u*i)/r:0;f<u;++f,d=c)e=a[f],l=g[e],c=d+(l>0?l*y:0)+i,g[e]={data:n[e],index:f,value:l,startAngle:d,endAngle:c,padAngle:m};return g}return p.value=function(n){return arguments.length?(t=typeof n=="function"?n:T(+n),p):t},p.sortValues=function(n){return arguments.length?(h=n,x=null,p):h},p.sort=function(n){return arguments.length?(x=n,h=null,p):x},p.startAngle=function(n){return arguments.length?(w=typeof n=="function"?n:T(+n),p):w},p.endAngle=function(n){return arguments.length?(v=typeof n=="function"?n:T(+n),p):v},p.padAngle=function(n){return arguments.length?(A=typeof n=="function"?n:T(+n),p):A},p}function $n({label:t,rows:h}){const x=cn(),[w,v]=fn(Math.round,120),{tip:A,showAt:p,hide:n}=gn(),[f,u]=an.useState(null),e=h.filter(i=>i.value!==null&&i.valuLine truncated
|
||||
import{r as an,j as K}from"./vendor-react-Bf71BWbF.js";import{u as cn,fx as fn}from"./index-BOpK0UVB.js";import{u as gn,i as hn,e as pn,C as yn}from"./layout-Bzzn7HLw.js";import{w as dn,c as T,a as mn}from"./array-C0P64tl-.js";const on=Math.abs,P=Math.atan2,k=Math.cos,vn=Math.max,rn=Math.min,C=Math.sin,F=Math.sqrt,S=1e-12,V=Math.PI,X=V/2,W=2*V;function xn(t){return t>1?0:t<-1?V:Math.acos(t)}function ln(t){return t>=1?X:t<=-1?-X:Math.asin(t)}function An(t){return t.innerRadius}function Mn(t){return t.outerRadius}function Rn(t){return t.startAngle}function Pn(t){return t.endAngle}function wn(t){return t&&t.padAngle}function Tn(t,h,x,w,v,A,p,n){var f=x-t,u=w-h,e=p-v,y=n-A,r=y*f-e*u;if(!(r*r<S))return r=(e*(h-A)-y*(t-v))/r,[t+r*f,h+r*u]}function U(t,h,x,w,v,A,p){var n=t-x,f=h-w,u=(p?A:-A)/F(n*n+f*f),e=u*f,y=-u*n,r=t+e,a=h+y,g=x+e,d=w+y,j=(r+g)/2,c=(a+d)/2,m=g-r,i=d-a,l=m*m+i*i,M=v-A,R=r*d-g*a,I=(i<0?-1:1)*F(vn(0,M*M*l-R*R)),$=(R*i-m*I)/l,B=(-R*m-i*I)/l,b=(R*i+m*I)/l,E=(-R*m+i*I)/l,L=$-j,s=B-c,o=b-j,N=E-c;return L*L+s*s>o*o+N*N&&($=b,B=E),{cx:$,cy:B,x01:-e,y01:-y,x11:$*(v/M-1),y11:B*(v/M-1)}}function jn(){var t=An,h=Mn,x=T(0),w=null,v=Rn,A=Pn,p=wn,n=null,f=dn(u);function u(){var e,y,r=+t.apply(this,arguments),a=+h.apply(this,arguments),g=v.apply(this,arguments)-X,d=A.apply(this,arguments)-X,j=on(d-g),c=d>g;if(n||(n=e=f()),a<r&&(y=a,a=r,r=y),!(a>S))n.moveTo(0,0);else if(j>W-S)n.moveTo(a*k(g),a*C(g)),n.arc(0,0,a,g,d,!c),r>S&&(n.moveTo(r*k(d),r*C(d)),n.arc(0,0,r,d,g,c));else{var m=g,i=d,l=g,M=d,R=j,I=j,$=p.apply(this,arguments)/2,B=$>S&&(w?+w.apply(this,arguments):F(r*r+a*a)),b=rn(on(a-r)/2,+x.apply(this,arguments)),E=b,L=b,s,o;if(B>S){var N=ln(B/r*C($)),O=ln(B/a*C($));(R-=N*2)>S?(N*=c?1:-1,l+=N,M-=N):(R=0,l=M=(g+d)/2),(I-=O*2)>S?(O*=c?1:-1,m+=O,i-=O):(I=0,m=i=(g+d)/2)}var q=a*k(m),z=a*C(m),G=r*k(M),H=r*C(M);if(b>S){var J=a*k(i),Q=a*C(i),Y=r*k(l),Z=r*C(l),D;if(j<V)if(D=Tn(q,z,Y,Z,J,Q,G,H)){var _=q-D[0],nn=z-D[1],en=J-D[0],tn=Q-D[1],sn=1/C(xn((_*en+nn*tn)/(F(_*_+nn*nn)*F(en*en+tn*tn)))/2),un=F(D[0]*D[0]+D[1]*D[1]);E=rn(b,(r-un)/(sn-1)),L=rn(b,(a-un)/(sn+1))}else E=L=0}I>S?L>S?(s=U(Y,Z,q,z,a,L,c),o=U(J,Q,G,H,a,L,c),n.moveTo(s.cx+s.x01,s.cy+s.y01),L<b?n.arc(s.cx,s.cy,L,P(s.y01,s.x01),P(o.y01,o.x01),!c):(n.arc(s.cx,s.cy,L,P(s.y01,s.x01),P(s.y11,s.x11),!c),n.arc(0,0,a,P(s.cy+s.y11,s.cx+s.x11),P(o.cy+o.y11,o.cx+o.x11),!c),n.arc(o.cx,o.cy,L,P(o.y11,o.x11),P(o.y01,o.x01),!c))):(n.moveTo(q,z),n.arc(0,0,a,m,i,!c)):n.moveTo(q,z),!(r>S)||!(R>S)?n.lineTo(G,H):E>S?(s=U(G,H,J,Q,r,-E,c),o=U(q,z,Y,Z,r,-E,c),n.lineTo(s.cx+s.x01,s.cy+s.y01),E<b?n.arc(s.cx,s.cy,E,P(s.y01,s.x01),P(o.y01,o.x01),!c):(n.arc(s.cx,s.cy,E,P(s.y01,s.x01),P(s.y11,s.x11),!c),n.arc(0,0,r,P(s.cy+s.y11,s.cx+s.x11),P(o.cy+o.y11,o.cx+o.x11),c),n.arc(o.cx,o.cy,E,P(o.y11,o.x11),P(o.y01,o.x01),!c))):n.arc(0,0,r,M,l,c)}if(n.closePath(),e)return n=null,e+""||null}return u.centroid=function(){var e=(+t.apply(this,arguments)+ +h.apply(this,arguments))/2,y=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-V/2;return[k(y)*e,C(y)*e]},u.innerRadius=function(e){return arguments.length?(t=typeof e=="function"?e:T(+e),u):t},u.outerRadius=function(e){return arguments.length?(h=typeof e=="function"?e:T(+e),u):h},u.cornerRadius=function(e){return arguments.length?(x=typeof e=="function"?e:T(+e),u):x},u.padRadius=function(e){return arguments.length?(w=e==null?null:typeof e=="function"?e:T(+e),u):w},u.startAngle=function(e){return arguments.length?(v=typeof e=="function"?e:T(+e),u):v},u.endAngle=function(e){return arguments.length?(A=typeof e=="function"?e:T(+e),u):A},u.padAngle=function(e){return arguments.length?(p=typeof e=="function"?e:T(+e),u):p},u.context=function(e){return arguments.length?(n=e??null,u):n},u}function Sn(t,h){return h<t?-1:h>t?1:h>=t?0:NaN}function En(t){return t}function Ln(){var t=En,h=Sn,x=null,w=T(0),v=T(W),A=T(0);function p(n){var f,u=(n=mn(n)).length,e,y,r=0,a=new Array(u),g=new Array(u),d=+w.apply(this,arguments),j=Math.min(W,Math.max(-W,v.apply(this,arguments)-d)),c,m=Math.min(Math.abs(j)/u,A.apply(this,arguments)),i=m*(j<0?-1:1),l;for(f=0;f<u;++f)(l=g[a[f]=f]=+t(n[f],f,n))>0&&(r+=l);for(h!=null?a.sort(function(M,R){return h(g[M],g[R])}):x!=null&&a.sort(function(M,R){return x(n[M],n[R])}),f=0,y=r?(j-u*i)/r:0;f<u;++f,d=c)e=a[f],l=g[e],c=d+(l>0?l*y:0)+i,g[e]={data:n[e],index:f,value:l,startAngle:d,endAngle:c,padAngle:m};return g}return p.value=function(n){return arguments.length?(t=typeof n=="function"?n:T(+n),p):t},p.sortValues=function(n){return arguments.length?(h=n,x=null,p):h},p.sort=function(n){return arguments.length?(x=n,h=null,p):x},p.startAngle=function(n){return arguments.length?(w=typeof n=="function"?n:T(+n),p):w},p.endAngle=function(n){return arguments.length?(v=typeof n=="function"?n:T(+n),p):v},p.padAngle=function(n){return arguments.length?(A=typeof n=="function"?n:T(+n),p):A},p}function $n({label:t,rows:h}){const x=cn(),[w,v]=fn(Math.round,120),{tip:A,showAt:p,hide:n}=gn(),[f,u]=an.useState(null),e=h.filter(i=>i.value!==null&&i.valuLine truncated
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
import{r as h,j as n}from"./vendor-react-Bf71BWbF.js";import{a4 as g,eq as j,er as b,aw as y,h as v,bD as E,bG as L,u as k,a6 as T,a as N,aa as H,es as _,bg as D,et as K,eu as M,ev as R,ew as S,aL as p,bw as C,aK as F,L as O,bt as W,aJ as A,B,aM as I,E as J}from"./index-Bw0aJc9a.js";import{D as P}from"./Table-Km6Zv-S8.js";import{d as V,e as q}from"./files-BxEOxSF8.js";import"./useGridSelectionCheckbox-COXIVEmS.js";import"./Virtualizer-DCY9HC9Z.js";import"./ListLayout-_fDlx5XY.js";const w={buffer_overflow:["event.gap.overflow","event.gapHelp.overflow"],evicted:["event.gap.evicted","event.gapHelp.evicted"]};function G(e,t){const r=e.event==="flow.gap"&&Object.hasOwn(w,e.data.reason)?w[e.data.reason]:void 0;return r&&{title:t(r[0]),text:t(r[1])}}function z(e,t){const r=l=>l?[{id:"flow",label:t("event.viewFlow"),href:v("flows",{tab:"records",id:l})}]:[];switch(e.event){case"flow.updated":return r(e.data.resource_id);case"flow.gap":return[...r(e.data.resource_id),{id:"recording",label:t("ui.recordingSettings"),href:E}];case"generation.changed":return[{id:"config",label:t("event.viewConfig"),href:v("config")}];default:return[]}}const x=new WeakMap;function Q(e,t,r,l){const s=x.get(e);if(s&&s.locale===t)return s.row;const i=l?{key:"event.lostHistory"}:j(e,r),o={id:e.id,timestamp:y(e.data.observed_at,t),iso:e.data.observed_at,kind:e.event,kindText:g(b,e.event,r),summary:r(i.key,i.params),help:G(e,r),links:z(e,r)};return x.set(e,{locale:t,row:o}),o}function U(e,t,r,l,s,i,o,u,a=!1,c=()=>!1){const m=t==="without-runtime"||u.includes(t)?t:"all",f=e.filter(d=>m==="all"||(m==="without-runtime"?d.event!=="runtime.updated":d.event===m)).slice(0,s);return{kind:m,rows:f.map(d=>Q(d,i,o,c(d))),kinds:[{id:"without-runtime",label:o("event.withoutRuntime")},{id:"all",label:o("event.allKinds")},...u.map(d=>({id:d,label:g(b,d,o)}))],status:a&&l!==!1?{tone:"err",text:o("event.disconnected")}:{tone:r?"ok":l===null?"muted":"warn",text:o(l===!1?"event.unavailable":r?"event.connected":l===null?"ui.loading":"event.reconnecting")},limitText:o("event.limit",{n:s}),shown:f}}function X(e){return JSON.stringify(e,null,2)+`
|
||||
import{r as h,j as n}from"./vendor-react-Bf71BWbF.js";import{a4 as g,eq as j,er as b,aw as y,h as v,bD as E,bG as L,u as k,a6 as T,a as N,aa as H,es as _,bg as D,et as K,eu as M,ev as R,ew as S,aL as p,bw as C,aK as F,L as O,bt as W,aJ as A,B,aM as I,E as J}from"./index-BOpK0UVB.js";import{D as P}from"./Table-BkehX7fw.js";import{d as V,e as q}from"./files-BxEOxSF8.js";import"./useGridSelectionCheckbox-C4VxQajJ.js";import"./Virtualizer-BIsXGNLZ.js";import"./ListLayout-CkBMjK9o.js";const w={buffer_overflow:["event.gap.overflow","event.gapHelp.overflow"],evicted:["event.gap.evicted","event.gapHelp.evicted"]};function G(e,t){const r=e.event==="flow.gap"&&Object.hasOwn(w,e.data.reason)?w[e.data.reason]:void 0;return r&&{title:t(r[0]),text:t(r[1])}}function z(e,t){const r=l=>l?[{id:"flow",label:t("event.viewFlow"),href:v("flows",{tab:"records",id:l})}]:[];switch(e.event){case"flow.updated":return r(e.data.resource_id);case"flow.gap":return[...r(e.data.resource_id),{id:"recording",label:t("ui.recordingSettings"),href:E}];case"generation.changed":return[{id:"config",label:t("event.viewConfig"),href:v("config")}];default:return[]}}const x=new WeakMap;function Q(e,t,r,l){const s=x.get(e);if(s&&s.locale===t)return s.row;const i=l?{key:"event.lostHistory"}:j(e,r),o={id:e.id,timestamp:y(e.data.observed_at,t),iso:e.data.observed_at,kind:e.event,kindText:g(b,e.event,r),summary:r(i.key,i.params),help:G(e,r),links:z(e,r)};return x.set(e,{locale:t,row:o}),o}function U(e,t,r,l,s,i,o,u,a=!1,c=()=>!1){const m=t==="without-runtime"||u.includes(t)?t:"all",f=e.filter(d=>m==="all"||(m==="without-runtime"?d.event!=="runtime.updated":d.event===m)).slice(0,s);return{kind:m,rows:f.map(d=>Q(d,i,o,c(d))),kinds:[{id:"without-runtime",label:o("event.withoutRuntime")},{id:"all",label:o("event.allKinds")},...u.map(d=>({id:d,label:g(b,d,o)}))],status:a&&l!==!1?{tone:"err",text:o("event.disconnected")}:{tone:r?"ok":l===null?"muted":"warn",text:o(l===!1?"event.unavailable":r?"event.connected":l===null?"ui.loading":"event.reconnecting")},limitText:o("event.limit",{n:s}),shown:f}}function X(e){return JSON.stringify(e,null,2)+`
|
||||
`}function Y(){const e=L(),t=k(),r=T[N()],s=H().data?.resources.events.kinds,[i,o]=h.useState("without-runtime"),u=i!=="all"&&i!=="runtime.updated"&&s?.includes(i),a=_(i!=="without-runtime"&&!u),c=h.useMemo(()=>U(a.events,i,a.connected,a.available,S,r,t,s??[],!!a.error,R),[a.events,i,a.connected,a.available,a.error,r,t,s]);return D(c.kind,o),{...c,setKind:o,cursor:a.cursor,error:a.error,retry:()=>void K().then(()=>M(e)),loading:!a.error&&!a.connected&&a.available!==!1&&!a.events.length,export:()=>V(q("doona-events","json"),X(c.shown),"application/json")}}function ae(){const e=k(),t=Y(),r=h.useMemo(()=>[{id:"t",label:e("ui.time"),minWidth:200,grow:0,drop:1,render:s=>n.jsx(p,{className:"rp-code",text:s.iso,children:s.timestamp})},{id:"k",label:e("event.kind"),minWidth:168,drop:2,render:s=>n.jsx(p,{text:s.kind,children:s.kindText})},{id:"m",label:e("event.summary"),minWidth:240,isRowHeader:!0,render:s=>n.jsx(C,{fill:!0,help:s.help,children:n.jsx(p,{children:s.summary})})}],[e]),l=h.useCallback(s=>n.jsxs(n.Fragment,{children:[n.jsx(F,{inline:!0,items:[[e("ui.time"),s.timestamp],[e("event.kind"),s.kindText],[e("event.summary"),s.summary]]}),s.links.length>0&&n.jsx("div",{className:"rp-cluster",children:s.links.map(i=>n.jsx(O,{appearance:"button",small:!0,href:i.href,children:i.label},i.id))})]}),[e]);return n.jsxs("div",{className:"rp-page",children:[n.jsxs("div",{className:"rp-toolbar",children:[n.jsx(W,{label:e("event.kind"),side:!0,value:t.kind,onChange:t.setKind,items:t.kinds}),n.jsx(A,{small:!0,tone:t.status.tone,children:t.status.text}),t.cursor&&n.jsx(p,{text:t.cursor,children:n.jsx("span",{className:"rp-label",children:e("event.cursor")})}),n.jsx("span",{className:"rp-label",children:t.limitText}),n.jsx("span",{className:"rp-grow"}),n.jsxs(B,{isDisabled:!t.rows.length,onPress:t.export,children:[n.jsx(I,{}),e("event.export")]})]}),t.error&&n.jsx(J,{error:t.error,onRetry:t.retry}),n.jsx(P,{label:e("nav.events"),stream:!0,fit:!0,height:442,loading:t.loading,rows:t.rows,empty:e("event.empty"),cols:r,detail:l})]})}export{ae as Events};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{j as s}from"./vendor-react-Bf71BWbF.js";import{aL as t}from"./index-Bw0aJc9a.js";function p({facts:l,lead:r}){return l.length?s.jsx("dl",{className:"rp-strip rp-facts"+(r?" rp-facts-lead":""),style:{"--facts":l.length,"--facts-rest":l.length-1},children:l.map((e,i)=>s.jsxs("div",{className:"rp-card"+(e.tone?" "+e.tone:""),children:[s.jsxs("dt",{className:"rp-tile-head"+(e.tint?" rp-tint-"+e.tint:""),children:[e.icon,e.label]}),s.jsxs("dd",{className:"rp-tile-body",children:[r&&i===0?s.jsx(t,{className:"rp-big",cut:"start",children:e.value}):s.jsx("span",{className:"rp-big",title:e.value,children:e.value}),e.caption&&s.jsx("span",{className:"rp-fact-caption",title:e.caption,children:e.caption})]})]},e.label))}):null}export{p as F};
|
||||
import{j as s}from"./vendor-react-Bf71BWbF.js";import{aL as t}from"./index-BOpK0UVB.js";function p({facts:l,lead:r}){return l.length?s.jsx("dl",{className:"rp-strip rp-facts"+(r?" rp-facts-lead":""),style:{"--facts":l.length,"--facts-rest":l.length-1},children:l.map((e,i)=>s.jsxs("div",{className:"rp-card"+(e.tone?" "+e.tone:""),children:[s.jsxs("dt",{className:"rp-tile-head"+(e.tint?" rp-tint-"+e.tint:""),children:[e.icon,e.label]}),s.jsxs("dd",{className:"rp-tile-body",children:[r&&i===0?s.jsx(t,{className:"rp-big",cut:"start",children:e.value}):s.jsx("span",{className:"rp-big",title:e.value,children:e.value}),e.caption&&s.jsx("span",{className:"rp-fact-caption",title:e.caption,children:e.caption})]})]},e.label))}):null}export{p as F};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{r as b,j as l}from"./vendor-react-Bf71BWbF.js";import{bl as we,by as xe,Z as K,b0 as ve,bz as ye,bA as je,bc as ke,bk as _e,bj as Me,a0 as T,b4 as F,a4 as $,b8 as Le,b9 as Ne,a6 as ie,aw as Te,h as Se,aX as Z,a3 as J,bB as Re,a_ as Ce,a5 as Pe,u as C,a as ce,aU as Ie,B as R,bC as Oe,c as te,aO as z,aa as Y,ac as O,ae as Fe,ad as Ee,f as He,bp as De,bD as $e,bh as We,j as q,E as A,bx as Be,aL as V,bb as Ae,b3 as Ue,bs as de,bt as Ve,aj as ne,L as se,bv as Qe,aK as ae,ak as ue,aN as Ge}from"./index-Bw0aJc9a.js";import{w as L}from"./labels-Bgu_ZhL8.js";import{c as Ke,C as Je}from"./Coverage-DhDWz2sB.js";import{g as ze}from"./policyText-CltaDVEo.js";import{f as Xe}from"./nav-CS6FFQFP.js";import{D as Ze}from"./Table-Km6Zv-S8.js";import{T as Ye}from"./TimeCell-DKHUJpad.js";import{b as fe,u as me,c as qe}from"./flows-D3eabARZ.js";import{u as et}from"./outbounds-DMhWS-9H.js";import{u as tt,R as nt}from"./useQuickRule-BmFeKwTA.js";import"./useGridSelectionCheckbox-COXIVEmS.js";import"./Virtualizer-DCY9HC9Z.js";import"./ListLayout-_fDlx5XY.js";import"./DaeCode-B8yPDjSE.js";const st=["client","rule","outbound","node"],at=e=>new Map(e.map(t=>[t.id,t.name])),X="\0";function ot(e,t){if(e.rule_id)return e.rule_generation_id!==null&&e.rule_generation_id===t?e.rule_id:e.rule_id+X+e.rule_expression}function pe(e,t,n,r){switch(t){case"client":{const a=K(e.input?.src??void 0);return{label:a??"unknown",unknown:!a}}case"rule":return e.rule_expression?{label:e.rule_expression,unknown:!1,key:ot(e,r)}:{label:"unknown",unknown:!0};case"outbound":return e.outbound?{label:e.outbound,unknown:!1}:{label:"unknown",unknown:!0};case"node":{if(xe(e.outbound))return null;const a=e.chain.at(-1)??null;return a?{label:n.get(a)??a,unknown:!1,key:a}:{label:"unknown",unknown:!0}}}}const W=(e,t)=>ve(e,t.unknown?"":t.key??t.label),ge=e=>we(e,st)?.kind,rt=new Map;function he(e,t,n){const r=ge(t);return r?e.filter(a=>{const s=pe(a,r,rt,n?.generation_id);return s!==null&&W(r,s)===t}):[]}function lt(e,t,n,r){const a=e.slice(0,e.indexOf(":")),s=e.slice(e.indexOf(":")+1);return s===""?r(null):a==="rule"?s.includes(X)?s.slice(s.indexOf(X)+1):t.find(c=>c.rule_id===s)?.expression??s:a==="node"?n.get(s)??s:a==="client"?s:r(s)}function it(e,t,n,r,a="rule"){const s=at(n),c=new Map(t.map(d=>[d.id,d])),i=new Map(t.map(d=>[d.name,d])),o=new Map(n.map(d=>[d.id,d])),m=new Map,w=new Map,f=new Map,p=new Map,v=(d,g)=>{const x=d+">"+g;let u=p.get(x);return u||p.set(x,u={source:d,target:g,count:0}),u},j=(d,g,x=!1)=>{const u=W("node",{key:d,label:g,unknown:x});let N=f.get(u);if(!N){const E=x?void 0:o.get(d),H=E&&je(E);f.set(u,N={id:u,label:g,count:0,unknown:x||void 0,latency:ke(H),unavailable:H?.state==="unavailable"})}return N},_=(d,g=!1)=>{const x=W("outbound",{label:d,unknown:g});let u=w.get(x);if(u)return u;const N=g?void 0:i.get(d),E=g?{groups:[],member:null}:ye(d,N?.selection.tcp_member_id?"tcp":"udp",i,c,o),H=E.groups.map(U=>({name:U.name,kind:U.policy.kind,policy:U.policy.native})),B=E.member,be=g?"unknown":d==="direct"||d==="block"?d:H.length?"group":"unknown";return u={id:x,label:d,count:0,unknown:g||void 0,kind:be,groups:H,node:B&&j(B,s.get(B)??B).id},w.set(x,u),u.node&&v(x,u.node),u},h=(d,g,x=!1)=>{let u=m.get(d);return u||m.set(d,u={id:d,label:g,count:0,unknown:x||void 0,outbound:null,must:!1,fallback:!1}),u};if(a==="rule")for(const d of r?.rules??[]){const g=h(W("rule",{key:d.rule_id,label:d.expression}),d.expression);g.must=d.must,g.fallback=d.kind==="fallback",d.outbound&&(g.outbound=_(d.outbound).id,v(g.id,g.outbound))}const k=[a,"outbound","node"];for(const d of e){let g;for(const x of k){const u=pe(d,x,s,r?.generation_id);if(!u)break;const N=x==="outbound"?_(u.label,u.unknown):x==="node"?j(u.key??u.label,u.label,u.unknown):h(W(x,u),u.label,u.unknown);N.count++,g&&v(g.id,N.id).count++,g=N}}for(const d of t)_(d.name);const M=new Set([...m.values()].map(d=>d.outbound)),P=new Set([...w.values()].flatMap(d=>d.groups.slice(1).map(g=>g.name))),y=[...w.values()].filter(d=>d.count||M.has(d.id)||!P.has(d.label)),S=new Set(y.map(d=>d.id));return{by:a,leaves:[...m.values()],outbounds:y,nodes:[...f.values()],links:[...p.values()].filter(d=>S.has(d.source)||S.has(d.target))}}const oe=new WeakMap;function ee(e){const t=oe.get(e);if(t)return t;const n=new Map,r=new Map,a=new Map;for(const i of e.links){for(const[o,m]of[[n,i.source],[r,i.target]]){let w=o.get(m);w||o.set(m,w=[]),w.push(i)}(!a.has(i.source)||a.get(i.source).count<i.count)&&a.set(i.source,i)}const s=new Map;for(const i of[...e.leaves,...e.outbounds]){const o=("groups"in i?i.node:i.outbound)??a.get(i.id)?.target;o&&s.set(i.id,o)}const c={outgoing:n,incoming:r,parents:s};return oe.set(e,c),c}function ct(e){const t=new Map;let n=0;const r=new Map,{parents:a}=ee(e);for(const i of[...e.leaves,...e.outbounds]){const o=a.get(i.id);if(o){let m=r.get(o);m||r.set(o,m=[]),m.push(i.id)}}const s=i=>{const o=r.get(i)??[];if(!o.length){t.set(i,n++);return}for(const m of o)s(m);t.set(i,(t.get(o[0])+t.get(o[o.lengLine truncated
|
||||
import{r as b,j as l}from"./vendor-react-Bf71BWbF.js";import{bl as we,by as xe,Z as K,b0 as ve,bz as ye,bA as je,bc as ke,bk as _e,bj as Me,a0 as T,b4 as F,a4 as $,b8 as Le,b9 as Ne,a6 as ie,aw as Te,h as Se,aX as Z,a3 as J,bB as Re,a_ as Ce,a5 as Pe,u as C,a as ce,aU as Ie,B as R,bC as Oe,c as te,aO as z,aa as Y,ac as O,ae as Fe,ad as Ee,f as He,bp as De,bD as $e,bh as We,j as q,E as A,bx as Be,aL as V,bb as Ae,b3 as Ue,bs as de,bt as Ve,aj as ne,L as se,bv as Qe,aK as ae,ak as ue,aN as Ge}from"./index-BOpK0UVB.js";import{w as L}from"./labels-Bgu_ZhL8.js";import{c as Ke,C as Je}from"./Coverage-BJmgp_Br.js";import{g as ze}from"./policyText-y7dbn7hu.js";import{f as Xe}from"./nav-BiwTft4m.js";import{D as Ze}from"./Table-BkehX7fw.js";import{T as Ye}from"./TimeCell-COfj2dEh.js";import{b as fe,u as me,c as qe}from"./flows-BW6GjUpE.js";import{u as et}from"./outbounds-BVwoUbXQ.js";import{u as tt,R as nt}from"./useQuickRule-qFvcUoSC.js";import"./useGridSelectionCheckbox-C4VxQajJ.js";import"./Virtualizer-BIsXGNLZ.js";import"./ListLayout-CkBMjK9o.js";import"./DaeCode-B8yPDjSE.js";const st=["client","rule","outbound","node"],at=e=>new Map(e.map(t=>[t.id,t.name])),X="\0";function ot(e,t){if(e.rule_id)return e.rule_generation_id!==null&&e.rule_generation_id===t?e.rule_id:e.rule_id+X+e.rule_expression}function pe(e,t,n,r){switch(t){case"client":{const a=K(e.input?.src??void 0);return{label:a??"unknown",unknown:!a}}case"rule":return e.rule_expression?{label:e.rule_expression,unknown:!1,key:ot(e,r)}:{label:"unknown",unknown:!0};case"outbound":return e.outbound?{label:e.outbound,unknown:!1}:{label:"unknown",unknown:!0};case"node":{if(xe(e.outbound))return null;const a=e.chain.at(-1)??null;return a?{label:n.get(a)??a,unknown:!1,key:a}:{label:"unknown",unknown:!0}}}}const W=(e,t)=>ve(e,t.unknown?"":t.key??t.label),ge=e=>we(e,st)?.kind,rt=new Map;function he(e,t,n){const r=ge(t);return r?e.filter(a=>{const s=pe(a,r,rt,n?.generation_id);return s!==null&&W(r,s)===t}):[]}function lt(e,t,n,r){const a=e.slice(0,e.indexOf(":")),s=e.slice(e.indexOf(":")+1);return s===""?r(null):a==="rule"?s.includes(X)?s.slice(s.indexOf(X)+1):t.find(c=>c.rule_id===s)?.expression??s:a==="node"?n.get(s)??s:a==="client"?s:r(s)}function it(e,t,n,r,a="rule"){const s=at(n),c=new Map(t.map(d=>[d.id,d])),i=new Map(t.map(d=>[d.name,d])),o=new Map(n.map(d=>[d.id,d])),m=new Map,w=new Map,f=new Map,p=new Map,v=(d,g)=>{const x=d+">"+g;let u=p.get(x);return u||p.set(x,u={source:d,target:g,count:0}),u},j=(d,g,x=!1)=>{const u=W("node",{key:d,label:g,unknown:x});let N=f.get(u);if(!N){const E=x?void 0:o.get(d),H=E&&je(E);f.set(u,N={id:u,label:g,count:0,unknown:x||void 0,latency:ke(H),unavailable:H?.state==="unavailable"})}return N},_=(d,g=!1)=>{const x=W("outbound",{label:d,unknown:g});let u=w.get(x);if(u)return u;const N=g?void 0:i.get(d),E=g?{groups:[],member:null}:ye(d,N?.selection.tcp_member_id?"tcp":"udp",i,c,o),H=E.groups.map(U=>({name:U.name,kind:U.policy.kind,policy:U.policy.native})),B=E.member,be=g?"unknown":d==="direct"||d==="block"?d:H.length?"group":"unknown";return u={id:x,label:d,count:0,unknown:g||void 0,kind:be,groups:H,node:B&&j(B,s.get(B)??B).id},w.set(x,u),u.node&&v(x,u.node),u},h=(d,g,x=!1)=>{let u=m.get(d);return u||m.set(d,u={id:d,label:g,count:0,unknown:x||void 0,outbound:null,must:!1,fallback:!1}),u};if(a==="rule")for(const d of r?.rules??[]){const g=h(W("rule",{key:d.rule_id,label:d.expression}),d.expression);g.must=d.must,g.fallback=d.kind==="fallback",d.outbound&&(g.outbound=_(d.outbound).id,v(g.id,g.outbound))}const k=[a,"outbound","node"];for(const d of e){let g;for(const x of k){const u=pe(d,x,s,r?.generation_id);if(!u)break;const N=x==="outbound"?_(u.label,u.unknown):x==="node"?j(u.key??u.label,u.label,u.unknown):h(W(x,u),u.label,u.unknown);N.count++,g&&v(g.id,N.id).count++,g=N}}for(const d of t)_(d.name);const M=new Set([...m.values()].map(d=>d.outbound)),P=new Set([...w.values()].flatMap(d=>d.groups.slice(1).map(g=>g.name))),y=[...w.values()].filter(d=>d.count||M.has(d.id)||!P.has(d.label)),S=new Set(y.map(d=>d.id));return{by:a,leaves:[...m.values()],outbounds:y,nodes:[...f.values()],links:[...p.values()].filter(d=>S.has(d.source)||S.has(d.target))}}const oe=new WeakMap;function ee(e){const t=oe.get(e);if(t)return t;const n=new Map,r=new Map,a=new Map;for(const i of e.links){for(const[o,m]of[[n,i.source],[r,i.target]]){let w=o.get(m);w||o.set(m,w=[]),w.push(i)}(!a.has(i.source)||a.get(i.source).count<i.count)&&a.set(i.source,i)}const s=new Map;for(const i of[...e.leaves,...e.outbounds]){const o=("groups"in i?i.node:i.outbound)??a.get(i.id)?.target;o&&s.set(i.id,o)}const c={outgoing:n,incoming:r,parents:s};return oe.set(e,c),c}function ct(e){const t=new Map;let n=0;const r=new Map,{parents:a}=ee(e);for(const i of[...e.leaves,...e.outbounds]){const o=a.get(i.id);if(o){let m=r.get(o);m||r.set(o,m=[]),m.push(i.id)}}const s=i=>{const o=r.get(i)??[];if(!o.length){t.set(i,n++);return}for(const m of o)s(m);t.set(i,(t.get(o[0])+t.get(o[o.lengLine truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{f4 as v}from"./index-Bw0aJc9a.js";import{$ as R,c,a as S,b as p}from"./Virtualizer-DCY9HC9Z.js";const f=48;class N extends R{constructor(t={}){super(),this.rowSize=t?.rowSize??t?.rowHeight??null,this.orientation=t.orientation??"vertical",this.estimatedRowSize=t?.estimatedRowSize??t?.estimatedRowHeight??null,this.headingSize=t?.headingSize??t?.headingHeight??null,this.estimatedHeadingSize=t?.estimatedHeadingSize??t?.estimatedHeadingHeight??null,this.loaderSize=t?.loaderSize??t?.loaderHeight??null,this.dropIndicatorThickness=t.dropIndicatorThickness||2,this.gap=t.gap||0,this.padding=t.padding||0,this.layoutNodes=new Map,this.rootNodes=[],this.lastCollection=null,this.invalidateEverything=!1,this.validRect=new c,this.requestedRect=new c,this.contentSize=new S}get collection(){return this.virtualizer.collection}get rowHeight(){return this.rowSize}get estimatedRowHeight(){return this.estimatedRowSize}get headingHeight(){return this.headingSize}get estimatedHeadingHeight(){return this.estimatedHeadingSize}get loaderHeight(){return this.loaderSize}getLayoutInfo(t){return this.ensureLayoutInfo(t),this.layoutNodes.get(t)?.layoutInfo||null}getVisibleLayoutInfos(t){let e=this.orientation==="horizontal"?"x":"y",i=this.orientation==="horizontal"?"width":"height";if(t[i]>1){let s=(this.rowSize??this.estimatedRowSize??f)+this.gap;t=t.copy();let o=Math.floor(t[e]/s)*s,l=t[i]+t[e]-o;t[e]=o,t[i]=Math.ceil(l/s)*s}this.layoutIfNeeded(t);let r=[],h=s=>{for(let o of s)this.isVisible(o,t)&&(r.push(o.layoutInfo),o.children&&h(o.children))};return h(this.rootNodes),r}layoutIfNeeded(t){if(this.lastCollection){this.requestedRect.containsRect(t)||(this.requestedRect=this.requestedRect.union(t),this.rootNodes=this.buildCollection());for(let e of this.virtualizer.persistedKeys)if(this.ensureLayoutInfo(e))return}}ensureLayoutInfo(t){return!this.layoutNodes.has(t)&&this.requestedRect.area<this.contentSize.area&&this.lastCollection?(this.requestedRect=new c(0,0,1/0,1/0),this.rootNodes=this.buildCollection(),this.requestedRect=new c(0,0,this.contentSize.width,this.contentSize.height),!0):!1}isVisible(t,e){return t.layoutInfo.rect.intersects(e)||t.layoutInfo.isSticky||t.layoutInfo.type==="header"||t.layoutInfo.type==="loader"||this.virtualizer.isPersistedKey(t.layoutInfo.key)}shouldInvalidateEverything(t){let e=t.layoutOptions;return t.sizeChanged||this.rowSize!==(e?.rowSize??e?.rowHeight??this.rowSize)||this.orientation!==(e?.orientation??this.orientation)||this.headingSize!==(e?.headingSize??e?.headingHeight??this.headingSize)||this.loaderSize!==(e?.loaderSize??e?.loaderHeight??this.loaderSize)||this.gap!==(e?.gap??this.gap)||this.padding!==(e?.padding??this.padding)}shouldInvalidateLayoutOptions(t,e){return(t?.rowSize??t?.rowHeight)!==(e?.rowSize??e?.rowHeight)||t.orientation!==e.orientation||(t?.estimatedRowSize??t?.estimatedRowHeight)!==(e?.estimatedRowSize??e?.estimatedRowHeight)||(t?.headingSize??t?.headingHeight)!==(e?.headingSize??e?.headingHeight)||(t?.estimatedHeadingSize??t?.estimatedHeadingHeight)!==(e?.estimatedHeadingSize??e?.estimatedHeadingHeight)||(t?.loaderSize??t?.loaderHeight)!==(e?.loaderSize??e?.loaderHeight)||t.dropIndicatorThickness!==e.dropIndicatorThickness||t.gap!==e.gap||t.padding!==e.padding}update(t){let e=this.virtualizer.collection;this.invalidateEverything=this.shouldInvalidateEverything(t),this.invalidateEverything&&(this.requestedRect=this.virtualizer.visibleRect.copy(),this.layoutNodes.clear());let i=t.layoutOptions;if(this.rowSize=i?.rowSize??i?.rowHeight??this.rowSize,this.orientation=i?.orientation??this.orientation,this.estimatedRowSize=i?.estimatedRowSize??i?.estimatedRowHeight??this.estimatedRowSize,this.headingSize=i?.headingSize??i?.headingHeight??this.headingSize,this.estimatedHeadingSize=i?.estimatedHeadingSize??i?.estimatedHeadingHeight??this.estimatedHeadingSize,this.loaderSize=i?.loaderSize??i?.loaderHeight??this.loaderSize,this.dropIndicatorThickness=i?.dropIndicatorThickness??this.dropIndicatorThickness,this.gap=i?.gap??this.gap,this.padding=i?.padding??this.padding,this.rootNodes=this.buildCollection(),this.lastCollection&&e!==this.lastCollection)for(let r of this.lastCollection.getKeys())e.getItem(r)||this.layoutNodes.get(r)&&this.layoutNodes.delete(r);this.lastCollection=e,this.invalidateEverything=!1,this.validRect=this.requestedRect.copy()}buildCollection(t=this.padding){let e=this.virtualizer.collection,i=this.orientation==="horizontal"?"x":"y",r=this.orientation==="horizontal"?"maxX":"maxY",h=H(e,a=>a.type!=="content"),s=h.filter(a=>a.type==="loader"),o=[],l=e?.size===0;l&&(t=0);for(let a of h){let n=(this.rowSize??this.estimatedRowSize??f)+this.gap;if(a.type==="item"&&t+n<this.requestedRect[i]&&!this.isValid(a,t)){t+=n;continue}let d=this.orientation==="horizontal"?this.buildChild(a,t,this.padding,null):this.buildChild(a,this.padding,t,null);if(t=d.layoutInfo.rect[r]+this.gap,o.push(d),a.type==="loader"){let u=s.indexOf(a);s.splice(u,1)}if((a.type==="item"||a.type==="loader"Line truncated
|
||||
import{f4 as v}from"./index-BOpK0UVB.js";import{$ as R,c,a as S,b as p}from"./Virtualizer-BIsXGNLZ.js";const f=48;class N extends R{constructor(t={}){super(),this.rowSize=t?.rowSize??t?.rowHeight??null,this.orientation=t.orientation??"vertical",this.estimatedRowSize=t?.estimatedRowSize??t?.estimatedRowHeight??null,this.headingSize=t?.headingSize??t?.headingHeight??null,this.estimatedHeadingSize=t?.estimatedHeadingSize??t?.estimatedHeadingHeight??null,this.loaderSize=t?.loaderSize??t?.loaderHeight??null,this.dropIndicatorThickness=t.dropIndicatorThickness||2,this.gap=t.gap||0,this.padding=t.padding||0,this.layoutNodes=new Map,this.rootNodes=[],this.lastCollection=null,this.invalidateEverything=!1,this.validRect=new c,this.requestedRect=new c,this.contentSize=new S}get collection(){return this.virtualizer.collection}get rowHeight(){return this.rowSize}get estimatedRowHeight(){return this.estimatedRowSize}get headingHeight(){return this.headingSize}get estimatedHeadingHeight(){return this.estimatedHeadingSize}get loaderHeight(){return this.loaderSize}getLayoutInfo(t){return this.ensureLayoutInfo(t),this.layoutNodes.get(t)?.layoutInfo||null}getVisibleLayoutInfos(t){let e=this.orientation==="horizontal"?"x":"y",i=this.orientation==="horizontal"?"width":"height";if(t[i]>1){let s=(this.rowSize??this.estimatedRowSize??f)+this.gap;t=t.copy();let o=Math.floor(t[e]/s)*s,l=t[i]+t[e]-o;t[e]=o,t[i]=Math.ceil(l/s)*s}this.layoutIfNeeded(t);let r=[],h=s=>{for(let o of s)this.isVisible(o,t)&&(r.push(o.layoutInfo),o.children&&h(o.children))};return h(this.rootNodes),r}layoutIfNeeded(t){if(this.lastCollection){this.requestedRect.containsRect(t)||(this.requestedRect=this.requestedRect.union(t),this.rootNodes=this.buildCollection());for(let e of this.virtualizer.persistedKeys)if(this.ensureLayoutInfo(e))return}}ensureLayoutInfo(t){return!this.layoutNodes.has(t)&&this.requestedRect.area<this.contentSize.area&&this.lastCollection?(this.requestedRect=new c(0,0,1/0,1/0),this.rootNodes=this.buildCollection(),this.requestedRect=new c(0,0,this.contentSize.width,this.contentSize.height),!0):!1}isVisible(t,e){return t.layoutInfo.rect.intersects(e)||t.layoutInfo.isSticky||t.layoutInfo.type==="header"||t.layoutInfo.type==="loader"||this.virtualizer.isPersistedKey(t.layoutInfo.key)}shouldInvalidateEverything(t){let e=t.layoutOptions;return t.sizeChanged||this.rowSize!==(e?.rowSize??e?.rowHeight??this.rowSize)||this.orientation!==(e?.orientation??this.orientation)||this.headingSize!==(e?.headingSize??e?.headingHeight??this.headingSize)||this.loaderSize!==(e?.loaderSize??e?.loaderHeight??this.loaderSize)||this.gap!==(e?.gap??this.gap)||this.padding!==(e?.padding??this.padding)}shouldInvalidateLayoutOptions(t,e){return(t?.rowSize??t?.rowHeight)!==(e?.rowSize??e?.rowHeight)||t.orientation!==e.orientation||(t?.estimatedRowSize??t?.estimatedRowHeight)!==(e?.estimatedRowSize??e?.estimatedRowHeight)||(t?.headingSize??t?.headingHeight)!==(e?.headingSize??e?.headingHeight)||(t?.estimatedHeadingSize??t?.estimatedHeadingHeight)!==(e?.estimatedHeadingSize??e?.estimatedHeadingHeight)||(t?.loaderSize??t?.loaderHeight)!==(e?.loaderSize??e?.loaderHeight)||t.dropIndicatorThickness!==e.dropIndicatorThickness||t.gap!==e.gap||t.padding!==e.padding}update(t){let e=this.virtualizer.collection;this.invalidateEverything=this.shouldInvalidateEverything(t),this.invalidateEverything&&(this.requestedRect=this.virtualizer.visibleRect.copy(),this.layoutNodes.clear());let i=t.layoutOptions;if(this.rowSize=i?.rowSize??i?.rowHeight??this.rowSize,this.orientation=i?.orientation??this.orientation,this.estimatedRowSize=i?.estimatedRowSize??i?.estimatedRowHeight??this.estimatedRowSize,this.headingSize=i?.headingSize??i?.headingHeight??this.headingSize,this.estimatedHeadingSize=i?.estimatedHeadingSize??i?.estimatedHeadingHeight??this.estimatedHeadingSize,this.loaderSize=i?.loaderSize??i?.loaderHeight??this.loaderSize,this.dropIndicatorThickness=i?.dropIndicatorThickness??this.dropIndicatorThickness,this.gap=i?.gap??this.gap,this.padding=i?.padding??this.padding,this.rootNodes=this.buildCollection(),this.lastCollection&&e!==this.lastCollection)for(let r of this.lastCollection.getKeys())e.getItem(r)||this.layoutNodes.get(r)&&this.layoutNodes.delete(r);this.lastCollection=e,this.invalidateEverything=!1,this.validRect=this.requestedRect.copy()}buildCollection(t=this.padding){let e=this.virtualizer.collection,i=this.orientation==="horizontal"?"x":"y",r=this.orientation==="horizontal"?"maxX":"maxY",h=H(e,a=>a.type!=="content"),s=h.filter(a=>a.type==="loader"),o=[],l=e?.size===0;l&&(t=0);for(let a of h){let n=(this.rowSize??this.estimatedRowSize??f)+this.gap;if(a.type==="item"&&t+n<this.requestedRect[i]&&!this.isValid(a,t)){t+=n;continue}let d=this.orientation==="horizontal"?this.buildChild(a,t,this.padding,null):this.buildChild(a,this.padding,t,null);if(t=d.layoutInfo.rect[r]+this.gap,o.push(d),a.type==="loader"){let u=s.indexOf(a);s.splice(u,1)}if((a.type==="item"||a.type==="loader"Line truncated
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./LoginShowcase-hawa0qI8.js","./vendor-react-Bf71BWbF.js","./index-Bw0aJc9a.js","./index-7R3bVGRM.css"])))=>i.map(i=>d[i]);
|
||||
import{u as G,a as ne,e as re,d as K,A as I,i as oe,b as ie,s as ae,r as le,w as ce,n as V,c as ue,f as de,L as U,h as me,g as ge,P as pe,S as fe,l as he,E as Z,j as we,I as xe,T as E,B as ye,k as je,_ as ke}from"./index-Bw0aJc9a.js";import{r as l,j as t}from"./vendor-react-Bf71BWbF.js";import{D as q,s as ve,d as be,a as Te,o as Se}from"./auth-DzCdgIKH.js";function Ee(s,r,o,c){return s.some(n=>n.id===r&&V(n.api)===V(o))?s.map(n=>n.id===r?{...n,token:c.trim()}:n):null}const Ne=/^[A-Za-z0-9_.-]{1,64}$/;function _e(s,r,o,c){const n={};r?Ne.test(r)||(n.username="login.badUsername"):n.username="login.usernameRequired";const u=[...o].length;return u?s==="setup"&&u<8?n.password="login.passwordShort":u>128||new TextEncoder().encode(o).length>512?n.password="login.passwordLong":s==="setup"&&o!==c&&(n.confirm="login.mismatch"):n.password="login.passwordRequired",n}function Ae(s){if(!(s instanceof I))return null;if(s.code==="invalid_credentials")return{key:"login.invalidCredentials"};if(s.code==="setup_required")return{key:"login.needsSetup",switchTo:"setup"};if(s.code==="setup_already_completed")return{key:"login.alreadySetUp",switchTo:"login"};if(s.code==="permission_denied")return{key:"login.setupPeer"};if(s.code==="rate_limited"){const r=s.retryAfter??60;return{key:"login.rateLimited",params:{n:r},wait:r}}return null}function Pe(s){return s instanceof SyntaxError?!0:s instanceof I&&(s.status===404||s.status===401&&(!s.code||s.code==="authentication_required"))}async function Ce(s,r){try{return ve(await be(s,r))}catch(o){if(!Pe(o))throw o;return!(o instanceof I)||o.status!==404||await Te(s,r)?"token":"no-api"}}function Le(s,r,o){try{const{profiles:c,activeId:n}=le(),u=Ee(c,s,r,o);if(!u)return"login.stale";ce({profiles:u,activeId:n})}catch{return"settings.saveError"}return null}async function De(s,r,o,c){let n;try{n=await Se(r,o,c)}catch(u){return Ae(u)??{error:u}}try{ae(s,r,n.token,n.expires_at)}catch{return{key:"settings.saveError"}}return null}function Re(s,r){const{kind:o,failure:c,attempt:n,ended:u,rejected:h}=s;return o==="no-api"?null:c!==null?{tone:"negative",text:typeof c=="string"?c:r(c.key,c.params),focus:!0,id:n}:u?{tone:"informative",text:r("login.sessionEnded"),focus:!1,id:0}:h&&o==="token"?{tone:"negative",text:r("login.rejected"),focus:!1,id:0}:null}const Me=s=>typeof s!="string"&&s.key==="login.rateLimited";function Ue(s,r){return Math.max(0,Math.ceil((s-r)/1e3))}function qe(s,r,o,c){const n=G(),u=ne(),[h]=l.useState(()=>re(s,r)),[a,x]=l.useState(null),[y,j]=l.useState({attempt:0,error:null});l.useEffect(()=>{const i=new AbortController;return Ce(r,i.signal).then(g=>x(g),g=>{i.signal.aborted||j(m=>({...m,error:g instanceof Error?g:new Error(String(g))}))}),()=>i.abort()},[r,y.attempt]);const[p,N]=l.useState(""),d=oe(r),[e,_]=l.useState(d?q.username:""),[f,k]=l.useState(d?q.password:""),[v,F]=l.useState(""),[A,J]=l.useState(!1),[B,H]=l.useState(!1),[P,O]=l.useState({}),[C,b]=l.useState(null),[W,X]=l.useState(0),[T,Y]=l.useState(0),[S,z]=l.useState(Date.now);l.useEffect(()=>{if(T<=S)return;const i=setTimeout(()=>z(Date.now()),(T-S)%1e3||1e3);return()=>clearTimeout(i)},[T,S]);const w=Ue(T,S),L=(i,g)=>m=>{g(m),P[i]&&O(({[i]:M,...se})=>se)},ee=()=>{if(!p.trim())return;const i=Le(s,r,p);i?b({key:i}):location.reload()},te=async i=>{const g=_e(i,e,f,v);if(O(g),Object.keys(g).length)return;H(!0);const m=await De(s,r,i,{username:e,password:f});if(!m){location.reload();return}if(H(!1),"error"in m){b(n("login.failed",{error:ie(m.error,n)}));return}if(m.wait){const M=Date.now();z(M),Y(M+m.wait*1e3)}m.switchTo&&(x(m.switchTo),F("")),b(m)},D=a==="setup"||a==="login",R=i=>P[i]?n(P[i]):void 0;return{kind:a,discoveryError:y.error,retryDiscovery:()=>j(i=>({attempt:i.attempt+1,error:null})),title:n(a==="no-api"?"login.noApiTitle":a==="setup"?"login.setupTitle":a==="token"?"login.title":"login.passwordTitle"),note:a==="no-api"?n("login.noApiNote"):a==="setup"?n("login.setupNote",{backend:o}):a==="login"?n("login.connectedTo",{backend:o}):n("login.note",{backend:o}),demoNote:d&&a==="login"?n("login.demoNote",q):null,alert:Re({kind:a,failure:C&&!w&&Me(C)?null:C,attempt:W,ended:h,rejected:c},n),busy:B,token:p,setToken:N,username:e,setUsername:L("username",_),usernameError:R("username"),password:f,setPassword:L("password",k),passwordError:R("password"),confirm:v,setConfirm:L("confirm",F),confirmError:R("confirm"),submit:()=>{B||w||a==="no-api"||(b(null),X(i=>i+1),D?te(a):ee())},canSubmit:a!=="no-api"&&!w&&(D||!!p.trim()),submitText:w?n("login.retryIn",{n:w}):n(a==="setup"?"login.create":a==="login"?"login.signIn":"login.submit"),secretType:A?"text":"password",toggle:()=>J(i=>!i),toggleText:n(D?A?"login.hidePassword":"login.showPassword":A?"settings.hideToken":"settings.showToken"),guideHref:K(u),requirementsHref:K(u,"no-native-api")}}function Q({className:s,...r}){return t.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:10,height:10,viewBox:"0 0 12 12","aria-hidden":"true",focusable:"false",className:ue("rp-icon rp-linLine truncated
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./LoginShowcase-B9vkePHH.js","./vendor-react-Bf71BWbF.js","./index-BOpK0UVB.js","./index-tAbIWhIz.css"])))=>i.map(i=>d[i]);
|
||||
import{u as G,a as ne,e as re,d as K,A as I,i as oe,b as ie,s as ae,r as le,w as ce,n as V,c as ue,f as de,L as U,h as me,g as ge,P as pe,S as fe,l as he,E as Z,j as we,I as xe,T as E,B as ye,k as je,_ as ke}from"./index-BOpK0UVB.js";import{r as l,j as t}from"./vendor-react-Bf71BWbF.js";import{D as q,s as ve,d as be,a as Te,o as Se}from"./auth-DKKBdTVr.js";function Ee(s,r,o,c){return s.some(n=>n.id===r&&V(n.api)===V(o))?s.map(n=>n.id===r?{...n,token:c.trim()}:n):null}const Ne=/^[A-Za-z0-9_.-]{1,64}$/;function _e(s,r,o,c){const n={};r?Ne.test(r)||(n.username="login.badUsername"):n.username="login.usernameRequired";const u=[...o].length;return u?s==="setup"&&u<8?n.password="login.passwordShort":u>128||new TextEncoder().encode(o).length>512?n.password="login.passwordLong":s==="setup"&&o!==c&&(n.confirm="login.mismatch"):n.password="login.passwordRequired",n}function Ae(s){if(!(s instanceof I))return null;if(s.code==="invalid_credentials")return{key:"login.invalidCredentials"};if(s.code==="setup_required")return{key:"login.needsSetup",switchTo:"setup"};if(s.code==="setup_already_completed")return{key:"login.alreadySetUp",switchTo:"login"};if(s.code==="permission_denied")return{key:"login.setupPeer"};if(s.code==="rate_limited"){const r=s.retryAfter??60;return{key:"login.rateLimited",params:{n:r},wait:r}}return null}function Pe(s){return s instanceof SyntaxError?!0:s instanceof I&&(s.status===404||s.status===401&&(!s.code||s.code==="authentication_required"))}async function Ce(s,r){try{return ve(await be(s,r))}catch(o){if(!Pe(o))throw o;return!(o instanceof I)||o.status!==404||await Te(s,r)?"token":"no-api"}}function Le(s,r,o){try{const{profiles:c,activeId:n}=le(),u=Ee(c,s,r,o);if(!u)return"login.stale";ce({profiles:u,activeId:n})}catch{return"settings.saveError"}return null}async function De(s,r,o,c){let n;try{n=await Se(r,o,c)}catch(u){return Ae(u)??{error:u}}try{ae(s,r,n.token,n.expires_at)}catch{return{key:"settings.saveError"}}return null}function Re(s,r){const{kind:o,failure:c,attempt:n,ended:u,rejected:h}=s;return o==="no-api"?null:c!==null?{tone:"negative",text:typeof c=="string"?c:r(c.key,c.params),focus:!0,id:n}:u?{tone:"informative",text:r("login.sessionEnded"),focus:!1,id:0}:h&&o==="token"?{tone:"negative",text:r("login.rejected"),focus:!1,id:0}:null}const Me=s=>typeof s!="string"&&s.key==="login.rateLimited";function Ue(s,r){return Math.max(0,Math.ceil((s-r)/1e3))}function qe(s,r,o,c){const n=G(),u=ne(),[h]=l.useState(()=>re(s,r)),[a,x]=l.useState(null),[y,j]=l.useState({attempt:0,error:null});l.useEffect(()=>{const i=new AbortController;return Ce(r,i.signal).then(g=>x(g),g=>{i.signal.aborted||j(m=>({...m,error:g instanceof Error?g:new Error(String(g))}))}),()=>i.abort()},[r,y.attempt]);const[p,N]=l.useState(""),d=oe(r),[e,_]=l.useState(d?q.username:""),[f,k]=l.useState(d?q.password:""),[v,F]=l.useState(""),[A,J]=l.useState(!1),[B,H]=l.useState(!1),[P,O]=l.useState({}),[C,b]=l.useState(null),[W,X]=l.useState(0),[T,Y]=l.useState(0),[S,z]=l.useState(Date.now);l.useEffect(()=>{if(T<=S)return;const i=setTimeout(()=>z(Date.now()),(T-S)%1e3||1e3);return()=>clearTimeout(i)},[T,S]);const w=Ue(T,S),L=(i,g)=>m=>{g(m),P[i]&&O(({[i]:M,...se})=>se)},ee=()=>{if(!p.trim())return;const i=Le(s,r,p);i?b({key:i}):location.reload()},te=async i=>{const g=_e(i,e,f,v);if(O(g),Object.keys(g).length)return;H(!0);const m=await De(s,r,i,{username:e,password:f});if(!m){location.reload();return}if(H(!1),"error"in m){b(n("login.failed",{error:ie(m.error,n)}));return}if(m.wait){const M=Date.now();z(M),Y(M+m.wait*1e3)}m.switchTo&&(x(m.switchTo),F("")),b(m)},D=a==="setup"||a==="login",R=i=>P[i]?n(P[i]):void 0;return{kind:a,discoveryError:y.error,retryDiscovery:()=>j(i=>({attempt:i.attempt+1,error:null})),title:n(a==="no-api"?"login.noApiTitle":a==="setup"?"login.setupTitle":a==="token"?"login.title":"login.passwordTitle"),note:a==="no-api"?n("login.noApiNote"):a==="setup"?n("login.setupNote",{backend:o}):a==="login"?n("login.connectedTo",{backend:o}):n("login.note",{backend:o}),demoNote:d&&a==="login"?n("login.demoNote",q):null,alert:Re({kind:a,failure:C&&!w&&Me(C)?null:C,attempt:W,ended:h,rejected:c},n),busy:B,token:p,setToken:N,username:e,setUsername:L("username",_),usernameError:R("username"),password:f,setPassword:L("password",k),passwordError:R("password"),confirm:v,setConfirm:L("confirm",F),confirmError:R("confirm"),submit:()=>{B||w||a==="no-api"||(b(null),X(i=>i+1),D?te(a):ee())},canSubmit:a!=="no-api"&&!w&&(D||!!p.trim()),submitText:w?n("login.retryIn",{n:w}):n(a==="setup"?"login.create":a==="login"?"login.signIn":"login.submit"),secretType:A?"text":"password",toggle:()=>J(i=>!i),toggleText:n(D?A?"login.hidePassword":"login.showPassword":A?"settings.hideToken":"settings.showToken"),guideHref:K(u),requirementsHref:K(u,"no-native-api")}}function Q({className:s,...r}){return t.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:10,height:10,viewBox:"0 0 12 12","aria-hidden":"true",focusable:"false",className:ue("rp-icon rp-linLine truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{j as U,r as I}from"./vendor-react-Bf71BWbF.js";import{fD as O1,u as K1,a as U1,f as N1,a6 as V1,aQ as X1}from"./index-Bw0aJc9a.js";function Q1({label:r,className:c,isDisabled:f,ref:e,canvasRef:l}){return U.jsx("button",{ref:e,type:"button",className:c,"aria-label":r,disabled:f,children:U.jsx("canvas",{ref:l})})}const q1=[["ink","M657 1228c-12-4-23-14-28-26-1-4-2-4-4-4-22 4-36 3-49-3-11-6-18-16-20-27-2-11 3-23 12-34 3-3 6-6 6-6 0 0-7-1-15-1-34-2-70-7-100-14-49-12-98-36-134-67l-5-4-12 4c-20 7-36 9-60 9-21 0-43-4-57-10-13-5-25-16-30-25-5-10-4-23 3-34 4-6 16-18 24-22l6-4-3-8c-2-5-2-9-2-12 1-6 5-15 9-18 4-5 16-13 21-14 3-1 5-2 6-2 0-1-1-6-3-12-21-73-6-145 45-212l7-10-12-2c-15-1-23-3-34-7-24-9-40-29-40-49 0-19 7-34 36-72 15-21 27-39 35-54 11-19 10-17 5-28-2-4-5-11-6-14-2-8-3-32-1-43 4-28 18-59 42-90l3-5-6-4c-11-9-20-21-23-32-2-6-2-9-2-17 1-9 1-10 4-18 6-11 15-20 29-27 14-7 24-10 47-15 1 0 3-3 7-11 19-37 51-71 88-94 12-8 32-18 44-22 10-3 29-8 33-8 1 0 5-2 8-5 11-8 25-14 39-16 12-2 49-1 63 2 21 4 34 9 45 19 8 7 10 9 15 18 4 7 4 7 13 12 34 18 63 46 86 81 10 16 20 38 26 57 4 12 8 34 10 48 2 13 2 43 0 56l-1 10 6 7c8 8 14 19 18 28 3 9 4 24 2 33-3 14-14 27-29 35-9 5-19 7-31 8l-9 1 0 8c0 4 0 15 0 25 0 16-1 31-5 47l0 3 14 0c27 0 58 5 83 14 21 9 51 25 68 39 3 2 6 5 7 5 0 1 6-2 14-6 27-14 49-17 69-11 26 8 38 34 27 64-2 5-3 9-3 10 0 0 4 1 8 3 14 7 24 19 29 34 8 22 0 45-24 73l-5 6 3 9c6 26 8 63 5 89-2 14-7 33-12 48-9 22-26 52-43 72-10 13-34 36-47 46-28 22-59 39-93 52-16 7-44 16-47 16-1 0-1 1-1 3 9 31 7 61-3 81-8 16-19 27-33 34-9 4-14 5-25 5-15 0-28-4-39-13l-6-5-7 6c-9 7-18 13-26 16-9 3-27 4-35 1z"],["paper","M582 1098c-44-2-79-6-117-16-55-14-102-41-141-81-42-43-67-93-75-148-2-14-1-43 1-56 6-30 16-57 32-82 8-12 24-33 32-42 6-7 7-7 17-10 58-18 110-56 126-92 2-5 2-9 3-16 1-14-2-21-15-33-13-14-21-24-33-39-18-26-28-35-45-43-11-5-21-7-33-7-13 0-23 2-33 7-6 3-9 3-9 3-4-6-4-28-2-42 5-23 18-49 37-73 14-18 37-39 56-53 5-4 6-4 11-4 41 1 105 13 154 28 32 9 72 25 104 42 18 9 51 27 66 37 8 5 8 5 11 13 7 16 13 37 16 56 2 11 2 41 1 54-4 39-19 74-44 104-8 9-10 14-9 20 1 5 7 10 13 12 7 2 14-1 24-11 10-11 22-29 32-48 3-5 4-7 6-7 2-1 14-1 27-1 22 0 24 0 37 2 34 8 68 24 98 48 13 11 15 12 20 12 5 0 7-1 16-7 22-14 41-21 53-18 13 3 16 15 7 32-2 5-6 11-8 15-4 8-4 14 0 19 4 5 7 6 17 7 15 1 23 5 27 14 3 6 3 15 0 22-2 6-10 18-20 30-9 11-11 15-8 24 3 10 6 33 7 52 0 26-2 47-10 70-18 53-57 101-111 135-40 25-87 43-144 54-66 14-132 19-194 17z"],["ink","M517 445c-7-2-13-6-18-12-7-7-9-14-9-25 0-7 0-8 3-15 7-13 17-21 31-22 23-1 43 18 41 40-2 19-17 33-36 35-4 0-9-1-12-1z"],["yellow","M541 220c-13-3-27-7-41-9-6-1-14-3-17-3l-5-1 2-6c3-15 13-40 23-59 20-39 43-66 64-73 11-3 56-1 74 4 7 1 13 4 17 7 3 3 3 4-1 4-5 0-17 4-24 7-35 18-62 59-79 118-2 8-4 14-4 14 0 0-4-1-9-3z"],["yellow","M446 203c-4-1-19-1-35-2-16 0-29 0-29-1 0-1 6-12 12-20 22-34 53-62 87-78 10-5 32-13 33-12 0 0-2 3-6 8-19 27-38 69-47 102-1 4-1 4-5 4-3 0-7-1-10-1z"],["yellow","M569 226c13-58 39-102 70-119 14-7 21-6 40 1 53 23 96 73 113 132 9 29 11 67 7 95-71-43-149-81-230-109z"],["yellow","M780 426c-1-2-5-19-5-19 0-1 3 0 8 0 6 0 8 0 10-2 5-4 3-6-21-21-50-32-74-46-109-63-71-36-143-57-225-67-48-6-99-5-107 1-4 3-5 5-2 7 1 2 3 2 10 3l8 0-4 4c-3 3-9 8-13 12l-9 8-4-2c-6-4-13-11-16-17-3-5-4-12-3-17 2-8 11-17 22-22 22-10 60-14 101-12 63 3 121 16 167 36 71 31 145 67 214 105 17 10 27 31 23 45-1 5-6 12-10 15-6 4-15 6-25 7-8 0-10 0-10-1z"],["yellow","M251 640c-19-4-32-16-32-29 0-10 5-19 23-43 26-34 37-50 50-75 6-12 9-17 13-20 12-11 29-13 45-7 11 5 17 10 37 36 9 13 19 25 24 30 5 5 10 10 12 13 2 3 2 5 2 10 0 5-1 8-4 12-17 29-73 61-123 71-14 3-38 4-47 2z"],["yellow","M226 1028c-12-1-24-5-31-10-12-8-13-16-2-27 5-5 19-13 30-17 7-3 11-6 11-8 0-3-1-5-8-9-7-6-10-10-10-14 0-4 1-5 4-8 2-2 6-4 9-5 3-1 5-2 5-2 1 0 4 7 8 14 15 29 28 49 49 72 4 5 7 8 7 9-1 1-21 5-29 6-13 1-31 1-43-1z"],["yellow","M663 1201c-7-4-9-12-7-24 1-7 1-8 0-10-3-4-7-4-15-1-18 7-40 10-48 7-5-2-8-6-8-11 0-7 8-16 29-30l10-7 19 0c22-1 52-4 78-7 18-3 57-9 65-11 6-2 11-1 14 1 2 3 4 7 5 20 4 39-13 70-39 68-9-1-16-5-29-17-14-12-14-12-27 1-11 11-20 18-28 21-7 3-15 3-19 0z"]],N={width:940,height:1192},K=1.4,v=52,Z=72,f1=500,J1=250,$=22,Y=22,i1=Y+2,l1=16,u1=12,Y1=56,A1=17,E=9,D1=18,q=1/120,h1=1500,e1=430,B=48,Z1=e1*e1/(2*h1),H1=Math.max(2.2*v,v+Z1+4),z1=200,_1=z1*h1/(2*e1),J=.84*v*N.width/N.height/2,d1=.84*v/2;function C1(r,c){let f=0;for(;r>=1e3&&f<c.length-1;f++)r/=1e3;return[r,f]}function O(r,c){const f=["unit.megabyte","unit.gigabyte","unit.terabyte","unit.petabyte"],[e,l]=C1(r,f);return O1(e,c,f[l],l?2:1)}function G1(r){return r<6?[100,150,200,300,450,650][r]:[1,1.5,2.5,4,6][(r-6)%5]*Math.pow(10,3+Math.floor((r-6)/5))}function ee(r,c){const f=["unit.megabitPerSecond","unit.gigabitPerSecond","unit.terabitPerSecond","unit.petabitPerSecond"],[e,l]=C1(G1(r),f);return O1(e,c,f[l],Math.round(e*10)%10?1:0)}function I1(r){const c=Math.pow(.9,r);return{speed:_1-(_1-110)*c,gap:H1+(205-H1)*c,space:z1+70*c,swing:r<6?0:34*(1-Math.pow(.8,r-5)),drift:r>=6}}function te(r)Line truncated
|
||||
import{j as U,r as I}from"./vendor-react-Bf71BWbF.js";import{fD as O1,u as K1,a as U1,f as N1,a6 as V1,aQ as X1}from"./index-BOpK0UVB.js";function Q1({label:r,className:c,isDisabled:f,ref:e,canvasRef:l}){return U.jsx("button",{ref:e,type:"button",className:c,"aria-label":r,disabled:f,children:U.jsx("canvas",{ref:l})})}const q1=[["ink","M657 1228c-12-4-23-14-28-26-1-4-2-4-4-4-22 4-36 3-49-3-11-6-18-16-20-27-2-11 3-23 12-34 3-3 6-6 6-6 0 0-7-1-15-1-34-2-70-7-100-14-49-12-98-36-134-67l-5-4-12 4c-20 7-36 9-60 9-21 0-43-4-57-10-13-5-25-16-30-25-5-10-4-23 3-34 4-6 16-18 24-22l6-4-3-8c-2-5-2-9-2-12 1-6 5-15 9-18 4-5 16-13 21-14 3-1 5-2 6-2 0-1-1-6-3-12-21-73-6-145 45-212l7-10-12-2c-15-1-23-3-34-7-24-9-40-29-40-49 0-19 7-34 36-72 15-21 27-39 35-54 11-19 10-17 5-28-2-4-5-11-6-14-2-8-3-32-1-43 4-28 18-59 42-90l3-5-6-4c-11-9-20-21-23-32-2-6-2-9-2-17 1-9 1-10 4-18 6-11 15-20 29-27 14-7 24-10 47-15 1 0 3-3 7-11 19-37 51-71 88-94 12-8 32-18 44-22 10-3 29-8 33-8 1 0 5-2 8-5 11-8 25-14 39-16 12-2 49-1 63 2 21 4 34 9 45 19 8 7 10 9 15 18 4 7 4 7 13 12 34 18 63 46 86 81 10 16 20 38 26 57 4 12 8 34 10 48 2 13 2 43 0 56l-1 10 6 7c8 8 14 19 18 28 3 9 4 24 2 33-3 14-14 27-29 35-9 5-19 7-31 8l-9 1 0 8c0 4 0 15 0 25 0 16-1 31-5 47l0 3 14 0c27 0 58 5 83 14 21 9 51 25 68 39 3 2 6 5 7 5 0 1 6-2 14-6 27-14 49-17 69-11 26 8 38 34 27 64-2 5-3 9-3 10 0 0 4 1 8 3 14 7 24 19 29 34 8 22 0 45-24 73l-5 6 3 9c6 26 8 63 5 89-2 14-7 33-12 48-9 22-26 52-43 72-10 13-34 36-47 46-28 22-59 39-93 52-16 7-44 16-47 16-1 0-1 1-1 3 9 31 7 61-3 81-8 16-19 27-33 34-9 4-14 5-25 5-15 0-28-4-39-13l-6-5-7 6c-9 7-18 13-26 16-9 3-27 4-35 1z"],["paper","M582 1098c-44-2-79-6-117-16-55-14-102-41-141-81-42-43-67-93-75-148-2-14-1-43 1-56 6-30 16-57 32-82 8-12 24-33 32-42 6-7 7-7 17-10 58-18 110-56 126-92 2-5 2-9 3-16 1-14-2-21-15-33-13-14-21-24-33-39-18-26-28-35-45-43-11-5-21-7-33-7-13 0-23 2-33 7-6 3-9 3-9 3-4-6-4-28-2-42 5-23 18-49 37-73 14-18 37-39 56-53 5-4 6-4 11-4 41 1 105 13 154 28 32 9 72 25 104 42 18 9 51 27 66 37 8 5 8 5 11 13 7 16 13 37 16 56 2 11 2 41 1 54-4 39-19 74-44 104-8 9-10 14-9 20 1 5 7 10 13 12 7 2 14-1 24-11 10-11 22-29 32-48 3-5 4-7 6-7 2-1 14-1 27-1 22 0 24 0 37 2 34 8 68 24 98 48 13 11 15 12 20 12 5 0 7-1 16-7 22-14 41-21 53-18 13 3 16 15 7 32-2 5-6 11-8 15-4 8-4 14 0 19 4 5 7 6 17 7 15 1 23 5 27 14 3 6 3 15 0 22-2 6-10 18-20 30-9 11-11 15-8 24 3 10 6 33 7 52 0 26-2 47-10 70-18 53-57 101-111 135-40 25-87 43-144 54-66 14-132 19-194 17z"],["ink","M517 445c-7-2-13-6-18-12-7-7-9-14-9-25 0-7 0-8 3-15 7-13 17-21 31-22 23-1 43 18 41 40-2 19-17 33-36 35-4 0-9-1-12-1z"],["yellow","M541 220c-13-3-27-7-41-9-6-1-14-3-17-3l-5-1 2-6c3-15 13-40 23-59 20-39 43-66 64-73 11-3 56-1 74 4 7 1 13 4 17 7 3 3 3 4-1 4-5 0-17 4-24 7-35 18-62 59-79 118-2 8-4 14-4 14 0 0-4-1-9-3z"],["yellow","M446 203c-4-1-19-1-35-2-16 0-29 0-29-1 0-1 6-12 12-20 22-34 53-62 87-78 10-5 32-13 33-12 0 0-2 3-6 8-19 27-38 69-47 102-1 4-1 4-5 4-3 0-7-1-10-1z"],["yellow","M569 226c13-58 39-102 70-119 14-7 21-6 40 1 53 23 96 73 113 132 9 29 11 67 7 95-71-43-149-81-230-109z"],["yellow","M780 426c-1-2-5-19-5-19 0-1 3 0 8 0 6 0 8 0 10-2 5-4 3-6-21-21-50-32-74-46-109-63-71-36-143-57-225-67-48-6-99-5-107 1-4 3-5 5-2 7 1 2 3 2 10 3l8 0-4 4c-3 3-9 8-13 12l-9 8-4-2c-6-4-13-11-16-17-3-5-4-12-3-17 2-8 11-17 22-22 22-10 60-14 101-12 63 3 121 16 167 36 71 31 145 67 214 105 17 10 27 31 23 45-1 5-6 12-10 15-6 4-15 6-25 7-8 0-10 0-10-1z"],["yellow","M251 640c-19-4-32-16-32-29 0-10 5-19 23-43 26-34 37-50 50-75 6-12 9-17 13-20 12-11 29-13 45-7 11 5 17 10 37 36 9 13 19 25 24 30 5 5 10 10 12 13 2 3 2 5 2 10 0 5-1 8-4 12-17 29-73 61-123 71-14 3-38 4-47 2z"],["yellow","M226 1028c-12-1-24-5-31-10-12-8-13-16-2-27 5-5 19-13 30-17 7-3 11-6 11-8 0-3-1-5-8-9-7-6-10-10-10-14 0-4 1-5 4-8 2-2 6-4 9-5 3-1 5-2 5-2 1 0 4 7 8 14 15 29 28 49 49 72 4 5 7 8 7 9-1 1-21 5-29 6-13 1-31 1-43-1z"],["yellow","M663 1201c-7-4-9-12-7-24 1-7 1-8 0-10-3-4-7-4-15-1-18 7-40 10-48 7-5-2-8-6-8-11 0-7 8-16 29-30l10-7 19 0c22-1 52-4 78-7 18-3 57-9 65-11 6-2 11-1 14 1 2 3 4 7 5 20 4 39-13 70-39 68-9-1-16-5-29-17-14-12-14-12-27 1-11 11-20 18-28 21-7 3-15 3-19 0z"]],N={width:940,height:1192},K=1.4,v=52,Z=72,f1=500,J1=250,$=22,Y=22,i1=Y+2,l1=16,u1=12,Y1=56,A1=17,E=9,D1=18,q=1/120,h1=1500,e1=430,B=48,Z1=e1*e1/(2*h1),H1=Math.max(2.2*v,v+Z1+4),z1=200,_1=z1*h1/(2*e1),J=.84*v*N.width/N.height/2,d1=.84*v/2;function C1(r,c){let f=0;for(;r>=1e3&&f<c.length-1;f++)r/=1e3;return[r,f]}function O(r,c){const f=["unit.megabyte","unit.gigabyte","unit.terabyte","unit.petabyte"],[e,l]=C1(r,f);return O1(e,c,f[l],l?2:1)}function G1(r){return r<6?[100,150,200,300,450,650][r]:[1,1.5,2.5,4,6][(r-6)%5]*Math.pow(10,3+Math.floor((r-6)/5))}function ee(r,c){const f=["unit.megabitPerSecond","unit.gigabitPerSecond","unit.terabitPerSecond","unit.petabitPerSecond"],[e,l]=C1(G1(r),f);return O1(e,c,f[l],Math.round(e*10)%10?1:0)}function I1(r){const c=Math.pow(.9,r);return{speed:_1-(_1-110)*c,gap:H1+(205-H1)*c,space:z1+70*c,swing:r<6?0:34*(1-Math.pow(.8,r-5)),drift:r>=6}}function te(r)Line truncated
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
import{j as r,r as x}from"./vendor-react-Bf71BWbF.js";import{aT as P,u as L,a6 as O,a as D,aI as B,H as T,B as W,ex as H,bP as k,ey as C,aN as I,a4 as N,aw as _,aa as q,aF as J,bI as G,ez as K,dl as V,eA as z,aL as S,aJ as F,aK as U,bt as Q,T as X,cN as Y,aM as Z,E as ee}from"./index-Bw0aJc9a.js";import{F as te}from"./FactStrip-DtkOGBRy.js";import{u as se,h as ae,C as re,t as oe}from"./layout-BWzq8YqC.js";import{D as ne}from"./Table-Km6Zv-S8.js";import{A as le}from"./ActionGroup-DLxTuKht.js";import{d as ie,e as ce}from"./files-BxEOxSF8.js";import{r as ge}from"./recorder-DlDpPhd4.js";import"./useGridSelectionCheckbox-COXIVEmS.js";import"./Virtualizer-DCY9HC9Z.js";import"./ListLayout-_fDlx5XY.js";function ue({label:a,rows:t,columns:e}){const n=P(),{ref:s,tip:o,show:c,hide:p}=se();return r.jsxs("div",{className:"rp-heatmap rp-chart-hover",ref:s,onPointerLeave:p,role:"group","aria-label":a,"aria-describedby":n,style:{"--cols":e.length},children:[t.map(i=>{const g=Math.max(...i.counts);return r.jsxs("div",{className:"row",children:[r.jsx("div",{className:"head",children:i.label}),r.jsx("div",{className:"cells",children:i.counts.map((b,v)=>r.jsx("span",{className:"cell t"+ae(b,g),style:{"--tone":i.color},onPointerMove:d=>c(d,[i.titles[v]]),role:"img","aria-label":i.titles[v]},v))})]},i.id)}),e.length>0&&r.jsxs("div",{className:"row times","aria-hidden":"true",children:[r.jsx("div",{className:"head"}),r.jsxs("div",{className:"ends",children:[r.jsx("span",{children:e[0]}),e.length>2&&r.jsx("span",{children:e[Math.floor(e.length/2)]}),e.length>1&&r.jsx("span",{children:e[e.length-1]})]})]}),r.jsx(re,{tip:o})]})}const A=new WeakMap;function E(a){let t=A.get(a);return t===void 0&&A.set(a,t=Date.parse(a.ts)),t}const M=["error","warn","info","debug","trace"];function de(a,t,e,n=24){const s=e?M.indexOf(e):M.length-1,o=M.filter((u,h)=>t.includes(u)&&h<=s),c=a.map(E).filter(Number.isFinite);if(!c.length)return{rows:o.map(u=>({level:u,counts:[]})),buckets:[],width:0,busiest:null};const p=Math.min(...c),i=Math.max(...c),g=oe(p,i,n),b=g.length>1?g[1]-g[0]:Math.max(i-p,6e4),v=new Map(o.map(u=>[u,new Array(g.length).fill(0)])),d=new Array(g.length).fill(0),j=new Array(g.length).fill(0);for(const u of a){const h=E(u),w=v.get(u.level);if(!w||!Number.isFinite(h))continue;const y=Math.min(g.length-1,Math.floor((h-g[0])/b));w[y]++,d[y]++,u.level==="error"&&j[y]++}const f=u=>u.reduce((h,w,y)=>w>u[h]?y:h,0),m=j.reduce((u,h)=>u+h,0),l=f(m?j:d);return{rows:o.map(u=>({level:u,counts:v.get(u)})),buckets:g,width:b,busiest:{start:g[l],count:m?j[l]:d[l],errors:m}}}function pe({records:a,offered:t,minimum:e,setMinimum:n}){const s=L(),o=O[D()],c=B(),p=x.useMemo(()=>de(a,t,e),[a,t,e]),i=x.useMemo(()=>new Intl.DateTimeFormat(o,{hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),[o]),g=x.useCallback(f=>`${i.format(f)}–${i.format(f+p.width)}`,[i,p.width]),b=x.useMemo(()=>{const f=Object.keys(T).map(m=>{const l=s(T[m]);return[m,{text:l,label:r.jsxs(W,{quiet:!0,small:!0,className:m===e?"current":void 0,label:s(m===e?"log.chart.current":"log.chart.minimum",{level:l}),onPress:()=>n(m),children:[m===e&&r.jsx(H,{}),l]})}]});return new Map(f)},[e,n,s]),v=x.useMemo(()=>{const f={error:c.negative,warn:c.notice,info:c.info,debug:c.subtle,trace:c.muted},m=p.buckets.map(g);return{columns:p.buckets.map(l=>i.format(l)),rows:p.rows.map(l=>{const{text:u,label:h}=b.get(l.level);return{id:l.level,color:f[l.level],label:h,counts:l.counts,titles:l.counts.map((w,y)=>s("log.chart.cell",{time:m[y],level:u,n:w}))}})}},[p,g,i,b,c,s]);if(!a.length)return null;const d=p.busiest,j=d?d.errors?[{label:s("log.chart.errors"),value:s("log.chart.count",{n:d.errors}),icon:r.jsx(k,{}),tone:"negative"},{label:s("log.chart.peakErrors"),icon:r.jsx(C,{}),tint:"c1",value:g(d.start),caption:s("log.chart.count",{n:d.count})}]:[{label:s("log.chart.errors"),value:s("log.chart.count",{n:0}),icon:r.jsx(k,{}),tint:"c5"},{label:s("log.chart.peak"),icon:r.jsx(C,{}),tint:"c1",value:g(d.start),caption:s("log.chart.count",{n:d.count})}]:[];return r.jsxs("div",{className:"rp-chart-page",children:[r.jsx(te,{facts:j}),r.jsx(I,{title:s("log.chart.title"),note:s("log.chart.sample",{n:a.length}),children:r.jsx(ue,{label:s("log.chart.title"),columns:v.columns,rows:v.rows})})]})}const R=["trace","debug","info","warn","error"],me={trace:"muted",debug:"neutral",info:"info",warn:"warn",error:"err"},$=new WeakMap;function he(a,t,e){const n=$.get(a);if(n&&n.locale===t)return n.row;const s={id:a.id,timestamp:_(a.ts,t),iso:a.ts,levelText:N(T,a.level,e),tone:me[a.level],target:a.target,gap:!1,message:a.message+(a.fields?" "+Object.entries(a.fields).map(([o,c])=>`${o}=${typeof c=="string"?c:JSON.stringify(c)}`).join(" "):"")};return $.set(a,{locale:t,row:s}),s}function fe(a,t,e,n,s,o=new Set,c){const p=i=>!!c&&R.indexOf(i)<R.indexOf(c);return{rows:a.flatMap(i=>{const g=he(i,n,s);return o.has(i)?[{...g,id:`gap ${i.id}`,timestamp:"",iso:"",levelText:"",target:"",gap:!0,message:s("log.gap")},g]:[g]}),levels:t.map(i=>Line truncated
|
||||
import{j as r,r as x}from"./vendor-react-Bf71BWbF.js";import{aT as P,u as L,a6 as O,a as D,aI as B,H as T,B as W,ex as H,bP as k,ey as C,aN as I,a4 as N,aw as _,aa as q,aF as J,bI as G,ez as K,dl as V,eA as z,aL as S,aJ as F,aK as U,bt as Q,T as X,cN as Y,aM as Z,E as ee}from"./index-BOpK0UVB.js";import{F as te}from"./FactStrip-CPXeRki4.js";import{u as se,h as ae,C as re,t as oe}from"./layout-Bzzn7HLw.js";import{D as ne}from"./Table-BkehX7fw.js";import{A as le}from"./ActionGroup-BU73NzbX.js";import{d as ie,e as ce}from"./files-BxEOxSF8.js";import{r as ge}from"./recorder-DlDpPhd4.js";import"./useGridSelectionCheckbox-C4VxQajJ.js";import"./Virtualizer-BIsXGNLZ.js";import"./ListLayout-CkBMjK9o.js";function ue({label:a,rows:t,columns:e}){const n=P(),{ref:s,tip:o,show:c,hide:p}=se();return r.jsxs("div",{className:"rp-heatmap rp-chart-hover",ref:s,onPointerLeave:p,role:"group","aria-label":a,"aria-describedby":n,style:{"--cols":e.length},children:[t.map(i=>{const g=Math.max(...i.counts);return r.jsxs("div",{className:"row",children:[r.jsx("div",{className:"head",children:i.label}),r.jsx("div",{className:"cells",children:i.counts.map((b,v)=>r.jsx("span",{className:"cell t"+ae(b,g),style:{"--tone":i.color},onPointerMove:d=>c(d,[i.titles[v]]),role:"img","aria-label":i.titles[v]},v))})]},i.id)}),e.length>0&&r.jsxs("div",{className:"row times","aria-hidden":"true",children:[r.jsx("div",{className:"head"}),r.jsxs("div",{className:"ends",children:[r.jsx("span",{children:e[0]}),e.length>2&&r.jsx("span",{children:e[Math.floor(e.length/2)]}),e.length>1&&r.jsx("span",{children:e[e.length-1]})]})]}),r.jsx(re,{tip:o})]})}const A=new WeakMap;function E(a){let t=A.get(a);return t===void 0&&A.set(a,t=Date.parse(a.ts)),t}const M=["error","warn","info","debug","trace"];function de(a,t,e,n=24){const s=e?M.indexOf(e):M.length-1,o=M.filter((u,h)=>t.includes(u)&&h<=s),c=a.map(E).filter(Number.isFinite);if(!c.length)return{rows:o.map(u=>({level:u,counts:[]})),buckets:[],width:0,busiest:null};const p=Math.min(...c),i=Math.max(...c),g=oe(p,i,n),b=g.length>1?g[1]-g[0]:Math.max(i-p,6e4),v=new Map(o.map(u=>[u,new Array(g.length).fill(0)])),d=new Array(g.length).fill(0),j=new Array(g.length).fill(0);for(const u of a){const h=E(u),w=v.get(u.level);if(!w||!Number.isFinite(h))continue;const y=Math.min(g.length-1,Math.floor((h-g[0])/b));w[y]++,d[y]++,u.level==="error"&&j[y]++}const f=u=>u.reduce((h,w,y)=>w>u[h]?y:h,0),m=j.reduce((u,h)=>u+h,0),l=f(m?j:d);return{rows:o.map(u=>({level:u,counts:v.get(u)})),buckets:g,width:b,busiest:{start:g[l],count:m?j[l]:d[l],errors:m}}}function pe({records:a,offered:t,minimum:e,setMinimum:n}){const s=L(),o=O[D()],c=B(),p=x.useMemo(()=>de(a,t,e),[a,t,e]),i=x.useMemo(()=>new Intl.DateTimeFormat(o,{hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),[o]),g=x.useCallback(f=>`${i.format(f)}–${i.format(f+p.width)}`,[i,p.width]),b=x.useMemo(()=>{const f=Object.keys(T).map(m=>{const l=s(T[m]);return[m,{text:l,label:r.jsxs(W,{quiet:!0,small:!0,className:m===e?"current":void 0,label:s(m===e?"log.chart.current":"log.chart.minimum",{level:l}),onPress:()=>n(m),children:[m===e&&r.jsx(H,{}),l]})}]});return new Map(f)},[e,n,s]),v=x.useMemo(()=>{const f={error:c.negative,warn:c.notice,info:c.info,debug:c.subtle,trace:c.muted},m=p.buckets.map(g);return{columns:p.buckets.map(l=>i.format(l)),rows:p.rows.map(l=>{const{text:u,label:h}=b.get(l.level);return{id:l.level,color:f[l.level],label:h,counts:l.counts,titles:l.counts.map((w,y)=>s("log.chart.cell",{time:m[y],level:u,n:w}))}})}},[p,g,i,b,c,s]);if(!a.length)return null;const d=p.busiest,j=d?d.errors?[{label:s("log.chart.errors"),value:s("log.chart.count",{n:d.errors}),icon:r.jsx(k,{}),tone:"negative"},{label:s("log.chart.peakErrors"),icon:r.jsx(C,{}),tint:"c1",value:g(d.start),caption:s("log.chart.count",{n:d.count})}]:[{label:s("log.chart.errors"),value:s("log.chart.count",{n:0}),icon:r.jsx(k,{}),tint:"c5"},{label:s("log.chart.peak"),icon:r.jsx(C,{}),tint:"c1",value:g(d.start),caption:s("log.chart.count",{n:d.count})}]:[];return r.jsxs("div",{className:"rp-chart-page",children:[r.jsx(te,{facts:j}),r.jsx(I,{title:s("log.chart.title"),note:s("log.chart.sample",{n:a.length}),children:r.jsx(ue,{label:s("log.chart.title"),columns:v.columns,rows:v.rows})})]})}const R=["trace","debug","info","warn","error"],me={trace:"muted",debug:"neutral",info:"info",warn:"warn",error:"err"},$=new WeakMap;function he(a,t,e){const n=$.get(a);if(n&&n.locale===t)return n.row;const s={id:a.id,timestamp:_(a.ts,t),iso:a.ts,levelText:N(T,a.level,e),tone:me[a.level],target:a.target,gap:!1,message:a.message+(a.fields?" "+Object.entries(a.fields).map(([o,c])=>`${o}=${typeof c=="string"?c:JSON.stringify(c)}`).join(" "):"")};return $.set(a,{locale:t,row:s}),s}function fe(a,t,e,n,s,o=new Set,c){const p=i=>!!c&&R.indexOf(i)<R.indexOf(c);return{rows:a.flatMap(i=>{const g=he(i,n,s);return o.has(i)?[{...g,id:`gap ${i.id}`,timestamp:"",iso:"",levelText:"",target:"",gap:!0,message:s("log.gap")},g]:[g]}),levels:t.map(i=>Line truncated
|
||||
`)+`
|
||||
`}const we=[];function ye({go:a}){const t=L(),e=O[D()],n=q(),s=J(),[o,c]=x.useState("info"),p=x.useCallback(y=>c(y),[]),[i,g]=x.useState(""),[b,v]=x.useState(!1),d=n.data?.resources.logs,j=d?.filters?.includes("target")??!1,f=G(j?i.trim():""),m=ve(o,d?.levels),l=K({level:m,target:f,paused:b}),u=V(n.data?.resources.runtime_settings.available??!1).data,h=u?.log?.level,w=x.useMemo(()=>fe(l.records,d?.levels??[],s.data?.engine.name,e,t,l.gaps,h),[l.records,l.gaps,d,s.data,e,t,h]);return{...w,empty:xe(u?.recording?.logs,!!f,t),status:be(l.connected,!!l.error,b,l.pending,z,t),records:l.records,offered:d?.levels??we,level:m??"",setLevel:p,filtersTarget:j,target:i,setTarget:g,paused:b,setPaused:v,error:n.error??l.error,loading:!n.error&&!l.error&&!l.connected&&!l.records.length,clear:l.clear,openRecording:n.data?.resources.runtime_settings.available?()=>a("settings","card=runtime"):null,retry:n.error?n.refetch:l.retry,export:()=>ie(ce(w.exportBase,"txt"),je(l.records,l.gaps,t),"text/plain;charset=utf-8")}}function $e({go:a}){const t=L(),e=ye({go:a}),n=x.useMemo(()=>[{id:"ts",label:t("ui.time"),minWidth:200,grow:0,drop:2,render:o=>!o.gap&&r.jsx(S,{className:"rp-code",text:o.iso,children:o.timestamp})},{id:"level",label:t("log.level"),minWidth:90,grow:0,drop:3,render:o=>!o.gap&&r.jsx(F,{small:!0,tone:o.tone,children:o.levelText})},{id:"target",label:t("log.target"),minWidth:160,grow:0,drop:1,render:o=>r.jsx("span",{className:"rp-code",children:o.target??"—"})},{id:"message",label:t("log.message"),minWidth:280,grow:3,isRowHeader:!0,render:o=>r.jsx(S,{children:o.message})}],[t]),s=x.useCallback(o=>r.jsx(U,{inline:!0,items:o.gap?[[t("log.message"),o.message]]:[[t("ui.time"),o.timestamp],[t("log.level"),o.levelText],[t("log.target"),o.target??"—"],[t("log.message"),o.message]]}),[t]);return r.jsxs("div",{className:"rp-page",children:[r.jsxs("div",{className:"rp-toolbar",children:[r.jsx(Q,{side:!0,label:t("log.level"),value:e.level,onChange:e.setLevel,items:e.levels}),e.filtersTarget&&r.jsx(X,{search:!0,label:t("log.target"),value:e.target,width:240,placeholder:t("log.targetPlaceholder"),onChange:e.setTarget}),r.jsx(Y,{isSelected:e.paused,onChange:e.setPaused,children:t("log.pause")}),r.jsx(F,{small:!0,tone:e.status.tone,children:e.status.text}),e.recordedText&&r.jsx("span",{className:"rp-label",children:e.recordedText}),r.jsx("span",{className:"rp-grow"}),r.jsx(le,{actions:[{id:"clear",label:t("log.clear"),isDisabled:!e.rows.length,onAction:e.clear},{id:"export",label:t("log.export"),icon:r.jsx(Z,{}),isDisabled:!e.rows.length,onAction:e.export},...e.openRecording?[{id:"recording",label:t("ui.recordingSettings"),onAction:e.openRecording}]:[]]})]}),r.jsx(ee,{error:e.error,onRetry:e.retry}),r.jsx(pe,{records:e.records,offered:e.offered,minimum:e.level,setMinimum:e.setLevel}),r.jsx(ne,{label:t("nav.logs"),stream:!0,rows:e.rows,height:640,loading:e.loading,empty:e.empty,cols:n,detail:s})]})}export{$e as Logs};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{j as e}from"./vendor-react-Bf71BWbF.js";import{u as s,ai as a,T as c}from"./index-Bw0aJc9a.js";import{d as i}from"./Virtualizer-DCY9HC9Z.js";import{$ as b}from"./useFilter-Tjznm3lB.js";import{$ as f}from"./ListLayout-_fDlx5XY.js";function x({children:t}){const o=s(),{contains:r}=b({sensitivity:"base"});return e.jsxs(a,{filter:r,children:[e.jsx(c,{search:!0,label:o("policy.filter"),autoFocus:!0,className:"rp-menu-search"}),e.jsx(i,{layout:f,layoutOptions:{rowHeight:32,headingHeight:26},children:t})]})}export{x as NodeSearch};
|
||||
import{j as e}from"./vendor-react-Bf71BWbF.js";import{u as s,ai as a,T as c}from"./index-BOpK0UVB.js";import{d as i}from"./Virtualizer-BIsXGNLZ.js";import{$ as b}from"./useFilter-6_o4NyOf.js";import{$ as f}from"./ListLayout-CkBMjK9o.js";function x({children:t}){const o=s(),{contains:r}=b({sensitivity:"base"});return e.jsxs(a,{filter:r,children:[e.jsx(c,{search:!0,label:o("policy.filter"),autoFocus:!0,className:"rp-menu-search"}),e.jsx(i,{layout:f,layoutOptions:{rowHeight:32,headingHeight:26},children:t})]})}export{x as NodeSearch};
|
||||
@@ -1,5 +0,0 @@
|
||||
import{r as y,j as o}from"./vendor-react-Bf71BWbF.js";import{u as ne,aT as Fn,L as On,B as X,aW as ke,bA as Be,a6 as Pe,a as me,aa as rn,ad as ln,ac as de,ae as In,af as dn,c_ as En,aI as $n,E as cn,j as Bn,ak as Wn,a_ as ee,bM as un,bN as qn,bP as Hn,aN as Un,bB as mn,bs as Vn,a3 as ye,bQ as zn,aL as ce,aO as Qn,br as pn,aJ as Kn,bS as Jn,aj as Xn,T as K,bt as Fe,y as Me,z as Yn,q as W,Q as fn,dN as Ze,U as je,dO as xe,V as Zn,F as es,dP as hn,dQ as ns,a9 as ss,M as Se,dR as bn,ay as as,b7 as os,as as ts,at as rs,a4 as en,aw as is,av as Le,a5 as Oe,bc as ls,cK as ds,bm as G,cT as ge,de as We,b as Ne,dd as cs,bg as us,dS as ms,by as ps,dT as nn,cS as fs,dU as hs,dV as bs,cO as vs,ap as gs,aF as ks,ag as ys,cP as js,dW as xs,dX as Ns,d9 as ws,bj as Ps,bk as Ms,a0 as Ge,dY as Ss,dZ as Ts,d_ as _s,cW as Cs,cU as sn,bx as As,ah as Ls,I as Gs,cN as an,du as Ds,dt as Rs}from"./index-Bw0aJc9a.js";import{F as Fs}from"./FactStrip-DtkOGBRy.js";import{u as Os,C as Is,p as Es}from"./layout-BWzq8YqC.js";import{D as vn,c as $s}from"./Table-Km6Zv-S8.js";import{T as Bs}from"./TimeCell-DKHUJpad.js";import{M as Ws}from"./ActionGroup-DLxTuKht.js";import{A as qs}from"./AddCircle-D11CyK2n.js";import{u as Hs}from"./outbounds-DMhWS-9H.js";import{p as Us,b as Vs}from"./policyText-CltaDVEo.js";import{a as Ie}from"./setup-DLvQ_6ZI.js";import{u as zs}from"./useRefreshAll-D0DryBsY.js";import{$ as Qs}from"./useFilter-Tjznm3lB.js";import{p as Ks}from"./probe-D0Quphno.js";import{o as Js,P as Xs}from"./openGroup-Dk9B33qx.js";import{n as Ys}from"./nav-DONyavaI.js";import"./useGridSelectionCheckbox-COXIVEmS.js";import"./Virtualizer-DCY9HC9Z.js";import"./ListLayout-_fDlx5XY.js";function on({kind:e,color:a}){return o.jsx("i",{className:"rp-marker "+e,style:a?{color:a}:void 0,"aria-hidden":"true"})}function Zs({label:e,groups:a,legend:n,max:s,fmt:l,limit:t=10,showAll:r}){const b=ne(),c=Fn(),{ref:i,tip:f,show:u,hide:h}=Os(),[d,m]=y.useState(new Set),p=[0,s/4,s/2,3*s/4,s],j=w=>Math.min(100,w/s*100);return o.jsxs("div",{className:"rp-markerplot rp-chart-hover",ref:i,onPointerLeave:h,role:"group","aria-label":e,"aria-describedby":c,children:[o.jsx("ul",{className:"legend",children:n.map(w=>o.jsxs("li",{children:[o.jsx(on,{kind:w.kind}),w.label]},w.kind))}),o.jsxs("div",{className:"axis","aria-hidden":"true",children:[o.jsx("span",{}),o.jsx("div",{className:"scale",children:p.map(w=>o.jsx("span",{style:{insetInlineStart:`${j(w)}%`},children:l(w)},w))}),o.jsx("span",{})]}),a.map(w=>o.jsxs("section",{"aria-label":w.label,children:[a.length>1&&o.jsx("h4",{className:"rp-label",children:w.label}),(d.has(w.id)?w.rows:w.rows.slice(0,t)).map(g=>{const P=Object.values(g.values).filter(x=>x!==void 0),C=j(Math.min(...P)),F=j(Math.max(...P));return o.jsxs("div",{className:"row",onPointerMove:x=>u(x,[g.label,...g.details]),children:[o.jsx("span",{className:"name",children:g.href?o.jsx(On,{appearance:"link",href:g.href,children:g.label}):g.label}),o.jsxs("div",{className:"track",role:"img","aria-label":g.label+b("ui.separator")+g.description,children:[p.map(x=>o.jsx("i",{className:"grid",style:{insetInlineStart:`${j(x)}%`}},x)),F>C&&o.jsx("i",{className:"span",style:{insetInlineStart:`${C}%`,width:`${F-C}%`}}),["tick","diamond","dot"].map(x=>g.values[x]===void 0?null:o.jsx("span",{className:"at "+x+(g.values[x]>s?" over":""),style:{insetInlineStart:`${j(g.values[x])}%`},children:o.jsx(on,{kind:x,color:x==="dot"?g.tone:void 0})},x))]}),o.jsx("span",{className:"value",children:g.text})]},g.id)}),!d.has(w.id)&&w.rows.length>t&&o.jsx("div",{className:"row more",children:o.jsx(X,{quiet:!0,small:!0,onPress:()=>m(g=>new Set([...g,w.id])),children:r(w.rows.length)})}),w.notes.map(g=>o.jsx("p",{className:"rp-note note",children:g},g))]},w.id)),o.jsx(Is,{tip:f})]})}function ea(e,a,n,s){const l=ke(s),t=new Map((a??[]).map(i=>[i.id,i.name])),r=new Map,b=(i,f)=>{let u=r.get(i);return u||r.set(i,u={id:i,label:f,rows:[],missing:[]}),u};for(const i of e){const f=Be(i),u=n==="protocol"?[["protocol:"+(i.protocol??""),i.protocol??null]]:i.group_ids.length?i.group_ids.map(h=>["group:"+h,t.get(h)??h]):[["group:",null]];for(const[h,d]of u){const m=b(h,d);f?.state==="healthy"&&f.latency_ms!==null?m.rows.push({id:i.id,name:i.name,latest:f.latency_ms,moving:f.moving_avg_ms,avg10:f.avg10_ms}):m.missing.push({id:i.id,name:i.name,state:f?.state==="unavailable"?"unavailable":"unmeasured"})}}const c=[...r.values()];for(const i of c)i.rows.sort((f,u)=>f.latest-u.latest||l(f.name,u.name)),i.missing.sort((f,u)=>l(f.name,u.name));return c.sort((i,f)=>(i.label===null?1:0)-(f.label===null?1:0)||l(i.label??"",f.label??""))}function na(e){const a=e.flatMap(n=>n.rows);return{moving:a.some(n=>n.moving!==null),avg10:a.some(n=>n.avg10!==null)}}function sa(e){const a=e.flatMap(l=>l.rows.flatMap(t=>[t.latest,t.moving??t.latest])).sort((l,t)=>l-t),n=Math.max(10,(Es(a,90)??0)*1.25),s=n<=100?20:n<=500?100:n<=2e3?500:1e3;return Math.ceil(n/s)*s}function aa(){const e=Pe[me()],a=rn().data?.resources,n=ln(de(a,Line truncated
|
||||
`,r.from-1)+1,c=/^[ \t]*$/.test(e.slice(b,r.from))?b:r.from,i=l.children.find(p=>p.from===r.from);if(i){for(;n[t+1]?.from<i.to;)t++;if(i.line===i.endLine)continue;const p=fn(e,i,n),j=p.find(g=>g.name==="url"),w=p.find(g=>g.name==="interval");s.push({from:c,to:i.to,block:i,tag:i.name,host:j?we(W(j.value)):null,interval:w?ca(W(w.value)):null,fields:p,parts:null});continue}const f=n[t+1];f&&e.slice(f.from,f.to)===":"&&!e.slice(f.to).startsWith("//")&&(t+=2);const u=n[t];if(!u||u.from>=l.close)break;if(u.kind!=="quoted")for(;n[t+1]?.from===n[t].to&&!/[(){}]/.test(e.slice(n[t+1].from,n[t+1].to));)t++;if(e[n[t+1]?.from]==="(")for(t++;n[t+1]&&!(e[n[t].from]===")"&&n[t].parens===1);)t++;let h=n[t].to,d;n[t+1]?.kind==="comment"&&n[t+1].line===n[t].line&&(d=e.slice(n[t+1].from,n[t+1].to),h=n[++t].to);const m=ua(e.slice(c,h));m&&s.push({from:c,to:h,tag:m.tag,host:we(m.url),interval:null,fields:[],parts:m,comment:d})}return s}function ma(e){return yn(e).map(({tag:a,host:n,interval:s})=>({tag:a,host:n,interval:s}))}function pa(e,a,n){const s=yn(e).find(c=>c.tag===a);if(!s||s.interval===n)return e;const l=e.slice(s.from,s.to).match(/^[ \t]*/)?.[0]??" ",t=l+(l.includes(" ")?" ":" ");if(s.parts){const c=[`${l}${Zn(a)}: {`,`${t}url: ${je(s.parts.url)}`];return s.parts.ua!==null&&c.push(`${t}ua: ${je(s.parts.ua)}`),c.push(`${t}interval: '${n}s'`,`${l}}${s.comment?" "+s.comment:""}`),e.slice(0,s.from)+c.join(`
|
||||
`)+e.slice(s.to)}const r=s.fields.find(c=>c.name==="interval");if(r)return e.slice(0,r.valueFrom)+` '${n}s'`+e.slice(r.valueTo);if(!s.block)return e;const b=e.lastIndexOf(`
|
||||
`,s.block.close-1)+1;return e.slice(0,b)+`${t}interval: '${n}s'
|
||||
`+e.slice(b)}function fa(e,a,n,s){const l=Be(e),t=l?.state==="healthy"&&l.latency_ms!=null;return{id:e.id,name:e.name,protocol:e.protocol??"—",latency:t?ee(l.latency_ms,s):l?.state==="unavailable"?s("ui.unavailable"):"—",latencyClass:t?`ms ${mn(l.latency_ms)??""}`.trimEnd():l?.state==="unavailable"?"ms err":"ms",groups:e.group_ids.length?ye(n,e.group_ids.map(r=>a.get(r)??r)):"—",probeLabel:s("nodes.probe",{name:e.name}),joinLabel:s("nodes.joinGroup",{name:e.name}),removeLabel:s("nodes.remove",{name:e.name})}}const ha=e=>ls(Be(e)),Ee=(e,a)=>Se(e).filter(n=>bn(n).subtags.includes(a)).map(n=>n.name),ba=(e,a)=>Se(e).some(n=>bn(n).rules.some(s=>Me(s).tokens.some(l=>(l.kind==="text"||l.kind==="quoted")&&W(s.slice(l.from,l.to))===a)));function va(e,a,n){return{here:Ee(a.content??"",n),elsewhere:e.filter(s=>s.id!==a.id&&Ee(s.content??"",n).length>0||ba(s.content??"",n))}}function ga(e,a,n,s){const l=new Map;for(const p of a){if(!p.provider_id||!p.subscription_tag)continue;const j=l.get(p.provider_id)??new Set;j.add(p.subscription_tag),l.set(p.provider_id,j)}const t=p=>{const j=l.get(p);return j?.size===1?[...j][0]:void 0},r=p=>{const j=we(p.url_redacted),w=j?n.filter(g=>g.host===j):[];return w.length===1?w[0].tag:void 0},b=new Map,c=e.filter(p=>p.kind==="subscription");for(const p of c){const j=t(p.id)??r(p);j&&b.set(p.id,j)}const i=c.filter(p=>!b.has(p.id)),f=new Set(b.values()),u=n.filter(p=>!f.has(p.tag));i.length===1&&u.length===1&&b.set(i[0].id,u[0].tag);const h=e.map(p=>{const j=t(p.id);return{...p,displayName:b.get(p.id)??p.name,configTag:p.kind==="subscription"&&j&&n.filter(w=>w.tag===j).length===1?j:void 0,sourceTag:p.kind==="subscription"?p.name:void 0}}),d={builtin:0,unattributed:0};for(const p of a)p.provider_id==null&&d[hn(p)]++;const m=[];for(const p of["builtin","unattributed"]){const j=d[p];j&&m.push({id:ns(p,e),name:s(p==="builtin"?"nodes.kind.builtin":"nodes.kind.unattributed"),kind:p,url_redacted:null,node_count:j,updated_at:null,expires_at:null,traffic:null,status:"ok",last_error:null})}return{list:[...m,...h]}}function ka(e,a){return a!==null&&e.some(n=>n.id===a)?a:(e.find(n=>n.kind!=="builtin"&&n.kind!=="unattributed")??e[0])?.id??null}function ya(e,a,n){return e.filter(s=>a===void 0||(a===null?s.provider_id==null&&hn(s)==="builtin"==(n==="builtin"):s.provider_id===a))}function ja(e,a){const n=new Map(e.map(s=>[s.id,s.displayName??s.name]));return s=>n.get(ss(s,a))??"—"}function xa(e,a,n,s,l,t,r){const b=a.trim(),c=e.filter(d=>(!b||t(d.name,b))&&(!n||d.group_ids.includes(n))&&(!s||d.protocol===s)),i=l.direction==="ascending"?1:-1,f=ke(r),u=l.column==="latency"?new Map(c.map(d=>[d.id,ha(d)])):new Map,h={name:(d,m)=>f(d.name,m.name),protocol:(d,m)=>f(d.protocol??"",m.protocol??""),latency:(d,m)=>ds(u.get(d.id),u.get(m.id))||f(d.name,m.name)};return c.sort((d,m)=>i*(h[l.column]??h.name)(d,m))}const $e=[3600,21600,43200,86400];function qe(e,a,n){return e===0?n("nodes.manualOnly"):$e.includes(e)?n("nodes.everyHours",{n:e/3600}):as(String(e),a)}function jn(e,a,n){return[0,...$e,...e===null||e===0||$e.includes(e)?[]:[e]].map(s=>({id:String(s),label:qe(s,a,n)}))}function Na(e,a){const n={name:e.name.trim(),kind:"subscription",url:e.value.trim()},s=Number(e.interval);a?.update_interval!==void 0&&e.interval&&s!==a.update_interval&&(n.update_interval=s);const l=e.agent.trim();return a?.user_agent!==void 0&&l&&l!==a.user_agent&&(n.user_agent=l),a?.cache!==void 0&&e.cache!==null&&e.cache!==a.cache&&(n.cache=e.cache),n}function wa(e,a,n,s){const l={subscription:"nodes.kind.subscription",file:"nodes.kind.file",inline:"nodes.kind.inline",builtin:"nodes.kind.builtin",unattributed:"nodes.kind.unattributed"},t={ok:"nodes.status.ok",stale:"nodes.status.stale",error:"nodes.status.error"},r={ok:"ok",stale:"warn",error:"err"},b=e.kind==="builtin"||e.kind==="unattributed",c=e.traffic?os(e.traffic.upload_bytes,e.traffic.download_bytes):null,i=e.kind==="subscription"?a:void 0,f=e.displayName??e.name;return{id:e.id,name:f,url:e.url_redacted??void 0,kind:en(l,e.kind,s),count:Oe(e.node_count,n),usage:c===null?"—":e.traffic?.total_bytes?s("ui.fraction",{part:Le(c,n),whole:Le(e.traffic.total_bytes,n)}):Le(c,n),updatedAt:b?null:e.updated_at,expires:e.expires_at?is(e.expires_at,n):"—",interval:i==null?"—":qe(i,n,s),intervalValue:i==null?"":String(i),hasInterval:i!==void 0,intervalLabel:s("nodes.intervalOf",{name:f}),intervals:i===void 0?[]:jn(i,n,s),status:b?null:en(t,e.status,s),tone:r[e.status],error:e.last_error?ts(rs(e.last_error.code,e.last_error.message,s),s):void 0,refreshLabel:s("nodes.refresh",{name:f}),removeLabel:s("nodes.remove",{name:f})}}const xn=e=>/^[a-z][a-z0-9+.-]*:\/\/\S+$/i.test(e.trim());function Pa(e,a,n,s){const l=a.trim();return e!=="provider"&&e!=="node"||!l&&!n.trim()?null:l?e==="node"?xn(n)?null:s("nodes.linkInvalid"):xe(l)?Ie(n)?null:s("nodes.urlInvalid"):s("nodes.nameInvalid"):s("nodes.nameMissing")}function Ma(e){const a=ne(),n=Pe[me()],{refresh:s}=e,l=new Map(e.entries.map(r=>[r.t
Line truncated
|
||||
@@ -0,0 +1,5 @@
|
||||
import{r as j,j as o}from"./vendor-react-Bf71BWbF.js";import{u as ne,aT as Fn,L as On,B as X,aW as ke,bA as Be,a6 as Pe,a as me,aa as rn,ad as ln,ac as de,ae as In,af as dn,c_ as $n,aI as En,E as cn,j as Bn,ak as Wn,a_ as ee,bM as un,bN as qn,bP as Hn,aN as Un,bB as mn,bs as Vn,a3 as ye,bQ as zn,aL as ce,aO as Qn,br as pn,aJ as Kn,bS as Jn,aj as Xn,T as K,bt as Fe,y as Me,z as Yn,q as W,Q as fn,dN as Ze,U as je,dO as xe,V as Zn,F as es,dP as hn,dQ as ns,a9 as ss,M as Se,dR as bn,ay as as,b7 as os,as as ts,at as rs,a4 as en,aw as is,av as Le,a5 as Oe,bc as ls,cK as ds,bm as G,cT as ge,de as We,b as Ne,dd as cs,bg as us,dS as ms,by as ps,dT as nn,cS as fs,dU as hs,dV as bs,cO as vs,ap as gs,aF as ks,ag as ys,cP as js,dW as xs,dX as Ns,d9 as ws,bj as Ps,bk as Ms,a0 as Ge,dY as Ss,dZ as Ts,d_ as _s,cW as Cs,cU as sn,bx as As,ah as Ls,I as Gs,cN as an,du as Ds,dt as Rs}from"./index-BOpK0UVB.js";import{F as Fs}from"./FactStrip-CPXeRki4.js";import{u as Os,C as Is,p as $s}from"./layout-Bzzn7HLw.js";import{D as vn,c as Es}from"./Table-BkehX7fw.js";import{T as Bs}from"./TimeCell-COfj2dEh.js";import{M as Ws}from"./ActionGroup-BU73NzbX.js";import{A as qs}from"./AddCircle-0OKZjQ6F.js";import{u as Hs}from"./outbounds-BVwoUbXQ.js";import{p as Us,b as Vs}from"./policyText-y7dbn7hu.js";import{a as Ie}from"./setup-V0SWKTBk.js";import{u as zs}from"./useRefreshAll-CFXNBP5e.js";import{$ as Qs}from"./useFilter-6_o4NyOf.js";import{p as Ks}from"./probe-BHjulBb8.js";import{o as Js,P as Xs}from"./openGroup-B1VdMhOs.js";import{n as Ys}from"./nav-BFm4Dw7L.js";import"./useGridSelectionCheckbox-C4VxQajJ.js";import"./Virtualizer-BIsXGNLZ.js";import"./ListLayout-CkBMjK9o.js";function on({kind:e,color:a}){return o.jsx("i",{className:"rp-marker "+e,style:a?{color:a}:void 0,"aria-hidden":"true"})}function Zs({label:e,groups:a,legend:n,max:s,fmt:i,limit:t=10,showAll:r}){const b=ne(),c=Fn(),{ref:l,tip:m,show:u,hide:f}=Os(),[h,p]=j.useState(new Set),d=[0,s/4,s/2,3*s/4,s],g=x=>Math.min(100,x/s*100);return o.jsxs("div",{className:"rp-markerplot rp-chart-hover",ref:l,onPointerLeave:f,role:"group","aria-label":e,"aria-describedby":c,children:[o.jsx("ul",{className:"legend",children:n.map(x=>o.jsxs("li",{children:[o.jsx(on,{kind:x.kind}),x.label]},x.kind))}),o.jsxs("div",{className:"axis","aria-hidden":"true",children:[o.jsx("span",{}),o.jsx("div",{className:"scale",children:d.map(x=>o.jsx("span",{style:{insetInlineStart:`${g(x)}%`},children:i(x)},x))}),o.jsx("span",{})]}),a.map(x=>o.jsxs("section",{"aria-label":x.label,children:[a.length>1&&o.jsx("h4",{className:"rp-label",children:x.label}),(h.has(x.id)?x.rows:x.rows.slice(0,t)).map(k=>{const P=Object.values(k.values).filter(N=>N!==void 0),C=g(Math.min(...P)),F=g(Math.max(...P));return o.jsxs("div",{className:"row",onPointerMove:N=>u(N,[k.label,...k.details]),children:[o.jsx("span",{className:"name",children:k.href?o.jsx(On,{appearance:"link",href:k.href,children:k.label}):k.label}),o.jsxs("div",{className:"track",role:"img","aria-label":k.label+b("ui.separator")+k.description,children:[d.map(N=>o.jsx("i",{className:"grid",style:{insetInlineStart:`${g(N)}%`}},N)),F>C&&o.jsx("i",{className:"span",style:{insetInlineStart:`${C}%`,width:`${F-C}%`}}),["tick","diamond","dot"].map(N=>k.values[N]===void 0?null:o.jsx("span",{className:"at "+N+(k.values[N]>s?" over":""),style:{insetInlineStart:`${g(k.values[N])}%`},children:o.jsx(on,{kind:N,color:N==="dot"?k.tone:void 0})},N))]}),o.jsx("span",{className:"value",children:k.text})]},k.id)}),!h.has(x.id)&&x.rows.length>t&&o.jsx("div",{className:"row more",children:o.jsx(X,{quiet:!0,small:!0,onPress:()=>p(k=>new Set([...k,x.id])),children:r(x.rows.length)})}),x.notes.map(k=>o.jsx("p",{className:"rp-note note",children:k},k))]},x.id)),o.jsx(Is,{tip:m})]})}function ea(e,a,n,s){const i=ke(s),t=new Map((a??[]).map(l=>[l.id,l.name])),r=new Map,b=(l,m)=>{let u=r.get(l);return u||r.set(l,u={id:l,label:m,rows:[],missing:[]}),u};for(const l of e){const m=Be(l),u=n==="protocol"?[["protocol:"+(l.protocol??""),l.protocol??null]]:l.group_ids.length?l.group_ids.map(f=>["group:"+f,t.get(f)??f]):[["group:",null]];for(const[f,h]of u){const p=b(f,h);m?.state==="healthy"&&m.latency_ms!==null?p.rows.push({id:l.id,name:l.name,latest:m.latency_ms,moving:m.moving_avg_ms,avg10:m.avg10_ms}):p.missing.push({id:l.id,name:l.name,state:m?.state==="unavailable"?"unavailable":"unmeasured"})}}const c=[...r.values()];for(const l of c)l.rows.sort((m,u)=>m.latest-u.latest||i(m.name,u.name)),l.missing.sort((m,u)=>i(m.name,u.name));return c.sort((l,m)=>(l.label===null?1:0)-(m.label===null?1:0)||i(l.label??"",m.label??""))}function na(e){const a=e.flatMap(n=>n.rows);return{moving:a.some(n=>n.moving!==null),avg10:a.some(n=>n.avg10!==null)}}function sa(e){const a=e.flatMap(i=>i.rows.flatMap(t=>[t.latest,t.moving??t.latest])).sort((i,t)=>i-t),n=Math.max(10,($s(a,90)??0)*1.25),s=n<=100?20:n<=500?100:n<=2e3?500:1e3;return Math.ceil(n/s)*s}function aa(){const e=Pe[me()],a=rn().data?.resources,n=ln(de(a,Line truncated
|
||||
`,r.from-1)+1,c=/^[ \t]*$/.test(e.slice(b,r.from))?b:r.from,l=i.children.find(d=>d.from===r.from);if(l){for(;n[t+1]?.from<l.to;)t++;if(l.line===l.endLine)continue;const d=fn(e,l,n),g=d.find(k=>k.name==="url"),x=d.find(k=>k.name==="interval");s.push({from:c,to:l.to,block:l,tag:l.name,host:g?we(W(g.value)):null,interval:x?ca(W(x.value)):null,fields:d,parts:null});continue}const m=n[t+1];m&&e.slice(m.from,m.to)===":"&&!e.slice(m.to).startsWith("//")&&(t+=2);const u=n[t];if(!u||u.from>=i.close)break;if(u.kind!=="quoted")for(;n[t+1]?.from===n[t].to&&!/[(){}]/.test(e.slice(n[t+1].from,n[t+1].to));)t++;if(e[n[t+1]?.from]==="(")for(t++;n[t+1]&&!(e[n[t].from]===")"&&n[t].parens===1);)t++;let f=n[t].to,h;n[t+1]?.kind==="comment"&&n[t+1].line===n[t].line&&(h=e.slice(n[t+1].from,n[t+1].to),f=n[++t].to);const p=ua(e.slice(c,f));p&&s.push({from:c,to:f,tag:p.tag,host:we(p.url),interval:null,fields:[],parts:p,comment:h})}return s}function ma(e){return yn(e).map(({tag:a,host:n,interval:s})=>({tag:a,host:n,interval:s}))}function pa(e,a,n){const s=yn(e).find(c=>c.tag===a);if(!s||s.interval===n)return e;const i=e.slice(s.from,s.to).match(/^[ \t]*/)?.[0]??" ",t=i+(i.includes(" ")?" ":" ");if(s.parts){const c=[`${i}${Zn(a)}: {`,`${t}url: ${je(s.parts.url)}`];return s.parts.ua!==null&&c.push(`${t}ua: ${je(s.parts.ua)}`),c.push(`${t}interval: '${n}s'`,`${i}}${s.comment?" "+s.comment:""}`),e.slice(0,s.from)+c.join(`
|
||||
`)+e.slice(s.to)}const r=s.fields.find(c=>c.name==="interval");if(r)return e.slice(0,r.valueFrom)+` '${n}s'`+e.slice(r.valueTo);if(!s.block)return e;const b=e.lastIndexOf(`
|
||||
`,s.block.close-1)+1;return e.slice(0,b)+`${t}interval: '${n}s'
|
||||
`+e.slice(b)}function fa(e,a,n,s){const i=Be(e),t=i?.state==="healthy"&&i.latency_ms!=null;return{id:e.id,name:e.name,protocol:e.protocol??"—",latency:t?ee(i.latency_ms,s):i?.state==="unavailable"?s("ui.unavailable"):"—",latencyClass:t?`ms ${mn(i.latency_ms)}`:i?.state==="unavailable"?"ms err":"ms",groups:e.group_ids.length?ye(n,e.group_ids.map(r=>a.get(r)??r)):"—",probeLabel:s("nodes.probe",{name:e.name}),joinLabel:s("nodes.joinGroup",{name:e.name}),removeLabel:s("nodes.remove",{name:e.name})}}const ha=e=>ls(Be(e)),$e=(e,a)=>Se(e).filter(n=>bn(n).subtags.includes(a)).map(n=>n.name),ba=(e,a)=>Se(e).some(n=>bn(n).rules.some(s=>Me(s).tokens.some(i=>(i.kind==="text"||i.kind==="quoted")&&W(s.slice(i.from,i.to))===a)));function va(e,a,n){return{here:$e(a.content??"",n),elsewhere:e.filter(s=>s.id!==a.id&&$e(s.content??"",n).length>0||ba(s.content??"",n))}}function ga(e,a,n,s){const i=new Map;for(const d of a){if(!d.provider_id||!d.subscription_tag)continue;const g=i.get(d.provider_id)??new Set;g.add(d.subscription_tag),i.set(d.provider_id,g)}const t=d=>{const g=i.get(d);return g?.size===1?[...g][0]:void 0},r=d=>{const g=we(d.url_redacted),x=g?n.filter(k=>k.host===g):[];return x.length===1?x[0].tag:void 0},b=new Map,c=e.filter(d=>d.kind==="subscription");for(const d of c){const g=t(d.id)??r(d);g&&b.set(d.id,g)}const l=c.filter(d=>!b.has(d.id)),m=new Set(b.values()),u=n.filter(d=>!m.has(d.tag));l.length===1&&u.length===1&&b.set(l[0].id,u[0].tag);const f=e.map(d=>{const g=t(d.id);return{...d,displayName:b.get(d.id)??d.name,configTag:d.kind==="subscription"&&g&&n.filter(x=>x.tag===g).length===1?g:void 0,sourceTag:d.kind==="subscription"?d.name:void 0}}),h={builtin:0,unattributed:0};for(const d of a)d.provider_id==null&&h[hn(d)]++;const p=[];for(const d of["builtin","unattributed"]){const g=h[d];g&&p.push({id:ns(d,e),name:s(d==="builtin"?"nodes.kind.builtin":"nodes.kind.unattributed"),kind:d,url_redacted:null,node_count:g,updated_at:null,expires_at:null,traffic:null,status:"ok",last_error:null})}return{list:[...p,...f]}}function ka(e,a){return a!==null&&e.some(n=>n.id===a)?a:(e.find(n=>n.kind!=="builtin"&&n.kind!=="unattributed")??e[0])?.id??null}function ya(e,a,n){return e.filter(s=>a===void 0||(a===null?s.provider_id==null&&hn(s)==="builtin"==(n==="builtin"):s.provider_id===a))}function ja(e,a){const n=new Map(e.map(s=>[s.id,s.displayName??s.name]));return s=>n.get(ss(s,a))??"—"}function xa(e,a,n,s,i,t,r){const b=a.trim(),c=e.filter(h=>(!b||t(h.name,b))&&(!n||h.group_ids.includes(n))&&(!s||h.protocol===s)),l=i.direction==="ascending"?1:-1,m=ke(r),u=i.column==="latency"?new Map(c.map(h=>[h.id,ha(h)])):new Map,f={name:(h,p)=>m(h.name,p.name),protocol:(h,p)=>m(h.protocol??"",p.protocol??""),latency:(h,p)=>ds(u.get(h.id),u.get(p.id))||m(h.name,p.name)};return c.sort((h,p)=>l*(f[i.column]??f.name)(h,p))}const Ee=[3600,21600,43200,86400];function qe(e,a,n){return e===0?n("nodes.manualOnly"):Ee.includes(e)?n("nodes.everyHours",{n:e/3600}):as(String(e),a)}function jn(e,a,n){return[0,...Ee,...e===null||e===0||Ee.includes(e)?[]:[e]].map(s=>({id:String(s),label:qe(s,a,n)}))}function Na(e,a){const n={name:e.name.trim(),kind:"subscription",url:e.value.trim()},s=Number(e.interval);a?.update_interval!==void 0&&e.interval&&s!==a.update_interval&&(n.update_interval=s);const i=e.agent.trim();return a?.user_agent!==void 0&&i&&i!==a.user_agent&&(n.user_agent=i),a?.cache!==void 0&&e.cache!==null&&e.cache!==a.cache&&(n.cache=e.cache),n}function wa(e,a,n,s){const i={subscription:"nodes.kind.subscription",file:"nodes.kind.file",inline:"nodes.kind.inline",builtin:"nodes.kind.builtin",unattributed:"nodes.kind.unattributed"},t={ok:"nodes.status.ok",stale:"nodes.status.stale",error:"nodes.status.error"},r={ok:"ok",stale:"warn",error:"err"},b=e.kind==="builtin"||e.kind==="unattributed",c=e.traffic?os(e.traffic.upload_bytes,e.traffic.download_bytes):null,l=e.kind==="subscription"?a:void 0,m=e.displayName??e.name;return{id:e.id,name:m,url:e.url_redacted??void 0,kind:en(i,e.kind,s),count:Oe(e.node_count,n),usage:c===null?"—":e.traffic?.total_bytes?s("ui.fraction",{part:Le(c,n),whole:Le(e.traffic.total_bytes,n)}):Le(c,n),updatedAt:b?null:e.updated_at,expires:e.expires_at?is(e.expires_at,n):"—",interval:l==null?"—":qe(l,n,s),intervalValue:l==null?"":String(l),hasInterval:l!==void 0,intervalLabel:s("nodes.intervalOf",{name:m}),intervals:l===void 0?[]:jn(l,n,s),status:b?null:en(t,e.status,s),tone:r[e.status],error:e.last_error?ts(rs(e.last_error.code,e.last_error.message,s),s):void 0,refreshLabel:s("nodes.refresh",{name:m}),removeLabel:s("nodes.remove",{name:m})}}const xn=e=>/^[a-z][a-z0-9+.-]*:\/\/\S+$/i.test(e.trim());function Pa(e,a,n,s){const i=a.trim();return e!=="provider"&&e!=="node"||!i&&!n.trim()?null:i?e==="node"?xn(n)?null:s("nodes.linkInvalid"):xe(i)?Ie(n)?null:s("nodes.urlInvalid"):s("nodes.nameInvalid"):s("nodes.nameMissing")}function Ma(e){const a=ne(),n=Pe[me()],{refresh:s}=e,i=new Map(e.entries.map(r=>[r.tag,r.interval]
Line truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{r as B,j as t}from"./vendor-react-Bf71BWbF.js";import{ap as K,aq as $,ar as I,as as P,at as M,au as G,av as b,aw as D,ax as J,ay as z,az as Q,aA as X,h as u,a5 as _,aB as Y,u as T,a as Z,a6 as ee,aa as te,aC as ae,ac as R,aD as se,aE as re,aF as oe,aG as ie,aH as ne,aI as ce,aJ as w,E as N,L as V,aK as H,aL as A,aM as le,aN as k,aO as de,ak as S,aP as pe,aQ as ue,j as U,aR as ve,B as me,aS as he}from"./index-Bw0aJc9a.js";import{d as fe,e as ge}from"./files-BxEOxSF8.js";import{D as xe,t as O}from"./Table-Km6Zv-S8.js";import{A as be}from"./ActionGroup-DLxTuKht.js";import{D as ye}from"./DaeCode-B8yPDjSE.js";import"./useGridSelectionCheckbox-COXIVEmS.js";import"./Virtualizer-DCY9HC9Z.js";import"./ListLayout-_fDlx5XY.js";const je={connections:u("connections",{tab:"list"}),flows:u("flows",{tab:"records"}),routing_trace:u("rules",{tab:"trace"}),dns_query:u("dns",{tab:"query"}),dns_cache:u("dns",{tab:"cache"}),dns_log:u("dns",{tab:"log"}),events:u("events"),probes:u("nodes",{tab:"latency"}),traffic_history:u("activity"),memory_history:u("activity"),runtime_outbounds:u("activity"),logs:u("logs"),providers:u("nodes"),rules:u("rules",{tab:"list"}),config:u("config"),config_validate:u("config",{tab:"validate"}),runtime_settings:u("settings",{card:"runtime"}),geodata:u("settings",{card:"geodata"})},W={ebpf:"ov.v.ebpf",userspace:"ov.v.userspace",mock:"ov.v.mock",active:"ov.v.active",degraded:"ov.v.degraded",detached:"ov.v.detached",failed:"ov.v.failed",disabled:"ov.v.disabled",full:"ov.v.full",partial:"ov.v.partial",none:"ov.v.none",real:"ov.v.real",loaded:"ov.v.loaded",not_loaded:"ov.v.notLoaded",attached:"ov.v.attached",partially_attached:"ov.v.partiallyAttached",published:"ov.v.published",not_published:"ov.v.notPublished",healthy:"ov.v.healthy",ready:"ov.v.ready",error:"ov.v.error",unknown:"ov.v.unknown",ingress:"ov.v.ingress",egress:"ov.v.egress"};function F(o,s){return W[o]?s(W[o]):o}function we(o,s,e){if(o==="degraded")return{title:e("ov.v.degraded"),text:e(s?"ov.degradedHelp.runtime":"ov.degradedHelp.datapath")};if(o==="unknown")return{title:e("ov.v.unknown"),text:e("ov.unknownHelp")}}function ke(o,s,e,a){if(o!=="unknown"||!s.length)return;const r=new Intl.ListFormat(a,{type:"conjunction"}).format(s);return{title:e("ov.v.notVerified"),text:e("ov.notVerifiedHelp",{hooks:r})}}function _e(o,s,e,a,r=!1,i=[]){const c=o.ebpf,d=c?.maps?.conn_state,l=(f,h)=>{const v=we(h,r,e);return v?{label:e(f),value:F(h,e),help:v}:[e(f),F(h,e)]},p=c?.maps?.state??"unknown",m=c&&ke(c.hooks,i,e,a);return[l("ov.f.kind",o.kind),l("ov.f.state",o.state),...o.visibility==="partial"&&c?[]:[l("ov.f.visibility",o.visibility)],...c?[l("ov.f.backend",c.backend),l("ov.f.programs",c.programs),m?{label:e("ov.f.hooks"),value:e("ov.v.notVerified"),help:m}:l("ov.f.hooks",c.hooks),l("ov.f.routing",c.routing.state),l("ov.f.health",c.health),...p==="partial"&&d&&!d.occupancy_known?[[e("ov.f.maps"),e("ov.mapCapacity",{capacity:_(d.capacity,a)})]]:[l("ov.f.maps",p),[e("ov.f.connState"),d?.occupancy_known&&d.occupancy!==null?e("ui.fraction",{part:_(d.occupancy,a),whole:_(d.capacity,a)}):d?e("ov.occupancyUnknown",{capacity:_(d.capacity,a)}):s]]]:[]]}const Le={service:"ov.v.cgroupService",shared:"ov.v.cgroupShared"},Ne={service:"ov.cgroupHelp.service",shared:"ov.cgroupHelp.shared"};function He(o,s,e,a=[],r=!1){const i=o.cgroup?.scope,c=p=>{const m=Y(p??null);return m===null?"—":_(m,e)},d=[["ov.f.rss",b(o.process?.rss_bytes??null,e)],["ov.f.cgroupCurrent",b(o.cgroup?.current_bytes??null,e)],["ov.f.cgroupLimit",r&&o.cgroup?.limit_bytes===null?s("ov.noLimit"):b(o.cgroup?.limit_bytes??null,e)],["ov.f.cgroupScope",i&&i!=="unknown"?s(Le[i]):"—"],["ov.f.oomHigh",c(o.cgroup?.events?.high)],["ov.f.oom",c(o.cgroup?.events?.oom)],["ov.f.oomKill",c(o.cgroup?.events?.oom_kill)],["ov.f.ebpfBytes",b(o.kernel?.ebpf_bytes??null,e)]],l=[...a,...i==="unknown"?["ov.f.cgroupScope"]:[],...o.kernel?[]:["ov.f.ebpfBytes"]];return d.filter(([p])=>!l.includes(p)).map(([p,m])=>p==="ov.f.cgroupScope"&&i&&i!=="unknown"?{label:s(p),value:m,help:{title:s(p),text:s("ui.valuePair",{label:m,value:s(Ne[i])})}}:[s(p),m])}function Se(o,s,e,a){const{capabilities:r,runtime:i,version:c,memory:d,datapath:l,limits:p=[]}=o,m=K(c).uncheckedHooks,f=i?.lifecycle.state,h=i?.generation.config_revision??"—",v=i?.last_reload,y=$(d?.cgroup?.current_bytes??null,d?.cgroup?.limit_bytes??null),g=n=>n===null?"—":_(n,e),x=(n,j)=>n?"ready":j?"loading":"unavailable";return{status:X(f,l?.state,a(s.capabilities||s.runtime?"ov.loading":"ov.unknown"),a),strip:[{label:a("ov.config"),value:J(h),full:h,help:{title:a("ov.config"),text:a("config.revisionHelp")}},[a("ov.uptime"),z(i?.lifecycle.uptime_seconds??null,e)],[a("ov.cpu"),Q(i?.process.cpu_percent,a)],[a("ov.lastReload"),v?D(v.finished_at,e):"—"]],reload:v?{tooltip:v.operation_id,tone:v.status==="succeeded"?"ok":v.status==="failed"?"err":"warn",text:a(v.status==="succeeded"?"ov.succeeded":v.status==="failed"?"ov.failed":"ov.running")}:null,engine:{state:Line truncated
|
||||
import{r as B,j as t}from"./vendor-react-Bf71BWbF.js";import{ap as K,aq as $,ar as I,as as P,at as M,au as G,av as b,aw as D,ax as J,ay as z,az as Q,aA as X,h as u,a5 as _,aB as Y,u as T,a as Z,a6 as ee,aa as te,aC as ae,ac as R,aD as se,aE as re,aF as oe,aG as ie,aH as ne,aI as ce,aJ as w,E as N,L as V,aK as H,aL as A,aM as le,aN as k,aO as de,ak as S,aP as pe,aQ as ue,j as U,aR as ve,B as me,aS as he}from"./index-BOpK0UVB.js";import{d as fe,e as ge}from"./files-BxEOxSF8.js";import{D as xe,t as O}from"./Table-BkehX7fw.js";import{A as be}from"./ActionGroup-BU73NzbX.js";import{D as ye}from"./DaeCode-B8yPDjSE.js";import"./useGridSelectionCheckbox-C4VxQajJ.js";import"./Virtualizer-BIsXGNLZ.js";import"./ListLayout-CkBMjK9o.js";const je={connections:u("connections",{tab:"list"}),flows:u("flows",{tab:"records"}),routing_trace:u("rules",{tab:"trace"}),dns_query:u("dns",{tab:"query"}),dns_cache:u("dns",{tab:"cache"}),dns_log:u("dns",{tab:"log"}),events:u("events"),probes:u("nodes",{tab:"latency"}),traffic_history:u("activity"),memory_history:u("activity"),runtime_outbounds:u("activity"),logs:u("logs"),providers:u("nodes"),rules:u("rules",{tab:"list"}),config:u("config"),config_validate:u("config",{tab:"validate"}),runtime_settings:u("settings",{card:"runtime"}),geodata:u("settings",{card:"geodata"})},W={ebpf:"ov.v.ebpf",userspace:"ov.v.userspace",mock:"ov.v.mock",active:"ov.v.active",degraded:"ov.v.degraded",detached:"ov.v.detached",failed:"ov.v.failed",disabled:"ov.v.disabled",full:"ov.v.full",partial:"ov.v.partial",none:"ov.v.none",real:"ov.v.real",loaded:"ov.v.loaded",not_loaded:"ov.v.notLoaded",attached:"ov.v.attached",partially_attached:"ov.v.partiallyAttached",published:"ov.v.published",not_published:"ov.v.notPublished",healthy:"ov.v.healthy",ready:"ov.v.ready",error:"ov.v.error",unknown:"ov.v.unknown",ingress:"ov.v.ingress",egress:"ov.v.egress"};function F(o,s){return W[o]?s(W[o]):o}function we(o,s,e){if(o==="degraded")return{title:e("ov.v.degraded"),text:e(s?"ov.degradedHelp.runtime":"ov.degradedHelp.datapath")};if(o==="unknown")return{title:e("ov.v.unknown"),text:e("ov.unknownHelp")}}function ke(o,s,e,a){if(o!=="unknown"||!s.length)return;const r=new Intl.ListFormat(a,{type:"conjunction"}).format(s);return{title:e("ov.v.notVerified"),text:e("ov.notVerifiedHelp",{hooks:r})}}function _e(o,s,e,a,r=!1,i=[]){const c=o.ebpf,d=c?.maps?.conn_state,l=(f,h)=>{const v=we(h,r,e);return v?{label:e(f),value:F(h,e),help:v}:[e(f),F(h,e)]},p=c?.maps?.state??"unknown",m=c&&ke(c.hooks,i,e,a);return[l("ov.f.kind",o.kind),l("ov.f.state",o.state),...o.visibility==="partial"&&c?[]:[l("ov.f.visibility",o.visibility)],...c?[l("ov.f.backend",c.backend),l("ov.f.programs",c.programs),m?{label:e("ov.f.hooks"),value:e("ov.v.notVerified"),help:m}:l("ov.f.hooks",c.hooks),l("ov.f.routing",c.routing.state),l("ov.f.health",c.health),...p==="partial"&&d&&!d.occupancy_known?[[e("ov.f.maps"),e("ov.mapCapacity",{capacity:_(d.capacity,a)})]]:[l("ov.f.maps",p),[e("ov.f.connState"),d?.occupancy_known&&d.occupancy!==null?e("ui.fraction",{part:_(d.occupancy,a),whole:_(d.capacity,a)}):d?e("ov.occupancyUnknown",{capacity:_(d.capacity,a)}):s]]]:[]]}const Le={service:"ov.v.cgroupService",shared:"ov.v.cgroupShared"},Ne={service:"ov.cgroupHelp.service",shared:"ov.cgroupHelp.shared"};function He(o,s,e,a=[],r=!1){const i=o.cgroup?.scope,c=p=>{const m=Y(p??null);return m===null?"—":_(m,e)},d=[["ov.f.rss",b(o.process?.rss_bytes??null,e)],["ov.f.cgroupCurrent",b(o.cgroup?.current_bytes??null,e)],["ov.f.cgroupLimit",r&&o.cgroup?.limit_bytes===null?s("ov.noLimit"):b(o.cgroup?.limit_bytes??null,e)],["ov.f.cgroupScope",i&&i!=="unknown"?s(Le[i]):"—"],["ov.f.oomHigh",c(o.cgroup?.events?.high)],["ov.f.oom",c(o.cgroup?.events?.oom)],["ov.f.oomKill",c(o.cgroup?.events?.oom_kill)],["ov.f.ebpfBytes",b(o.kernel?.ebpf_bytes??null,e)]],l=[...a,...i==="unknown"?["ov.f.cgroupScope"]:[],...o.kernel?[]:["ov.f.ebpfBytes"]];return d.filter(([p])=>!l.includes(p)).map(([p,m])=>p==="ov.f.cgroupScope"&&i&&i!=="unknown"?{label:s(p),value:m,help:{title:s(p),text:s("ui.valuePair",{label:m,value:s(Ne[i])})}}:[s(p),m])}function Se(o,s,e,a){const{capabilities:r,runtime:i,version:c,memory:d,datapath:l,limits:p=[]}=o,m=K(c).uncheckedHooks,f=i?.lifecycle.state,h=i?.generation.config_revision??"—",v=i?.last_reload,y=$(d?.cgroup?.current_bytes??null,d?.cgroup?.limit_bytes??null),g=n=>n===null?"—":_(n,e),x=(n,j)=>n?"ready":j?"loading":"unavailable";return{status:X(f,l?.state,a(s.capabilities||s.runtime?"ov.loading":"ov.unknown"),a),strip:[{label:a("ov.config"),value:J(h),full:h,help:{title:a("ov.config"),text:a("config.revisionHelp")}},[a("ov.uptime"),z(i?.lifecycle.uptime_seconds??null,e)],[a("ov.cpu"),Q(i?.process.cpu_percent,a)],[a("ov.lastReload"),v?D(v.finished_at,e):"—"]],reload:v?{tooltip:v.operation_id,tone:v.status==="succeeded"?"ok":v.status==="failed"?"err":"warn",text:a(v.status==="succeeded"?"ov.succeeded":v.status==="failed"?"ov.failed":"ov.running")}:null,engine:{state:Line truncated
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./Arrange-BwxzZLbt.js","./vendor-react-Bf71BWbF.js","./index-Bw0aJc9a.js","./index-7R3bVGRM.css","./Virtualizer-DCY9HC9Z.js","./ListLayout-_fDlx5XY.js","./DaeCode-B8yPDjSE.js","./policyText-CltaDVEo.js","./openGroup-Dk9B33qx.js","./useFilter-Tjznm3lB.js","./ActionGroup-DLxTuKht.js","./useGridSelectionCheckbox-COXIVEmS.js","./nav-BASDWt23.js","./Arrange-Dd3j3leY.css"])))=>i.map(i=>d[i]);
|
||||
import{bT as it,bU as ot,bV as rt,bW as pe,bX as te,bY as Ie,bZ as nt,b_ as at,b$ as lt,c0 as st,c1 as je,c2 as re,c3 as ne,c4 as me,c5 as G,c6 as W,c7 as q,c8 as ee,c9 as ct,ca as ae,cb as Ke,cc as dt,cd as ut,ce as He,cf as pt,cg as de,ch as fe,ci as Oe,cj as ue,ck as ft,cl as ke,cm as Se,cn as he,co as be,cp as Fe,cq as ht,cr as bt,cs as mt,ct as Be,cu as gt,cv as yt,cw as le,cx as vt,cy as xt,cz as $t,cA as kt,cB as wt,cC as Pt,cD as It,cE as St,cF as Et,cG as Dt,cH as Mt,cI as jt,M as Ct,b as ce,cJ as Nt,a4 as _t,bc as Ge,bB as Tt,a_ as Lt,K as zt,cK as At,aW as Rt,a5 as Kt,u as B,a6 as Ht,a as Ot,ak as we,bC as Ft,cL as ge,c as ye,T as Ee,br as Bt,cM as Gt,cN as Ue,ah as Ve,I as Ut,B as Y,aj as Vt,bd as Wt,aa as qt,ae as Yt,ac as ve,ad as Xt,bA as Jt,cO as Qt,ag as Zt,cP as ei,bj as ti,bk as ii,cQ as oi,bL as ri,cR as We,cS as qe,R as ni,bm as U,cT as ai,cU as li,bg as si,cV as ci,cW as di,A as ui,E as Ye,cX as pi,bx as fi,j as Xe,aN as hi,bQ as bi,aO as mi,aJ as se,bw as gi,cY as yi,aK as vi,bs as xi,cZ as $i,_ as ki}from"./index-Bw0aJc9a.js";import{r as f,$ as S,j as c}from"./vendor-react-Bf71BWbF.js";import{M as wi}from"./ActionGroup-DLxTuKht.js";import{$ as Pi,a as Ii,b as Si,c as Ei,d as Di}from"./useGridSelectionCheckbox-COXIVEmS.js";import{$ as Mi,a as F,b as xe,c as J,d as ji}from"./Virtualizer-DCY9HC9Z.js";import{$ as Ci}from"./useFilter-Tjznm3lB.js";import{g as Ni,a as _i}from"./policyText-CltaDVEo.js";import{P as Ti,o as Li}from"./openGroup-Dk9B33qx.js";import{p as Je}from"./nav-BASDWt23.js";const De=new WeakMap;function Pe(i,t){let{id:e}=De.get(i)??{};if(!e)throw new Error("Unknown list");return`${e}-${zi(t)}`}function zi(i){return typeof i=="string"?i.replace(/\s*/g,""):""+i}function Ai(i,t,e){let{isVirtualized:o,keyboardDelegate:r,layoutDelegate:n,onAction:s,disallowTypeAhead:l,linkBehavior:a="action",keyboardNavigationBehavior:p="arrow",escapeKeyBehavior:d="clearSelection",shouldSelectOnPressUp:v}=i;!i["aria-label"]&&!i["aria-labelledby"]&&console.warn("An aria-label or aria-labelledby prop is required for accessibility.");let{listProps:h}=it({selectionManager:t.selectionManager,collection:t.collection,disabledKeys:t.disabledKeys,ref:e,keyboardDelegate:r,layoutDelegate:n,isVirtualized:o,selectOnFocus:t.selectionManager.selectionBehavior==="replace",shouldFocusWrap:i.shouldFocusWrap,linkBehavior:a,disallowTypeAhead:l,autoFocus:i.autoFocus,escapeKeyBehavior:d,UNSTABLE_focusOnEntry:i.UNSTABLE_focusOnEntry}),g=ot(i.id);De.set(t,{id:g,onAction:s,linkBehavior:a,keyboardNavigationBehavior:p,shouldSelectOnPressUp:v});let x=Pi({selectionManager:t.selectionManager,hasItemActions:!!s}),P=rt(e,{isDisabled:t.collection.size!==0}),m=pe(i,{labelable:!0}),b=te(m,{role:"grid",id:g,"aria-multiselectable":t.selectionManager.selectionMode==="multiple"?"true":void 0},t.collection.size===0?{tabIndex:P?-1:0}:h,x);return o&&(b["aria-rowcount"]=t.collection.size,b["aria-colcount"]=1),Ii({},t),{gridProps:b}}const Ce={expand:{ltr:"ArrowRight",rtl:"ArrowLeft"},collapse:{ltr:"ArrowLeft",rtl:"ArrowRight"}};function Ri(i,t,e){let{node:o,isVirtualized:r,focusMode:n="row",allowsArrowNavigation:s}=i,{direction:l}=Ie(),{onAction:a,linkBehavior:p,keyboardNavigationBehavior:d,shouldSelectOnPressUp:v}=De.get(t),h=nt(),g=f.useRef(null),x=()=>{if(e.current!==null){if(n==="child"){if(je(e.current)&&e.current!==re(ne(e.current)))return;let D=me(e.current,{tabbable:!0}).firstChild();if(D){G(D),W(D,{containingElement:q(D)});return}}(g.current!=null&&o.key!==g.current||!je(e.current))&&G(e.current)}},P={},m=i.hasChildItems,b=t.selectionManager.isLink(o.key);if(o!=null&&"expandedKeys"in t){let u=t.collection.getChildren?.(o.key);m=m||[...u??[]].length>1,a==null&&!b&&t.selectionManager.selectionMode==="none"&&m&&(a=()=>t.toggleKey(o.key));let D=m?t.expandedKeys.has(o.key):void 0,w=1,j=o.index;if(o.level>=0&&o?.parentKey!=null){let C=t.collection.getItem(o.parentKey);if(C){let z=Ki(C,t.collection);w=[...z].filter(R=>R.type==="item").length,j>0&&z[0].type!=="item"&&(j-=1)}}else w=[...t.collection].filter(C=>C.level===0&&C.type==="item").length;P={"aria-expanded":D,"aria-level":o.level+1,"aria-posinset":j+1,"aria-setsize":w}}let{itemProps:$,...I}=at({selectionManager:t.selectionManager,key:o.key,ref:e,isVirtualized:r,shouldSelectOnPressUp:i.shouldSelectOnPressUp||v,onAction:a||o.props?.onAction?lt(o.props?.onAction,a?()=>a(o.key):void 0):void 0,focus:x,linkBehavior:p}),M=u=>{let D=re(ne(e.current));if(!ae(u.currentTarget,ee(u))||!e.current||!D)return;let w=me(e.current);if(w.currentNode=D,!Ne(u,t,o,m,l,D,e.current,s))switch(u.key){case"ArrowLeft":if(d==="arrow"){let j=l==="rtl"?w.nextNode():w.previousNode();if(j)u.preventDefault(),u.stopPropagation(),G(j),W(j,{containingElement:q(e.current)});else if(u.preventDefault(),u.stopPropagation(),l==="rtl")G(e.current),W(e.current,{containingElement:q(e.current)});else{w.currentNode=e.current;let C=_e(w);C&&(G(C),W(C,{containingElement:q(e.current)}))}}break;case"ArrowRight":if(d==="arrow"){lLine truncated
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./Arrange-Bbxnsdc8.js","./vendor-react-Bf71BWbF.js","./index-BOpK0UVB.js","./index-tAbIWhIz.css","./Virtualizer-BIsXGNLZ.js","./ListLayout-CkBMjK9o.js","./DaeCode-B8yPDjSE.js","./policyText-y7dbn7hu.js","./openGroup-B1VdMhOs.js","./useFilter-6_o4NyOf.js","./ActionGroup-BU73NzbX.js","./useGridSelectionCheckbox-C4VxQajJ.js","./nav-BASDWt23.js","./Arrange-Dd3j3leY.css"])))=>i.map(i=>d[i]);
|
||||
import{bT as it,bU as ot,bV as rt,bW as pe,bX as te,bY as Ie,bZ as nt,b_ as at,b$ as lt,c0 as st,c1 as je,c2 as re,c3 as ne,c4 as me,c5 as G,c6 as W,c7 as q,c8 as ee,c9 as ct,ca as ae,cb as Ke,cc as dt,cd as ut,ce as He,cf as pt,cg as de,ch as fe,ci as Oe,cj as ue,ck as ft,cl as ke,cm as Se,cn as he,co as be,cp as Fe,cq as ht,cr as bt,cs as mt,ct as Be,cu as gt,cv as yt,cw as le,cx as vt,cy as xt,cz as $t,cA as kt,cB as wt,cC as Pt,cD as It,cE as St,cF as Et,cG as Dt,cH as Mt,cI as jt,M as Ct,b as ce,cJ as Nt,a4 as _t,bc as Ge,bB as Tt,a_ as Lt,K as zt,cK as At,aW as Rt,a5 as Kt,u as B,a6 as Ht,a as Ot,ak as we,bC as Ft,cL as ge,c as ye,T as Ee,br as Bt,cM as Gt,cN as Ue,ah as Ve,I as Ut,B as Y,aj as Vt,bd as Wt,aa as qt,ae as Yt,ac as ve,ad as Xt,bA as Jt,cO as Qt,ag as Zt,cP as ei,bj as ti,bk as ii,cQ as oi,bL as ri,cR as We,cS as qe,R as ni,bm as U,cT as ai,cU as li,bg as si,cV as ci,cW as di,A as ui,E as Ye,cX as pi,bx as fi,j as Xe,aN as hi,bQ as bi,aO as mi,aJ as se,bw as gi,cY as yi,aK as vi,bs as xi,cZ as $i,_ as ki}from"./index-BOpK0UVB.js";import{r as f,$ as S,j as c}from"./vendor-react-Bf71BWbF.js";import{M as wi}from"./ActionGroup-BU73NzbX.js";import{$ as Pi,a as Ii,b as Si,c as Ei,d as Di}from"./useGridSelectionCheckbox-C4VxQajJ.js";import{$ as Mi,a as F,b as xe,c as J,d as ji}from"./Virtualizer-BIsXGNLZ.js";import{$ as Ci}from"./useFilter-6_o4NyOf.js";import{g as Ni,a as _i}from"./policyText-y7dbn7hu.js";import{P as Ti,o as Li}from"./openGroup-B1VdMhOs.js";import{p as Je}from"./nav-BASDWt23.js";const De=new WeakMap;function Pe(i,t){let{id:e}=De.get(i)??{};if(!e)throw new Error("Unknown list");return`${e}-${zi(t)}`}function zi(i){return typeof i=="string"?i.replace(/\s*/g,""):""+i}function Ai(i,t,e){let{isVirtualized:o,keyboardDelegate:r,layoutDelegate:n,onAction:s,disallowTypeAhead:l,linkBehavior:a="action",keyboardNavigationBehavior:p="arrow",escapeKeyBehavior:d="clearSelection",shouldSelectOnPressUp:v}=i;!i["aria-label"]&&!i["aria-labelledby"]&&console.warn("An aria-label or aria-labelledby prop is required for accessibility.");let{listProps:h}=it({selectionManager:t.selectionManager,collection:t.collection,disabledKeys:t.disabledKeys,ref:e,keyboardDelegate:r,layoutDelegate:n,isVirtualized:o,selectOnFocus:t.selectionManager.selectionBehavior==="replace",shouldFocusWrap:i.shouldFocusWrap,linkBehavior:a,disallowTypeAhead:l,autoFocus:i.autoFocus,escapeKeyBehavior:d,UNSTABLE_focusOnEntry:i.UNSTABLE_focusOnEntry}),g=ot(i.id);De.set(t,{id:g,onAction:s,linkBehavior:a,keyboardNavigationBehavior:p,shouldSelectOnPressUp:v});let x=Pi({selectionManager:t.selectionManager,hasItemActions:!!s}),P=rt(e,{isDisabled:t.collection.size!==0}),m=pe(i,{labelable:!0}),b=te(m,{role:"grid",id:g,"aria-multiselectable":t.selectionManager.selectionMode==="multiple"?"true":void 0},t.collection.size===0?{tabIndex:P?-1:0}:h,x);return o&&(b["aria-rowcount"]=t.collection.size,b["aria-colcount"]=1),Ii({},t),{gridProps:b}}const Ce={expand:{ltr:"ArrowRight",rtl:"ArrowLeft"},collapse:{ltr:"ArrowLeft",rtl:"ArrowRight"}};function Ri(i,t,e){let{node:o,isVirtualized:r,focusMode:n="row",allowsArrowNavigation:s}=i,{direction:l}=Ie(),{onAction:a,linkBehavior:p,keyboardNavigationBehavior:d,shouldSelectOnPressUp:v}=De.get(t),h=nt(),g=f.useRef(null),x=()=>{if(e.current!==null){if(n==="child"){if(je(e.current)&&e.current!==re(ne(e.current)))return;let D=me(e.current,{tabbable:!0}).firstChild();if(D){G(D),W(D,{containingElement:q(D)});return}}(g.current!=null&&o.key!==g.current||!je(e.current))&&G(e.current)}},P={},m=i.hasChildItems,b=t.selectionManager.isLink(o.key);if(o!=null&&"expandedKeys"in t){let u=t.collection.getChildren?.(o.key);m=m||[...u??[]].length>1,a==null&&!b&&t.selectionManager.selectionMode==="none"&&m&&(a=()=>t.toggleKey(o.key));let D=m?t.expandedKeys.has(o.key):void 0,w=1,j=o.index;if(o.level>=0&&o?.parentKey!=null){let C=t.collection.getItem(o.parentKey);if(C){let z=Ki(C,t.collection);w=[...z].filter(R=>R.type==="item").length,j>0&&z[0].type!=="item"&&(j-=1)}}else w=[...t.collection].filter(C=>C.level===0&&C.type==="item").length;P={"aria-expanded":D,"aria-level":o.level+1,"aria-posinset":j+1,"aria-setsize":w}}let{itemProps:$,...I}=at({selectionManager:t.selectionManager,key:o.key,ref:e,isVirtualized:r,shouldSelectOnPressUp:i.shouldSelectOnPressUp||v,onAction:a||o.props?.onAction?lt(o.props?.onAction,a?()=>a(o.key):void 0):void 0,focus:x,linkBehavior:p}),M=u=>{let D=re(ne(e.current));if(!ae(u.currentTarget,ee(u))||!e.current||!D)return;let w=me(e.current);if(w.currentNode=D,!Ne(u,t,o,m,l,D,e.current,s))switch(u.key){case"ArrowLeft":if(d==="arrow"){let j=l==="rtl"?w.nextNode():w.previousNode();if(j)u.preventDefault(),u.stopPropagation(),G(j),W(j,{containingElement:q(e.current)});else if(u.preventDefault(),u.stopPropagation(),l==="rtl")G(e.current),W(e.current,{containingElement:q(e.current)});else{w.currentNode=e.current;let C=_e(w);C&&(G(C),W(C,{containingElement:q(e.current)}))}}break;case"ArrowRight":if(d==="arrow"){lLine truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{r as g,j as i}from"./vendor-react-Bf71BWbF.js";import{bk as ds,bA as us,a_ as cs,a3 as ee,a4 as Ie,by as Fe,aX as ps,h as be,c_ as ms,ac as C,c$ as bs,aw as qe,a6 as de,d0 as Oe,d1 as hs,d2 as fs,d3 as gs,q as xs,a7 as We,d4 as Ve,d5 as Ue,d6 as ys,a5 as ve,a0 as _e,d7 as ks,d8 as js,d9 as Be,y as vs,da as _s,db as Qe,dc as ws,bg as Ns,u as O,a as we,bG as Rs,aa as ue,ae as Ke,ad as Ls,dd as Cs,af as Hs,bH as qs,bm as oe,bq as Ss,Y as fe,bz as Ds,b3 as Ms,de as $e,c as Ps,df as Ts,dg as Es,cS as As,dh as Is,di as Fs,dj as Os,dk as Ws,ag as Ne,dl as Vs,dm as Ge,dn as Je,dp as ze,dq as Ye,dr as Xe,aL as he,aO as Ze,B,ds as Us,aj as Se,bt as ae,cN as Bs,bQ as es,aN as se,I as Qs,E as Re,dt as Ks,bs as ss,T as $,du as $s,bw as Gs,aJ as ns,bK as Js,dv as De,L as ke,bh as zs,bj as Ys,j as Xs,bx as Zs,bb as en,cY as sn,bR as nn,aK as ge}from"./index-Bw0aJc9a.js";import{u as rs,r as rn,b as tn,a as on}from"./flows-D3eabARZ.js";import{q as an}from"./dns-BCg5F0Tv.js";import{i as Me}from"./setup-DLvQ_6ZI.js";import{c as ln,C as dn}from"./Coverage-DhDWz2sB.js";import{w as un}from"./labels-Bgu_ZhL8.js";import{r as cn}from"./nav-xc_Z_1Qd.js";import{r as pn}from"./recorder-DlDpPhd4.js";import{p as mn}from"./probe-D0Quphno.js";import{u as bn,R as hn}from"./useQuickRule-BmFeKwTA.js";import{D as Le}from"./Table-Km6Zv-S8.js";import{D as Z}from"./DaeCode-B8yPDjSE.js";import"./useGridSelectionCheckbox-COXIVEmS.js";import"./Virtualizer-DCY9HC9Z.js";import"./ListLayout-_fDlx5XY.js";function is(e){const s=new Map;for(const t of e){const o=t.rule_id,a=o===null?null:t.rule_expression,c=t.rule_source,r=JSON.stringify([o,a,c]),d=s.get(r);d?d.count++:s.set(r,{id:o,expression:a,source:c,count:1,share:0})}const n=[...s.values()];for(const t of n)t.share=t.count/e.length;return n.sort((t,o)=>o.count-t.count)}const fn={domainSuffix:"example.com, example.org",domain:"www.example.com",geosite:"netflix, cn",dip:"10.0.0.0/8, 224.0.0.0/4",geoip:"cn, private",sip:"192.168.1.10",dport:"80, 443",sport:"53",pname:"curl, firefox",l4proto:"udp",qnameSuffix:"example.com, lan",qnameFull:"www.example.com",qnameKeyword:"tracker",qnameGeosite:"cn, category-ads-all",qtype:"A, AAAA, HTTPS",upstream:"alidns",answerIp:"0.0.0.0/32, 10.0.0.0/8",answerGeoip:"cn, private"},xe={kernel:"rule.sourceKernel",recomputed:"rule.sourceRecomputed",unknown:"rule.sourceUnknown"},gn={kernel:"rule.sourceHelp.kernel",recomputed:"rule.sourceHelp.recomputed",unknown:"rule.sourceHelp.unknown"};function ts(e,s){return s?Be(s):e.file==="<redacted>"?"":e.file}const Pe=(e,s,n)=>e?n("conn.ruleNoPosition"):s?n("ui.changeApplying"):void 0,xn={conditionInvalid:"rule.conditionInvalid",targetMissing:"rule.outboundMissing"};function yn(e,s,n,t=xn){return e.valid?s?null:n(t.targetMissing):e.mode==="pick"?e.pickError??n("rule.valuesMissing"):n(e.rawInvalid?t.conditionInvalid:"rule.conditionMissing")}function kn({loaded:e,busy:s,available:n,invalid:t,modeOffered:o},a){return!e||s?null:n?t?a(t):o?null:a("rule.resolveUnavailable"):a("rule.traceUnavailable")}function os(e,s,n,t,o,a,c=null){const r=de[a],d=new Map(s.map(p=>[p.id,p])),f=p=>{if(p)return d.get(p.source_id)},b=new Map,y=p=>{const u=p.source&&d.get(p.source.source_id);return u?u.writable?(b.has(u.id)||b.set(u.id,vs(u.content)),n(u,p,b.get(u.id))!==null?null:u.kind==="include"?o("rule.inInclude",{file:Be(u)}):o("rule.notLocated")):o("config.readOnlyAttempt"):o("rule.notLocated")},h=e.map(p=>{const u=f(p.source),L=p.source?ts(p.source,u):"",k=y(p);return{id:p.rule_id,number:p.kind==="fallback"?"—":ve(p.index+1,r),expression:p.expression,...t(p),position:p.source?L?`${L}:${p.source.line}`:o("rule.lineOnly",{n:p.source.line}):"—",removable:p.kind==="rule"&&k===null,editReason:k,removeReason:p.kind==="rule"?k:null,sourceQuery:u&&p.source?_e("",{tab:"source",source:u.id,line:String(p.source.line)}):null}}),x=e.find(p=>p.kind==="fallback");return{rows:h,positions:[...x?.source?y(x)===null?[{id:"end",label:o("rule.positionEnd")}]:[]:c?[c]:[],...e.filter((p,u)=>h[u].removable).map(p=>({id:p.rule_id,label:o("rule.positionBefore",{n:p.index+1}),desc:p.expression}))]}}function jn(e,s,n,t,o,a,c){const r=de[c],d=new Map(e.map(b=>[b.rule_id,b.expression])),f=new Map;for(const b of is(n?.flows??[]))b.id!==null&&d.get(b.id)===b.expression&&f.set(b.id,(f.get(b.id)??0)+b.count);return{...os(e,t,Qe,b=>({outbound:b.outbound??"",must:b.must,hits:f.has(b.rule_id)?ve(f.get(b.rule_id),r):"—"}),a,c),caption:s!==void 0?a("rule.dictionaryCaption",{n:e.length,generation:s}):null,outbounds:ys(o)}}function vn(e){const s=/\s*->\s*('[^']*'|"[^"]*"|\S+)$/.exec(e.expression);return e.kind==="rule"&&s&&s[1].toLowerCase()===We(e).toLowerCase()?e.expression.slice(0,s.index):e.expression}function _n(e,s,n,t,o,a){const c=Oe(t,e),r=[...new Set(hs(s,t).map(d=>d.name))];return{...os(s,t,(d,f,b)=>Ve(d,f,e,b),d=>({expression:vn(d),outbound:xs(We(d)),must:!1,hits:"—"}),o,a,c&&{id:"end",...gs(c.anchor,e,o)}),caption:n!==void 0?o("rule.dictionaryCaption",{n:s.length,gLine truncated
|
||||
import{r as g,j as i}from"./vendor-react-Bf71BWbF.js";import{bk as ds,bA as us,a_ as cs,a3 as ee,a4 as Ie,by as Fe,aX as ps,h as be,c_ as ms,ac as C,c$ as bs,aw as qe,a6 as de,d0 as Oe,d1 as hs,d2 as fs,d3 as gs,q as xs,a7 as We,d4 as Ve,d5 as Ue,d6 as ys,a5 as ve,a0 as _e,d7 as ks,d8 as js,d9 as Be,y as vs,da as _s,db as Qe,dc as ws,bg as Ns,u as O,a as we,bG as Rs,aa as ue,ae as Ke,ad as Ls,dd as Cs,af as Hs,bH as qs,bm as oe,bq as Ss,Y as fe,bz as Ds,b3 as Ms,de as $e,c as Ps,df as Ts,dg as Es,cS as As,dh as Is,di as Fs,dj as Os,dk as Ws,ag as Ne,dl as Vs,dm as Ge,dn as Je,dp as ze,dq as Ye,dr as Xe,aL as he,aO as Ze,B,ds as Us,aj as Se,bt as ae,cN as Bs,bQ as es,aN as se,I as Qs,E as Re,dt as Ks,bs as ss,T as $,du as $s,bw as Gs,aJ as ns,bK as Js,dv as De,L as ke,bh as zs,bj as Ys,j as Xs,bx as Zs,bb as en,cY as sn,bR as nn,aK as ge}from"./index-BOpK0UVB.js";import{u as rs,r as rn,b as tn,a as on}from"./flows-BW6GjUpE.js";import{q as an}from"./dns-BY6DX1P3.js";import{i as Me}from"./setup-V0SWKTBk.js";import{c as ln,C as dn}from"./Coverage-BJmgp_Br.js";import{w as un}from"./labels-Bgu_ZhL8.js";import{r as cn}from"./nav-DEBjyEJ7.js";import{r as pn}from"./recorder-DlDpPhd4.js";import{p as mn}from"./probe-BHjulBb8.js";import{u as bn,R as hn}from"./useQuickRule-qFvcUoSC.js";import{D as Le}from"./Table-BkehX7fw.js";import{D as Z}from"./DaeCode-B8yPDjSE.js";import"./useGridSelectionCheckbox-C4VxQajJ.js";import"./Virtualizer-BIsXGNLZ.js";import"./ListLayout-CkBMjK9o.js";function is(e){const s=new Map;for(const t of e){const o=t.rule_id,a=o===null?null:t.rule_expression,c=t.rule_source,r=JSON.stringify([o,a,c]),d=s.get(r);d?d.count++:s.set(r,{id:o,expression:a,source:c,count:1,share:0})}const n=[...s.values()];for(const t of n)t.share=t.count/e.length;return n.sort((t,o)=>o.count-t.count)}const fn={domainSuffix:"example.com, example.org",domain:"www.example.com",geosite:"netflix, cn",dip:"10.0.0.0/8, 224.0.0.0/4",geoip:"cn, private",sip:"192.168.1.10",dport:"80, 443",sport:"53",pname:"curl, firefox",l4proto:"udp",qnameSuffix:"example.com, lan",qnameFull:"www.example.com",qnameKeyword:"tracker",qnameGeosite:"cn, category-ads-all",qtype:"A, AAAA, HTTPS",upstream:"alidns",answerIp:"0.0.0.0/32, 10.0.0.0/8",answerGeoip:"cn, private"},xe={kernel:"rule.sourceKernel",recomputed:"rule.sourceRecomputed",unknown:"rule.sourceUnknown"},gn={kernel:"rule.sourceHelp.kernel",recomputed:"rule.sourceHelp.recomputed",unknown:"rule.sourceHelp.unknown"};function ts(e,s){return s?Be(s):e.file==="<redacted>"?"":e.file}const Pe=(e,s,n)=>e?n("conn.ruleNoPosition"):s?n("ui.changeApplying"):void 0,xn={conditionInvalid:"rule.conditionInvalid",targetMissing:"rule.outboundMissing"};function yn(e,s,n,t=xn){return e.valid?s?null:n(t.targetMissing):e.mode==="pick"?e.pickError??n("rule.valuesMissing"):n(e.rawInvalid?t.conditionInvalid:"rule.conditionMissing")}function kn({loaded:e,busy:s,available:n,invalid:t,modeOffered:o},a){return!e||s?null:n?t?a(t):o?null:a("rule.resolveUnavailable"):a("rule.traceUnavailable")}function os(e,s,n,t,o,a,c=null){const r=de[a],d=new Map(s.map(p=>[p.id,p])),f=p=>{if(p)return d.get(p.source_id)},b=new Map,y=p=>{const u=p.source&&d.get(p.source.source_id);return u?u.writable?(b.has(u.id)||b.set(u.id,vs(u.content)),n(u,p,b.get(u.id))!==null?null:u.kind==="include"?o("rule.inInclude",{file:Be(u)}):o("rule.notLocated")):o("config.readOnlyAttempt"):o("rule.notLocated")},h=e.map(p=>{const u=f(p.source),L=p.source?ts(p.source,u):"",k=y(p);return{id:p.rule_id,number:p.kind==="fallback"?"—":ve(p.index+1,r),expression:p.expression,...t(p),position:p.source?L?`${L}:${p.source.line}`:o("rule.lineOnly",{n:p.source.line}):"—",removable:p.kind==="rule"&&k===null,editReason:k,removeReason:p.kind==="rule"?k:null,sourceQuery:u&&p.source?_e("",{tab:"source",source:u.id,line:String(p.source.line)}):null}}),x=e.find(p=>p.kind==="fallback");return{rows:h,positions:[...x?.source?y(x)===null?[{id:"end",label:o("rule.positionEnd")}]:[]:c?[c]:[],...e.filter((p,u)=>h[u].removable).map(p=>({id:p.rule_id,label:o("rule.positionBefore",{n:p.index+1}),desc:p.expression}))]}}function jn(e,s,n,t,o,a,c){const r=de[c],d=new Map(e.map(b=>[b.rule_id,b.expression])),f=new Map;for(const b of is(n?.flows??[]))b.id!==null&&d.get(b.id)===b.expression&&f.set(b.id,(f.get(b.id)??0)+b.count);return{...os(e,t,Qe,b=>({outbound:b.outbound??"",must:b.must,hits:f.has(b.rule_id)?ve(f.get(b.rule_id),r):"—"}),a,c),caption:s!==void 0?a("rule.dictionaryCaption",{n:e.length,generation:s}):null,outbounds:ys(o)}}function vn(e){const s=/\s*->\s*('[^']*'|"[^"]*"|\S+)$/.exec(e.expression);return e.kind==="rule"&&s&&s[1].toLowerCase()===We(e).toLowerCase()?e.expression.slice(0,s.index):e.expression}function _n(e,s,n,t,o,a){const c=Oe(t,e),r=[...new Set(hs(s,t).map(d=>d.name))];return{...os(s,t,(d,f,b)=>Ve(d,f,e,b),d=>({expression:vn(d),outbound:xs(We(d)),must:!1,hits:"—"}),o,a,c&&{id:"end",...gs(c.anchor,e,o)}),caption:n!==void 0?o("rule.dictionaryCaption",{n:s.length,gLine truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{r as h,j as d}from"./vendor-react-Bf71BWbF.js";import{$ as w,a0 as f,a1 as I,a2 as O,a3 as D,a4 as P,a5 as M,a6 as T,a7 as L,a8 as Q,a9 as V,u as q,a as B,aa as F,ab as z,ac as v,ad as G,ae as J,af as U,ag as W,ah as X,ai as Y,T as Z,B as E,aj as ee,E as se,j as te,ak as ae,al as ne,am as ie,an as re,ao as oe}from"./index-Bw0aJc9a.js";import{u as de,a as le}from"./flows-D3eabARZ.js";import{d as ce}from"./nav-CdRBQuvD.js";import{r as ue}from"./nav-xc_Z_1Qd.js";import{f as pe}from"./nav-CS6FFQFP.js";import{s as me}from"./nav-D5WY5Qjf.js";import{c as he,s as fe,a as ge}from"./nav-BFiTWnsa.js";import{c as be}from"./nav-Wiib71Wo.js";import{n as ye}from"./nav-DONyavaI.js";import{p as xe}from"./nav-BASDWt23.js";const g=(t,a,e,r,i,o="")=>({hit:{id:a,label:e,description:r,route:i,query:o},keys:t.flatMap(n=>n==null?[]:[n.toLowerCase()])});function ve(t,a,e){const r=s=>Q(s,t),i=t?.resources,o=a?.sources.find(s=>s.kind==="main"),n=[...be().map(s=>({path:"connections",params:{tab:s.id},titleKey:s.titleKey})),...ye(i).map(s=>({path:"nodes",params:{tab:s.id},titleKey:s.titleKey})),...xe().map(s=>({path:"policies",params:{tab:s.id},titleKey:s.titleKey})),...pe(i).map(s=>({path:"flows",params:{tab:s.id},titleKey:s.titleKey})),...ue(i).map(s=>({path:"rules",params:{tab:s.id},titleKey:s.titleKey})),...ce(i).map(s=>({path:"dns",params:{tab:s.id},titleKey:s.titleKey})),...he(fe(i,o)).map(s=>({path:"config",params:{tab:s.id},titleKey:s.titleKey})),...me(i).map(s=>({path:"settings",params:{card:s.id},titleKey:s.titleKey}))];return[...w.filter(s=>s.nav&&r(s.path)).map(s=>({route:s.path,query:"",title:e(s.nav.titleKey),parent:""})),...n.filter(s=>r(s.path)).map(s=>({route:s.path,query:f("",s.params),title:e(s.titleKey),parent:e(w.find(c=>c.path===s.path).nav.titleKey)}))].map(s=>g([s.title,s.parent&&s.parent+" "+s.title],`page:${s.route}?${s.query}`,s.title,s.parent||void 0,s.route,s.query))}function $e(t,a){return I(t).map(e=>g([e.domain,e.dst,e.src],`connection:${e.id}`,e.domain||e.dst||e.src||e.id,O(e,a),"connections",f("",{id:e.id})))}function je(t,a,e){const r=a?.providers??[],i=o=>f("",{provider:V(o,r),q:o.name});return(t??[]).map(o=>g([o.name],`node:${o.id}`,o.name,D(e,o.group_ids)||void 0,"nodes",i(o)))}function Ke(t){return(t??[]).map(a=>g([a.name],`group:${a.id}`,a.name,a.policy.native,"policies",f("",{group:a.id})))}function we(t,a){return(t?.providers??[]).map(e=>g([e.name],`provider:${e.id}`,e.name,a("search.nodeCount",{n:e.node_count}),"nodes",f("",{provider:e.id})))}function Le(t,a){return(t?.sources??[]).map(e=>g([e.path],`source:${e.id}`,e.path,P(ge,e.kind,a),"config",f("",{tab:"source",source:e.id})))}function Ee(t,a){return(t?.rules??[]).filter(e=>e.kind==="rule").map(e=>g([e.expression,e.outbound],`rule:${e.rule_id}`,e.expression,`#${M(e.index+1,T[a])} → ${e.outbound}`,"rules",f("",{tab:"list",rule:e.rule_id})))}function Me(t,a,e){return[{list:t?.request??[],title:e("rule.dns.request")},{list:t?.response??[],title:e("rule.dns.response")}].flatMap(({list:i,title:o})=>i.filter(n=>n.kind==="rule").map(n=>g([n.expression,L(n)],`dns-rule:${n.rule_id}`,n.expression,`${o} #${M(n.index+1,T[a])} → ${L(n)}`,"rules",f("",{tab:"dns"}))))}function Te(t,a,e){return{sections:[{id:"pages",title:e("search.pages"),entries:t.pages},{id:"conns",title:e("nav.connections"),entries:t.conns},{id:"nodes",title:e("search.nodes"),entries:t.nodes},{id:"groups",title:e("search.groups"),entries:t.groups},{id:"providers",title:e("search.providers"),entries:t.providers},{id:"sources",title:e("search.sources"),entries:t.sources},{id:"rules",title:e("nav.rules"),entries:t.rules},{id:"dnsRules",title:e("rule.dnsTitle"),entries:t.dnsRules}],partial:a?.truncated?e("conn.truncated"):null}}function qe(t,a){const e=t.trim().toLowerCase(),r=e?8:5,i=new Map;return{sections:a.sections.map(n=>{const l=[];for(const{hit:s,keys:c}of n.entries){if(l.length===r)break;c.some(b=>b.includes(e))&&(l.push(s),i.set(s.id,s))}return{id:n.id,title:n.title,items:l}}).filter(n=>n.items.length>0),byId:i,partial:a.partial}}function Re(t,a){const e=q(),r=B(),[i,o]=h.useState(""),n=F(),l=n.data?.resources,s=z(void 0,v(l,"connections",{whileLoading:!1})),c=G(v(l,"nodes",{whileLoading:!1})),b=J(v(l,"groups",{whileLoading:!1})),y=U(v(l,"providers",{whileLoading:!1})),x=W(v(l,"config",{whileLoading:!1})),u=de(v(l,"rules",{whileLoading:!1})),p=le(v(l,"dns_rules",{whileLoading:!1})),j=[n,s,c,b,y,x,u,p],R=h.useMemo(()=>ve(n.data,x.data,e),[n.data,x.data,e]),C=h.useMemo(()=>$e(s.data,e),[s.data,e]),N=h.useMemo(()=>je(c.data,y.data,r),[c.data,y.data,r]),k=h.useMemo(()=>Ke(b.data),[b.data]),H=h.useMemo(()=>we(y.data,e),[y.data,e]),_=h.useMemo(()=>Le(x.data,e),[x.data,e]),S=h.useMemo(()=>Ee(u.data,r),[u.data,r]),A=h.useMemo(()=>Me(p.data,r,e),[p.data,r,e]),$=qe(i,Te({pages:R,conns:C,nodes:N,groups:k,providers:H,sources:_,rules:S,dnsRules:A},s.data,e));return{q:i,setQ:o,sections:$.sections,partial:$.partial,openConnections:()=>{t("connections"),a()},empty:$.byId.size===0,errLine truncated
|
||||
import{r as h,j as d}from"./vendor-react-Bf71BWbF.js";import{$ as w,a0 as f,a1 as I,a2 as O,a3 as D,a4 as P,a5 as M,a6 as T,a7 as L,a8 as Q,a9 as V,u as q,a as B,aa as F,ab as z,ac as v,ad as G,ae as J,af as U,ag as W,ah as X,ai as Y,T as Z,B as E,aj as ee,E as se,j as te,ak as ae,al as ne,am as ie,an as re,ao as oe}from"./index-BOpK0UVB.js";import{u as de,a as le}from"./flows-BW6GjUpE.js";import{d as ce}from"./nav-B9ea5ZPQ.js";import{r as ue}from"./nav-DEBjyEJ7.js";import{f as pe}from"./nav-BiwTft4m.js";import{s as me}from"./nav-D5WY5Qjf.js";import{c as he,s as fe,a as ge}from"./nav-BFiTWnsa.js";import{c as be}from"./nav-Wiib71Wo.js";import{n as ye}from"./nav-BFm4Dw7L.js";import{p as xe}from"./nav-BASDWt23.js";const g=(t,a,e,r,i,o="")=>({hit:{id:a,label:e,description:r,route:i,query:o},keys:t.flatMap(n=>n==null?[]:[n.toLowerCase()])});function ve(t,a,e){const r=s=>Q(s,t),i=t?.resources,o=a?.sources.find(s=>s.kind==="main"),n=[...be().map(s=>({path:"connections",params:{tab:s.id},titleKey:s.titleKey})),...ye(i).map(s=>({path:"nodes",params:{tab:s.id},titleKey:s.titleKey})),...xe().map(s=>({path:"policies",params:{tab:s.id},titleKey:s.titleKey})),...pe(i).map(s=>({path:"flows",params:{tab:s.id},titleKey:s.titleKey})),...ue(i).map(s=>({path:"rules",params:{tab:s.id},titleKey:s.titleKey})),...ce(i).map(s=>({path:"dns",params:{tab:s.id},titleKey:s.titleKey})),...he(fe(i,o)).map(s=>({path:"config",params:{tab:s.id},titleKey:s.titleKey})),...me(i).map(s=>({path:"settings",params:{card:s.id},titleKey:s.titleKey}))];return[...w.filter(s=>s.nav&&r(s.path)).map(s=>({route:s.path,query:"",title:e(s.nav.titleKey),parent:""})),...n.filter(s=>r(s.path)).map(s=>({route:s.path,query:f("",s.params),title:e(s.titleKey),parent:e(w.find(c=>c.path===s.path).nav.titleKey)}))].map(s=>g([s.title,s.parent&&s.parent+" "+s.title],`page:${s.route}?${s.query}`,s.title,s.parent||void 0,s.route,s.query))}function $e(t,a){return I(t).map(e=>g([e.domain,e.dst,e.src],`connection:${e.id}`,e.domain||e.dst||e.src||e.id,O(e,a),"connections",f("",{id:e.id})))}function je(t,a,e){const r=a?.providers??[],i=o=>f("",{provider:V(o,r),q:o.name});return(t??[]).map(o=>g([o.name],`node:${o.id}`,o.name,D(e,o.group_ids)||void 0,"nodes",i(o)))}function Ke(t){return(t??[]).map(a=>g([a.name],`group:${a.id}`,a.name,a.policy.native,"policies",f("",{group:a.id})))}function we(t,a){return(t?.providers??[]).map(e=>g([e.name],`provider:${e.id}`,e.name,a("search.nodeCount",{n:e.node_count}),"nodes",f("",{provider:e.id})))}function Le(t,a){return(t?.sources??[]).map(e=>g([e.path],`source:${e.id}`,e.path,P(ge,e.kind,a),"config",f("",{tab:"source",source:e.id})))}function Ee(t,a){return(t?.rules??[]).filter(e=>e.kind==="rule").map(e=>g([e.expression,e.outbound],`rule:${e.rule_id}`,e.expression,`#${M(e.index+1,T[a])} → ${e.outbound}`,"rules",f("",{tab:"list",rule:e.rule_id})))}function Me(t,a,e){return[{list:t?.request??[],title:e("rule.dns.request")},{list:t?.response??[],title:e("rule.dns.response")}].flatMap(({list:i,title:o})=>i.filter(n=>n.kind==="rule").map(n=>g([n.expression,L(n)],`dns-rule:${n.rule_id}`,n.expression,`${o} #${M(n.index+1,T[a])} → ${L(n)}`,"rules",f("",{tab:"dns"}))))}function Te(t,a,e){return{sections:[{id:"pages",title:e("search.pages"),entries:t.pages},{id:"conns",title:e("nav.connections"),entries:t.conns},{id:"nodes",title:e("search.nodes"),entries:t.nodes},{id:"groups",title:e("search.groups"),entries:t.groups},{id:"providers",title:e("search.providers"),entries:t.providers},{id:"sources",title:e("search.sources"),entries:t.sources},{id:"rules",title:e("nav.rules"),entries:t.rules},{id:"dnsRules",title:e("rule.dnsTitle"),entries:t.dnsRules}],partial:a?.truncated?e("conn.truncated"):null}}function qe(t,a){const e=t.trim().toLowerCase(),r=e?8:5,i=new Map;return{sections:a.sections.map(n=>{const l=[];for(const{hit:s,keys:c}of n.entries){if(l.length===r)break;c.some(b=>b.includes(e))&&(l.push(s),i.set(s.id,s))}return{id:n.id,title:n.title,items:l}}).filter(n=>n.items.length>0),byId:i,partial:a.partial}}function Re(t,a){const e=q(),r=B(),[i,o]=h.useState(""),n=F(),l=n.data?.resources,s=z(void 0,v(l,"connections",{whileLoading:!1})),c=G(v(l,"nodes",{whileLoading:!1})),b=J(v(l,"groups",{whileLoading:!1})),y=U(v(l,"providers",{whileLoading:!1})),x=W(v(l,"config",{whileLoading:!1})),u=de(v(l,"rules",{whileLoading:!1})),p=le(v(l,"dns_rules",{whileLoading:!1})),j=[n,s,c,b,y,x,u,p],R=h.useMemo(()=>ve(n.data,x.data,e),[n.data,x.data,e]),C=h.useMemo(()=>$e(s.data,e),[s.data,e]),N=h.useMemo(()=>je(c.data,y.data,r),[c.data,y.data,r]),k=h.useMemo(()=>Ke(b.data),[b.data]),H=h.useMemo(()=>we(y.data,e),[y.data,e]),_=h.useMemo(()=>Le(x.data,e),[x.data,e]),S=h.useMemo(()=>Ee(u.data,r),[u.data,r]),A=h.useMemo(()=>Me(p.data,r,e),[p.data,r,e]),$=qe(i,Te({pages:R,conns:C,nodes:N,groups:k,providers:H,sources:_,rules:S,dnsRules:A},s.data,e));return{q:i,setQ:o,sections:$.sections,partial:$.partial,openConnections:()=>{t("connections"),a()},empty:$.byId.size===0,errLine truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{r as h,a as ss,j as t}from"./vendor-react-Bf71BWbF.js";import{av as fe,ap as ts,a3 as Ve,h as as,d as qe,a5 as ue,A as Ne,eB as ns,u as W,eC as rs,cS as ze,eD as Ke,n as je,i as ye,bm as F,o as Ae,eE as os,w as is,a$ as ls,eF as cs,aa as ve,aF as We,eG as ds,eH as us,r as gs,eI as ps,bq as be,eJ as fs,eK as ms,a6 as Pe,a as Re,dl as $e,a4 as hs,H as vs,aN as ne,E as Q,j as me,I as bs,bt as V,T as le,aJ as _e,bQ as ce,B as T,aC as xs,ac as we,af as js,dV as ys,eL as ws,bi as ks,aG as Ns,eM as Je,b as Te,bn as _s,bu as Ie,L as Ce,aL as Ee,as as Cs,at as Ss,eN as Ps,eO as Rs,ae as Ls,de as Ds,cN as Se,em as As,cY as Ts,aK as Is,dt as he,eP as Ue,eQ as Es,eR as Us,eS as Hs,br as Fs}from"./index-Bw0aJc9a.js";import{d as Bs,c as Os}from"./auth-DzCdgIKH.js";import{g as Le,c as Gs,a as re,b as Ms}from"./nav-D5WY5Qjf.js";import{D as Vs}from"./Table-Km6Zv-S8.js";import{T as qs}from"./TimeCell-DKHUJpad.js";import{A as zs}from"./ActionGroup-DLxTuKht.js";import{c as Ks}from"./dns-BCg5F0Tv.js";import{u as Ws}from"./useRefreshAll-D0DryBsY.js";import{g as ge,v as $s}from"./geodata-De9_qBkH.js";import"./useGridSelectionCheckbox-COXIVEmS.js";import"./Virtualizer-DCY9HC9Z.js";import"./ListLayout-_fDlx5XY.js";const He=["record_flows","record_logs","record_dns_log"],pe={record_flows:{state:"flows",label:"settings.recordFlows"},record_logs:{state:"logs",label:"settings.recordLogs"},record_dns_log:{state:"dns_log",label:"settings.recordDnsLog"}},Js={auto:"settings.record.auto",on:"settings.record.on",off:"settings.record.off"},Qs=s=>s;function Ys(s,e,a,n){const r=a?!a.allowed:!1;return{id:s,label:n(pe[s].label),value:e,items:["auto","on","off"].map(o=>({id:o,label:n(o==="auto"&&s==="record_flows"?"settings.record.autoFlows":Js[o])})),disabled:r,tone:r?"muted":a?.active?"ok":"neutral",status:n(r?"settings.recordingForbidden":a?.active?"settings.recordingActive":"settings.recordingIdle")}}function Xs(s,e){if(!s)return null;const a=s.grace_remaining_seconds??0;return a>0?e("settings.recordingGrace",{n:a}):s.events?e(s.events.active?"settings.recordingEvents":"settings.recordingDetached"):null}const Zs=60,et=(s,e)=>s==="auto"?e("settings.recordFlowsAuto",{n:Zs}):null,st=["log.buffered_records","dns_log.max_records","flows.max_flows","flows.retention_seconds"],ie={"log.buffered_records":{read:s=>s.log?.buffered_records,write:(s,e)=>{(s.log??={}).buffered_records=e},label:"settings.logBuffer"},"dns_log.max_records":{read:s=>s.dns_log?.max_records,write:(s,e)=>{(s.dns_log??={}).max_records=e},label:"settings.dnsLogSize"},"flows.max_flows":{read:s=>s.flows?.max_flows,write:(s,e)=>{(s.flows??={}).max_flows=e},label:"settings.flowsMax"},"flows.retention_seconds":{read:s=>s.flows?.retention_seconds,write:(s,e)=>{(s.flows??={}).retention_seconds=e},label:"settings.flowsRetention"}};function tt(s,e,a,n,r,o){const i=ie[s];return{id:s,value:e,label:o(i.label),invalid:!/^\d+$/.test(e)||Number(e)<a||n!==void 0&&Number(e)>n,description:n===void 0?o("settings.rangeMin",{min:ue(a,r)}):o("settings.range",{min:ue(a,r),max:ue(n,r)})}}function at(s,e){return s.map(a=>({id:a.kind,kind:a.kind,size:fe(a.size_bytes,e),modifiedAt:a.modified_at,sha:a.sha256.slice(0,12),shaTitle:a.sha256,source:a.source_redacted??"—",fetched:a.fetched_url_redacted??"—",verified:a.verified===!0}))}function nt(s,e,a){return{choices:s.map(n=>({id:n.id,label:n.name})),result:e?{text:a(e.key,e.params),role:e.error?"alert":"status",request:e.requestId?a("ui.requestNote",{requestId:e.requestId}):"",error:!!e.error,id:e.id??0}:null}}function rt(s,e){return s?null:e("settings.noProfile")}function ot({busy:s,invalid:e},a){return!s&&e?a("settings.runtimeInvalid",{field:e}):null}function Qe({busy:s,loaded:e,failed:a},n){return!s&&!e&&a?n("settings.geodataUnread"):null}function it(s,e,a,n){const r=s?.resources;if(!r?.geodata.available||r.geodata.can_update!==!0||Le(r))return null;const o=ts(e),i=o.reason("geodata",s);if(i?.code!=="no-download-urls")return null;const l=Ve(n,i.settings.map(w=>o.settingName(w.key)));return{text:a("settings.geodataFromConfig",{keys:l}),docs:{href:qe(n,"state-db"),text:a("ov.lim.docsStateDb")},config:r.config.available?{href:as("config",{tab:"source"}),text:a("nav.config")}:void 0}}function lt(s,e){return s.flatMap(a=>a.items).find(a=>a.id===e)?.label??e}function ct(s,e,a,n,r=""){return e.aborted&&e.reason?.name==="TimeoutError"?{key:"settings.timeout"}:e.aborted?null:s instanceof Ne?s.status===401?{key:r?"settings.tokenRejected":"settings.unauthorized"}:s.code==="empty_response"?{key:"settings.nonJson"}:s.code==="invalid_discovery"?{key:"settings.invalidResponse"}:{key:"settings.httpError",params:{status:s.status}}:s instanceof SyntaxError?{key:"settings.nonJson"}:s instanceof TypeError&&new URL(a).origin!==n?{key:"settings.cors"}:{key:"settings.network"}}async function dt(s,e,a,n){try{const r=await ns(s,e).discovery(a);if(!r||!Number.isInteger(r.api_major)||r.api_major<1)throw new Ne(200,"invalid_discovery","Missing API version");return{version:StLine truncated
|
||||
import{r as h,a as ss,j as t}from"./vendor-react-Bf71BWbF.js";import{av as fe,ap as ts,a3 as Ve,h as as,d as qe,a5 as ue,A as Ne,eB as ns,u as W,eC as rs,cS as ze,eD as Ke,n as je,i as ye,bm as F,o as Ae,eE as os,w as is,a$ as ls,eF as cs,aa as ve,aF as We,eG as ds,eH as us,r as gs,eI as ps,bq as be,eJ as fs,eK as ms,a6 as Pe,a as Re,dl as $e,a4 as hs,H as vs,aN as ne,E as Q,j as me,I as bs,bt as V,T as le,aJ as _e,bQ as ce,B as T,aC as xs,ac as we,af as js,dV as ys,eL as ws,bi as ks,aG as Ns,eM as Je,b as Te,bn as _s,bu as Ie,L as Ce,aL as Ee,as as Cs,at as Ss,eN as Ps,eO as Rs,ae as Ls,de as Ds,cN as Se,em as As,cY as Ts,aK as Is,dt as he,eP as Ue,eQ as Es,eR as Us,eS as Hs,br as Fs}from"./index-BOpK0UVB.js";import{d as Bs,c as Os}from"./auth-DKKBdTVr.js";import{g as Le,c as Gs,a as re,b as Ms}from"./nav-D5WY5Qjf.js";import{D as Vs}from"./Table-BkehX7fw.js";import{T as qs}from"./TimeCell-COfj2dEh.js";import{A as zs}from"./ActionGroup-BU73NzbX.js";import{c as Ks}from"./dns-BY6DX1P3.js";import{u as Ws}from"./useRefreshAll-CFXNBP5e.js";import{g as ge,v as $s}from"./geodata-De9_qBkH.js";import"./useGridSelectionCheckbox-C4VxQajJ.js";import"./Virtualizer-BIsXGNLZ.js";import"./ListLayout-CkBMjK9o.js";const He=["record_flows","record_logs","record_dns_log"],pe={record_flows:{state:"flows",label:"settings.recordFlows"},record_logs:{state:"logs",label:"settings.recordLogs"},record_dns_log:{state:"dns_log",label:"settings.recordDnsLog"}},Js={auto:"settings.record.auto",on:"settings.record.on",off:"settings.record.off"},Qs=s=>s;function Ys(s,e,a,n){const r=a?!a.allowed:!1;return{id:s,label:n(pe[s].label),value:e,items:["auto","on","off"].map(o=>({id:o,label:n(o==="auto"&&s==="record_flows"?"settings.record.autoFlows":Js[o])})),disabled:r,tone:r?"muted":a?.active?"ok":"neutral",status:n(r?"settings.recordingForbidden":a?.active?"settings.recordingActive":"settings.recordingIdle")}}function Xs(s,e){if(!s)return null;const a=s.grace_remaining_seconds??0;return a>0?e("settings.recordingGrace",{n:a}):s.events?e(s.events.active?"settings.recordingEvents":"settings.recordingDetached"):null}const Zs=60,et=(s,e)=>s==="auto"?e("settings.recordFlowsAuto",{n:Zs}):null,st=["log.buffered_records","dns_log.max_records","flows.max_flows","flows.retention_seconds"],ie={"log.buffered_records":{read:s=>s.log?.buffered_records,write:(s,e)=>{(s.log??={}).buffered_records=e},label:"settings.logBuffer"},"dns_log.max_records":{read:s=>s.dns_log?.max_records,write:(s,e)=>{(s.dns_log??={}).max_records=e},label:"settings.dnsLogSize"},"flows.max_flows":{read:s=>s.flows?.max_flows,write:(s,e)=>{(s.flows??={}).max_flows=e},label:"settings.flowsMax"},"flows.retention_seconds":{read:s=>s.flows?.retention_seconds,write:(s,e)=>{(s.flows??={}).retention_seconds=e},label:"settings.flowsRetention"}};function tt(s,e,a,n,r,o){const i=ie[s];return{id:s,value:e,label:o(i.label),invalid:!/^\d+$/.test(e)||Number(e)<a||n!==void 0&&Number(e)>n,description:n===void 0?o("settings.rangeMin",{min:ue(a,r)}):o("settings.range",{min:ue(a,r),max:ue(n,r)})}}function at(s,e){return s.map(a=>({id:a.kind,kind:a.kind,size:fe(a.size_bytes,e),modifiedAt:a.modified_at,sha:a.sha256.slice(0,12),shaTitle:a.sha256,source:a.source_redacted??"—",fetched:a.fetched_url_redacted??"—",verified:a.verified===!0}))}function nt(s,e,a){return{choices:s.map(n=>({id:n.id,label:n.name})),result:e?{text:a(e.key,e.params),role:e.error?"alert":"status",request:e.requestId?a("ui.requestNote",{requestId:e.requestId}):"",error:!!e.error,id:e.id??0}:null}}function rt(s,e){return s?null:e("settings.noProfile")}function ot({busy:s,invalid:e},a){return!s&&e?a("settings.runtimeInvalid",{field:e}):null}function Qe({busy:s,loaded:e,failed:a},n){return!s&&!e&&a?n("settings.geodataUnread"):null}function it(s,e,a,n){const r=s?.resources;if(!r?.geodata.available||r.geodata.can_update!==!0||Le(r))return null;const o=ts(e),i=o.reason("geodata",s);if(i?.code!=="no-download-urls")return null;const l=Ve(n,i.settings.map(w=>o.settingName(w.key)));return{text:a("settings.geodataFromConfig",{keys:l}),docs:{href:qe(n,"state-db"),text:a("ov.lim.docsStateDb")},config:r.config.available?{href:as("config",{tab:"source"}),text:a("nav.config")}:void 0}}function lt(s,e){return s.flatMap(a=>a.items).find(a=>a.id===e)?.label??e}function ct(s,e,a,n,r=""){return e.aborted&&e.reason?.name==="TimeoutError"?{key:"settings.timeout"}:e.aborted?null:s instanceof Ne?s.status===401?{key:r?"settings.tokenRejected":"settings.unauthorized"}:s.code==="empty_response"?{key:"settings.nonJson"}:s.code==="invalid_discovery"?{key:"settings.invalidResponse"}:{key:"settings.httpError",params:{status:s.status}}:s instanceof SyntaxError?{key:"settings.nonJson"}:s instanceof TypeError&&new URL(a).origin!==n?{key:"settings.cors"}:{key:"settings.network"}}async function dt(s,e,a,n){try{const r=await ns(s,e).discovery(a);if(!r||!Number.isInteger(r.api_major)||r.api_major<1)throw new Ne(200,"invalid_discovery","Missing API version");return{version:StLine truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{r as x,j as r}from"./vendor-react-Bf71BWbF.js";import{aI as k,fx as P,fy as S}from"./index-Bw0aJc9a.js";import{u as T,C as B,f as W,n as v,g as j}from"./layout-BWzq8YqC.js";import{G as I,C as L}from"./AreaCurve-BriPYJva.js";import"./array-C0P64tl-.js";function R(i){let t=i.parentElement;for(;t&&getComputedStyle(t).overflow==="visible";)t=t.parentElement;const l=i.getBoundingClientRect();if(!t)return{x:-l.left,y:-l.top,width:document.documentElement.clientWidth,height:document.documentElement.clientHeight};const h=t.getBoundingClientRect();return{x:h.left+t.clientLeft-l.left,y:h.top+t.clientTop-l.top,width:t.clientWidth,height:t.clientHeight}}function A({values:i,timestamps:t,color:l,fmt:h,locale:p,height:f=32,floor:m=0}){const g=x.useId(),C=k(),[o,y]=x.useState(null),[u,e]=P(Math.round,120),{tip:M,showAt:b,hide:E}=T(),c=i.filter(n=>n!==null),w=[m>0?0:Math.min(...c)*.85,Math.max(Math.max(...c)*1.05||1,m)],d=n=>j(n,[Math.min(...t),Math.max(...t)],[0,e?.width??0]),a=n=>j(n,w,[(e?.height??f)-2,2]);return x.useLayoutEffect(()=>{if(o===null||i[o]==null||!h||!p||!u.current||!e){E();return}b({x:d(t[o]),y:a(i[o]),width:e.width,bounds:R(u.current),label:S(p).format(t[o]),lines:[h(i[o])]})}),r.jsx("div",{ref:u,style:{height:f,width:"100%",position:"relative"},"aria-hidden":c.length?!0:void 0,onPointerLeave:()=>y(null),children:c.length>0&&e&&r.jsxs(r.Fragment,{children:[r.jsx(B,{tip:M}),r.jsxs("svg",{className:"rp-activity-surface",width:e.width,height:e.height,viewBox:`0 0 ${e.width} ${e.height}`,style:{display:"block"},onPointerMove:n=>{const s=W(n,n.currentTarget,e);y(s.x<0||s.x>e.width||s.y<2||s.y>e.height-2?null:v(t.map(d),s.x))},children:[r.jsx("defs",{children:r.jsx(I,{id:g,color:l})}),r.jsx(L,{points:i.map((n,s)=>n===null?null:{x:d(t[s]),y:a(n)}),baseline:a(Math.max(0,w[0])),color:l,id:g,strokeWidth:1.5}),o!==null&&i[o]!=null&&r.jsx("circle",{cx:d(t[o]),cy:a(i[o]),r:4,fill:l,stroke:C.base,strokeWidth:2})]})]})})}export{A as SparkPlot};
|
||||
import{r as x,j as r}from"./vendor-react-Bf71BWbF.js";import{aI as k,fx as P,fy as S}from"./index-BOpK0UVB.js";import{u as T,C as B,f as W,n as v,g as j}from"./layout-Bzzn7HLw.js";import{G as I,C as L}from"./AreaCurve-BriPYJva.js";import"./array-C0P64tl-.js";function R(i){let t=i.parentElement;for(;t&&getComputedStyle(t).overflow==="visible";)t=t.parentElement;const l=i.getBoundingClientRect();if(!t)return{x:-l.left,y:-l.top,width:document.documentElement.clientWidth,height:document.documentElement.clientHeight};const h=t.getBoundingClientRect();return{x:h.left+t.clientLeft-l.left,y:h.top+t.clientTop-l.top,width:t.clientWidth,height:t.clientHeight}}function A({values:i,timestamps:t,color:l,fmt:h,locale:p,height:f=32,floor:m=0}){const g=x.useId(),C=k(),[o,y]=x.useState(null),[u,e]=P(Math.round,120),{tip:M,showAt:b,hide:E}=T(),c=i.filter(n=>n!==null),w=[m>0?0:Math.min(...c)*.85,Math.max(Math.max(...c)*1.05||1,m)],d=n=>j(n,[Math.min(...t),Math.max(...t)],[0,e?.width??0]),a=n=>j(n,w,[(e?.height??f)-2,2]);return x.useLayoutEffect(()=>{if(o===null||i[o]==null||!h||!p||!u.current||!e){E();return}b({x:d(t[o]),y:a(i[o]),width:e.width,bounds:R(u.current),label:S(p).format(t[o]),lines:[h(i[o])]})}),r.jsx("div",{ref:u,style:{height:f,width:"100%",position:"relative"},"aria-hidden":c.length?!0:void 0,onPointerLeave:()=>y(null),children:c.length>0&&e&&r.jsxs(r.Fragment,{children:[r.jsx(B,{tip:M}),r.jsxs("svg",{className:"rp-activity-surface",width:e.width,height:e.height,viewBox:`0 0 ${e.width} ${e.height}`,style:{display:"block"},onPointerMove:n=>{const s=W(n,n.currentTarget,e);y(s.x<0||s.x>e.width||s.y<2||s.y>e.height-2?null:v(t.map(d),s.x))},children:[r.jsx("defs",{children:r.jsx(I,{id:g,color:l})}),r.jsx(L,{points:i.map((n,s)=>n===null?null:{x:d(t[s]),y:a(n)}),baseline:a(Math.max(0,w[0])),color:l,id:g,strokeWidth:1.5}),o!==null&&i[o]!=null&&r.jsx("circle",{cx:d(t[o]),cy:a(i[o]),r:4,fill:l,stroke:C.base,strokeWidth:2})]})]})})}export{A as SparkPlot};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{r as f,$,b as Vt,j as E}from"./vendor-react-Bf71BWbF.js";import{eY as Ot,eZ as He,e_ as Ut,e$ as Ze,c8 as ee,f0 as _t,f1 as ie,f2 as he,f3 as ht,f4 as N,f5 as jt,f6 as Yt,f7 as ft,f8 as Xt,f9 as Ke,cz as yt,bY as ae,fa as Gt,bU as Be,bW as Y,ca as fe,bV as qt,bX as L,fb as D,fc as be,fd as Le,fe as Zt,b_ as pt,c4 as Pe,c1 as Qe,c2 as ve,c3 as Ie,c5 as J,c9 as Qt,c6 as de,c7 as ce,ff as gt,fg as Jt,fh as Je,b$ as el,fi as tl,c0 as ll,fj as il,fk as rl,cm as Se,cb as bt,cd as Ve,cc as nl,fl as Oe,cj as H,ch as me,cn as le,cE as ol,fm as al,ct as et,ci as se,fn as sl,cA as dl,cl as ye,cp as Me,cC as cl,cu as ul,cB as hl,cD as fl,cF as yl,fo as pl,ck as Ce,ce as Ue,cs as mt,co as W,fp as $t,cq as gl,cv as bl,cw as ze,fq as tt,fr as ml,fs as $l,ft as De,fu as xl,cG as wl,cH as vl,cI as Cl,u as xt,aU as lt,f as kl,j as Kl,ak as Il,bo as Rl,eP as wt,c as vt,fv as Sl,fw as Ml,aL as Dl}from"./index-Bw0aJc9a.js";import{$ as El,a as Pl,e as zl,b as Tl,c as Ct,d as kt}from"./useGridSelectionCheckbox-COXIVEmS.js";import{a as Nl,c as oe,b as ue,d as Hl}from"./Virtualizer-DCY9HC9Z.js";import{$ as Wl}from"./ListLayout-_fDlx5XY.js";function Fl(n){let{onMoveStart:e,onMove:t,onMoveEnd:l}=n,i=f.useRef({didMove:!1,lastPosition:null,id:null}),{addGlobalListener:r,removeGlobalListener:o}=Ot(),s=f.useCallback((y,g,p,h)=>{p===0&&h===0||(i.current.didMove||(i.current.didMove=!0,e?.({type:"movestart",pointerType:g,shiftKey:y.shiftKey,metaKey:y.metaKey,ctrlKey:y.ctrlKey,altKey:y.altKey})),t?.({type:"move",pointerType:g,deltaX:p,deltaY:h,shiftKey:y.shiftKey,metaKey:y.metaKey,ctrlKey:y.ctrlKey,altKey:y.altKey}))},[e,t,i]),a=He(s),d=f.useCallback((y,g)=>{Ut(),i.current.didMove&&l?.({type:"moveend",pointerType:g,shiftKey:y.shiftKey,metaKey:y.metaKey,ctrlKey:y.ctrlKey,altKey:y.altKey})},[l,i]),c=He(d);return{moveProps:f.useMemo(()=>{let y={},g=()=>{_t(),i.current.didMove=!1};{let h=b=>{if(b.pointerId===i.current.id){let k=b.pointerType||"mouse";a(b,k,b.pageX-(i.current.lastPosition?.pageX??0),b.pageY-(i.current.lastPosition?.pageY??0)),i.current.lastPosition={pageX:b.pageX,pageY:b.pageY}}},x=b=>{if(b.pointerId===i.current.id){let k=b.pointerType||"mouse";c(b,k),i.current.id=null;let w=Ze(ee(b));o(w,"pointermove",h,!1),o(w,"pointerup",x,!1),o(w,"pointercancel",x,!1)}};y.onPointerDown=b=>{if(b.button===0&&i.current.id==null){g(),b.stopPropagation(),b.preventDefault(),i.current.lastPosition={pageX:b.pageX,pageY:b.pageY},i.current.id=b.pointerId;let k=Ze(ee(b));r(k,"pointermove",h,!1),r(k,"pointerup",x,!1),r(k,"pointercancel",x,!1)}}}let p=(h,x,b)=>{g(),a(h,"keyboard",x,b),c(h,"keyboard")};return y.onKeyDown=h=>{switch(h.key){case"Left":case"ArrowLeft":h.preventDefault(),h.stopPropagation(),p(h,-1,0);break;case"Right":case"ArrowRight":h.preventDefault(),h.stopPropagation(),p(h,1,0);break;case"Up":case"ArrowUp":h.preventDefault(),h.stopPropagation(),p(h,0,-1);break;case"Down":case"ArrowDown":h.preventDefault(),h.stopPropagation(),p(h,0,1);break}},y},[r,o,i])}}const it=10,rt=5;class Al{setup(e,t,l){this.delegate=e,this.state=t,this.direction=l}getDropTargetFromPoint(e,t,l){let i=this.delegate.getDropTargetFromPoint(e,t,l);return!i||i.type==="root"?i:this.resolveDropTarget(i,e,t,l)}resolveDropTarget(e,t,l,i){let r=this.pointerTracking,o=l-r.lastY,s=t-r.lastX,a=r.yDirection,d=r.xDirection;if(Math.abs(o)>rt&&(a=o>0?"down":"up",r.yDirection=a,r.lastY=l),Math.abs(s)>it&&(d=s>0?"right":"left",r.xDirection=d,r.lastX=t),e.dropPosition==="before"){let y=this.state.collection.getKeyBefore(e.key);for(;y!=null;){let g=this.state.collection.getItem(y);if(g?.type==="item")break;y=g?.parentKey??null}if(y!=null){let g={type:"item",key:y,dropPosition:"after"};i(g)&&(e=g)}}let c=this.getPotentialTargets(e,i);if(c.length===0)return{type:"root"};let u;return c.length>1?u=this.selectTarget(c,e,t,l,a,d):(u=c[0],r.boundaryContext=null),u}getPotentialTargets(e,t){if(e.dropPosition==="on")return[e];let l=e,i=this.state.collection,r=i.getItem(l.key);for(;r&&r?.type!=="item"&&r.nextKey!=null;)l.key=r.nextKey,r=i.getItem(r.nextKey);let o=[l];if(r&&r.hasChildNodes&&this.state.expandedKeys.has(r.key)&&i.getChildren&&l.dropPosition==="after"){let d=r.firstChildKey!=null?i.getItem(r.firstChildKey):null;for(;d&&d.type!=="item";)d=d.nextKey!=null?i.getItem(d.nextKey):null;if(d?.type==="item"){const c={type:"item",key:d.key,dropPosition:"before"};return t(c)?[c]:[]}}if(r?.nextKey!=null)return[e];let s=r?.parentKey,a=[];for(;s!=null;){let d=i.getItem(s),c=d?.nextKey!=null?i.getItem(d.nextKey):null;if(!c||c.parentKey!==s){if(d?.type==="item"){let y={type:"item",key:s,dropPosition:"after"};t(y)&&a.push(y)}if(c)break}s=d?.parentKey}if(a.length>0&&o.push(...a),o.length===1){let d=i.getKeyAfter(l.key),c=d!=null?i.getItem(d):null;if(d!=null&&c&&r&&c.level!=null&&r.level!=null&&c.level>r.level){let u={type:"item",key:d,dropPosition:"before"};if(t(u))return[u]}}return o.filter(t)}selectTarget(e,t,l,i,r,o){if(e.length<2)return e[0];let s=this.pointerTracking,d=this.state.collectionLine truncated
|
||||
import{r as f,$,b as Vt,j as E}from"./vendor-react-Bf71BWbF.js";import{eY as Ot,eZ as He,e_ as Ut,e$ as Ze,c8 as ee,f0 as _t,f1 as ie,f2 as he,f3 as ht,f4 as N,f5 as jt,f6 as Yt,f7 as ft,f8 as Xt,f9 as Ke,cz as yt,bY as ae,fa as Gt,bU as Be,bW as Y,ca as fe,bV as qt,bX as L,fb as D,fc as be,fd as Le,fe as Zt,b_ as pt,c4 as Pe,c1 as Qe,c2 as ve,c3 as Ie,c5 as J,c9 as Qt,c6 as de,c7 as ce,ff as gt,fg as Jt,fh as Je,b$ as el,fi as tl,c0 as ll,fj as il,fk as rl,cm as Se,cb as bt,cd as Ve,cc as nl,fl as Oe,cj as H,ch as me,cn as le,cE as ol,fm as al,ct as et,ci as se,fn as sl,cA as dl,cl as ye,cp as Me,cC as cl,cu as ul,cB as hl,cD as fl,cF as yl,fo as pl,ck as Ce,ce as Ue,cs as mt,co as W,fp as $t,cq as gl,cv as bl,cw as ze,fq as tt,fr as ml,fs as $l,ft as De,fu as xl,cG as wl,cH as vl,cI as Cl,u as xt,aU as lt,f as kl,j as Kl,ak as Il,bo as Rl,eP as wt,c as vt,fv as Sl,fw as Ml,aL as Dl}from"./index-BOpK0UVB.js";import{$ as El,a as Pl,e as zl,b as Tl,c as Ct,d as kt}from"./useGridSelectionCheckbox-C4VxQajJ.js";import{a as Nl,c as oe,b as ue,d as Hl}from"./Virtualizer-BIsXGNLZ.js";import{$ as Wl}from"./ListLayout-CkBMjK9o.js";function Fl(n){let{onMoveStart:e,onMove:t,onMoveEnd:l}=n,i=f.useRef({didMove:!1,lastPosition:null,id:null}),{addGlobalListener:r,removeGlobalListener:o}=Ot(),s=f.useCallback((y,g,p,h)=>{p===0&&h===0||(i.current.didMove||(i.current.didMove=!0,e?.({type:"movestart",pointerType:g,shiftKey:y.shiftKey,metaKey:y.metaKey,ctrlKey:y.ctrlKey,altKey:y.altKey})),t?.({type:"move",pointerType:g,deltaX:p,deltaY:h,shiftKey:y.shiftKey,metaKey:y.metaKey,ctrlKey:y.ctrlKey,altKey:y.altKey}))},[e,t,i]),a=He(s),d=f.useCallback((y,g)=>{Ut(),i.current.didMove&&l?.({type:"moveend",pointerType:g,shiftKey:y.shiftKey,metaKey:y.metaKey,ctrlKey:y.ctrlKey,altKey:y.altKey})},[l,i]),c=He(d);return{moveProps:f.useMemo(()=>{let y={},g=()=>{_t(),i.current.didMove=!1};{let h=b=>{if(b.pointerId===i.current.id){let k=b.pointerType||"mouse";a(b,k,b.pageX-(i.current.lastPosition?.pageX??0),b.pageY-(i.current.lastPosition?.pageY??0)),i.current.lastPosition={pageX:b.pageX,pageY:b.pageY}}},x=b=>{if(b.pointerId===i.current.id){let k=b.pointerType||"mouse";c(b,k),i.current.id=null;let w=Ze(ee(b));o(w,"pointermove",h,!1),o(w,"pointerup",x,!1),o(w,"pointercancel",x,!1)}};y.onPointerDown=b=>{if(b.button===0&&i.current.id==null){g(),b.stopPropagation(),b.preventDefault(),i.current.lastPosition={pageX:b.pageX,pageY:b.pageY},i.current.id=b.pointerId;let k=Ze(ee(b));r(k,"pointermove",h,!1),r(k,"pointerup",x,!1),r(k,"pointercancel",x,!1)}}}let p=(h,x,b)=>{g(),a(h,"keyboard",x,b),c(h,"keyboard")};return y.onKeyDown=h=>{switch(h.key){case"Left":case"ArrowLeft":h.preventDefault(),h.stopPropagation(),p(h,-1,0);break;case"Right":case"ArrowRight":h.preventDefault(),h.stopPropagation(),p(h,1,0);break;case"Up":case"ArrowUp":h.preventDefault(),h.stopPropagation(),p(h,0,-1);break;case"Down":case"ArrowDown":h.preventDefault(),h.stopPropagation(),p(h,0,1);break}},y},[r,o,i])}}const it=10,rt=5;class Al{setup(e,t,l){this.delegate=e,this.state=t,this.direction=l}getDropTargetFromPoint(e,t,l){let i=this.delegate.getDropTargetFromPoint(e,t,l);return!i||i.type==="root"?i:this.resolveDropTarget(i,e,t,l)}resolveDropTarget(e,t,l,i){let r=this.pointerTracking,o=l-r.lastY,s=t-r.lastX,a=r.yDirection,d=r.xDirection;if(Math.abs(o)>rt&&(a=o>0?"down":"up",r.yDirection=a,r.lastY=l),Math.abs(s)>it&&(d=s>0?"right":"left",r.xDirection=d,r.lastX=t),e.dropPosition==="before"){let y=this.state.collection.getKeyBefore(e.key);for(;y!=null;){let g=this.state.collection.getItem(y);if(g?.type==="item")break;y=g?.parentKey??null}if(y!=null){let g={type:"item",key:y,dropPosition:"after"};i(g)&&(e=g)}}let c=this.getPotentialTargets(e,i);if(c.length===0)return{type:"root"};let u;return c.length>1?u=this.selectTarget(c,e,t,l,a,d):(u=c[0],r.boundaryContext=null),u}getPotentialTargets(e,t){if(e.dropPosition==="on")return[e];let l=e,i=this.state.collection,r=i.getItem(l.key);for(;r&&r?.type!=="item"&&r.nextKey!=null;)l.key=r.nextKey,r=i.getItem(r.nextKey);let o=[l];if(r&&r.hasChildNodes&&this.state.expandedKeys.has(r.key)&&i.getChildren&&l.dropPosition==="after"){let d=r.firstChildKey!=null?i.getItem(r.firstChildKey):null;for(;d&&d.type!=="item";)d=d.nextKey!=null?i.getItem(d.nextKey):null;if(d?.type==="item"){const c={type:"item",key:d.key,dropPosition:"before"};return t(c)?[c]:[]}}if(r?.nextKey!=null)return[e];let s=r?.parentKey,a=[];for(;s!=null;){let d=i.getItem(s),c=d?.nextKey!=null?i.getItem(d.nextKey):null;if(!c||c.parentKey!==s){if(d?.type==="item"){let y={type:"item",key:s,dropPosition:"after"};t(y)&&a.push(y)}if(c)break}s=d?.parentKey}if(a.length>0&&o.push(...a),o.length===1){let d=i.getKeyAfter(l.key),c=d!=null?i.getItem(d):null;if(d!=null&&c&&r&&c.level!=null&&r.level!=null&&c.level>r.level){let u={type:"item",key:d,dropPosition:"before"};if(t(u))return[u]}}return o.filter(t)}selectTarget(e,t,l,i,r,o){if(e.length<2)return e[0];let s=this.pointerTracking,d=this.state.collectionLine truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{j as s}from"./vendor-react-Bf71BWbF.js";import{a6 as t,a as r,eO as i,aL as l,eN as n,aw as m}from"./index-Bw0aJc9a.js";function p({at:e}){const o=t[r()],a=i();return s.jsx(l,{text:e?m(e,o):void 0,children:n(e,o,a)})}export{p as T};
|
||||
import{j as s}from"./vendor-react-Bf71BWbF.js";import{a6 as t,a as r,eO as i,aL as l,eN as n,aw as m}from"./index-BOpK0UVB.js";function p({at:e}){const o=t[r()],a=i();return s.jsx(l,{text:e?m(e,o):void 0,children:n(e,o,a)})}export{p as T};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{bY as H,c8 as te,ca as ie,fz as ne,fA as le,c3 as se,eZ as F,fq as _,fs as re,fB as oe,cj as ae,fC as he}from"./index-Bw0aJc9a.js";import{r as f,$ as z,a as M}from"./vendor-react-Bf71BWbF.js";class x{constructor(e=0,t=0){this.x=e,this.y=t}copy(){return new x(this.x,this.y)}equals(e){return this.x===e.x&&this.y===e.y}isOrigin(){return this.x===0&&this.y===0}}class y{constructor(e=0,t=0,i=0,n=0){this.x=e,this.y=t,this.width=i,this.height=n}get maxX(){return this.x+this.width}get maxY(){return this.y+this.height}get area(){return this.width*this.height}get topLeft(){return new x(this.x,this.y)}get topRight(){return new x(this.maxX,this.y)}get bottomLeft(){return new x(this.x,this.maxY)}get bottomRight(){return new x(this.maxX,this.maxY)}intersects(e){return this.area>0&&e.area>0&&this.x<=e.x+e.width&&e.x<=this.x+this.width&&this.y<=e.y+e.height&&e.y<=this.y+this.height}containsRect(e){return this.x<=e.x&&this.y<=e.y&&this.maxX>=e.maxX&&this.maxY>=e.maxY}containsPoint(e){return this.x<=e.x&&this.y<=e.y&&this.maxX>=e.x&&this.maxY>=e.y}getCornerInRect(e){for(let t of["topLeft","topRight","bottomLeft","bottomRight"])if(e.containsPoint(this[t]))return t;return null}equals(e){return e.x===this.x&&e.y===this.y&&e.width===this.width&&e.height===this.height}pointEquals(e){return this.x===e.x&&this.y===e.y}sizeEquals(e){return this.width===e.width&&this.height===e.height}union(e){let t=Math.min(this.x,e.x),i=Math.min(this.y,e.y),n=Math.max(this.maxX,e.maxX)-t,s=Math.max(this.maxY,e.maxY)-i;return new y(t,i,n,s)}intersection(e){if(!this.intersects(e))return new y(0,0,0,0);let t=Math.max(this.x,e.x),i=Math.max(this.y,e.y);return new y(t,i,Math.min(this.maxX,e.maxX)-t,Math.min(this.maxY,e.maxY)-i)}copy(){return new y(this.x,this.y,this.width,this.height)}}class b{constructor(e=0,t=0){this.width=Math.max(e,0),this.height=Math.max(t,0)}copy(){return new b(this.width,this.height)}equals(e){return this.width===e.width&&this.height===e.height}get area(){return this.width*this.height}}let ce=0;class B{constructor(e,t){this.virtualizer=e,this.key=++ce,this.viewType=t,this.children=new Set,this.reusableViews=new Map,this.layoutInfo=null,this.content=null,this.rendered=null}prepareForReuse(){this.content=null,this.rendered=null,this.layoutInfo=null}getReusableView(e){let t=this.reusableViews.get(e);return t&&t.length>0?t.shift():new de(this.virtualizer,this,e)}reuseChild(e){e.prepareForReuse();let t=this.reusableViews.get(e.viewType);t||(t=[],this.reusableViews.set(e.viewType,t)),t.push(e)}}class ue extends B{constructor(e){super(e,"root")}}class de extends B{constructor(e,t,i){super(e,i),this.parent=t}}function fe(l,e){if(l===e)return!0;if(l.size!==e.size)return!1;for(let t of l)if(!e.has(t))return!1;return!0}class ye{setVisibleRect(e){let t=performance.now()-this.startTime;t<500&&(e.x!==this.visibleRect.x&&t>0&&(this.velocity.x=(e.x-this.visibleRect.x)/t),e.y!==this.visibleRect.y&&t>0&&(this.velocity.y=(e.y-this.visibleRect.y)/t)),this.startTime=performance.now(),this.visibleRect=e}getOverscannedRect(){let e=this.visibleRect.copy(),t=this.visibleRect.height/3;e.height+=t,this.velocity.y<0&&(e.y-=t);let i=this.visibleRect.width/3;return e.width+=i,this.velocity.x<0&&(e.x-=i),e}constructor(){this.startTime=0,this.velocity=new x(0,0),this.visibleRect=new y}}const we=4;function T(l){return l==="x"?"width":"height"}function ge(l,e,t,i,n){let s=t(l.key);if(!s)return null;let a=s.rect[l.corner][e]-i[e]-l.offset;if(a===0)return null;let h=i[e]+a,r=T(e),d=Math.max(0,n[r]-i[r]),u=Math.max(0,Math.min(d,h));return u!==i[e]?u:null}function ve(l,e,t,i,n=()=>!0){let s=T(e),a=null;for(let[h,r]of i){if(!r||!n(r))continue;let d=r.rect.intersection(t)[s];if(r.rect.area>0&&d>=we){let u=r.rect.getCornerInRect(t)??"topLeft",c=r.rect[u][e]-t[e];(!a||(l==="end"?c<a.offset:c>a.offset))&&(a={key:h,corner:u,offset:c})}}return a}function be(l,e,t,i){if(l==="start")return 0;let n=T(e);return Math.max(0,t[n]-i[n])}function X(l,e,t,i,n){if(t==="start")return l[i]<=n;let s=T(i);return e[s]-(l[i]+l[s])<=n}function pe(l,e,t,i,n,s,a,h,r,d){let u=c=>e==="x"?new y(c,r.y,r.width,r.height):new y(r.x,c,r.width,r.height);if(t){let c=ge(t,e,h,r,d);if(c!=null)return u(c)}if(i&&!n&&(!s||a>0)){let c=u(be(l,e,d,r));return c.equals(r)?null:c}return null}class me{reset(){this.hasSnappedToEdge=!1,this.hadEstimatedVisibleItems=!1,this.wasNearAnchorEdge=!1}captureBeforeLayout(e,t,i){return e?ve(e.edge,e.axis,i,t,e.isAnchorable):null}resolveAfterLayout(e){let{anchorInfo:t,anchor:i,postLayoutInfos:n,previousVisibleRect:s,previousContentSize:a,contentSize:h,itemSizeChanged:r,isScrolling:d,getLayoutInfo:u}=e;if(!t)return null;let c=this.hadEstimatedVisibleItems,o=this.wasNearAnchorEdge,m=!1;for(let V of n.values())if(V.estimatedSize){m=!0;break}if(this.hadEstimatedVisibleItems=m,c||(this.wasNearAnchorEdge=X(s,a,t.edge,t.axis,t.threshold)),s.area===0)return null;let w=t.axis==="x"?"width":"height",S=h[w]-a[w],$=!this.hasSnappedToEdge;if(this.hasSnappedToEdge=!0,!($||S!==0||r))Line truncated
|
||||
import{bY as H,c8 as te,ca as ie,fz as ne,fA as le,c3 as se,eZ as F,fq as _,fs as re,fB as oe,cj as ae,fC as he}from"./index-BOpK0UVB.js";import{r as f,$ as z,a as M}from"./vendor-react-Bf71BWbF.js";class x{constructor(e=0,t=0){this.x=e,this.y=t}copy(){return new x(this.x,this.y)}equals(e){return this.x===e.x&&this.y===e.y}isOrigin(){return this.x===0&&this.y===0}}class y{constructor(e=0,t=0,i=0,n=0){this.x=e,this.y=t,this.width=i,this.height=n}get maxX(){return this.x+this.width}get maxY(){return this.y+this.height}get area(){return this.width*this.height}get topLeft(){return new x(this.x,this.y)}get topRight(){return new x(this.maxX,this.y)}get bottomLeft(){return new x(this.x,this.maxY)}get bottomRight(){return new x(this.maxX,this.maxY)}intersects(e){return this.area>0&&e.area>0&&this.x<=e.x+e.width&&e.x<=this.x+this.width&&this.y<=e.y+e.height&&e.y<=this.y+this.height}containsRect(e){return this.x<=e.x&&this.y<=e.y&&this.maxX>=e.maxX&&this.maxY>=e.maxY}containsPoint(e){return this.x<=e.x&&this.y<=e.y&&this.maxX>=e.x&&this.maxY>=e.y}getCornerInRect(e){for(let t of["topLeft","topRight","bottomLeft","bottomRight"])if(e.containsPoint(this[t]))return t;return null}equals(e){return e.x===this.x&&e.y===this.y&&e.width===this.width&&e.height===this.height}pointEquals(e){return this.x===e.x&&this.y===e.y}sizeEquals(e){return this.width===e.width&&this.height===e.height}union(e){let t=Math.min(this.x,e.x),i=Math.min(this.y,e.y),n=Math.max(this.maxX,e.maxX)-t,s=Math.max(this.maxY,e.maxY)-i;return new y(t,i,n,s)}intersection(e){if(!this.intersects(e))return new y(0,0,0,0);let t=Math.max(this.x,e.x),i=Math.max(this.y,e.y);return new y(t,i,Math.min(this.maxX,e.maxX)-t,Math.min(this.maxY,e.maxY)-i)}copy(){return new y(this.x,this.y,this.width,this.height)}}class b{constructor(e=0,t=0){this.width=Math.max(e,0),this.height=Math.max(t,0)}copy(){return new b(this.width,this.height)}equals(e){return this.width===e.width&&this.height===e.height}get area(){return this.width*this.height}}let ce=0;class B{constructor(e,t){this.virtualizer=e,this.key=++ce,this.viewType=t,this.children=new Set,this.reusableViews=new Map,this.layoutInfo=null,this.content=null,this.rendered=null}prepareForReuse(){this.content=null,this.rendered=null,this.layoutInfo=null}getReusableView(e){let t=this.reusableViews.get(e);return t&&t.length>0?t.shift():new de(this.virtualizer,this,e)}reuseChild(e){e.prepareForReuse();let t=this.reusableViews.get(e.viewType);t||(t=[],this.reusableViews.set(e.viewType,t)),t.push(e)}}class ue extends B{constructor(e){super(e,"root")}}class de extends B{constructor(e,t,i){super(e,i),this.parent=t}}function fe(l,e){if(l===e)return!0;if(l.size!==e.size)return!1;for(let t of l)if(!e.has(t))return!1;return!0}class ye{setVisibleRect(e){let t=performance.now()-this.startTime;t<500&&(e.x!==this.visibleRect.x&&t>0&&(this.velocity.x=(e.x-this.visibleRect.x)/t),e.y!==this.visibleRect.y&&t>0&&(this.velocity.y=(e.y-this.visibleRect.y)/t)),this.startTime=performance.now(),this.visibleRect=e}getOverscannedRect(){let e=this.visibleRect.copy(),t=this.visibleRect.height/3;e.height+=t,this.velocity.y<0&&(e.y-=t);let i=this.visibleRect.width/3;return e.width+=i,this.velocity.x<0&&(e.x-=i),e}constructor(){this.startTime=0,this.velocity=new x(0,0),this.visibleRect=new y}}const we=4;function T(l){return l==="x"?"width":"height"}function ge(l,e,t,i,n){let s=t(l.key);if(!s)return null;let a=s.rect[l.corner][e]-i[e]-l.offset;if(a===0)return null;let h=i[e]+a,r=T(e),d=Math.max(0,n[r]-i[r]),u=Math.max(0,Math.min(d,h));return u!==i[e]?u:null}function ve(l,e,t,i,n=()=>!0){let s=T(e),a=null;for(let[h,r]of i){if(!r||!n(r))continue;let d=r.rect.intersection(t)[s];if(r.rect.area>0&&d>=we){let u=r.rect.getCornerInRect(t)??"topLeft",c=r.rect[u][e]-t[e];(!a||(l==="end"?c<a.offset:c>a.offset))&&(a={key:h,corner:u,offset:c})}}return a}function be(l,e,t,i){if(l==="start")return 0;let n=T(e);return Math.max(0,t[n]-i[n])}function X(l,e,t,i,n){if(t==="start")return l[i]<=n;let s=T(i);return e[s]-(l[i]+l[s])<=n}function pe(l,e,t,i,n,s,a,h,r,d){let u=c=>e==="x"?new y(c,r.y,r.width,r.height):new y(r.x,c,r.width,r.height);if(t){let c=ge(t,e,h,r,d);if(c!=null)return u(c)}if(i&&!n&&(!s||a>0)){let c=u(be(l,e,d,r));return c.equals(r)?null:c}return null}class me{reset(){this.hasSnappedToEdge=!1,this.hadEstimatedVisibleItems=!1,this.wasNearAnchorEdge=!1}captureBeforeLayout(e,t,i){return e?ve(e.edge,e.axis,i,t,e.isAnchorable):null}resolveAfterLayout(e){let{anchorInfo:t,anchor:i,postLayoutInfos:n,previousVisibleRect:s,previousContentSize:a,contentSize:h,itemSizeChanged:r,isScrolling:d,getLayoutInfo:u}=e;if(!t)return null;let c=this.hadEstimatedVisibleItems,o=this.wasNearAnchorEdge,m=!1;for(let V of n.values())if(V.estimatedSize){m=!0;break}if(this.hadEstimatedVisibleItems=m,c||(this.wasNearAnchorEdge=X(s,a,t.edge,t.axis,t.threshold)),s.area===0)return null;let w=t.axis==="x"?"width":"height",S=h[w]-a[w],$=!this.hasSnappedToEdge;if(this.hasSnappedToEdge=!0,!($||S!==0||r))Line truncated
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./auth-BReGn39D.js","./index-Bw0aJc9a.js","./vendor-react-Bf71BWbF.js","./index-7R3bVGRM.css"])))=>i.map(i=>d[i]);
|
||||
import{i as r,eT as s,eU as c,dN as u,_ as d}from"./index-Bw0aJc9a.js";const n=(o,e)=>new URL(o.replace(/\/+$/,"")+e,globalThis.location?.href),p=()=>d(()=>import("./auth-BReGn39D.js"),__vite__mapDeps([0,1,2,3]),import.meta.url),w={username:"demo",password:"demo"};async function l(o,e){if(r(o))return(await p()).mockDiscovery();const t=await s(n(o,"/api"),{headers:{Accept:"application/json"},cache:"no-store",signal:e});if(!t.ok)throw await c(t);const a=await t.json();if(a.name==="dae/honk-native")throw new u("login.engineOutdated");return a.auth}async function f(o,e){return(await s(n(o,"/api/v1/capabilities"),{headers:{Accept:"application/json"},cache:"no-store",signal:e})).status!==404}function m(o){return o.mode!=="password"?"token":o.setup_required?"setup":"login"}async function A(o,e,t,a){if(r(o))return(await p()).mockOpenSession(e,t);const i=await s(n(o,`/api/v1/auth/${e}`),{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(t),cache:"no-store",signal:a},e==="setup");if(!i.ok)throw await c(i);return i.json()}async function v(o,e,t){if(r(o))return;const a=await s(n(o,"/api/v1/auth/logout"),{method:"POST",headers:{Accept:"application/json",Authorization:"Bearer "+e},cache:"no-store",signal:t});if(!a.ok&&a.status!==401)throw await c(a)}export{w as D,f as a,v as c,l as d,A as o,m as s};
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./auth-DTgOavf4.js","./index-BOpK0UVB.js","./vendor-react-Bf71BWbF.js","./index-tAbIWhIz.css"])))=>i.map(i=>d[i]);
|
||||
import{i as r,eT as s,eU as c,dN as u,_ as d}from"./index-BOpK0UVB.js";const n=(o,e)=>new URL(o.replace(/\/+$/,"")+e,globalThis.location?.href),p=()=>d(()=>import("./auth-DTgOavf4.js"),__vite__mapDeps([0,1,2,3]),import.meta.url),w={username:"demo",password:"demo"};async function l(o,e){if(r(o))return(await p()).mockDiscovery();const t=await s(n(o,"/api"),{headers:{Accept:"application/json"},cache:"no-store",signal:e});if(!t.ok)throw await c(t);const a=await t.json();if(a.name==="dae/honk-native")throw new u("login.engineOutdated");return a.auth}async function f(o,e){return(await s(n(o,"/api/v1/capabilities"),{headers:{Accept:"application/json"},cache:"no-store",signal:e})).status!==404}function m(o){return o.mode!=="password"?"token":o.setup_required?"setup":"login"}async function A(o,e,t,a){if(r(o))return(await p()).mockOpenSession(e,t);const i=await s(n(o,`/api/v1/auth/${e}`),{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(t),cache:"no-store",signal:a},e==="setup");if(!i.ok)throw await c(i);return i.json()}async function v(o,e,t){if(r(o))return;const a=await s(n(o,"/api/v1/auth/logout"),{method:"POST",headers:{Accept:"application/json",Authorization:"Bearer "+e},cache:"no-store",signal:t});if(!a.ok&&a.status!==401)throw await c(a)}export{w as D,f as a,v as c,l as d,A as o,m as s};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{D as i}from"./auth-DzCdgIKH.js";import{A as r,o as p}from"./index-Bw0aJc9a.js";import"./vendor-react-Bf71BWbF.js";const a="demo-session-",l=12*36e5;function u(){return{mode:"password",setup_required:!1}}const c={auth_setup:"/api/v1/auth/setup",auth_login:"/api/v1/auth/login"};function w(e,t){if(e==="setup")throw new r(409,"setup_already_completed","Setup already completed");if(t.username!==i.username||t.password!==i.password)throw new r(401,"invalid_credentials","Invalid credentials");return{token:a+p(),expires_at:new Date(Date.now()+l).toISOString()}}function v(e){return!!e?.startsWith(a)}function y(e){return{...e,discovery:async t=>{const o=await e.discovery(t);return"status"in o?{...o,links:{...o.links,...c,auth_logout:"/api/v1/auth/logout"},auth:{...u(),anonymous_loopback:!1}}:o}}}function _(e){const t=()=>Promise.reject(new r(401,"authentication_required","Authentication required")),o=async n=>(n?.throwIfAborted(),{name:"daeuniverse/native",api_major:1,links:{...c},auth:u()});return new Proxy(e,{get:(n,s,d)=>s==="discovery"?o:typeof Reflect.get(n,s,d)=="function"?t:void 0})}export{u as mockDiscovery,w as mockOpenSession,v as mockSessionValid,_ as refuseWithoutSession,y as withPasswordAuth};
|
||||
import{D as i}from"./auth-DKKBdTVr.js";import{A as r,o as p}from"./index-BOpK0UVB.js";import"./vendor-react-Bf71BWbF.js";const a="demo-session-",l=12*36e5;function u(){return{mode:"password",setup_required:!1}}const c={auth_setup:"/api/v1/auth/setup",auth_login:"/api/v1/auth/login"};function w(e,t){if(e==="setup")throw new r(409,"setup_already_completed","Setup already completed");if(t.username!==i.username||t.password!==i.password)throw new r(401,"invalid_credentials","Invalid credentials");return{token:a+p(),expires_at:new Date(Date.now()+l).toISOString()}}function v(e){return!!e?.startsWith(a)}function y(e){return{...e,discovery:async t=>{const o=await e.discovery(t);return"status"in o?{...o,links:{...o.links,...c,auth_logout:"/api/v1/auth/logout"},auth:{...u(),anonymous_loopback:!1}}:o}}}function _(e){const t=()=>Promise.reject(new r(401,"authentication_required","Authentication required")),o=async n=>(n?.throwIfAborted(),{name:"daeuniverse/native",api_major:1,links:{...c},auth:u()});return new Proxy(e,{get:(n,s,d)=>s==="discovery"?o:typeof Reflect.get(n,s,d)=="function"?t:void 0})}export{u as mockDiscovery,w as mockOpenSession,v as mockSessionValid,_ as refuseWithoutSession,y as withPasswordAuth};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{r as m}from"./vendor-react-Bf71BWbF.js";import{bG as h,bH as g,aa as b,dI as w,ac as _,dK as L,A as C,W as v,cQ as y,dM as M,eV as E}from"./index-Bw0aJc9a.js";const x=100;function G(t){const s=L(t,t?.resources.dns_log.max_page_size);return s===void 0?void 0:Math.min(x,s)}async function z(t,s,n){try{return{page:await t(s),limit:s.limit}}catch(e){const{limit:a}=s;if(!(e instanceof C&&e.status===503&&e.code==="snapshot_unavailable"&&e.retryAfter!==null)||a===void 0||a<2)throw e;await v(e.retryAfter,n);const r=Math.ceil(a/4);return{page:await t({...s,limit:r}),limit:r}}}async function I(t,s){const n=()=>M(e=>t.dnsCache({cursor:e,limit:E,detail:"summary"},s),(e,a)=>e?(e.entries.push(...a.entries),e):{...a,entries:[...a.entries]});try{return await n()}catch(e){if(!(e instanceof C&&e.status===503&&e.code==="snapshot_unavailable"&&e.transient))throw e;return await v(e.retryAfter,s),n()}}function U(){const t=h(),{busy:s,run:n,cancel:e}=g({rethrow:!0});return{busy:s!==null,cancel:e,flush:m.useCallback(()=>n("flush",a=>A(t,a)),[t,n])}}function F(t,s=!0){const n=h(),e=t.name?.trim()||void 0,a=t.type&&t.type!=="all"?t.type:void 0,c=t.src?.trim()||void 0,r=b().data,o=G(r),i=w({key:["dnsLog",{name:e,type:a,src:c,limit:o}],fetch:async u=>{const l=await z(f=>n.dnsLog(f,u),{name:e,type:a,src:c,limit:o},u);return{...l.page,limit:l.limit}}},{enabled:s});return{...i,limit:i.data?i.data.limit:o}}const p=new WeakMap,d=new WeakMap;async function P(t,s){const n=d.get(t)??0,e=await I(t,s);return(d.get(t)??0)===n&&p.set(t,{at:Date.now(),list:{...e,entries:[]}}),e}const k=t=>{d.set(t,(d.get(t)??0)+1),p.delete(t)};function A(t,s){return t.flushDnsCache(s).finally(()=>k(t))}function S(t,s,n){return t.deleteDnsEntry(s,n).finally(()=>k(t))}function W(t,s){const n=p.get(t);return n&&Date.now()-n.at<y.background?Promise.resolve(n.list):t.dnsCache({limit:1,detail:"summary"},s)}function N(t=!0,s=!1){const n=h();return w({key:["dnsCache"],every:y.lists,fetch:e=>P(n,e)},{enabled:t,paused:s})}function H(t=!0,s=!1){const n=h();return w({key:["dnsCache",{usage:!0}],every:y.background,fetch:e=>W(n,e)},{enabled:t,paused:s})}function K(t=!1){const s=h(),n=b(),e=n.data?.resources,a=N(_(e,"dns_cache",{whileLoading:!1})&&!!e?.dns_cache.read,t),{refetch:c}=a,{busy:r,error:o,run:i,cancel:u}=g({rethrow:!0});return{capabilities:n,cache:a,busy:r,error:o,cancel:u,remove:m.useCallback(l=>i(l,async f=>{const D=await S(s,l,f);return c(),D}),[s,i,c]),flush:m.useCallback(()=>i("flush",async l=>{const f=await A(s,l);return c(),f}),[s,i,c])}}async function Q(t,s,n,e,a){const c=Math.max(1,Math.floor(e));let r;for(let o=0;o<n.length;o+=c){a.throwIfAborted();const i=n.slice(o,o+c),u=await t(s,i,a);a.throwIfAborted(),r?r.results.push(...u.results):r={...u,results:[...u.results]}}if(!r)throw new Error("DNS query requires at least one record type");return r}export{K as a,H as b,U as c,Q as q,F as u};
|
||||
import{r as m}from"./vendor-react-Bf71BWbF.js";import{bG as h,bH as g,aa as b,dI as w,ac as _,dK as L,A as C,W as v,cQ as y,dM as M,eV as E}from"./index-BOpK0UVB.js";const x=100;function G(t){const s=L(t,t?.resources.dns_log.max_page_size);return s===void 0?void 0:Math.min(x,s)}async function z(t,s,n){try{return{page:await t(s),limit:s.limit}}catch(e){const{limit:a}=s;if(!(e instanceof C&&e.status===503&&e.code==="snapshot_unavailable"&&e.retryAfter!==null)||a===void 0||a<2)throw e;await v(e.retryAfter,n);const r=Math.ceil(a/4);return{page:await t({...s,limit:r}),limit:r}}}async function I(t,s){const n=()=>M(e=>t.dnsCache({cursor:e,limit:E,detail:"summary"},s),(e,a)=>e?(e.entries.push(...a.entries),e):{...a,entries:[...a.entries]});try{return await n()}catch(e){if(!(e instanceof C&&e.status===503&&e.code==="snapshot_unavailable"&&e.transient))throw e;return await v(e.retryAfter,s),n()}}function U(){const t=h(),{busy:s,run:n,cancel:e}=g({rethrow:!0});return{busy:s!==null,cancel:e,flush:m.useCallback(()=>n("flush",a=>A(t,a)),[t,n])}}function F(t,s=!0){const n=h(),e=t.name?.trim()||void 0,a=t.type&&t.type!=="all"?t.type:void 0,c=t.src?.trim()||void 0,r=b().data,o=G(r),i=w({key:["dnsLog",{name:e,type:a,src:c,limit:o}],fetch:async u=>{const l=await z(f=>n.dnsLog(f,u),{name:e,type:a,src:c,limit:o},u);return{...l.page,limit:l.limit}}},{enabled:s});return{...i,limit:i.data?i.data.limit:o}}const p=new WeakMap,d=new WeakMap;async function P(t,s){const n=d.get(t)??0,e=await I(t,s);return(d.get(t)??0)===n&&p.set(t,{at:Date.now(),list:{...e,entries:[]}}),e}const k=t=>{d.set(t,(d.get(t)??0)+1),p.delete(t)};function A(t,s){return t.flushDnsCache(s).finally(()=>k(t))}function S(t,s,n){return t.deleteDnsEntry(s,n).finally(()=>k(t))}function W(t,s){const n=p.get(t);return n&&Date.now()-n.at<y.background?Promise.resolve(n.list):t.dnsCache({limit:1,detail:"summary"},s)}function N(t=!0,s=!1){const n=h();return w({key:["dnsCache"],every:y.lists,fetch:e=>P(n,e)},{enabled:t,paused:s})}function H(t=!0,s=!1){const n=h();return w({key:["dnsCache",{usage:!0}],every:y.background,fetch:e=>W(n,e)},{enabled:t,paused:s})}function K(t=!1){const s=h(),n=b(),e=n.data?.resources,a=N(_(e,"dns_cache",{whileLoading:!1})&&!!e?.dns_cache.read,t),{refetch:c}=a,{busy:r,error:o,run:i,cancel:u}=g({rethrow:!0});return{capabilities:n,cache:a,busy:r,error:o,cancel:u,remove:m.useCallback(l=>i(l,async f=>{const D=await S(s,l,f);return c(),D}),[s,i,c]),flush:m.useCallback(()=>i("flush",async l=>{const f=await A(s,l);return c(),f}),[s,i,c])}}async function Q(t,s,n,e,a){const c=Math.max(1,Math.floor(e));let r;for(let o=0;o<n.length;o+=c){a.throwIfAborted();const i=n.slice(o,o+c),u=await t(s,i,a);a.throwIfAborted(),r?r.results.push(...u.results):r={...u,results:[...u.results]}}if(!r)throw new Error("DNS query requires at least one record type");return r}export{K as a,H as b,U as c,Q as q,F as u};
|
||||
Loaded 100 of 206 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user