Update to Psiphon Conduit Manager v1.0.1

- UI Polish: Restored Rocket emoji 🚀 to headers and streamlined menu text.
- Resource Usage Layout: Updated dashboard to a 3-row layout (App, System, Total).
- System Stats Fix: Fixed System CPU calculation to show instantaneous usage.
- App Stats Normalization: Fixed App CPU to show percentage of Total System Capacity. Added (Raw% vCPU) display for multi-core clarity.
- Live Stats Fix: Increased log buffer to 2500 lines to prevent execution hangs in verbose mode.
- Performance: Optimized dashboard refresh rate to 5 seconds.
This commit is contained in:
2026-01-25 15:53:21 -06:00
committed by GitHub
parent f2579718ae
commit 0bf8617786

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# #
# ╔═══════════════════════════════════════════════════════════════════╗ # ╔═══════════════════════════════════════════════════════════════════╗
# ║ 🚀 PSIPHON CONDUIT MANAGER v1.0.0 # ║ 🚀 PSIPHON CONDUIT MANAGER v1.0.1
# ║ ║ # ║ ║
# ║ One-click setup for Psiphon Conduit ║ # ║ One-click setup for Psiphon Conduit ║
# ║ ║ # ║ ║
@@ -16,10 +16,10 @@
# Usage: # Usage:
# curl -sL https://raw.githubusercontent.com/SamNet-dev/conduit-manager/main/conduit.sh | sudo bash # curl -sL https://raw.githubusercontent.com/SamNet-dev/conduit-manager/main/conduit.sh | sudo bash
# #
# Reference: https://github.com/ssmirr/conduit/releases/tag/87cc1a3 # Reference: https://github.com/ssmirr/conduit/releases/tag/d8522a8
# Conduit CLI options: # Conduit CLI options:
# -m, --max-clients int maximum number of proxy clients (1-1000) (default 200) # -m, --max-clients int maximum number of proxy clients (1-1000) (default 200)
# -b, --bandwidth float bandwidth limit per peer in Mbps (1-40) (default 5) # -b, --bandwidth float bandwidth limit per peer in Mbps (1-40, or -1 for unlimited) (default 5)
# -v, --verbose increase verbosity (-v for verbose, -vv for debug) # -v, --verbose increase verbosity (-v for verbose, -vv for debug)
# #
@@ -31,8 +31,8 @@ if [ -z "$BASH_VERSION" ]; then
exit 1 exit 1
fi fi
VERSION="1.0.0" VERSION="1.0.1"
CONDUIT_IMAGE="ghcr.io/ssmirr/conduit/conduit:87cc1a3" CONDUIT_IMAGE="ghcr.io/ssmirr/conduit/conduit:d8522a8"
INSTALL_DIR="/opt/conduit" INSTALL_DIR="/opt/conduit"
FORCE_REINSTALL=false FORCE_REINSTALL=false
@@ -43,7 +43,7 @@ YELLOW='\033[1;33m'
BLUE='\033[0;34m' BLUE='\033[0;34m'
CYAN='\033[0;36m' CYAN='\033[0;36m'
BOLD='\033[1m' BOLD='\033[1m'
NC='\033[0m' # No Color NC='\033[0m'
#═══════════════════════════════════════════════════════════════════════ #═══════════════════════════════════════════════════════════════════════
# Utility Functions # Utility Functions
@@ -89,7 +89,7 @@ detect_os() {
HAS_SYSTEMD=false HAS_SYSTEMD=false
PKG_MANAGER="unknown" PKG_MANAGER="unknown"
# Detect OS from /etc/os-release (most modern distros) # Detect OS from /etc/os-release
if [ -f /etc/os-release ]; then if [ -f /etc/os-release ]; then
. /etc/os-release . /etc/os-release
OS="$ID" OS="$ID"
@@ -180,7 +180,7 @@ install_package() {
} }
check_dependencies() { check_dependencies() {
# Check for bash (Alpine uses ash by default) # Check for bash
if [ "$OS_FAMILY" = "alpine" ]; then if [ "$OS_FAMILY" = "alpine" ]; then
if ! command -v bash &>/dev/null; then if ! command -v bash &>/dev/null; then
log_info "Installing bash (required for this script)..." log_info "Installing bash (required for this script)..."
@@ -202,7 +202,7 @@ check_dependencies() {
esac esac
fi fi
# Check for free command (part of procps) # Check for free command
if ! command -v free &>/dev/null; then if ! command -v free &>/dev/null; then
case "$PKG_MANAGER" in case "$PKG_MANAGER" in
apt|dnf|yum) install_package procps ;; apt|dnf|yum) install_package procps ;;
@@ -213,13 +213,13 @@ check_dependencies() {
fi fi
} }
get_ram_gb() { get_ram_mb() {
# Get RAM in GB, minimum 1 for safety # Get RAM in MB
local ram="" local ram=""
# Try free command first # Try free command first
if command -v free &>/dev/null; then if command -v free &>/dev/null; then
ram=$(free -g 2>/dev/null | awk '/^Mem:/{print $2}') ram=$(free -m 2>/dev/null | awk '/^Mem:/{print $2}')
fi fi
# Fallback: parse /proc/meminfo # Fallback: parse /proc/meminfo
@@ -227,7 +227,7 @@ get_ram_gb() {
if [ -f /proc/meminfo ]; then if [ -f /proc/meminfo ]; then
local kb=$(awk '/^MemTotal:/{print $2}' /proc/meminfo 2>/dev/null) local kb=$(awk '/^MemTotal:/{print $2}' /proc/meminfo 2>/dev/null)
if [ -n "$kb" ]; then if [ -n "$kb" ]; then
ram=$((kb / 1024 / 1024)) ram=$((kb / 1024))
fi fi
fi fi
fi fi
@@ -240,17 +240,30 @@ get_ram_gb() {
fi fi
} }
calculate_recommended_clients() { get_cpu_cores() {
local ram_gb=$(get_ram_gb) local cores=1
if command -v nproc &>/dev/null; then
cores=$(nproc)
elif [ -f /proc/cpuinfo ]; then
cores=$(grep -c ^processor /proc/cpuinfo)
fi
if [ "$ram_gb" -ge 8 ]; then # Safety check
echo 1000 if [ -z "$cores" ] || [ "$cores" -lt 1 ] 2>/dev/null; then
elif [ "$ram_gb" -ge 4 ]; then echo 1
echo 700
elif [ "$ram_gb" -ge 2 ]; then
echo 400
else else
echo 200 echo "$cores"
fi
}
calculate_recommended_clients() {
local cores=$(get_cpu_cores)
# Logic: 100 clients per CPU core, max 1000
local recommended=$((cores * 100))
if [ "$recommended" -gt 1000 ]; then
echo 1000
else
echo "$recommended"
fi fi
} }
@@ -259,7 +272,8 @@ calculate_recommended_clients() {
#═══════════════════════════════════════════════════════════════════════ #═══════════════════════════════════════════════════════════════════════
prompt_settings() { prompt_settings() {
local ram_gb=$(get_ram_gb) local ram_mb=$(get_ram_mb)
local cpu_cores=$(get_cpu_cores)
local recommended=$(calculate_recommended_clients) local recommended=$(calculate_recommended_clients)
echo "" echo ""
@@ -268,12 +282,18 @@ prompt_settings() {
echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}" echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}"
echo "" echo ""
echo -e " ${BOLD}Server Info:${NC}" echo -e " ${BOLD}Server Info:${NC}"
echo -e " CPU Cores: ${GREEN}${cpu_cores}${NC}"
if [ "$ram_mb" -ge 1000 ]; then
local ram_gb=$(awk "BEGIN {printf \"%.1f\", $ram_mb/1024}")
echo -e " RAM: ${GREEN}${ram_gb} GB${NC}" echo -e " RAM: ${GREEN}${ram_gb} GB${NC}"
else
echo -e " RAM: ${GREEN}${ram_mb} MB${NC}"
fi
echo -e " Recommended max-clients: ${GREEN}${recommended}${NC}" echo -e " Recommended max-clients: ${GREEN}${recommended}${NC}"
echo "" echo ""
echo -e " ${BOLD}Conduit Options:${NC}" echo -e " ${BOLD}Conduit Options:${NC}"
echo -e " ${YELLOW}--max-clients${NC} Maximum proxy clients (1-1000)" echo -e " ${YELLOW}--max-clients${NC} Maximum proxy clients (1-1000)"
echo -e " ${YELLOW}--bandwidth${NC} Bandwidth per peer in Mbps (1-40)" echo -e " ${YELLOW}--bandwidth${NC} Bandwidth per peer in Mbps (1-40, or -1 for unlimited)"
echo "" echo ""
# Max clients prompt # Max clients prompt
@@ -296,6 +316,17 @@ prompt_settings() {
# Bandwidth prompt # Bandwidth prompt
echo -e "${CYAN}───────────────────────────────────────────────────────────────${NC}" echo -e "${CYAN}───────────────────────────────────────────────────────────────${NC}"
echo -e " Do you want to set ${BOLD}UNLIMITED${NC} bandwidth? (Recommended for servers)"
echo -e " ${YELLOW}Note: High bandwidth usage may attract attention.${NC}"
echo -e "${CYAN}───────────────────────────────────────────────────────────────${NC}"
read -p " Set unlimited bandwidth? [y/N] " unlimited_bw < /dev/tty || true
if [[ "$unlimited_bw" =~ ^[Yy] ]]; then
BANDWIDTH="-1"
echo -e " Selected: ${GREEN}Unlimited (-1)${NC}"
else
echo ""
echo -e "${CYAN}───────────────────────────────────────────────────────────────${NC}"
echo -e " Enter bandwidth per peer in Mbps (1-40)" echo -e " Enter bandwidth per peer in Mbps (1-40)"
echo -e " Press Enter for default: ${GREEN}5${NC} Mbps" echo -e " Press Enter for default: ${GREEN}5${NC} Mbps"
echo -e "${CYAN}───────────────────────────────────────────────────────────────${NC}" echo -e "${CYAN}───────────────────────────────────────────────────────────────${NC}"
@@ -306,7 +337,6 @@ prompt_settings() {
elif [[ "$input_bandwidth" =~ ^[0-9]+$ ]] && [ "$input_bandwidth" -ge 1 ] && [ "$input_bandwidth" -le 40 ]; then elif [[ "$input_bandwidth" =~ ^[0-9]+$ ]] && [ "$input_bandwidth" -ge 1 ] && [ "$input_bandwidth" -le 40 ]; then
BANDWIDTH=$input_bandwidth BANDWIDTH=$input_bandwidth
elif [[ "$input_bandwidth" =~ ^[0-9]*\.[0-9]+$ ]]; then elif [[ "$input_bandwidth" =~ ^[0-9]*\.[0-9]+$ ]]; then
# Handle decimal - validate the whole number is in range
local float_ok=$(awk -v val="$input_bandwidth" 'BEGIN { print (val >= 1 && val <= 40) ? "yes" : "no" }') local float_ok=$(awk -v val="$input_bandwidth" 'BEGIN { print (val >= 1 && val <= 40) ? "yes" : "no" }')
if [ "$float_ok" = "yes" ]; then if [ "$float_ok" = "yes" ]; then
BANDWIDTH=$input_bandwidth BANDWIDTH=$input_bandwidth
@@ -318,12 +348,17 @@ prompt_settings() {
log_warn "Invalid input. Using default: 5 Mbps" log_warn "Invalid input. Using default: 5 Mbps"
BANDWIDTH=5 BANDWIDTH=5
fi fi
fi
echo "" echo ""
echo -e "${CYAN}───────────────────────────────────────────────────────────────${NC}" echo -e "${CYAN}───────────────────────────────────────────────────────────────${NC}"
echo -e " ${BOLD}Your Settings:${NC}" echo -e " ${BOLD}Your Settings:${NC}"
echo -e " Max Clients: ${GREEN}${MAX_CLIENTS}${NC}" echo -e " Max Clients: ${GREEN}${MAX_CLIENTS}${NC}"
if [ "$BANDWIDTH" == "-1" ]; then
echo -e " Bandwidth: ${GREEN}Unlimited${NC}"
else
echo -e " Bandwidth: ${GREEN}${BANDWIDTH}${NC} Mbps" echo -e " Bandwidth: ${GREEN}${BANDWIDTH}${NC} Mbps"
fi
echo -e "${CYAN}───────────────────────────────────────────────────────────────${NC}" echo -e "${CYAN}───────────────────────────────────────────────────────────────${NC}"
echo "" echo ""
@@ -345,13 +380,13 @@ install_docker() {
log_info "Installing Docker..." log_info "Installing Docker..."
# Alpine uses a different method # Alpine
if [ "$OS_FAMILY" = "alpine" ]; then if [ "$OS_FAMILY" = "alpine" ]; then
apk add --no-cache docker docker-cli-compose 2>/dev/null apk add --no-cache docker docker-cli-compose 2>/dev/null
rc-update add docker boot 2>/dev/null || true rc-update add docker boot 2>/dev/null || true
service docker start 2>/dev/null || rc-service docker start 2>/dev/null || true service docker start 2>/dev/null || rc-service docker start 2>/dev/null || true
else else
# Use official Docker install script for most distros # Use official Docker install
curl -fsSL https://get.docker.com | sh curl -fsSL https://get.docker.com | sh
# Enable and start Docker # Enable and start Docker
@@ -371,7 +406,7 @@ install_docker() {
fi fi
fi fi
# Wait for Docker to be ready (up to 30 seconds for slow systems) # Wait for Docker to be ready
sleep 3 sleep 3
local retries=27 local retries=27
while ! docker info &>/dev/null && [ $retries -gt 0 ]; do while ! docker info &>/dev/null && [ $retries -gt 0 ]; do
@@ -393,8 +428,8 @@ run_conduit() {
# Stop existing container # Stop existing container
docker rm -f conduit 2>/dev/null || true docker rm -f conduit 2>/dev/null || true
# Pull latest image # Pull image
log_info "Pulling Conduit image from ghcr.io/ssmirr/conduit..." log_info "Pulling Conduit image ($CONDUIT_IMAGE)..."
if ! docker pull $CONDUIT_IMAGE; then if ! docker pull $CONDUIT_IMAGE; then
log_error "Failed to pull Conduit image. Check your internet connection." log_error "Failed to pull Conduit image. Check your internet connection."
exit 1 exit 1
@@ -413,7 +448,11 @@ run_conduit() {
if docker ps | grep -q conduit; then if docker ps | grep -q conduit; then
log_success "Conduit container is running" log_success "Conduit container is running"
if [ "$BANDWIDTH" == "-1" ]; then
log_success "Settings: max-clients=$MAX_CLIENTS, bandwidth=Unlimited"
else
log_success "Settings: max-clients=$MAX_CLIENTS, bandwidth=${BANDWIDTH}Mbps" log_success "Settings: max-clients=$MAX_CLIENTS, bandwidth=${BANDWIDTH}Mbps"
fi
else else
log_error "Conduit failed to start" log_error "Conduit failed to start"
docker logs conduit 2>&1 | tail -10 docker logs conduit 2>&1 | tail -10
@@ -430,7 +469,6 @@ MAX_CLIENTS=$MAX_CLIENTS
BANDWIDTH=$BANDWIDTH BANDWIDTH=$BANDWIDTH
EOF EOF
# Verify write succeeded
if [ ! -f "$INSTALL_DIR/settings.conf" ]; then if [ ! -f "$INSTALL_DIR/settings.conf" ]; then
log_error "Failed to save settings. Check disk space and permissions." log_error "Failed to save settings. Check disk space and permissions."
return 1 return 1
@@ -546,12 +584,12 @@ create_management_script() {
#!/bin/bash #!/bin/bash
# #
# Psiphon Conduit Manager # Psiphon Conduit Manager
# Reference: https://github.com/ssmirr/conduit/releases/tag/87cc1a3 # Reference: https://github.com/ssmirr/conduit/releases/tag/d8522a8
# #
VERSION="1.0.0" VERSION="1.0.1"
INSTALL_DIR="/opt/conduit" INSTALL_DIR="/opt/conduit"
CONDUIT_IMAGE="ghcr.io/ssmirr/conduit/conduit:87cc1a3" CONDUIT_IMAGE="ghcr.io/ssmirr/conduit/conduit:d8522a8"
# Colors # Colors
RED='\033[0;31m' RED='\033[0;31m'
@@ -612,30 +650,26 @@ print_live_stats_header() {
echo "║ CONDUIT LIVE STATISTICS ║" echo "║ CONDUIT LIVE STATISTICS ║"
echo "╠═══════════════════════════════════════════════════════════════════╣" echo "╠═══════════════════════════════════════════════════════════════════╣"
printf "║ Max Clients: ${GREEN}%-52s${CYAN}║\n" "${MAX_CLIENTS}" printf "║ Max Clients: ${GREEN}%-52s${CYAN}║\n" "${MAX_CLIENTS}"
if [ "$BANDWIDTH" == "-1" ]; then
printf "║ Bandwidth: ${GREEN}%-52s${CYAN}║\n" "Unlimited"
else
printf "║ Bandwidth: ${GREEN}%-52s${CYAN}║\n" "${BANDWIDTH} Mbps" printf "║ Bandwidth: ${GREEN}%-52s${CYAN}║\n" "${BANDWIDTH} Mbps"
fi
echo "║ ║" echo "║ ║"
echo "║ Press Ctrl+C to exit ║"
echo "╚═══════════════════════════════════════════════════════════════════╝" echo "╚═══════════════════════════════════════════════════════════════════╝"
echo -e "${NC}" echo -e "${NC}"
} }
get_container_resources() {
# Get CPU and memory usage from docker stats
if docker ps 2>/dev/null | grep -q "[[:space:]]conduit$"; then get_node_id() {
local stats=$(docker stats conduit --no-stream --format "{{.CPUPerc}}|{{.MemUsage}}|{{.MemPerc}}" 2>/dev/null) if docker volume inspect conduit-data >/dev/null 2>&1; then
if [ -n "$stats" ]; then local mountpoint=$(docker volume inspect conduit-data --format '{{ .Mountpoint }}')
CPU_USAGE=$(echo "$stats" | cut -d'|' -f1) if [ -f "$mountpoint/conduit_key.json" ]; then
MEM_USAGE=$(echo "$stats" | cut -d'|' -f2) # Extract privateKeyBase64, decode, take last 32 bytes, encode base64
MEM_PERC=$(echo "$stats" | cut -d'|' -f3) # Logic provided by user
else cat "$mountpoint/conduit_key.json" | grep "privateKeyBase64" | awk -F'"' '{print $4}' | base64 -d 2>/dev/null | tail -c 32 | base64 | tr -d '=\n'
CPU_USAGE="N/A"
MEM_USAGE="N/A"
MEM_PERC="N/A"
fi fi
else
CPU_USAGE="N/A"
MEM_USAGE="N/A"
MEM_PERC="N/A"
fi fi
} }
@@ -658,20 +692,23 @@ show_dashboard() {
show_status "live" show_status "live"
# Get and show resource usage # System Resource Usage is now part of show_status
get_container_resources
# Show Node ID in its own section
local node_id=$(get_node_id)
if [ -n "$node_id" ]; then
echo -e "${CYAN}═══ CONDUIT ID ═══${NC}\033[K"
echo -e " ${CYAN}${node_id}${NC}\033[K"
echo "" echo ""
echo -e "${CYAN}═══ RESOURCE USAGE ═══${NC}\033[K" fi
echo -e " CPU: ${YELLOW}${CPU_USAGE}${NC}\033[K"
echo -e " Memory: ${YELLOW}${MEM_USAGE}${NC} (${MEM_PERC})\033[K" echo -e "${BOLD}Refreshes every 5 seconds. Press any key to return to menu...${NC}\033[K"
echo ""
echo -e "${BOLD}Refreshes every 10 seconds. Press any key to return to menu...${NC}\033[K"
# Clear any leftover content below (Erase Down) # Clear any leftover content below (Erase Down)
tput ed 2>/dev/null || true tput ed 2>/dev/null || true
# Wait 10 seconds for keypress. Signal will interrupt this read. # Wait 4 seconds for keypress (compensating for processing time)
if read -t 10 -n 1; then if read -t 4 -n 1; then
stop_dashboard=1 stop_dashboard=1
fi fi
done done
@@ -682,13 +719,94 @@ show_dashboard() {
trap - SIGINT SIGTERM # Reset traps trap - SIGINT SIGTERM # Reset traps
} }
get_container_stats() {
# Get CPU and RAM usage for conduit container
# Returns: "CPU_PERCENT RAM_USAGE"
local stats=$(docker stats --no-stream --format "{{.CPUPerc}} {{.MemUsage}}" conduit 2>/dev/null)
if [ -z "$stats" ]; then
echo "0% 0MiB"
else
# Extract just the raw numbers/units, simpler format
echo "$stats"
fi
}
get_cpu_cores() {
local cores=1
if command -v nproc &>/dev/null; then
cores=$(nproc)
elif [ -f /proc/cpuinfo ]; then
cores=$(grep -c ^processor /proc/cpuinfo)
fi
if [ -z "$cores" ] || [ "$cores" -lt 1 ] 2>/dev/null; then echo 1; else echo "$cores"; fi
}
get_system_stats() {
# Get System CPU (Live Delta) and RAM
# Returns: "CPU_PERCENT RAM_USED RAM_TOTAL RAM_PCT"
# 1. System CPU (Live Delta)
local sys_cpu="0%"
if [ -f /proc/stat ]; then
# Read 1
read -r cpu user nice system idle iowait irq softirq steal guest < /proc/stat
local total1=$((user + nice + system + idle + iowait + irq + softirq + steal))
local work1=$((user + nice + system + irq + softirq + steal))
sleep 0.1
# Read 2
read -r cpu user nice system idle iowait irq softirq steal guest < /proc/stat
local total2=$((user + nice + system + idle + iowait + irq + softirq + steal))
local work2=$((user + nice + system + irq + softirq + steal))
local total_delta=$((total2 - total1))
local work_delta=$((work2 - work1))
if [ "$total_delta" -gt 0 ]; then
local cpu_usage=$((work_delta * 100 / total_delta))
sys_cpu="${cpu_usage}%"
fi
else
sys_cpu="N/A"
fi
# 2. System RAM (Used, Total, Percentage)
local sys_ram_used="N/A"
local sys_ram_total="N/A"
local sys_ram_pct="N/A"
if command -v free &>/dev/null; then
# Output: used total percentage
local ram_data=$(free -m 2>/dev/null | awk '/^Mem:/{printf "%s %s %.2f%%", $3, $2, ($3/$2)*100}')
local ram_human=$(free -h 2>/dev/null | awk '/^Mem:/{print $3 " " $2}')
sys_ram_used=$(echo "$ram_human" | awk '{print $1}')
sys_ram_total=$(echo "$ram_human" | awk '{print $2}')
sys_ram_pct=$(echo "$ram_data" | awk '{print $3}')
fi
echo "$sys_cpu $sys_ram_used $sys_ram_total $sys_ram_pct"
}
show_live_stats() { show_live_stats() {
print_header print_header
echo -e "${YELLOW}Reading traffic history...${NC}" echo -e "${YELLOW}Reading traffic history...${NC}"
echo -e "${CYAN}Press Ctrl+C to return to menu${NC}" echo -e "${CYAN}Press ANY KEY to return to menu${NC}"
echo "" echo ""
# Run logs in background
# Stream logs, filter for [STATS], and strip everything before [STATS] # Stream logs, filter for [STATS], and strip everything before [STATS]
docker logs -f --tail 200 conduit 2>&1 | grep --line-buffered "\[STATS\]" | sed -u -e 's/.*\[STATS\]/[STATS]/' # Tail 2500 to reliably capture stats (performance cost is negligible)
docker logs -f --tail 2500 conduit 2>&1 | grep --line-buffered "\[STATS\]" | sed -u -e 's/.*\[STATS\]/[STATS]/' &
local cmd_pid=$!
# Wait for any key press
read -n 1 -s -r
# Kill the background process
kill $cmd_pid 2>/dev/null
wait $cmd_pid 2>/dev/null
} }
show_status() { show_status() {
@@ -699,45 +817,103 @@ show_status() {
fi fi
echo "" echo ""
echo -e "${CYAN}═══ CONDUIT STATUS ═══${NC}${EL}"
if docker ps 2>/dev/null | grep -q "[[:space:]]conduit$"; then if docker ps 2>/dev/null | grep -q "[[:space:]]conduit$"; then
if [ -n "$stats" ]; then # Fetch stats once
local stats=$(docker logs --tail 1000 conduit 2>&1 | grep "STATS" | tail -1) local logs=$(docker logs --tail 1000 conduit 2>&1 | grep "STATS" | tail -1)
# Get Resource Stats
local stats=$(get_container_stats)
# Normalize App CPU (Docker % / Cores)
local raw_app_cpu=$(echo "$stats" | awk '{print $1}' | tr -d '%')
local num_cores=$(get_cpu_cores)
local app_cpu="0%"
local app_cpu_display=""
if [[ "$raw_app_cpu" =~ ^[0-9.]+$ ]]; then
# Use awk for floating point math
app_cpu=$(awk -v cpu="$raw_app_cpu" -v cores="$num_cores" 'BEGIN {printf "%.2f%%", cpu / cores}')
if [ "$num_cores" -gt 1 ]; then
app_cpu_display="${app_cpu} (${raw_app_cpu}% vCPU)"
else else
local stats=$(docker logs --tail 1000 conduit 2>&1 | grep "STATS" | tail -1) app_cpu_display="${app_cpu}"
fi
else
app_cpu="${raw_app_cpu}%"
app_cpu_display="${app_cpu}"
fi fi
if [ -n "$stats" ]; then # Keep full "Used / Limit" string for App RAM
local connecting=$(echo "$stats" | sed -n 's/.*Connecting:[[:space:]]*\([0-9]*\).*/\1/p') local app_ram=$(echo "$stats" | awk '{print $2, $3, $4}')
local connected=$(echo "$stats" | sed -n 's/.*Connected:[[:space:]]*\([0-9]*\).*/\1/p')
local upload=$(echo "$stats" | sed -n 's/.*Up:[[:space:]]*\([^|]*\).*/\1/p' | xargs)
local download=$(echo "$stats" | sed -n 's/.*Down:[[:space:]]*\([^|]*\).*/\1/p' | xargs)
local uptime=$(echo "$stats" | sed -n 's/.*Uptime:[[:space:]]*\(.*\)/\1/p' | xargs)
[ -n "$uptime" ] && echo -e " Container: ${GREEN}Running${NC} (${CYAN}Uptime: ${uptime}${NC})${EL}" || echo -e " Container: ${GREEN}Running${NC}${EL}" local sys_stats=$(get_system_stats)
local sys_cpu=$(echo "$sys_stats" | awk '{print $1}')
local sys_ram_used=$(echo "$sys_stats" | awk '{print $2}')
local sys_ram_total=$(echo "$sys_stats" | awk '{print $3}')
local sys_ram_pct=$(echo "$sys_stats" | awk '{print $4}')
if [ -n "$logs" ]; then
local connecting=$(echo "$logs" | sed -n 's/.*Connecting:[[:space:]]*\([0-9]*\).*/\1/p')
local connected=$(echo "$logs" | sed -n 's/.*Connected:[[:space:]]*\([0-9]*\).*/\1/p')
local upload=$(echo "$logs" | sed -n 's/.*Up:[[:space:]]*\([^|]*\).*/\1/p' | xargs)
local download=$(echo "$logs" | sed -n 's/.*Down:[[:space:]]*\([^|]*\).*/\1/p' | xargs)
local uptime=$(echo "$logs" | sed -n 's/.*Uptime:[[:space:]]*\(.*\)/\1/p' | xargs)
# Default to 0 if missing/empty # Default to 0 if missing/empty
connecting=${connecting:-0} connecting=${connecting:-0}
connected=${connected:-0} connected=${connected:-0}
echo -e " Clients: ${GREEN}${connected}${NC} connected, ${YELLOW}${connecting}${NC} connecting${EL}" echo -e "🚀 PSIPHON CONDUIT MANAGER v${VERSION}"
echo -e "${NC}"
[ -n "$upload" ] && echo -e " Upload: ${CYAN}${upload}${NC}${EL}" if [ -n "$uptime" ]; then
[ -n "$download" ] && echo -e " Download: ${CYAN}${download}${NC}${EL}" echo -e "${BOLD}Status:${NC} ${GREEN}Running${NC} (${uptime}) | ${BOLD}Clients:${NC} ${GREEN}${connected}${NC} connected, ${YELLOW}${connecting}${NC} connecting"
else else
echo -e " Container: ${GREEN}Running${NC}${EL}" echo -e "${BOLD}Status:${NC} ${GREEN}Running${NC} | ${BOLD}Clients:${NC} ${GREEN}${connected}${NC} connected, ${YELLOW}${connecting}${NC} connecting"
echo -e " Stats: ${YELLOW}Waiting for first stats...${NC}${EL}" fi
echo ""
echo -e "${CYAN}═══ Traffic ═══${NC}"
[ -n "$upload" ] && echo -e " Upload: ${CYAN}${upload}${NC}"
[ -n "$download" ] && echo -e " Download: ${CYAN}${download}${NC}"
echo ""
echo -e "${CYAN}═══ Resource Usage ═══${NC}"
printf " %-8s CPU: ${YELLOW}%-20s${NC} | RAM: ${YELLOW}%-20s${NC}\n" "App:" "$app_cpu_display" "$app_ram"
printf " %-8s CPU: ${YELLOW}%-20s${NC} | RAM: ${YELLOW}%-20s${NC}\n" "System:" "$sys_cpu" "$sys_ram_used / $sys_ram_total"
printf " %-8s CPU: ${YELLOW}%-20s${NC} | RAM: ${YELLOW}%-20s${NC}\n" "Total:" "$sys_cpu" "$sys_ram_pct"
else
echo -e "🚀 PSIPHON CONDUIT MANAGER v${VERSION}"
echo -e "${NC}"
echo -e "${BOLD}Status:${NC} ${GREEN}Running${NC}"
echo ""
echo -e "${CYAN}═══ Resource Usage ═══${NC}"
printf " %-8s CPU: ${YELLOW}%-20s${NC} | RAM: ${YELLOW}%-20s${NC}\n" "App:" "$app_cpu_display" "$app_ram"
printf " %-8s CPU: ${YELLOW}%-20s${NC} | RAM: ${YELLOW}%-20s${NC}\n" "System:" "$sys_cpu" "$sys_ram_used / $sys_ram_total"
printf " %-8s CPU: ${YELLOW}%-20s${NC} | RAM: ${YELLOW}%-20s${NC}\n" "Total:" "$sys_cpu" "$sys_ram_pct"
echo ""
echo -e " Stats: ${YELLOW}Waiting for first stats...${NC}"
fi fi
else else
echo -e " Container: ${RED}Stopped${NC}${EL}" echo -e "🚀 PSIPHON CONDUIT MANAGER v${VERSION}"
echo -e "${NC}"
echo -e "${BOLD}Status:${NC} ${RED}Stopped${NC}"
fi fi
echo "" echo ""
echo -e "${CYAN}═══ SETTINGS ═══${NC}${EL}" echo -e "${CYAN}═══ SETTINGS ═══${NC}${EL}"
echo -e " Max Clients: ${MAX_CLIENTS}${EL}" echo -e " Max Clients: ${MAX_CLIENTS}${EL}"
if [ "$BANDWIDTH" == "-1" ]; then
echo -e " Bandwidth: Unlimited${EL}"
else
echo -e " Bandwidth: ${BANDWIDTH} Mbps${EL}" echo -e " Bandwidth: ${BANDWIDTH} Mbps${EL}"
fi
echo "" echo ""
@@ -812,11 +988,33 @@ change_settings() {
echo "" echo ""
echo -e "${CYAN}Current Settings:${NC}" echo -e "${CYAN}Current Settings:${NC}"
echo -e " Max Clients: ${MAX_CLIENTS}" echo -e " Max Clients: ${MAX_CLIENTS}"
if [ "$BANDWIDTH" == "-1" ]; then
echo -e " Bandwidth: Unlimited"
else
echo -e " Bandwidth: ${BANDWIDTH} Mbps" echo -e " Bandwidth: ${BANDWIDTH} Mbps"
fi
echo "" echo ""
read -p "New max-clients (1-1000) [${MAX_CLIENTS}]: " new_clients < /dev/tty || true read -p "New max-clients (1-1000) [${MAX_CLIENTS}]: " new_clients < /dev/tty || true
read -p "New bandwidth in Mbps (1-40) [${BANDWIDTH}]: " new_bandwidth < /dev/tty || true
# Bandwidth prompt logic for settings menu
echo ""
if [ "$BANDWIDTH" == "-1" ]; then
echo "Current bandwidth: Unlimited"
else
echo "Current bandwidth: ${BANDWIDTH} Mbps"
fi
read -p "Set unlimited bandwidth (-1)? [y/N]: " set_unlimited < /dev/tty || true
if [[ "$set_unlimited" =~ ^[Yy] ]]; then
new_bandwidth="-1"
else
read -p "New bandwidth in Mbps (1-40) [${BANDWIDTH}]: " input_bw < /dev/tty || true
if [ -n "$input_bw" ]; then
new_bandwidth="$input_bw"
fi
fi
# Validate max-clients # Validate max-clients
if [ -n "$new_clients" ]; then if [ -n "$new_clients" ]; then
@@ -829,7 +1027,9 @@ change_settings() {
# Validate bandwidth # Validate bandwidth
if [ -n "$new_bandwidth" ]; then if [ -n "$new_bandwidth" ]; then
if [[ "$new_bandwidth" =~ ^[0-9]+$ ]] && [ "$new_bandwidth" -ge 1 ] && [ "$new_bandwidth" -le 40 ]; then if [ "$new_bandwidth" = "-1" ]; then
BANDWIDTH="-1"
elif [[ "$new_bandwidth" =~ ^[0-9]+$ ]] && [ "$new_bandwidth" -ge 1 ] && [ "$new_bandwidth" -le 40 ]; then
BANDWIDTH=$new_bandwidth BANDWIDTH=$new_bandwidth
elif [[ "$new_bandwidth" =~ ^[0-9]*\.[0-9]+$ ]]; then elif [[ "$new_bandwidth" =~ ^[0-9]*\.[0-9]+$ ]]; then
local float_ok=$(awk -v val="$new_bandwidth" 'BEGIN { print (val >= 1 && val <= 40) ? "yes" : "no" }') local float_ok=$(awk -v val="$new_bandwidth" 'BEGIN { print (val >= 1 && val <= 40) ? "yes" : "no" }')
@@ -866,7 +1066,11 @@ EOF
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Settings updated and Conduit restarted${NC}" echo -e "${GREEN}✓ Settings updated and Conduit restarted${NC}"
echo -e " Max Clients: ${MAX_CLIENTS}" echo -e " Max Clients: ${MAX_CLIENTS}"
if [ "$BANDWIDTH" == "-1" ]; then
echo -e " Bandwidth: Unlimited"
else
echo -e " Bandwidth: ${BANDWIDTH} Mbps" echo -e " Bandwidth: ${BANDWIDTH} Mbps"
fi
else else
echo -e "${RED}✗ Failed to restart Conduit${NC}" echo -e "${RED}✗ Failed to restart Conduit${NC}"
fi fi
@@ -957,7 +1161,7 @@ show_menu() {
echo -e "${CYAN}─────────────────────────────────────────────────────────────────${NC}" echo -e "${CYAN}─────────────────────────────────────────────────────────────────${NC}"
echo -e "${CYAN} MANAGEMENT OPTIONS${NC}" echo -e "${CYAN} MANAGEMENT OPTIONS${NC}"
echo -e "${CYAN}─────────────────────────────────────────────────────────────────${NC}" echo -e "${CYAN}─────────────────────────────────────────────────────────────────${NC}"
echo -e " 1. 📈 View status dashboard (Live CPU/RAM)" echo -e " 1. 📈 View status dashboard"
echo -e " 2. 📜 View traffic history (Scrolling Logs)" echo -e " 2. 📜 View traffic history (Scrolling Logs)"
echo -e " 3. 📋 View raw logs (Filtered)" echo -e " 3. 📋 View raw logs (Filtered)"
echo -e " 4. ⚙️ Change settings (max-clients, bandwidth)" echo -e " 4. ⚙️ Change settings (max-clients, bandwidth)"
@@ -1059,7 +1263,7 @@ esac
MANAGEMENT MANAGEMENT
chmod +x $INSTALL_DIR/conduit chmod +x $INSTALL_DIR/conduit
# Force create symlink (remove existing first) # Force create symlink
rm -f /usr/local/bin/conduit 2>/dev/null || true rm -f /usr/local/bin/conduit 2>/dev/null || true
ln -s $INSTALL_DIR/conduit /usr/local/bin/conduit ln -s $INSTALL_DIR/conduit /usr/local/bin/conduit
@@ -1071,7 +1275,6 @@ MANAGEMENT
#═══════════════════════════════════════════════════════════════════════ #═══════════════════════════════════════════════════════════════════════
print_summary() { print_summary() {
# Determine which init system was used
local init_type="Enabled" local init_type="Enabled"
if [ "$HAS_SYSTEMD" = "true" ]; then if [ "$HAS_SYSTEMD" = "true" ]; then
init_type="Enabled (systemd)" init_type="Enabled (systemd)"
@@ -1088,9 +1291,13 @@ print_summary() {
echo -e "${GREEN}${NC} Conduit is running and ready to help users! ${GREEN}${NC}" echo -e "${GREEN}${NC} Conduit is running and ready to help users! ${GREEN}${NC}"
echo -e "${GREEN}${NC} ${GREEN}${NC}" echo -e "${GREEN}${NC} ${GREEN}${NC}"
echo -e "${GREEN}${NC} 📊 Settings: ${GREEN}${NC}" echo -e "${GREEN}${NC} 📊 Settings: ${GREEN}${NC}"
echo -e "${GREEN}${NC} Max Clients: ${CYAN}${MAX_CLIENTS}${NC} ${GREEN}${NC}" printf "${GREEN}${NC} Max Clients: ${CYAN}%-4s${NC} ${GREEN}${NC}\n" "${MAX_CLIENTS}"
echo -e "${GREEN}${NC} Bandwidth: ${CYAN}${BANDWIDTH} Mbps${NC} ${GREEN}${NC}" if [ "$BANDWIDTH" == "-1" ]; then
echo -e "${GREEN}${NC} Auto-start: ${CYAN}${init_type}${NC} ${GREEN}${NC}" echo -e "${GREEN}${NC} Bandwidth: ${CYAN}Unlimited${NC} ${GREEN}${NC}"
else
printf "${GREEN}${NC} Bandwidth: ${CYAN}%-4s${NC} Mbps ${GREEN}${NC}\n" "${BANDWIDTH}"
fi
printf "${GREEN}${NC} Auto-start: ${CYAN}%-20s${NC} ${GREEN}${NC}\n" "${init_type}"
echo -e "${GREEN}${NC} ${GREEN}${NC}" echo -e "${GREEN}${NC} ${GREEN}${NC}"
echo -e "${GREEN}╠═══════════════════════════════════════════════════════════════════╣${NC}" echo -e "${GREEN}╠═══════════════════════════════════════════════════════════════════╣${NC}"
echo -e "${GREEN}${NC} COMMANDS: ${GREEN}${NC}" echo -e "${GREEN}${NC} COMMANDS: ${GREEN}${NC}"
@@ -1246,7 +1453,6 @@ main() {
2) 2)
echo "" echo ""
log_info "Starting fresh reinstall..." log_info "Starting fresh reinstall..."
# Continue with installation below
;; ;;
3) 3)
uninstall uninstall
@@ -1294,13 +1500,12 @@ main() {
print_summary print_summary
# Ask if user wants to view live stats
read -p "View live statistics now? [Y/n] " view_stats < /dev/tty || true read -p "View live statistics now? [Y/n] " view_stats < /dev/tty || true
if [[ ! "$view_stats" =~ ^[Nn] ]]; then if [[ ! "$view_stats" =~ ^[Nn] ]]; then
/opt/conduit/conduit stats /opt/conduit/conduit stats
fi fi
} }
# #
# REACHED END OF SCRIPT - VERSION 1.0.0 # REACHED END OF SCRIPT - VERSION 1.0.1
# ############################################################################### # ###############################################################################
main "$@" main "$@"