一切皆为插件的开发者工具运行时框架
🧩 核心特性:
- 插件热插拔 (importlib 动态加载)
- 依赖自动解析 (拓扑排序 + 循环检测)
- 企业级稳定 (熔断/降级/重试/隔离)
- 事件驱动 (发布/订阅事件总线)
- 完整配置 (YAML 配置 + 热重载)
181 lines
6.9 KiB
Bash
Executable File
181 lines
6.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# ═══════════════════════════════════════════════════════════
|
||
# FutureOSS 启动脚本 — Linux / macOS
|
||
# 自动检测 Python / 依赖 / 守护 / 崩溃重启
|
||
# ═══════════════════════════════════════════════════════════
|
||
|
||
set -e
|
||
|
||
# ── 颜色 ──
|
||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
||
CYAN='\033[0;36m'; WHITE='\033[1;37m'; BOLD='\033[1m'; NC='\033[0m'
|
||
|
||
LOGO="
|
||
███████╗ ██████╗ ██████╗ ██████╗ ██████╗ ██████╗
|
||
██╔════╝ ██╔══██╗ ██╔══██╗ ██╔══██╗ ██╔══██╗██╔════╝
|
||
█████╗ ██████╔╝ ██████╔╝ ██████╔╝ ██║ ██║██║ ███╗
|
||
██╔══╝ ██╔══██╗ ██╔══██╗ ██╔══██╗ ██║ ██║██║ ██║
|
||
██║ ██║ ██║ ██║ ██║ ██║ ██║ ██████╔╝╚██████╔╝
|
||
╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝"
|
||
|
||
info() { echo -e "${CYAN}ℹ $1${NC}"; }
|
||
ok() { echo -e "${GREEN}✓ $1${NC}"; }
|
||
warn() { echo -e "${YELLOW}⚠ $1${NC}"; }
|
||
err() { echo -e "${RED}✗ $1${NC}"; }
|
||
title() { echo -e "\n${BOLD}$1${NC}"; }
|
||
|
||
# ── 守护参数 ──
|
||
DAEMON=false
|
||
if [[ "$1" == "--daemon" || "$1" == "-d" ]]; then
|
||
DAEMON=true
|
||
fi
|
||
|
||
title "$LOGO"
|
||
echo -e "${WHITE} 一切皆为插件 · 零编译热插拔${NC}"
|
||
echo -e "${WHITE} https://gitee.com/starlight-apk/feature-oss${NC}"
|
||
echo ""
|
||
|
||
# ── 目录 ──
|
||
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
cd "$PROJECT_DIR"
|
||
|
||
# ═══════════════════════════════════════════════════════════
|
||
# 1. 检查 Python
|
||
# ═══════════════════════════════════════════════════════════
|
||
title "📦 环境检测"
|
||
|
||
find_python() {
|
||
for cmd in python3 python python3.12 python3.11 python3.10; do
|
||
if command -v "$cmd" &>/dev/null; then
|
||
echo "$cmd"
|
||
return
|
||
fi
|
||
done
|
||
return 1
|
||
}
|
||
|
||
PYTHON_CMD=$(find_python || true)
|
||
|
||
if [[ -z "$PYTHON_CMD" ]]; then
|
||
warn "未检测到 Python,正在自动安装..."
|
||
if command -v apt-get &>/dev/null; then
|
||
sudo apt-get update -qq && sudo apt-get install -y -qq python3 python3-pip python3-venv
|
||
elif command -v yum &>/dev/null; then
|
||
sudo yum install -y python3 python3-pip
|
||
elif command -v pacman &>/dev/null; then
|
||
sudo pacman -Sy --noconfirm python python-pip
|
||
elif command -v brew &>/dev/null; then
|
||
brew install python
|
||
elif command -v apk &>/dev/null; then
|
||
apk add python3 py3-pip
|
||
else
|
||
err "无法自动安装 Python,请手动安装 Python 3.10+"
|
||
exit 1
|
||
fi
|
||
PYTHON_CMD=$(find_python || true)
|
||
[[ -z "$PYTHON_CMD" ]] && { err "Python 安装失败"; exit 1; }
|
||
fi
|
||
|
||
PY_VER=$($PYTHON_CMD --version 2>&1)
|
||
ok "Python: $PY_VER ($PYTHON_CMD)"
|
||
|
||
# ═══════════════════════════════════════════════════════════
|
||
# 2. 虚拟环境 & 依赖
|
||
# ═══════════════════════════════════════════════════════════
|
||
title "📚 依赖安装"
|
||
|
||
VENV_DIR=".venv"
|
||
if [[ ! -d "$VENV_DIR" ]]; then
|
||
info "创建虚拟环境..."
|
||
$PYTHON_CMD -m venv "$VENV_DIR"
|
||
fi
|
||
|
||
source "$VENV_DIR/bin/activate"
|
||
PIP_CMD="$VENV_DIR/bin/pip"
|
||
|
||
if [[ -f "pyproject.toml" ]]; then
|
||
info "安装项目依赖 (pyproject.toml)..."
|
||
$PIP_CMD install -e . -q 2>/dev/null || $PIP_CMD install -e . --break-system-packages -q 2>/dev/null || true
|
||
fi
|
||
|
||
if [[ -f "requirements.txt" ]]; then
|
||
info "安装 requirements.txt..."
|
||
$PIP_CMD install -r requirements.txt -q 2>/dev/null || true
|
||
fi
|
||
|
||
# 核心依赖兜底
|
||
for pkg in click pyyaml websockets; do
|
||
$PYTHON_CMD -c "import $pkg" 2>/dev/null || {
|
||
info "安装 $pkg ..."
|
||
$PIP_CMD install "$pkg" -q 2>/dev/null || $PIP_CMD install "$pkg" --break-system-packages -q 2>/dev/null || true
|
||
}
|
||
done
|
||
|
||
ok "依赖就绪"
|
||
|
||
# ═══════════════════════════════════════════════════════════
|
||
# 3. 确保 data 目录
|
||
# ═══════════════════════════════════════════════════════════
|
||
mkdir -p data/html-render data/web-toolkit data/plugin-storage data/DCIM data/pkg
|
||
|
||
# ═══════════════════════════════════════════════════════════
|
||
# 4. 启动
|
||
# ═══════════════════════════════════════════════════════════
|
||
title "🚀 启动 FutureOSS"
|
||
|
||
if $DAEMON; then
|
||
title "🔒 守护模式"
|
||
LOG_FILE="logs/futureoss.log"
|
||
mkdir -p logs
|
||
PID_FILE="logs/futureoss.pid"
|
||
|
||
if [[ -f "$PID_FILE" ]]; then
|
||
OLD_PID=$(cat "$PID_FILE")
|
||
if kill -0 "$OLD_PID" 2>/dev/null; then
|
||
warn "已有进程运行 (PID: $OLD_PID),正在停止..."
|
||
kill "$OLD_PID" 2>/dev/null || true
|
||
sleep 2
|
||
fi
|
||
fi
|
||
|
||
nohup $PYTHON_CMD -m oss.cli serve > "$LOG_FILE" 2>&1 &
|
||
NEW_PID=$!
|
||
echo "$NEW_PID" > "$PID_FILE"
|
||
ok "已启动守护进程 (PID: $NEW_PID)"
|
||
info "日志: $LOG_FILE"
|
||
info "停止: kill $(cat $PID_FILE) 或 bash start.sh stop"
|
||
sleep 2
|
||
curl -s http://localhost:8080/health &>/dev/null && ok "服务就绪: http://localhost:8080" || warn "服务启动中,请稍候..."
|
||
exit 0
|
||
fi
|
||
|
||
# ── 前台模式 + 崩溃自动重启 ──
|
||
RESTART_DELAY=3
|
||
MAX_RESTARTS=0
|
||
RESTART_COUNT=0
|
||
|
||
run_server() {
|
||
$PYTHON_CMD -m oss.cli serve
|
||
}
|
||
|
||
while true; do
|
||
run_server
|
||
EXIT_CODE=$?
|
||
|
||
if [[ $EXIT_CODE -eq 0 ]]; then
|
||
ok "服务正常退出"
|
||
break
|
||
fi
|
||
|
||
RESTART_COUNT=$((RESTART_COUNT + 1))
|
||
warn "服务异常退出 (code: $EXIT_CODE),${RESTART_DELAY}s 后重启... (第 $RESTART_COUNT 次)"
|
||
sleep $RESTART_DELAY
|
||
|
||
# 指数退避,最大 30s
|
||
if [[ $RESTART_DELAY -lt 30 ]]; then
|
||
RESTART_DELAY=$((RESTART_DELAY * 2))
|
||
fi
|
||
done
|
||
|
||
deactivate 2>/dev/null || true
|