Skip to content

Instantly share code, notes, and snippets.

@kustomzone
Forked from sanity/peer-manager.sh
Created September 28, 2025 09:19
Show Gist options
  • Save kustomzone/d76a8aa8c568ce583da5c56c02746157 to your computer and use it in GitHub Desktop.
Save kustomzone/d76a8aa8c568ce583da5c56c02746157 to your computer and use it in GitHub Desktop.
Freenet Peer Manager - Systemd-based peer lifecycle management
#!/bin/bash
set -e
BASE_DIR="/mnt/media/freenet-peers"
PEERS_DIR="$BASE_DIR/peers"
STATE_DIR="$BASE_DIR/state"
CONFIG_FILE="$STATE_DIR/peer-config.json"
FREENET_BIN="/usr/local/bin/freenet"
GATEWAY_ADDR="127.0.0.1:31337"
NETWORK_PORT_START=40000
WS_PORT_START=45000
START_DELAY=30
init_config() {
if [ ! -f "$CONFIG_FILE" ]; then
echo '{"peers":{},"next_network_port":40000,"next_ws_port":45000}' | \
sudo tee "$CONFIG_FILE" > /dev/null
sudo chown freenet:freenet "$CONFIG_FILE"
sudo chmod 664 "$CONFIG_FILE"
fi
}
get_next_ports() {
local network_port=$(jq -r '.next_network_port' "$CONFIG_FILE")
local ws_port=$(jq -r '.next_ws_port' "$CONFIG_FILE")
echo "$network_port $ws_port"
}
update_next_ports() {
local network_port=$1
local ws_port=$2
local tmp_file=$(mktemp)
jq ".next_network_port = $network_port | .next_ws_port = $ws_port" "$CONFIG_FILE" > "$tmp_file"
sudo cp "$tmp_file" "$CONFIG_FILE"
sudo chown freenet:freenet "$CONFIG_FILE"
rm "$tmp_file"
}
generate_keypair() {
local peer_id=$1
local keypair_path="$PEERS_DIR/$peer_id/keypair.pem"
if [ ! -f "$keypair_path" ]; then
local tmp_dir=$(mktemp -d)
cd "$tmp_dir"
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048
sudo cp private.pem "$keypair_path"
sudo chown freenet:freenet "$keypair_path"
sudo chmod 600 "$keypair_path"
cd - > /dev/null
rm -rf "$tmp_dir"
fi
}
create_peer_config() {
local peer_id=$1
local network_port=$2
local ws_port=$3
local peer_dir="$PEERS_DIR/$peer_id"
local config_toml="$peer_dir/config/config.toml"
local gateways_toml="$peer_dir/config/gateways.toml"
if [ ! -f "$config_toml" ]; then
local tmp_file=$(mktemp)
cat > "$tmp_file" <<EOF
mode = "network"
network-address = "0.0.0.0"
network-port = $network_port
ws-api-address = "127.0.0.1"
ws-api-port = $ws_port
transport_keypair = "$peer_dir/keypair.pem"
log_level = "info"
contracts_dir = "$peer_dir/data/contracts"
delegates_dir = "$peer_dir/data/delegates"
secrets_dir = "$peer_dir/data/secrets"
db_dir = "$peer_dir/data/db"
event_log = "$peer_dir/data/_EVENT_LOG"
data_dir = "$peer_dir/data"
config_dir = "$peer_dir/config"
is_gateway = false
actor_clients = true
EOF
sudo cp "$tmp_file" "$config_toml"
sudo chown freenet:freenet "$config_toml"
rm "$tmp_file"
fi
if [ ! -f "$gateways_toml" ]; then
local tmp_file=$(mktemp)
cat > "$tmp_file" <<EOF
gateways = ["$GATEWAY_ADDR"]
EOF
sudo cp "$tmp_file" "$gateways_toml"
sudo chown freenet:freenet "$gateways_toml"
rm "$tmp_file"
fi
}
create_peer() {
local peer_id=$1
local network_port=$2
local ws_port=$3
local location=$(awk 'BEGIN{srand(); print rand()}')
echo "Creating peer $peer_id..."
local peer_dir="$PEERS_DIR/$peer_id"
sudo mkdir -p "$peer_dir"/{data,config}
sudo chown -R freenet:freenet "$peer_dir"
generate_keypair "$peer_id"
create_peer_config "$peer_id" "$network_port" "$ws_port"
local tmp_file=$(mktemp)
jq ".peers[\"$peer_id\"] = {
\"network_port\": $network_port,
\"ws_port\": $ws_port,
\"data_dir\": \"$peer_dir/data\",
\"config_dir\": \"$peer_dir/config\",
\"keypair\": \"$peer_dir/keypair.pem\",
\"location\": $location,
\"gateway\": \"$GATEWAY_ADDR\",
\"status\": \"stopped\"
}" "$CONFIG_FILE" > "$tmp_file"
sudo cp "$tmp_file" "$CONFIG_FILE"
sudo chown freenet:freenet "$CONFIG_FILE"
rm "$tmp_file"
create_systemd_service "$peer_id" "$network_port" "$ws_port"
echo "Created peer $peer_id (network:$network_port, ws:$ws_port, location:$location)"
}
create_systemd_service() {
local peer_id=$1
local network_port=$2
local ws_port=$3
local peer_dir="$PEERS_DIR/$peer_id"
local service_file="/etc/systemd/system/freenet-$peer_id.service"
sudo tee "$service_file" > /dev/null <<EOF
[Unit]
Description=Freenet Peer $peer_id
After=network.target freenet-gateway.service
[Service]
Type=simple
User=freenet
Group=freenet
Environment="RUST_LOG=info,freenet=info"
Environment="RUST_BACKTRACE=1"
ExecStart=$FREENET_BIN \\
--data-dir $peer_dir/data \\
--config-dir $peer_dir/config \\
--network-port $network_port \\
--ws-api-port $ws_port \\
network \\
--transport-keypair $peer_dir/keypair.pem
StandardOutput=append:$peer_dir/peer.log
StandardError=append:$peer_dir/peer.log
Restart=always
RestartSec=10s
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable "freenet-$peer_id.service"
}
start_peer() {
local peer_id=$1
if ! jq -e ".peers[\"$peer_id\"]" "$CONFIG_FILE" > /dev/null 2>&1; then
echo "Error: Peer $peer_id does not exist"
return 1
fi
echo "Starting peer $peer_id..."
sudo systemctl start "freenet-$peer_id"
local tmp_file=$(mktemp)
jq ".peers[\"$peer_id\"].status = \"running\" | .peers[\"$peer_id\"].started = \"$(date -Iseconds)\"" \
"$CONFIG_FILE" > "$tmp_file"
sudo cp "$tmp_file" "$CONFIG_FILE"
sudo chown freenet:freenet "$CONFIG_FILE"
rm "$tmp_file"
echo "Started peer $peer_id"
}
stop_peer() {
local peer_id=$1
if [ "$peer_id" = "all" ]; then
echo "Stopping all peers..."
for peer in $(jq -r '.peers | keys[]' "$CONFIG_FILE"); do
stop_peer "$peer"
done
return
fi
echo "Stopping peer $peer_id..."
sudo systemctl stop "freenet-$peer_id" 2>/dev/null || true
local tmp_file=$(mktemp)
jq ".peers[\"$peer_id\"].status = \"stopped\"" "$CONFIG_FILE" > "$tmp_file"
sudo cp "$tmp_file" "$CONFIG_FILE"
sudo chown freenet:freenet "$CONFIG_FILE"
rm "$tmp_file"
echo "Stopped peer $peer_id"
}
status_all() {
echo "=== Freenet Peer Status ==="
echo ""
if [ ! -f "$CONFIG_FILE" ]; then
echo "No peers configured"
return
fi
local peer_count=$(jq '.peers | length' "$CONFIG_FILE")
echo "Total peers: $peer_count"
echo ""
printf "%-12s %-10s %-12s %-10s %-10s %s\n" "PEER" "STATUS" "NETWORK" "WS_API" "LOCATION" "STARTED"
printf "%-12s %-10s %-12s %-10s %-10s %s\n" "----" "------" "-------" "------" "--------" "-------"
for peer in $(jq -r '.peers | keys[]' "$CONFIG_FILE" | sort); do
local status=$(jq -r ".peers[\"$peer\"].status" "$CONFIG_FILE")
local network_port=$(jq -r ".peers[\"$peer\"].network_port" "$CONFIG_FILE")
local ws_port=$(jq -r ".peers[\"$peer\"].ws_port" "$CONFIG_FILE")
local location=$(jq -r ".peers[\"$peer\"].location" "$CONFIG_FILE" | awk '{printf "%.6f", $1}')
local started=$(jq -r ".peers[\"$peer\"].started // \"never\"" "$CONFIG_FILE")
local systemd_status=""
if systemctl is-active --quiet "freenet-$peer" 2>/dev/null; then
systemd_status="running"
else
systemd_status="stopped"
fi
printf "%-12s %-10s %-12s %-10s %-10s %s\n" \
"$peer" "$systemd_status" "$network_port" "$ws_port" "$location" "$started"
done
}
list_peers() {
if [ ! -f "$CONFIG_FILE" ]; then
echo "No peers configured"
return
fi
jq -r '.peers | keys[]' "$CONFIG_FILE" | sort
}
show_logs() {
local peer_id=$1
if [ -z "$peer_id" ]; then
echo "Showing unified logs..."
sudo tail -f "$BASE_DIR"/peers/*/peer.log 2>/dev/null || echo "No logs available"
else
local log_file="$PEERS_DIR/$peer_id/peer.log"
if [ -f "$log_file" ]; then
sudo tail -f "$log_file"
else
echo "No log file for peer $peer_id"
fi
fi
}
info_peer() {
local peer_id=$1
if ! jq -e ".peers[\"$peer_id\"]" "$CONFIG_FILE" > /dev/null 2>&1; then
echo "Error: Peer $peer_id does not exist"
return 1
fi
echo "=== Peer $peer_id Info ==="
jq ".peers[\"$peer_id\"]" "$CONFIG_FILE"
}
cmd_start() {
local count=${1:-5}
init_config
echo "Starting $count peers with $START_DELAY second delay between each..."
for i in $(seq 1 "$count"); do
local peer_id=$(printf "peer-%02d" "$i")
if jq -e ".peers[\"$peer_id\"]" "$CONFIG_FILE" > /dev/null 2>&1; then
echo "Peer $peer_id already exists, starting it..."
start_peer "$peer_id"
else
read network_port ws_port < <(get_next_ports)
create_peer "$peer_id" "$network_port" "$ws_port"
update_next_ports $((network_port + 1)) $((ws_port + 1))
start_peer "$peer_id"
fi
if [ "$i" -lt "$count" ]; then
echo "Waiting $START_DELAY seconds before starting next peer..."
sleep "$START_DELAY"
fi
done
echo ""
echo "All peers started!"
status_all
}
enable_all() {
echo "Enabling all peer services..."
for peer in $(jq -r '.peers | keys[]' "$CONFIG_FILE"); do
echo " Enabling freenet-$peer.service..."
sudo systemctl enable "freenet-$peer.service"
done
echo "All peer services enabled"
}
start_all() {
echo "Starting all configured peers..."
for peer in $(jq -r '.peers | keys[]' "$CONFIG_FILE" | sort); do
if ! systemctl is-active --quiet "freenet-$peer" 2>/dev/null; then
echo " Starting $peer..."
start_peer "$peer"
else
echo " $peer already running"
fi
done
echo ""
status_all
}
case "${1:-}" in
init)
init_config
echo "Initialized configuration"
;;
start)
if [ "${2:-}" = "all" ]; then
start_all
else
cmd_start "${2:-5}"
fi
;;
stop)
stop_peer "${2:-all}"
;;
restart)
stop_peer "${2}"
sleep 2
start_peer "${2}"
;;
enable)
enable_all
;;
status)
status_all
;;
list)
list_peers
;;
logs)
show_logs "${2:-}"
;;
info)
info_peer "${2}"
;;
*)
echo "Usage: $0 {init|start [N|all]|stop [peer-id|all]|restart [peer-id]|enable|status|list|logs [peer-id]|info [peer-id]}"
echo ""
echo "Commands:"
echo " init Initialize configuration"
echo " start [N] Start N peers (default: 5)"
echo " start all Start all configured peers"
echo " stop [peer-id] Stop specific peer or all"
echo " restart [peer-id] Restart specific peer"
echo " enable Enable all peer services for auto-start"
echo " status Show all peer status"
echo " list List all peer IDs"
echo " logs [peer-id] Tail logs (specific peer or all)"
echo " info [peer-id] Show peer configuration"
exit 1
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment