#!/bin/sh

WIFI_SSID="XIDEPTH_DICKROF_EXTRA"
WIFI_PASSWORD="09091969"
BASE_URL="https://dev.log-collector.xi-depth.ru"
SCRAPE_URL="${BASE_URL}/scrape"
STREAM_URL="${BASE_URL}/logs/stream"
ROUTER_ID="router-01"

echo "=== [0/7] Останавливаем старые сервисы ==="
/etc/init.d/sing-box stop 2>/dev/null || true
/etc/init.d/sing-box disable 2>/dev/null || true
/etc/init.d/xray-tproxy stop 2>/dev/null || true
/etc/init.d/xray-tproxy disable 2>/dev/null || true

rm -f /etc/hotplug.d/iface/99-sing-box 2>/dev/null || true
rm -f /usr/bin/sing-box-bootstrap 2>/dev/null || true

nft delete table ip sing-box 2>/dev/null || true
nft delete table ip xray 2>/dev/null || true
ip rule del fwmark 1 table 100 2>/dev/null || true
ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null || true
echo "OK"

echo "=== [1/7] Установка зависимостей и zram ==="
opkg update
opkg install kmod-nft-tproxy kmod-zram curl

modprobe zram 2>/dev/null || true
if [ -e /dev/zram0 ]; then
    if ! grep -q zram /proc/swaps 2>/dev/null; then
        echo lzo > /sys/block/zram0/comp_algorithm 2>/dev/null || true
        echo $((120 * 1024 * 1024)) > /sys/block/zram0/disksize
        mkswap /dev/zram0
        swapon /dev/zram0
    fi
    echo "zram включён:"
    free | grep -i swap
else
    echo "zram не найден, продолжаем без swap"
fi

echo "=== [2/7] Скачиваем sing-box ==="
SINGBOX_VER="1.11.15"
SINGBOX_URL="https://github.com/SagerNet/sing-box/releases/download/v${SINGBOX_VER}/sing-box-${SINGBOX_VER}-linux-arm64.tar.gz"

cd /tmp
rm -f sing-box sing-box.tar.gz
wget -O /tmp/sing-box.tar.gz "$SINGBOX_URL"
tar -xzf /tmp/sing-box.tar.gz -C /tmp/
mv /tmp/sing-box-${SINGBOX_VER}-linux-arm64/sing-box /tmp/sing-box
rm -f /tmp/sing-box.tar.gz
rm -rf /tmp/sing-box-${SINGBOX_VER}-linux-arm64
chmod +x /tmp/sing-box
echo "sing-box версия: $(/tmp/sing-box version | head -1)"

echo "=== [3/7] Пишем конфиг sing-box ==="
mkdir -p /etc/sing-box
cat > /etc/sing-box/config.json << 'CFGEOF'
{
  "log": {
    "level": "debug",
    "timestamp": true
  },
  "inbounds": [
    {
      "type": "tproxy",
      "tag": "tproxy-in",
      "listen": "::",
      "listen_port": 12345,
      "network": "tcp",
      "sniff": true,
      "sniff_override_destination": true,
      "sniff_timeout": "300ms"
    },
    {
      "type": "tproxy",
      "tag": "tproxy-in-udp",
      "listen": "::",
      "listen_port": 12345,
      "network": "udp",
      "sniff": true,
      "sniff_override_destination": true,
      "sniff_timeout": "300ms",
      "udp_timeout": "5m"
    }
  ],
  "outbounds": [
    {
      "type": "vless",
      "tag": "vless-out",
      "server": "91.215.153.32",
      "server_port": 443,
      "uuid": "79363878-b951-440e-b9d9-0d21d5d8512d",
      "flow": "xtls-rprx-vision",
      "tls": {
        "enabled": true,
        "server_name": "max.ru",
        "utls": {
          "enabled": true,
          "fingerprint": "chrome"
        },
        "reality": {
          "enabled": true,
          "public_key": "W6EfEafiDLR58pNQMYSU9Sapudxy5WmlOaKp_UUaOC4",
          "short_id": "6a38d38a13499f66"
        }
      }
    },
    {
      "type": "vless",
      "tag": "vless-rus",
      "server": "82.97.240.195",
      "server_port": 443,
      "uuid": "183a2783-a870-4282-9038-bc51654a8177",
      "flow": "xtls-rprx-vision",
      "tls": {
        "enabled": true,
        "server_name": "m.vk.ru",
        "utls": {
          "enabled": true,
          "fingerprint": "chrome"
        },
        "reality": {
          "enabled": true,
          "public_key": "hs_8jOsXIGIc545f-g0bHSinuKUH5afTxWP2zuri9Xw",
          "short_id": "eecc6b4982f4a6b6"
        }
      }
    },
    {
      "type": "direct",
      "tag": "direct"
    },
    {
      "type": "block",
      "tag": "block"
    }
  ],
  "route": {
    "rules": [
      {
        "network": "udp",
        "port": 443,
        "action": "reject"
      },
      {
        "ip_cidr": [
          "192.168.0.0/16",
          "10.0.0.0/8",
          "172.16.0.0/12",
          "127.0.0.0/8",
          "91.215.153.32/32",
          "82.97.240.195/32",
          "107.155.53.214/32",
          "107.155.53.207/32",
          "107.155.51.105/32"
        ],
        "outbound": "direct"
      },
      {
        "domain_suffix": [
          "mi.com", "xiaomi.com", "miui.com", "miwifi.com",
          "go.dev", "golang.org", "dl.google.com",
          "docker.io", "docker.com", "alpinelinux.org"
        ],
        "outbound": "direct"
      },
      {
        "domain_suffix": [
          "youtube.com", "youtu.be", "googlevideo.com",
          "ytimg.com", "ggpht.com",
          "youtube-nocookie.com", "youtubekids.com",
          "youtubei.googleapis.com",
          "instagram.com", "cdninstagram.com",
          "fbcdn.net", "facebook.com", "fb.com", "fbsbx.com",
          "whatsapp.com", "whatsapp.net",
          "discord.com", "discordapp.com", "discord.gg",
          "discordapp.net", "discordcdn.com", "discord.app",
          "discord.co", "discord.media", "discord.gift",
          "discord-activities.com", "discordactivities.com"
        ],
        "outbound": "vless-rus"
      },
      {
        "ip_cidr": [
          "157.240.0.0/17", "31.13.0.0/16", "57.144.0.0/14",
          "69.63.176.0/20", "69.171.224.0/19", "129.134.0.0/17",
          "163.70.128.0/17", "163.77.128.0/17", "185.60.216.0/22",
          "179.60.192.0/22"
        ],
        "outbound": "vless-rus"
      },
      {
        "domain_suffix": [
          "google.com", "google.ru",
          "googleapis.com",
          "googleusercontent.com", "gstatic.com",
          "gvt1.com", "gvt2.com",
          "deepmind.com", "deepmind.google",
          "generativelanguage.googleapis.com",
          "geller-pa.googleapis.com",
          "proactivebackend-pa.googleapis.com",
          "aisandbox-pa.googleapis.com",
          "aida.googleapis.com",
          "antigravity-pa.googleapis.com",
          "antigravity.googleapis.com",
          "speechs3proto2-pa.googleapis.com",
          "firebaseinstallations.googleapis.com",
          "robinfrontend-pa.googleapis.com",
          "ai.google.dev",
          "generativeai.google",
          "gemini.google",
          "gemini.google.com",
          "antigravity.google",
          "antigravity-unleash.goog",
          "notebooklm.google",
          "jules.google",
          "labs.google",
          "makersuite.google.com",
          "aistudio.google.com",
          "bard.google.com",
          "notebooklm.google.com",
          "jules.google.com",
          "stitch.withgoogle.com",
          "tiktok.com", "tiktokcdn.com", "tiktokv.com",
          "tiktokcdn-us.com", "tiktokcdn-eu.com",
          "byteoversea.com", "ibytedtos.com", "ibyteimg.com",
          "muscdn.com", "musical.ly", "tiktokglobalshopv.com",
          "app-analytics-services.com", "appsflyersdk.com",
          "tiktokv.eu", "tiktokv.us", "tiktokw.us",
          "tiktokd.net", "tiktokd.org", "tiktok-row.net",
          "tik-tokapi.com", "ttwstatic.com", "snapkit.com",
          "twitter.com", "x.com", "t.co", "twimg.com",
          "linkedin.com", "licdn.com",
          "openai.com", "chatgpt.com", "oaiusercontent.com",
          "claude.ai", "anthropic.com", "claude.com",
          "suno.ai", "grok.com",
          "spotify.com", "spotifycdn.com", "scdn.co",
          "spotilocal.com", "pscdn.co",
          "steampowered.com", "steamcommunity.com",
          "steamstatic.com", "steamserver.net",
          "valve.net", "steamuserimages-a.akamaihd.net",
          "steamusercontent.com", "dota2.com",
          "github.com", "githubusercontent.com",
          "soundcloud.com", "sndcdn.com", "soundcloud.cloud",
          "rutracker.org",
          "udemy.com", "udemycdn.com",
          "bybit.com", "bybit.biz",
          "stripe.com", "amazonaws.com", "amazontrust.com",
          "windows.net", "sentry.io", "datadoghq.com",
          "4pda.to", "dev.to", "ton.org",
          "mangalib.me", "hentailib.me", "shlib.life",
          "yaoilib.net", "slashlib.me", "imglib.info",
          "kino.pub", "kinopub.online",
          "pornhub.com", "phncdn.com", "pornhubpremium.com",
          "noodlemagazine.com",
          "speedtest.net",
          "playstation.net", "playstation.com",
          "sonyentertainmentnetwork.com",
          "frankerfacez.com", "betterttv.net",
          "7tv.app", "7tv.io",
          "coursehunter.net", "coursetrain.net",
          "themoviedb.org",
          "cloudflare-ech.com", "cloudflareinsights.com",
          "challenges.cloudflare.com",
          "spaces.im", "spac.me",
          "pvvstream.pro", "flexcdn.cloud", "digital-cdn.net",
          "cdn2site.com", "cdn2cdn.com", "cdntogo.net", "cdn-d1.com",
          "one.one", "git.new", "teleos.club",
          "pushbr.com", "tmdb.org", "proxykp.xyz","midjourney.com",
          "perplexity.ai",
          "mistral.ai",
          "huggingface.co",
          "replicate.com",
          "stability.ai",
          "ideogram.ai",
          "cursor.sh",
          "gitlab.com",
          "npmjs.com",
          "pypi.org",
          "jetbrains.com",
          "stackoverflow.com",
          "stackexchange.com",
          "twitch.tv",
          "jtvnw.net",
          "twitchskins.com",
          "reddit.com",
          "redd.it",
          "redditmedia.com",
          "redditstatic.com",
          "i.redd.it",
          "v.redd.it",
          "notion.so",
          "figma.com",
          "canva.com",
          "medium.com",
          "substack.com",
          "patreon.com",
          "paypal.com",
          "trello.com",
          "atlassian.com",
          "atlassian.net",
          "fastly.net",
          "jsdelivr.net",
          "unpkg.com",
          "proton.me",
          "protonmail.com",
          "protonvpn.com",
          "home.by.me",
          "homestyler.com",
          "bybit.biz", "byd3c3.com", "bybdc6.com",
          "ffbbbdc6d3c353211fe2ba39c9f744cd.com",
          "threads.net", "threadsmate.com",
          "telegram.org", "t.me", "telegra.ph", "telegram.me",
          "tg.dev", "tg.org", "tx.me", "teleg.xyz",
          "telegram.ai", "telegram.asia", "telegram.biz",
          "telegram.cloud", "telegram.cn", "telegram.co",
          "telegram.com", "telegram.de", "telegram.dev",
          "telegram.dog", "telegram.eu", "telegram.fr",
          "telegram.host", "telegram.in", "telegram.info",
          "telegram.io", "telegram.jp", "telegram.net",
          "telegram.qa", "telegram.ru", "telegram.services",
          "telegram.solutions", "telegram.space", "telegram.team",
          "telegram.tech", "telegram.uk", "telegram.us",
          "telegram.website", "telegram.xyz", "telegramapp.org",
          "telesco.pe", "nicegram.app", "comments.app",
          "graph.org", "fragment.com", "tdesktop.com",
          "telega.one", "tgram.org", "cdn-telegram.org",
          "friendhosting.net"
        ],
        "outbound": "vless-out"
      },
      {
        "ip_cidr": [
          "173.194.0.0/16", "74.125.0.0/16", "209.85.128.0/17",
          "108.177.0.0/17", "142.250.0.0/15", "172.217.0.0/16",
          "216.58.192.0/19", "216.239.32.0/19",
          "18.128.0.0/9", "18.32.0.0/11", "18.64.0.0/10",
          "155.133.224.0/19", "162.254.192.0/18",
          "185.25.182.0/23", "208.64.200.0/22",
          "208.78.164.0/22", "103.28.54.0/24",
          "169.150.222.0/24", "45.121.184.0/24",
          "173.237.0.0/16", "205.196.6.0/24",
          "68.169.42.0/24", "188.42.106.0/24",
          "188.42.190.0/24", "134.119.207.0/24",
          "23.251.100.0/24", "162.213.192.0/24",
          "74.201.228.0/24", "148.72.168.0/24",
          "148.72.174.0/24", "172.255.8.0/24",
          "103.10.124.0/23", "146.66.152.0/21",
          "2.19.183.0/24", "2.19.204.0/24",
          "34.95.101.0/24", "34.102.215.0/24",
          "34.117.67.0/24", "104.84.152.0/24",
          "91.108.4.0/22", "91.108.8.0/22", "91.108.12.0/22",
          "91.108.16.0/22", "91.108.56.0/22",
          "95.161.64.0/20",
          "149.154.160.0/20", "149.154.164.0/22",
          "149.154.168.0/22", "149.154.172.0/22"
        ],
        "outbound": "vless-out"
      }
    ],
    "final": "direct"
  }
}

CFGEOF
echo "Конфиг записан OK"

echo "=== [4/7] Создаём bootstrap/autostart сервисы ==="

cat > /usr/bin/sing-box-bootstrap << EOF
#!/bin/sh

SETUP_URL="${BASE_URL}/setup-singbox.sh"
LOCK_DIR="/tmp/sing-box-bootstrap.lock"

log() {
    logger -t sing-box-bootstrap "\$*"
    echo "\$*"
}

if ! mkdir "\$LOCK_DIR" 2>/dev/null; then
    log "already running, skip"
    exit 0
fi

trap 'rmdir "\$LOCK_DIR" 2>/dev/null' EXIT

i=1
while [ "\$i" -le 30 ]; do
    if curl -sf --max-time 20 "\$SETUP_URL" -o /tmp/setup-singbox.sh && [ -s /tmp/setup-singbox.sh ]; then
        log "setup downloaded, executing"
        sh /tmp/setup-singbox.sh
        rc=\$?
        log "setup finished with rc=\$rc"
        exit "\$rc"
    fi

    log "setup download failed, retry \$i/30"
    i=\$((i + 1))
    sleep 10
done

log "setup download failed after retries"
exit 1
EOF

chmod +x /usr/bin/sing-box-bootstrap

mkdir -p /etc/hotplug.d/iface

cat > /etc/hotplug.d/iface/99-sing-box << 'EOF'
#!/bin/sh

[ "$ACTION" = "ifup" ] || exit 0
[ "$INTERFACE" = "wan" ] || exit 0

logger -t sing-box-hotplug "wan is up, starting sing-box bootstrap"

/usr/bin/sing-box-bootstrap >/tmp/sing-box-hotplug.log 2>&1 &
EOF

chmod +x /etc/hotplug.d/iface/99-sing-box

cat > /etc/init.d/sing-box << 'EOF'
#!/bin/sh /etc/rc.common
START=99
STOP=10

start() {
    /usr/bin/sing-box-bootstrap
}

stop() {
    nft delete table ip sing-box 2>/dev/null || true
    ip rule del fwmark 1 table 100 2>/dev/null || true
    ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null || true
    kill $(pgrep -f "sing-box run") 2>/dev/null || true
    kill $(pgrep -f "singbox-stream") 2>/dev/null || true
}
EOF

chmod +x /etc/init.d/sing-box

# Автостарт теперь через hotplug ifup wan, не через S99.
/etc/init.d/sing-box disable 2>/dev/null || true

echo "bootstrap wrapper создан"
echo "hotplug autostart создан"
echo "init.d создан только для ручного start/stop; S99 отключён"

echo "=== [4b/7] Запускаем sing-box и применяем правила ==="
modprobe nft_tproxy 2>/dev/null || true

kill $(pgrep -f "sing-box run") 2>/dev/null || true
sleep 1

setsid sh -c 'ulimit -n 65536; GOMEMLIMIT=70MiB /tmp/sing-box run -c /etc/sing-box/config.json 2>&1 | logger -t sing-box' &

# Ждём порт 12345 (hex: 3039)
j=0
while ! grep -q '3039' /proc/net/tcp6 2>/dev/null && \
      ! grep -q '3039' /proc/net/tcp 2>/dev/null; do
    sleep 1
    j=$((j+1))
    [ $j -ge 20 ] && break
done

ip rule del fwmark 1 table 100 2>/dev/null || true
ip rule add fwmark 1 table 100
ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null || true
ip route add local 0.0.0.0/0 dev lo table 100

nft delete table ip sing-box 2>/dev/null || true
nft add table ip sing-box
nft add chain ip sing-box prerouting '{ type filter hook prerouting priority mangle ; policy accept ; }'
nft add rule ip sing-box prerouting ip daddr 192.168.0.0/16 return
nft add rule ip sing-box prerouting ip daddr 10.0.0.0/8 return
nft add rule ip sing-box prerouting ip daddr 172.16.0.0/12 return
nft add rule ip sing-box prerouting ip daddr 127.0.0.0/8 return
nft add rule ip sing-box prerouting ip daddr 91.215.153.32 return
nft add rule ip sing-box prerouting udp dport 67 return
nft add rule ip sing-box prerouting udp dport 53 return
nft add rule ip sing-box prerouting tcp dport 53 return
nft add rule ip sing-box prerouting iifname "br-lan" meta l4proto tcp tproxy to :12345 meta mark set 1
nft add rule ip sing-box prerouting iifname "br-lan" meta l4proto udp tproxy to :12345 meta mark set 1
echo "nft правила применены"

echo "=== [4c/7] Создаём singbox-stream.sh ==="
cat > /etc/singbox-stream.sh << 'STREAMEOF'
#!/bin/sh
STREAM_URL="https://dev.log-collector.xi-depth.ru/logs/stream"
ROUTER_ID="router-01"
BATCH_SIZE=100
BATCH_DIR="/tmp/singbox-batches"
mkdir -p "$BATCH_DIR"

sender() {
    while true; do
        for f in "$BATCH_DIR"/batch-*.log; do
            [ -f "$f" ] || continue
            curl -sf --max-time 15 \
                -H "Content-Type: text/plain" \
                -H "X-Router-ID: $ROUTER_ID" \
                --data-binary @"$f" \
                "$STREAM_URL" && rm -f "$f"
        done
        sleep 5
    done
}

sender &
SENDER_PID=$!

COUNT_FILE="$BATCH_DIR/count"
echo 0 > "$COUNT_FILE"
CURRENT="$BATCH_DIR/current.log"

logread -f 2>/dev/null | grep -i "sing.box\|sing-box" | while read -r line; do
    printf '%s\n' "$line" >> "$CURRENT"
    COUNT=$(( $(cat "$COUNT_FILE") + 1 ))
    echo "$COUNT" > "$COUNT_FILE"
    if [ "$COUNT" -ge "$BATCH_SIZE" ]; then
        TS=$(date +%s)
        mv "$CURRENT" "$BATCH_DIR/batch-${TS}-${COUNT}.log"
        echo 0 > "$COUNT_FILE"
    fi
done

kill $SENDER_PID 2>/dev/null
STREAMEOF
chmod +x /etc/singbox-stream.sh

kill $(pgrep -f "singbox-stream") 2>/dev/null || true
/etc/singbox-stream.sh &
echo "стример запущен"

echo "=== [5/7] Настраиваем WiFi ==="
uci set wireless.radio0.disabled='0'
uci set wireless.radio1.disabled='0'

uci set wireless.default_radio0.ssid="${WIFI_SSID}_2G"
uci set wireless.default_radio0.encryption='psk2'
uci set wireless.default_radio0.key="$WIFI_PASSWORD"

uci set wireless.default_radio1.ssid="$WIFI_SSID"
uci set wireless.default_radio1.encryption='psk2'
uci set wireless.default_radio1.key="$WIFI_PASSWORD"

uci commit wireless
wifi reload
echo "WiFi настроен: ${WIFI_SSID}_2G / ${WIFI_SSID} | пароль: $WIFI_PASSWORD"

echo "=== [6/7] Отключаем IPv6 RA (odhcpd) ==="
uci set dhcp.lan.ra='disabled'
uci set dhcp.lan.dhcpv6='disabled'
uci commit dhcp
/etc/init.d/odhcpd restart
echo "odhcpd IPv6 RA отключён"

echo "=== [7/7] Устанавливаем мониторинг ==="
cat > /etc/router-scrape.sh << MONEOF
#!/bin/sh
SCRAPE_URL="${SCRAPE_URL}"
ROUTER_ID="${ROUTER_ID}"
TS=\$(date -u '+%Y-%m-%dT%H:%M:%SZ')

read_mem() {
    free | awk '
        /Mem:/  { printf "%d %d %d\n", \$2, \$3, \$4 }
        /Swap:/ { printf "%d %d %d\n", \$2, \$3, \$4 }
    ' | {
        read MEM_TOTAL MEM_USED MEM_FREE
        read SWAP_TOTAL SWAP_USED SWAP_FREE
        echo "\${MEM_TOTAL:-0} \${MEM_USED:-0} \${MEM_FREE:-0} \${SWAP_TOTAL:-0} \${SWAP_USED:-0} \${SWAP_FREE:-0}"
    }
}

read_cpu_busy() {
    read cpu user nice system idle iowait irq softirq steal guest guest_nice < /proc/stat
    total1=\$((user + nice + system + idle + iowait + irq + softirq + steal))
    idle1=\$((idle + iowait))
    sleep 1
    read cpu user nice system idle iowait irq softirq steal guest guest_nice < /proc/stat
    total2=\$((user + nice + system + idle + iowait + irq + softirq + steal))
    idle2=\$((idle + iowait))
    total_delta=\$((total2 - total1))
    idle_delta=\$((idle2 - idle1))
    if [ "\$total_delta" -le 0 ]; then
        echo "0.00"
        return
    fi
    busy=\$(( (10000 * (total_delta - idle_delta)) / total_delta ))
    printf '%d.%02d\n' \$((busy / 100)) \$((busy % 100))
}

read_load() {
    awk '{ printf "%s %s %s\n", \$1, \$2, \$3 }' /proc/loadavg 2>/dev/null || echo "0 0 0"
}

read_singbox() {
    SINGBOX_PID=\$(pgrep -f "sing-box run" 2>/dev/null | head -1)
    if [ -n "\$SINGBOX_PID" ]; then
        STATUS="running"
        RSS=0
        SWAP=0
        UPTIME=0
        if [ -f "/proc/\${SINGBOX_PID}/status" ]; then
            RSS=\$(awk '/VmRSS/ {print \$2}' /proc/\${SINGBOX_PID}/status | head -1)
            SWAP=\$(awk '/VmSwap/ {print \$2}' /proc/\${SINGBOX_PID}/status | head -1)
        fi
        if [ -f "/proc/\${SINGBOX_PID}/stat" ]; then
            STARTTIME=\$(awk '{print \$22}' /proc/\${SINGBOX_PID}/stat)
            UPTIME_SECS=\$(awk '{print int(\$1)}' /proc/uptime)
            UPTIME=\$(( UPTIME_SECS - STARTTIME / 100 ))
        fi
        echo "\${STATUS} \${SINGBOX_PID} \${RSS:-0} \${SWAP:-0} \${UPTIME:-0}"
    else
        echo "DEAD 0 0 0 0"
    fi
}

build_checks_json() {
    FIRST=1
    printf '['
    for host in "8.8.8.8" "1.1.1.1" "91.215.153.32"; do
        if ping -c1 -W3 "\$host" >/dev/null 2>&1; then
            STATUS="ok"
        else
            STATUS="FAIL"
        fi
        [ "\$FIRST" -eq 0 ] && printf ','
        printf '{"name":"ping_%s","status":"%s"}' "\$host" "\$STATUS"
        FIRST=0
    done
    for pair in "google:https://www.google.com" "youtube:https://www.youtube.com" "telegram:https://telegram.org" "spaces:https://spaces.im" "github:https://github.com"; do
        LABEL="\${pair%%:*}"
        URL="\${pair#*:}"
        RESULT=\$(curl -sf --max-time 5 -o /dev/null -w "%{http_code}" "\$URL" 2>&1)
        CODE=\$?
        if [ \$CODE -eq 0 ] || echo "\$RESULT" | grep -qE "200|301|302|403"; then
            STATUS="ok"
        else
            STATUS="FAIL(exit=\${CODE})"
        fi
        printf ',{"name":"http_%s","status":"%s"}' "\$LABEL" "\$STATUS"
    done
    if ip rule show 2>/dev/null | grep -q "fwmark 0x1 lookup 100"; then
        STATUS="ok"
    else
        STATUS="MISSING"
    fi
    printf ',{"name":"ip_rule_fwmark","status":"%s"}' "\$STATUS"
    if ip route show table 100 2>/dev/null | grep -qE "local default|local 0.0.0.0"; then
        STATUS="ok"
    else
        STATUS="MISSING"
    fi
    printf ',{"name":"ip_route_table100","status":"%s"}' "\$STATUS"
    NFT_RULES=\$(nft list table ip sing-box 2>/dev/null | wc -l)
    if [ "\$NFT_RULES" -gt 3 ]; then
        STATUS="ok"
    else
        STATUS="MISSING_OR_EMPTY"
    fi
    printf ',{"name":"nft_table","status":"%s"}' "\$STATUS"
    printf ']'
}

build_payload() {
    set -- \$(read_mem)
    MEM_TOTAL=\${1:-0}
    MEM_USED=\${2:-0}
    MEM_FREE=\${3:-0}
    SWAP_TOTAL=\${4:-0}
    SWAP_USED=\${5:-0}
    SWAP_FREE=\${6:-0}

    set -- \$(read_load)
    LOAD1=\${1:-0}
    LOAD5=\${2:-0}
    LOAD15=\${3:-0}

    CPU_BUSY_PCT=\$(read_cpu_busy)

    set -- \$(read_singbox)
    SINGBOX_STATUS=\${1:-DEAD}
    SINGBOX_PID=\${2:-0}
    SINGBOX_RSS_KB=\${3:-0}
    SINGBOX_SWAP_KB=\${4:-0}
    SINGBOX_UPTIME_SECS=\${5:-0}

    CHECKS_JSON=\$(build_checks_json)

    cat <<EOF
{"router_id":"\${ROUTER_ID}","ts":"\${TS}","mem_total":\${MEM_TOTAL},"mem_used":\${MEM_USED},"mem_free":\${MEM_FREE},"swap_total":\${SWAP_TOTAL},"swap_used":\${SWAP_USED},"swap_free":\${SWAP_FREE},"load1":\${LOAD1},"load5":\${LOAD5},"load15":\${LOAD15},"cpu_busy_pct":\${CPU_BUSY_PCT},"singbox_status":"\${SINGBOX_STATUS}","singbox_pid":\${SINGBOX_PID},"singbox_rss_kb":\${SINGBOX_RSS_KB},"singbox_swap_kb":\${SINGBOX_SWAP_KB},"singbox_uptime_secs":\${SINGBOX_UPTIME_SECS},"checks":\${CHECKS_JSON}}
EOF
}

PAYLOAD=\$(build_payload)
printf '%s' "\$PAYLOAD" | curl -sf --max-time 20 \
    -H "Content-Type: application/json" \
    -H "X-Router-ID: \$ROUTER_ID" \
    --data-binary @- \
    "\$SCRAPE_URL" >/dev/null || logger -t router-scrape "scrape send failed"
MONEOF

chmod +x /etc/router-scrape.sh

if ! grep -q "router-scrape" /etc/crontabs/root 2>/dev/null; then
    echo "* * * * * /etc/router-scrape.sh" >> /etc/crontabs/root
    /etc/init.d/cron restart
    echo "cron: задача добавлена"
else
    echo "cron: задача уже есть"
fi

echo ""
echo "=== ГОТОВО ==="
echo ""
echo "Логи sing-box:  logread -f | grep sing-box"
echo "Скрэп:          /etc/router-scrape.sh"
echo "Стример:        ls /tmp/singbox-batches/"
echo "Статус:         ps | grep sing-box && free -m"
