s
This commit is contained in:
@@ -95,6 +95,8 @@ NEKO_WEBRTC_UDPMUX_1=52300
|
||||
NEKO_WEBRTC_UDPMUX_2=52301
|
||||
NEKO_WEBRTC_UDPMUX_3=52302
|
||||
NEKO_WEBRTC_NAT1TO1=
|
||||
# 后台 watcher 会定期核对当前 LAN IP;若板子切换 Wi‑Fi / DHCP 后 IP 变化,会自动重启 Neko 刷新 WebRTC NAT 地址
|
||||
NEKO_IP_WATCH_INTERVAL=15
|
||||
NEKO_PLUGINS_ENABLED=true
|
||||
|
||||
# Redroid Android 13(需要 binderfs 或 /dev/binder*;安装脚本会在支持的内核上自动准备)
|
||||
|
||||
@@ -30,6 +30,7 @@ configure_sudoers
|
||||
configure_mdns
|
||||
install_browser_stack
|
||||
install_neko_browser
|
||||
install_neko_ip_watch_service
|
||||
install_redroid
|
||||
prepare_mitmproxy
|
||||
prepare_vscode_server
|
||||
|
||||
@@ -29,6 +29,7 @@ configure_wifi_profile
|
||||
install_shellcrash
|
||||
install_browser_stack
|
||||
install_neko_browser
|
||||
install_neko_ip_watch_service
|
||||
install_redroid
|
||||
prepare_mitmproxy
|
||||
prepare_vscode_server
|
||||
|
||||
@@ -777,6 +777,36 @@ UNIT
|
||||
systemctl enable --now live-console.service
|
||||
}
|
||||
|
||||
install_neko_ip_watch_service() {
|
||||
if [ "${ENABLE_NEKO:-1}" != "1" ]; then
|
||||
systemctl disable --now live-neko-ip-watch.service >/dev/null 2>&1 || true
|
||||
rm -f /etc/systemd/system/live-neko-ip-watch.service
|
||||
systemctl daemon-reload
|
||||
return 0
|
||||
fi
|
||||
log "Installing Neko LAN IP watcher"
|
||||
chmod +x "$ROOT_DIR/scripts/linux/neko_ip_watch.sh"
|
||||
cat >/etc/systemd/system/live-neko-ip-watch.service <<UNIT
|
||||
[Unit]
|
||||
Description=Live Neko LAN IP watcher
|
||||
After=network-online.target docker.service
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=$ROOT_DIR
|
||||
Environment=NEKO_IP_WATCH_INTERVAL=${NEKO_IP_WATCH_INTERVAL:-15}
|
||||
ExecStart=/bin/bash $ROOT_DIR/scripts/linux/neko_ip_watch.sh
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
UNIT
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now live-neko-ip-watch.service
|
||||
}
|
||||
|
||||
configure_sudoers() {
|
||||
log "Configuring sudoers for live control plane"
|
||||
cat >/etc/sudoers.d/live-control-plane <<SUDOERS
|
||||
|
||||
101
d2ypp2/scripts/linux/neko_ip_watch.sh
Normal file
101
d2ypp2/scripts/linux/neko_ip_watch.sh
Normal file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SELF_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
INSTALL_TAG="${INSTALL_TAG:-neko-ip-watch}"
|
||||
. "$SELF_DIR/lib/common.sh"
|
||||
|
||||
reload_watch_env() {
|
||||
unset ENABLE_NEKO NEKO_IP_WATCH_INTERVAL
|
||||
if [ -f "$STACK_ENV" ]; then
|
||||
set -a
|
||||
. "$STACK_ENV"
|
||||
set +a
|
||||
fi
|
||||
ENABLE_NEKO="${ENABLE_NEKO:-1}"
|
||||
NEKO_IP_WATCH_INTERVAL="${NEKO_IP_WATCH_INTERVAL:-15}"
|
||||
}
|
||||
|
||||
normalize_interval() {
|
||||
local value="${1:-15}"
|
||||
case "$value" in
|
||||
''|*[!0-9]*)
|
||||
value=15
|
||||
;;
|
||||
esac
|
||||
if [ "$value" -lt 5 ]; then
|
||||
value=5
|
||||
fi
|
||||
printf '%s\n' "$value"
|
||||
}
|
||||
|
||||
running_neko_nat1to1_values() {
|
||||
local name value
|
||||
for name in live-neko-1 live-neko-2 live-neko-3; do
|
||||
if ! docker ps --format '{{.Names}}' 2>/dev/null | grep -qx "$name"; then
|
||||
continue
|
||||
fi
|
||||
value="$(
|
||||
docker inspect "$name" --format '{{range .Config.Env}}{{println .}}{{end}}' 2>/dev/null |
|
||||
awk -F= '/^NEKO_WEBRTC_NAT1TO1=/{print $2; exit}'
|
||||
)"
|
||||
if [ -n "$value" ]; then
|
||||
printf '%s\n' "$value"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
maybe_refresh_neko_for_ip_change() {
|
||||
local preferred active interval cooldown active_value
|
||||
|
||||
if [ "${ENABLE_NEKO:-1}" != "1" ] || ! have docker; then
|
||||
return 0
|
||||
fi
|
||||
if ! docker ps --format '{{.Names}}' 2>/dev/null | grep -Eq '^live-neko-[123]$'; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
preferred="$(detect_preferred_lan_ip || true)"
|
||||
if [ -z "$preferred" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
active=""
|
||||
for active_value in $(running_neko_nat1to1_values || true); do
|
||||
[ -n "$active_value" ] || continue
|
||||
if [ "$active_value" != "$preferred" ]; then
|
||||
active="$active_value"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -z "$active" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
interval="$(normalize_interval "${NEKO_IP_WATCH_INTERVAL:-15}")"
|
||||
cooldown="$interval"
|
||||
if [ "$cooldown" -lt 15 ]; then
|
||||
cooldown=15
|
||||
fi
|
||||
|
||||
log "Detected Neko LAN IP drift: container=${active} current=${preferred}; restarting Neko"
|
||||
if bash "$SERVICE_CTL" neko restart; then
|
||||
log "Neko restart finished; refreshed NAT1TO1=${preferred}"
|
||||
else
|
||||
log "WARN: Neko restart failed after LAN IP drift"
|
||||
fi
|
||||
sleep "$cooldown"
|
||||
}
|
||||
|
||||
main() {
|
||||
load_env
|
||||
reload_watch_env
|
||||
log "Watching Neko LAN IP changes"
|
||||
while true; do
|
||||
reload_watch_env
|
||||
maybe_refresh_neko_for_ip_change
|
||||
sleep "$(normalize_interval "${NEKO_IP_WATCH_INTERVAL:-15}")"
|
||||
done
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# git pull 后若只改了 systemd 模板(如 StartLimit),执行本脚本重写 live-console.service 并 enable --now
|
||||
# git pull 后若改了 systemd 模板(如 live-console 或 Neko watcher),执行本脚本重写对应 unit 并 enable --now
|
||||
set -euo pipefail
|
||||
|
||||
SELF_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
@@ -10,4 +10,6 @@ ensure_root "$@"
|
||||
load_env
|
||||
log "Rewriting /etc/systemd/system/live-console.service from repo"
|
||||
install_live_console_service
|
||||
log "Rewriting /etc/systemd/system/live-neko-ip-watch.service from repo"
|
||||
install_neko_ip_watch_service
|
||||
log "Done. Check: systemctl status live-console.service --no-pager"
|
||||
|
||||
@@ -9,7 +9,7 @@ ensure_root "$@"
|
||||
load_env
|
||||
|
||||
log "Stopping systemd services"
|
||||
for svc in live-edge.service live-console.service live-webtty.service live-android-panel.service live-pulseaudio.service live-kmscube.service live-redroid-host.service netdata cockpit.socket shellcrash.service avahi-daemon; do
|
||||
for svc in live-edge.service live-console.service live-neko-ip-watch.service live-webtty.service live-android-panel.service live-pulseaudio.service live-kmscube.service live-redroid-host.service netdata cockpit.socket shellcrash.service avahi-daemon; do
|
||||
systemctl stop "$svc" >/dev/null 2>&1 || true
|
||||
systemctl disable "$svc" >/dev/null 2>&1 || true
|
||||
done
|
||||
@@ -42,6 +42,7 @@ fi
|
||||
log "Removing systemd unit files"
|
||||
rm -f /etc/systemd/system/live-edge.service
|
||||
rm -f /etc/systemd/system/live-console.service
|
||||
rm -f /etc/systemd/system/live-neko-ip-watch.service
|
||||
rm -f /etc/systemd/system/live-webtty.service
|
||||
rm -f /etc/systemd/system/live-android-panel.service
|
||||
rm -f /etc/systemd/system/live-pulseaudio.service
|
||||
|
||||
@@ -20,6 +20,9 @@ prepare_python_runtime
|
||||
log "Rebuilding web-console (npm)"
|
||||
prepare_web_console
|
||||
|
||||
log "Refreshing Neko LAN IP watcher unit"
|
||||
install_neko_ip_watch_service
|
||||
|
||||
log "Restarting live-console.service"
|
||||
systemctl daemon-reload
|
||||
systemctl restart live-console.service
|
||||
|
||||
@@ -86,6 +86,23 @@ class NekoConfigTests(unittest.TestCase):
|
||||
self.assertIn("NEKO_HTTP_PORT_2", common)
|
||||
self.assertIn("NEKO_WEBRTC_UDP_RANGE_3", common)
|
||||
|
||||
def test_neko_ip_watcher_is_installed_and_restarts_on_drift(self) -> None:
|
||||
common = (ROOT / "scripts" / "linux" / "lib" / "common.sh").read_text(encoding="utf-8")
|
||||
watcher = (ROOT / "scripts" / "linux" / "neko_ip_watch.sh").read_text(encoding="utf-8")
|
||||
upgrade = (ROOT / "scripts" / "linux" / "upgrade_live_console.sh").read_text(encoding="utf-8")
|
||||
uninstall = (ROOT / "scripts" / "linux" / "uninstall_stack.sh").read_text(encoding="utf-8")
|
||||
stack_env = (ROOT / "config" / "system-stack.env.example").read_text(encoding="utf-8")
|
||||
self.assertIn("install_neko_ip_watch_service()", common)
|
||||
self.assertIn("live-neko-ip-watch.service", common)
|
||||
self.assertIn("ExecStart=/bin/bash", common)
|
||||
self.assertIn("scripts/linux/neko_ip_watch.sh", common)
|
||||
self.assertIn("detect_preferred_lan_ip", watcher)
|
||||
self.assertIn('bash "$SERVICE_CTL" neko restart', watcher)
|
||||
self.assertIn("NEKO_IP_WATCH_INTERVAL", watcher)
|
||||
self.assertIn("install_neko_ip_watch_service", upgrade)
|
||||
self.assertIn("live-neko-ip-watch.service", uninstall)
|
||||
self.assertIn("NEKO_IP_WATCH_INTERVAL=15", stack_env)
|
||||
|
||||
def test_local_browser_prefers_chrome_on_x86_and_chromium_elsewhere(self) -> None:
|
||||
script = (ROOT / "scripts" / "linux" / "launch_browser.sh").read_text(encoding="utf-8")
|
||||
self.assertIn("x86_64|amd64", script)
|
||||
|
||||
Reference in New Issue
Block a user