#!/usr/bin/env bash # 大时代 Development Startup Script # Split-service mode only set -euo pipefail echo "==========================================" echo "大时代 Development Environment" echo "==========================================" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "${SCRIPT_DIR}" PIDS=() require_command() { local command_name="$1" if ! command -v "${command_name}" >/dev/null 2>&1; then echo -e "${RED}Missing required command: ${command_name}${NC}" exit 1 fi } check_python_module() { local module_name="$1" if ! python -c "import ${module_name}" >/dev/null 2>&1; then echo -e "${RED}Missing required Python module: ${module_name}${NC}" echo "Install dependencies with one of:" echo " pip install -r requirements.txt" echo " pip install -r requirements-dev.txt" echo " uv pip install -e '.[dev]'" exit 1 fi } load_env_file() { if [ -f .env ]; then echo -e "${GREEN}Loading environment from .env${NC}" set -a source .env set +a else echo -e "${YELLOW}Warning: .env file not found. Copy env.template to .env first if you need live credentials.${NC}" fi } check_env_var() { local var_name="$1" local severity="${2:-warn}" local value="${!var_name:-}" if [ -z "${value}" ]; then if [ "${severity}" = "error" ]; then echo -e "${RED}Missing required environment variable: ${var_name}${NC}" exit 1 fi echo -e "${YELLOW}Warning: ${var_name} is not set${NC}" fi } check_openclaw_gateway() { local target_host="127.0.0.1" local target_port="18789" if python - </dev/null 2>&1 import socket sock = socket.socket() sock.settimeout(1.0) sock.connect(("${target_host}", ${target_port})) sock.close() PY then echo -e "${GREEN}OpenClaw gateway reachable at ws://${target_host}:${target_port}${NC}" else echo -e "${YELLOW}Warning: OpenClaw gateway is not reachable at ws://${target_host}:${target_port}${NC}" echo " OpenClaw panel features may be unavailable until it is started." fi } print_prereq_help() { echo "Environment checks:" echo " - repo root: ${SCRIPT_DIR}" echo " - python: $(command -v python)" if [ -n "${VIRTUAL_ENV:-}" ]; then echo " - virtualenv: ${VIRTUAL_ENV}" else echo " - virtualenv: not activated" fi } start_service() { local name="$1" local app_path="$2" local port="$3" echo -e "${GREEN}Starting ${name}${NC} on port ${port}..." SERVICE_NAME="${name}" python -m uvicorn "${app_path}" \ --host 0.0.0.0 \ --port "${port}" \ --reload \ --reload-dir backend \ --log-level warning \ --no-access-log & PIDS+=($!) } cleanup() { if [ "${#PIDS[@]}" -gt 0 ]; then echo "" echo -e "${YELLOW}Stopping development services...${NC}" kill "${PIDS[@]}" 2>/dev/null || true wait "${PIDS[@]}" 2>/dev/null || true fi } kill_port() { local port="$1" local pids=$(lsof -ti :${port} 2>/dev/null || true) if [ -n "$pids" ]; then echo -e "${YELLOW}Port ${port} is in use, killing PID(s): ${pids}${NC}" echo "$pids" | xargs kill -9 2>/dev/null || true sleep 0.5 fi } trap cleanup EXIT INT TERM if [ $# -gt 0 ]; then echo -e "${YELLOW}Ignoring legacy mode argument(s): $*${NC}" echo "Split-service mode is now the only supported development mode." fi require_command python require_command lsof if [ -z "${VIRTUAL_ENV:-}" ]; then if [ -f ".venv/bin/activate" ]; then echo -e "${YELLOW}Virtual environment not activated; auto-activating .venv${NC}" # shellcheck disable=SC1091 source .venv/bin/activate else echo -e "${YELLOW}Warning: no active virtual environment and .venv not found${NC}" fi fi load_env_file print_prereq_help python - <<'PY' import sys if sys.version_info < (3, 9): raise SystemExit("Python 3.9+ is required") print(f"Python version OK: {sys.version.split()[0]}") PY check_python_module fastapi check_python_module uvicorn check_python_module websockets check_python_module yaml check_python_module dotenv check_env_var OPENAI_API_KEY check_env_var FINNHUB_API_KEY check_env_var FIN_DATA_SOURCE if ! command -v npm >/dev/null 2>&1; then echo -e "${YELLOW}Warning: npm is not installed. Frontend startup via 'evotraders frontend' will not work.${NC}" fi export TRADING_SERVICE_URL="${TRADING_SERVICE_URL:-http://localhost:8001}" export NEWS_SERVICE_URL="${NEWS_SERVICE_URL:-http://localhost:8002}" export RUNTIME_SERVICE_URL="${RUNTIME_SERVICE_URL:-http://localhost:8003}" export OPENCLAW_SERVICE_URL="${OPENCLAW_SERVICE_URL:-http://localhost:18789}" check_openclaw_gateway echo "" echo -e "${GREEN}Starting 大时代 split services (default mode)...${NC}" echo " agent_service: http://localhost:8000" echo " runtime_service: http://localhost:8003" echo " openclaw_gateway: ws://localhost:18789" echo " trading_service: http://localhost:8001" echo " news_service: http://localhost:8002" echo "" echo "Exported backend preference URLs:" echo " TRADING_SERVICE_URL=${TRADING_SERVICE_URL}" echo " NEWS_SERVICE_URL=${NEWS_SERVICE_URL}" echo " RUNTIME_SERVICE_URL=${RUNTIME_SERVICE_URL}" echo " OPENCLAW_SERVICE_URL=${OPENCLAW_SERVICE_URL}" echo "" echo -e "${GREEN}Checking ports...${NC}" kill_port 8000 kill_port 8001 kill_port 8002 kill_port 8003 kill_port 8765 start_service "agent_service" "backend.apps.agent_service:app" 8000 start_service "runtime_service" "backend.apps.runtime_service:app" 8003 start_service "trading_service" "backend.apps.trading_service:app" 8001 start_service "news_service" "backend.apps.news_service:app" 8002 echo -e "${GREEN}Starting Gateway (WebSocket, port 8765)...${NC}" SERVICE_NAME="gateway" python -m backend.main \ --mode live \ --host 0.0.0.0 \ --port 8765 & PIDS+=($!) echo -e "${GREEN}Split services are running.${NC}" echo "Use Ctrl+C to stop all services." wait