mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
refactor: 移除 Python 后端源码,全面迁移至 Rust gateway 架构
- 删除全部 Python 源码 (src/) 及 Alembic 迁移脚本,归档至 _deprecated_py_src/ - 重构 Rust gateway ai_pipeline: 拆分 planner/finalize 模块,新增 contracts/adaptation 层 - 重组 handlers 模块为 admin/public/proxy/internal/shared 子模块结构 - 新增 executor 模块,引入 Rust 原生数据库迁移 (aether-data/migrations) - 简化 CI/Docker 构建流程,移除 base image 二级构建,统一为单一 app image - 移除 Python 相关基础设施文件 (entrypoint.sh, gunicorn_conf.py, Dockerfile.base)
This commit is contained in:
39
_deprecated_py_src/api/payment/__init__.py
Normal file
39
_deprecated_py_src/api/payment/__init__.py
Normal file
@@ -0,0 +1,39 @@
|
||||
"""Payment API routes."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter
|
||||
from starlette.routing import BaseRoute
|
||||
|
||||
from .routes import router as payment_router
|
||||
|
||||
_RUST_OWNED_PAYMENT_ROUTE_SIGNATURES = frozenset(
|
||||
{
|
||||
("POST", "/api/payment/callback/{payment_method}"),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _route_is_rust_owned(route: BaseRoute) -> bool:
|
||||
path = getattr(route, "path", None)
|
||||
methods = getattr(route, "methods", None)
|
||||
if not isinstance(path, str) or not methods:
|
||||
return False
|
||||
return any(
|
||||
(method, path) in _RUST_OWNED_PAYMENT_ROUTE_SIGNATURES
|
||||
for method in methods
|
||||
if method not in {"HEAD", "OPTIONS"}
|
||||
)
|
||||
|
||||
|
||||
def _build_python_payment_router() -> APIRouter:
|
||||
router = APIRouter()
|
||||
router.include_router(payment_router)
|
||||
router.routes = [route for route in router.routes if not _route_is_rust_owned(route)]
|
||||
return router
|
||||
|
||||
|
||||
python_payment_router = _build_python_payment_router()
|
||||
router = python_payment_router
|
||||
|
||||
__all__ = ["python_payment_router", "router"]
|
||||
97
_deprecated_py_src/api/payment/routes.py
Normal file
97
_deprecated_py_src/api/payment/routes.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""支付回调接口。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import secrets
|
||||
from typing import Any
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from src.config import config
|
||||
from src.database import get_db
|
||||
from src.services.payment import PaymentService
|
||||
|
||||
router = APIRouter(prefix="/api/payment", tags=["Payment"])
|
||||
CALLBACK_TOKEN_HEADER = "x-payment-callback-token"
|
||||
CALLBACK_SIGNATURE_HEADER = "x-payment-callback-signature"
|
||||
|
||||
|
||||
class PaymentCallbackPayload(BaseModel):
|
||||
callback_key: str = Field(..., min_length=1, max_length=128)
|
||||
order_no: str | None = Field(default=None, max_length=64)
|
||||
gateway_order_id: str | None = Field(default=None, max_length=128)
|
||||
amount_usd: float = Field(..., gt=0, allow_inf_nan=False)
|
||||
pay_amount: float | None = Field(default=None, gt=0, allow_inf_nan=False)
|
||||
pay_currency: str | None = Field(default=None, min_length=3, max_length=3)
|
||||
exchange_rate: float | None = Field(default=None, gt=0, allow_inf_nan=False)
|
||||
payload: dict[str, Any] | None = None
|
||||
|
||||
|
||||
def _verify_callback_request_auth(request: Request) -> None:
|
||||
expected_token = config.payment_callback_secret
|
||||
if not expected_token:
|
||||
raise HTTPException(status_code=503, detail="payment callback is disabled")
|
||||
|
||||
provided_token = (request.headers.get(CALLBACK_TOKEN_HEADER) or "").strip()
|
||||
if not provided_token or not secrets.compare_digest(provided_token, expected_token):
|
||||
raise HTTPException(status_code=401, detail="invalid payment callback token")
|
||||
|
||||
|
||||
async def _process_callback(
|
||||
*,
|
||||
payment_method: str,
|
||||
request: Request,
|
||||
payload: PaymentCallbackPayload,
|
||||
db: Session = Depends(get_db),
|
||||
) -> dict[str, Any]:
|
||||
if not payment_method:
|
||||
raise HTTPException(status_code=400, detail="payment_method is required")
|
||||
_verify_callback_request_auth(request)
|
||||
callback_signature = (request.headers.get(CALLBACK_SIGNATURE_HEADER) or "").strip()
|
||||
if not callback_signature:
|
||||
raise HTTPException(status_code=401, detail="missing payment callback signature")
|
||||
|
||||
try:
|
||||
callback_payload = payload.payload if payload.payload is not None else payload.model_dump()
|
||||
result = PaymentService.handle_callback(
|
||||
db,
|
||||
payment_method=payment_method,
|
||||
callback_key=payload.callback_key,
|
||||
payload=callback_payload,
|
||||
callback_signature=callback_signature,
|
||||
callback_secret=config.payment_callback_secret,
|
||||
order_no=payload.order_no,
|
||||
gateway_order_id=payload.gateway_order_id,
|
||||
amount_usd=payload.amount_usd,
|
||||
pay_amount=payload.pay_amount,
|
||||
pay_currency=payload.pay_currency,
|
||||
exchange_rate=payload.exchange_rate,
|
||||
)
|
||||
db.commit()
|
||||
return {
|
||||
**result,
|
||||
"payment_method": payment_method,
|
||||
"request_path": request.url.path,
|
||||
}
|
||||
except Exception as exc:
|
||||
db.rollback()
|
||||
if isinstance(exc, HTTPException):
|
||||
raise
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.post("/callback/{payment_method}")
|
||||
async def handle_payment_callback(
|
||||
payment_method: str,
|
||||
request: Request,
|
||||
payload: PaymentCallbackPayload,
|
||||
db: Session = Depends(get_db),
|
||||
) -> dict[str, Any]:
|
||||
return await _process_callback(
|
||||
payment_method=payment_method,
|
||||
request=request,
|
||||
payload=payload,
|
||||
db=db,
|
||||
)
|
||||
Reference in New Issue
Block a user