#!/bin/bash # Exit immediately if a command exits with a non-zero status. # set -e # We will handle errors manually for cleanup # Instead of set -e, we'll check command statuses and exit if needed after attempting cleanup. # Default to not force killing processes FORCE_KILL=false # Parse command-line options while getopts "f" opt; do case ${opt} in f ) FORCE_KILL=true ;; \? ) echo "Invalid option: -$OPTARG" 1>&2 exit 1 ;; esac done shift $((OPTIND -1)) # Array to store PIDs of background processes BG_PIDS=() # Cleanup function cleanup() { echo "Caught signal, cleaning up background processes..." for pid in "${BG_PIDS[@]}"; do if ps -p "$pid" > /dev/null; then # Check if process exists echo "Stopping process $pid..." kill "$pid" fi done # Wait for all background processes to terminate for pid in "${BG_PIDS[@]}"; do if ps -p "$pid" > /dev/null; then wait "$pid" 2>/dev/null # Suppress "No such process" if already gone fi done echo "All background processes stopped." exit 0 # Exit script after cleanup } # Trap SIGINT (Ctrl+C) and SIGTERM trap cleanup SIGINT SIGTERM # Define circles and their base port # The client will need to know these port assignments. # Circle names should match what's in your mock data for consistency, # but for the WS server, it's what the server identifies itself as. # The client will use the lowercase_with_underscores version for the path. # Define circles and their ports using indexed arrays CIRCLE_NAMES=( "OurWorld" "My Personal Space" "threefold" "circles_app" ) CIRCLE_PORTS=( "9000" "9001" "9002" "9003" ) # Add more circles and their ports here if needed, ensuring arrays match # Build the WebSocket server first echo "Building circle_server_ws..." cargo build --package circle_server_ws if [ $? -ne 0 ]; then echo "Failed to build circle_server_ws"; cleanup; exit 1; fi echo "Building rhai_worker..." cargo build --package rhai_worker if [ $? -ne 0 ]; then echo "Failed to build rhai_worker"; cleanup; exit 1; fi # Paths to the compiled binaries WS_SERVER_BINARY="./target/debug/circle_server_ws" RHAI_WORKER_BINARY="./target/debug/rhai_worker" if [ ! -f "$WS_SERVER_BINARY" ]; then echo "Error: WebSocket server binary not found at $WS_SERVER_BINARY after build." cleanup exit 1 fi if [ ! -f "$RHAI_WORKER_BINARY" ]; then echo "Error: Rhai worker binary not found at $RHAI_WORKER_BINARY after build." cleanup exit 1 fi echo "Starting WebSocket servers..." for i in "${!CIRCLE_NAMES[@]}"; do NAME="${CIRCLE_NAMES[i]}" PORT="${CIRCLE_PORTS[i]}" if [ "$FORCE_KILL" = true ]; then echo "Checking if port $PORT is in use (force mode)..." # lsof -i : -t lists PIDs listening on the port # The output might be empty or multiple PIDs. # We'll kill any PID found. PIDS_ON_PORT=$(lsof -i ":$PORT" -t 2>/dev/null || true) # Suppress lsof error if port not in use, || true ensures command doesn't fail script if [ -n "$PIDS_ON_PORT" ]; then for PID_TO_KILL in $PIDS_ON_PORT; do echo "Port $PORT is in use by PID $PID_TO_KILL. Forcing kill..." kill -9 "$PID_TO_KILL" # Force kill # Add a small delay to give the OS time to free the port sleep 0.5 done else echo "Port $PORT is free." fi fi # The circle name passed to the server is the "identity" name. # The client will still connect to ws://localhost:PORT/ws echo "Starting server for '$NAME' on port $PORT..." # Run in background "$WS_SERVER_BINARY" --port "$PORT" --circle-name "$NAME" & BG_PIDS+=($!) # Store PID of the last backgrounded process done echo "All WebSocket servers launched." # Prepare circle names for rhai_worker # It expects names like "OurWorld", "My Personal Space" # We can directly use the CIRCLE_NAMES array echo "Starting Rhai worker for circles: ${CIRCLE_NAMES[@]}..." # Run rhai_worker in the background # Assuming default Redis URL redis://127.0.0.1/ "$RHAI_WORKER_BINARY" --circles "${CIRCLE_NAMES[@]}" & BG_PIDS+=($!) # Store PID of the Rhai worker echo "Rhai worker launched." echo "All processes launched. Press Ctrl+C to stop all servers and the worker." # Wait for all background PIDs. # If any of them exit prematurely, this script will also exit. # The trap will handle cleanup if Ctrl+C is pressed. for pid in "${BG_PIDS[@]}"; do wait "$pid" # If a process exits with an error, its exit code will be propagated by wait. # The script will then exit due to `wait` itself exiting with that code. # The trap should still run on SIGINT/SIGTERM. # For other signals or unexpected exits, the trap might not run. # More robust error handling for individual process failures could be added here. done # If all processes exited cleanly (e.g., were killed by the trap), # the script will reach here. The trap's exit 0 will handle this. # If they exited due to an error, `wait` would have exited the script. cleanup # Call cleanup if all jobs finished normally (e.g. if they self-terminate)