mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-06 01:17:46 +08:00
feat: 扩展 Rust gateway 全功能模块,新增 billing/crypto/wallet crate 及完整数据层
- 新增 aether-billing、aether-crypto、aether-wallet 独立 crate - aether-data 扩展 repository 层:announcements、auth_modules、billing、 candidate_selection、gemini_file_mappings、global_models、management_tokens、 oauth_providers、proxy_nodes、quota、users、wallet 等模块 - aether-gateway 新增 api/auth/billing/control/middleware/scheduler/usage/ video_tasks/hooks/maintenance/model_fetch/provider_transport 等功能模块 - 重构 executor decision 和 gateway state 为模块目录结构 - 新增 gateway router、frontdoor 路由层及对应测试 - Python 侧 API 路由重构,新增 compat/support 模块 - 前端 Logo 组件更新及 Provider 管理页面调整
This commit is contained in:
@@ -1,17 +1,32 @@
|
||||
#!/bin/bash
|
||||
# 本地开发启动脚本
|
||||
set -euo pipefail
|
||||
clear
|
||||
clear >/dev/null 2>&1 || true
|
||||
|
||||
# 加载 .env 文件
|
||||
set -a
|
||||
source .env
|
||||
set +a
|
||||
|
||||
dotenv_has_key() {
|
||||
local key="$1"
|
||||
rg -q "^[[:space:]]*${key}=" .env
|
||||
}
|
||||
|
||||
# 构建 DATABASE_URL
|
||||
export DATABASE_URL="postgresql://${DB_USER:-postgres}:${DB_PASSWORD}@${DB_HOST:-localhost}:${DB_PORT:-5432}/${DB_NAME:-aether}"
|
||||
export REDIS_URL=redis://:${REDIS_PASSWORD}@${REDIS_HOST:-localhost}:${REDIS_PORT:-6379}/0
|
||||
|
||||
if ! dotenv_has_key "AETHER_GATEWAY_DATA_POSTGRES_URL"; then
|
||||
export AETHER_GATEWAY_DATA_POSTGRES_URL="${DATABASE_URL}"
|
||||
fi
|
||||
if ! dotenv_has_key "AETHER_GATEWAY_DATA_REDIS_URL"; then
|
||||
export AETHER_GATEWAY_DATA_REDIS_URL="${REDIS_URL}"
|
||||
fi
|
||||
if ! dotenv_has_key "AETHER_GATEWAY_DATA_ENCRYPTION_KEY"; then
|
||||
export AETHER_GATEWAY_DATA_ENCRYPTION_KEY="${ENCRYPTION_KEY:-}"
|
||||
fi
|
||||
|
||||
# 开发环境连接池低配(节省内存)
|
||||
export DB_POOL_SIZE=${DB_POOL_SIZE:-5}
|
||||
export DB_MAX_OVERFLOW=${DB_MAX_OVERFLOW:-5}
|
||||
@@ -20,6 +35,7 @@ export HTTP_KEEPALIVE_CONNECTIONS=${HTTP_KEEPALIVE_CONNECTIONS:-5}
|
||||
|
||||
EXECUTOR_PID=""
|
||||
GATEWAY_PID=""
|
||||
STARTUP_WAIT_EARLY_EXIT=false
|
||||
|
||||
cleanup() {
|
||||
if [ -n "${GATEWAY_PID}" ]; then
|
||||
@@ -36,141 +52,136 @@ cleanup() {
|
||||
wait "${EXECUTOR_PID}" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
if [ "${EXECUTOR_TRANSPORT:-}" = "unix_socket" ] && [ -n "${EXECUTOR_SOCKET_PATH:-}" ]; then
|
||||
rm -f "${EXECUTOR_SOCKET_PATH}" >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
wait_for_startup() {
|
||||
local pid="$1"
|
||||
local timeout_seconds="$2"
|
||||
local service_name="$3"
|
||||
shift 3
|
||||
|
||||
STARTUP_WAIT_EARLY_EXIT=false
|
||||
|
||||
local attempts=$((timeout_seconds * 10))
|
||||
if [ "${attempts}" -lt 1 ]; then
|
||||
attempts=1
|
||||
fi
|
||||
|
||||
for ((i = 0; i < attempts; i++)); do
|
||||
if "$@" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! kill -0 "${pid}" >/dev/null 2>&1; then
|
||||
STARTUP_WAIT_EARLY_EXIT=true
|
||||
echo "=> ${service_name} 启动进程已提前退出,请检查上面的日志。"
|
||||
return 1
|
||||
fi
|
||||
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
if "$@" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! kill -0 "${pid}" >/dev/null 2>&1; then
|
||||
STARTUP_WAIT_EARLY_EXIT=true
|
||||
echo "=> ${service_name} 启动进程已提前退出,请检查上面的日志。"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "=> ${service_name} 在 ${timeout_seconds}s 内未通过启动检查。"
|
||||
echo "=> 如果这是冷编译或存在并发 cargo 构建,可调大 *_STARTUP_TIMEOUT_SECONDS 后重试。"
|
||||
return 1
|
||||
}
|
||||
|
||||
# 本地开发默认约定:
|
||||
# - Rust aether-gateway 绑定 APP_PORT,作为唯一公开入口
|
||||
# - ./dev.sh 不再启动 Python 宿主;本地默认只验证 Rust-owned 路径
|
||||
APP_PORT=${APP_PORT:-8084}
|
||||
PYTHON_INTERNAL_HOST=${PYTHON_INTERNAL_HOST:-127.0.0.1}
|
||||
PYTHON_INTERNAL_PORT=${PYTHON_INTERNAL_PORT:-18084}
|
||||
RUST_SERVICE_STARTUP_TIMEOUT_SECONDS=${RUST_SERVICE_STARTUP_TIMEOUT_SECONDS:-120}
|
||||
EXECUTOR_STARTUP_TIMEOUT_SECONDS=${EXECUTOR_STARTUP_TIMEOUT_SECONDS:-${RUST_SERVICE_STARTUP_TIMEOUT_SECONDS}}
|
||||
GATEWAY_STARTUP_TIMEOUT_SECONDS=${GATEWAY_STARTUP_TIMEOUT_SECONDS:-${RUST_SERVICE_STARTUP_TIMEOUT_SECONDS}}
|
||||
|
||||
should_start_executor=false
|
||||
if [ "${DEV_START_EXECUTOR:-false}" = "true" ] || [ "${EXECUTOR_BACKEND:-rust}" = "rust" ]; then
|
||||
should_start_executor=true
|
||||
fi
|
||||
|
||||
should_start_gateway=true
|
||||
if [ "${DEV_START_GATEWAY:-true}" != "true" ]; then
|
||||
should_start_gateway=false
|
||||
fi
|
||||
|
||||
if [ "${should_start_executor}" = "true" ]; then
|
||||
if ! command -v cargo >/dev/null 2>&1; then
|
||||
echo "=> 未找到 cargo,无法启动 aether-executor。请先安装 Rust toolchain。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${EXECUTOR_TRANSPORT:-}" ]; then
|
||||
if [ "${should_start_gateway}" = "true" ]; then
|
||||
export EXECUTOR_TRANSPORT=tcp
|
||||
else
|
||||
export EXECUTOR_TRANSPORT=unix_socket
|
||||
fi
|
||||
if [ -n "${EXECUTOR_TRANSPORT:-}" ] && [ "${EXECUTOR_TRANSPORT}" != "tcp" ]; then
|
||||
echo "=> 本地 ./dev.sh 只支持 gateway -> executor 的 TCP 模式。"
|
||||
echo "=> 请移除 EXECUTOR_TRANSPORT=${EXECUTOR_TRANSPORT},或改为 EXECUTOR_TRANSPORT=tcp。"
|
||||
exit 1
|
||||
fi
|
||||
export EXECUTOR_SOCKET_PATH=${EXECUTOR_SOCKET_PATH:-/tmp/aether-executor.sock}
|
||||
export EXECUTOR_TRANSPORT=tcp
|
||||
export EXECUTOR_BASE_URL=${EXECUTOR_BASE_URL:-http://127.0.0.1:5219}
|
||||
export EXECUTOR_BIND=${EXECUTOR_BIND:-127.0.0.1:5219}
|
||||
|
||||
if [ "${EXECUTOR_TRANSPORT}" = "unix_socket" ]; then
|
||||
rm -f "${EXECUTOR_SOCKET_PATH}"
|
||||
echo "=> 启动 aether-executor (unix socket: ${EXECUTOR_SOCKET_PATH})..."
|
||||
cargo run -q -p aether-executor -- --transport unix_socket --unix-socket "${EXECUTOR_SOCKET_PATH}" &
|
||||
EXECUTOR_PID=$!
|
||||
echo "=> 启动 aether-executor (tcp: ${EXECUTOR_BIND})..."
|
||||
cargo run -q -p aether-executor -- --transport tcp --bind "${EXECUTOR_BIND}" &
|
||||
EXECUTOR_PID=$!
|
||||
|
||||
for _ in {1..100}; do
|
||||
if [ -S "${EXECUTOR_SOCKET_PATH}" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
if [ ! -S "${EXECUTOR_SOCKET_PATH}" ]; then
|
||||
echo "=> aether-executor 未能在预期时间内启动。"
|
||||
exit 1
|
||||
if ! wait_for_startup "${EXECUTOR_PID}" "${EXECUTOR_STARTUP_TIMEOUT_SECONDS}" "aether-executor" curl -sf "${EXECUTOR_BASE_URL}/health"; then
|
||||
if [ "${STARTUP_WAIT_EARLY_EXIT}" = "true" ]; then
|
||||
EXECUTOR_PID=""
|
||||
fi
|
||||
else
|
||||
echo "=> 启动 aether-executor (tcp: ${EXECUTOR_BIND})..."
|
||||
cargo run -q -p aether-executor -- --transport tcp --bind "${EXECUTOR_BIND}" &
|
||||
EXECUTOR_PID=$!
|
||||
|
||||
for _ in {1..100}; do
|
||||
if curl -sf "${EXECUTOR_BASE_URL}/health" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
if ! curl -sf "${EXECUTOR_BASE_URL}/health" >/dev/null 2>&1; then
|
||||
echo "=> aether-executor 未能在预期时间内启动。"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "${should_start_gateway}" = "true" ]; then
|
||||
if ! command -v cargo >/dev/null 2>&1; then
|
||||
echo "=> 未找到 cargo,无法启动 aether-gateway。请先安装 Rust toolchain。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export AETHER_GATEWAY_BIND=${AETHER_GATEWAY_BIND:-0.0.0.0:${APP_PORT}}
|
||||
export AETHER_GATEWAY_UPSTREAM=${AETHER_GATEWAY_UPSTREAM:-http://${PYTHON_INTERNAL_HOST}:${PYTHON_INTERNAL_PORT}}
|
||||
export AETHER_GATEWAY_CONTROL_URL=${AETHER_GATEWAY_CONTROL_URL:-http://${PYTHON_INTERNAL_HOST}:${PYTHON_INTERNAL_PORT}}
|
||||
if [ "${should_start_executor}" = "true" ] && [ "${EXECUTOR_TRANSPORT:-}" = "tcp" ]; then
|
||||
export AETHER_GATEWAY_EXECUTOR_URL=${AETHER_GATEWAY_EXECUTOR_URL:-${EXECUTOR_BASE_URL}}
|
||||
fi
|
||||
|
||||
if [ -n "${AETHER_GATEWAY_EXECUTOR_URL:-}" ]; then
|
||||
echo "=> 启动 aether-gateway (${AETHER_GATEWAY_BIND} -> ${AETHER_GATEWAY_UPSTREAM}, control=${AETHER_GATEWAY_CONTROL_URL}, executor=${AETHER_GATEWAY_EXECUTOR_URL})..."
|
||||
cargo run -q -p aether-gateway -- --bind "${AETHER_GATEWAY_BIND}" --upstream "${AETHER_GATEWAY_UPSTREAM}" --control-url "${AETHER_GATEWAY_CONTROL_URL}" --executor-url "${AETHER_GATEWAY_EXECUTOR_URL}" &
|
||||
else
|
||||
echo "=> 启动 aether-gateway (${AETHER_GATEWAY_BIND} -> ${AETHER_GATEWAY_UPSTREAM}, control=${AETHER_GATEWAY_CONTROL_URL})..."
|
||||
cargo run -q -p aether-gateway -- --bind "${AETHER_GATEWAY_BIND}" --upstream "${AETHER_GATEWAY_UPSTREAM}" --control-url "${AETHER_GATEWAY_CONTROL_URL}" &
|
||||
fi
|
||||
GATEWAY_PID=$!
|
||||
|
||||
for _ in {1..100}; do
|
||||
if curl -sf "http://127.0.0.1:${APP_PORT}/_gateway/health" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
if ! curl -sf "http://127.0.0.1:${APP_PORT}/_gateway/health" >/dev/null 2>&1; then
|
||||
echo "=> aether-gateway 未能在预期时间内启动。"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
PYTHON_BIND_HOST=${HOST:-0.0.0.0}
|
||||
PYTHON_BIND_PORT=${PORT:-${APP_PORT}}
|
||||
if [ "${should_start_gateway}" = "true" ]; then
|
||||
PYTHON_BIND_HOST=${PYTHON_INTERNAL_HOST}
|
||||
PYTHON_BIND_PORT=${PYTHON_INTERNAL_PORT}
|
||||
if ! command -v cargo >/dev/null 2>&1; then
|
||||
echo "=> 未找到 cargo,无法启动 aether-gateway。请先安装 Rust toolchain。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export HOST="${PYTHON_BIND_HOST}"
|
||||
export PORT="${PYTHON_BIND_PORT}"
|
||||
export AETHER_GATEWAY_BIND=${AETHER_GATEWAY_BIND:-0.0.0.0:${APP_PORT}}
|
||||
export AETHER_GATEWAY_UPSTREAM=${AETHER_GATEWAY_UPSTREAM:-http://127.0.0.1:9}
|
||||
export AETHER_GATEWAY_VIDEO_TASK_TRUTH_SOURCE_MODE=${AETHER_GATEWAY_VIDEO_TASK_TRUTH_SOURCE_MODE:-rust-authoritative}
|
||||
if [ "${should_start_executor}" = "true" ] && [ "${EXECUTOR_TRANSPORT:-}" = "tcp" ]; then
|
||||
export AETHER_GATEWAY_EXECUTOR_URL=${AETHER_GATEWAY_EXECUTOR_URL:-${EXECUTOR_BASE_URL}}
|
||||
fi
|
||||
|
||||
# 启动 uvicorn(热重载模式,只监视 src 目录)
|
||||
echo "=> 启动本地开发服务器..."
|
||||
if [ "${should_start_gateway}" = "true" ]; then
|
||||
echo "=> 主入口: http://localhost:${APP_PORT} (aether-gateway)"
|
||||
echo "=> Python内部: http://${PYTHON_BIND_HOST}:${PYTHON_BIND_PORT}"
|
||||
echo "=> Control API: ${AETHER_GATEWAY_CONTROL_URL}"
|
||||
if [ -n "${AETHER_GATEWAY_EXECUTOR_URL:-}" ]; then
|
||||
echo "=> Executor API: ${AETHER_GATEWAY_EXECUTOR_URL}"
|
||||
fi
|
||||
GATEWAY_ARGS=(--bind "${AETHER_GATEWAY_BIND}" --upstream "${AETHER_GATEWAY_UPSTREAM}")
|
||||
if [ -n "${AETHER_GATEWAY_EXECUTOR_URL:-}" ]; then
|
||||
GATEWAY_ARGS+=(--executor-url "${AETHER_GATEWAY_EXECUTOR_URL}")
|
||||
fi
|
||||
|
||||
if [ -n "${AETHER_GATEWAY_EXECUTOR_URL:-}" ]; then
|
||||
echo "=> 启动 aether-gateway (Rust frontdoor: ${AETHER_GATEWAY_BIND}, upstream=${AETHER_GATEWAY_UPSTREAM}, executor=${AETHER_GATEWAY_EXECUTOR_URL})..."
|
||||
else
|
||||
echo "=> 后端地址: http://localhost:${APP_PORT}"
|
||||
echo "=> 启动 aether-gateway (Rust frontdoor: ${AETHER_GATEWAY_BIND}, upstream=${AETHER_GATEWAY_UPSTREAM})..."
|
||||
fi
|
||||
cargo run -q -p aether-gateway -- "${GATEWAY_ARGS[@]}" &
|
||||
GATEWAY_PID=$!
|
||||
|
||||
if ! wait_for_startup "${GATEWAY_PID}" "${GATEWAY_STARTUP_TIMEOUT_SECONDS}" "aether-gateway" curl -sf "http://127.0.0.1:${APP_PORT}/_gateway/health"; then
|
||||
if [ "${STARTUP_WAIT_EARLY_EXIT}" = "true" ]; then
|
||||
GATEWAY_PID=""
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=> 启动本地开发服务..."
|
||||
echo "=> Rust公开入口: http://localhost:${APP_PORT}"
|
||||
echo "=> Frontdoor健康检查: http://localhost:${APP_PORT}/_gateway/health"
|
||||
echo "=> Legacy upstream: ${AETHER_GATEWAY_UPSTREAM}"
|
||||
if [ -n "${AETHER_GATEWAY_EXECUTOR_URL:-}" ]; then
|
||||
echo "=> Executor API: ${AETHER_GATEWAY_EXECUTOR_URL}"
|
||||
fi
|
||||
echo "=> 数据库: ${DATABASE_URL}"
|
||||
if [ "${should_start_executor}" = "true" ]; then
|
||||
echo "=> Executor 后端: ${EXECUTOR_BACKEND:-rust} (${EXECUTOR_TRANSPORT})"
|
||||
fi
|
||||
echo "=> 提示: 未下沉到 Rust 的 legacy 路由会直接失败,除非你手动设置了可用的 upstream/control URL。"
|
||||
echo ""
|
||||
|
||||
uv run uvicorn src.main:app --reload --reload-dir src --host "${PYTHON_BIND_HOST}" --port "${PYTHON_BIND_PORT}"
|
||||
wait "${GATEWAY_PID}"
|
||||
|
||||
Reference in New Issue
Block a user