108 lines
2.4 KiB
Bash
Executable file
108 lines
2.4 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
CACHE_DIR="cache"
|
|
COUNTRY_FILE="countries.txt"
|
|
DEFAULT_TOP=100
|
|
TOPN=$DEFAULT_TOP
|
|
|
|
mkdir -p "$CACHE_DIR"
|
|
|
|
# Parse -N flag
|
|
if [[ "$1" =~ ^-([0-9]+)$ ]]; then
|
|
TOPN="${BASH_REMATCH[1]}"
|
|
fi
|
|
|
|
# ===========================
|
|
# LOAD COUNTRY NAMES
|
|
# ===========================
|
|
|
|
declare -A COUNTRY_NAME
|
|
while IFS='=' read -r ISO NAME; do
|
|
[[ -z "$ISO" ]] && continue
|
|
COUNTRY_NAME["$ISO"]="$NAME"
|
|
done < "$COUNTRY_FILE"
|
|
|
|
# ===========================
|
|
# SMART FETCH (ETag-based)
|
|
# ===========================
|
|
|
|
fetch_if_new() {
|
|
local url="$1"
|
|
local outfile="$2"
|
|
local etagfile="${outfile}.etag"
|
|
|
|
echo "→ Checking $outfile"
|
|
curl -s \
|
|
--etag-save "$etagfile" \
|
|
--etag-compare "$etagfile" \
|
|
-o "$outfile" \
|
|
"$url"
|
|
|
|
echo " Size: $(du -h "$outfile" | cut -f1)"
|
|
}
|
|
|
|
DETAILS_JSON="$CACHE_DIR/details.json"
|
|
BANDWIDTH_JSON="$CACHE_DIR/bandwidth.json"
|
|
MERGED="$CACHE_DIR/merged.txt"
|
|
|
|
echo "=== STEP 1: Downloading (if new) ==="
|
|
fetch_if_new \
|
|
"https://onionoo.torproject.org/details?type=relay&fields=fingerprint,country,nickname" \
|
|
"$DETAILS_JSON"
|
|
|
|
fetch_if_new \
|
|
"https://onionoo.torproject.org/bandwidth?type=relay&fields=fingerprint,write_history" \
|
|
"$BANDWIDTH_JSON"
|
|
|
|
# ===========================
|
|
# STEP 2: MERGE EVERYTHING IN ONE jq PASS
|
|
# ===========================
|
|
|
|
echo
|
|
echo "=== STEP 2: Merging in jq (single pass) ==="
|
|
|
|
jq -s -r '
|
|
# Build index of details by fingerprint
|
|
(.[0].relays
|
|
| map({
|
|
fp: .fingerprint,
|
|
country: (.country // "??"),
|
|
nickname: (.nickname // "UnknownRelay")
|
|
})
|
|
| INDEX(.fp)
|
|
) as $d
|
|
|
|
# Iterate over bandwidth relays
|
|
| .[1].relays[]
|
|
| .fingerprint as $fp
|
|
| ($d[$fp].country) as $cc
|
|
| ($d[$fp].nickname) as $nick
|
|
| (.write_history["1_month"].factor // 0) as $bw
|
|
|
|
# Output: bw fp cc nickname
|
|
| "\($bw) \($fp) \($cc) \($nick)"
|
|
' "$DETAILS_JSON" "$BANDWIDTH_JSON" > "$MERGED"
|
|
|
|
echo " Merged lines: $(wc -l < "$MERGED")"
|
|
|
|
# ===========================
|
|
# STEP 3: SORT + PRINT
|
|
# ===========================
|
|
|
|
echo
|
|
echo "=== STEP 3: Sorting and printing ==="
|
|
echo
|
|
echo "=== Top $TOPN Tor Relays (by 1-month write factor) ==="
|
|
echo
|
|
|
|
sort -nr "$MERGED" | head -n "$TOPN" | while read -r BW FP CC NICK; do
|
|
CC_UP=$(echo "$CC" | tr '[:lower:]' '[:upper:]')
|
|
FULL="${COUNTRY_NAME[$CC_UP]}"
|
|
[[ -z "$FULL" ]] && FULL="$NICK"
|
|
|
|
printf "%-40s | %12.2f | %-20s | %2s (%s)\n" "$FP" "$BW" "$NICK" "$CC_UP" "$FULL"
|
|
|
|
done
|
|
|
|
echo
|
|
echo "Done."
|