init
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
def main() -> None:
|
||||
print("Hello from backend!")
|
||||
@@ -0,0 +1,112 @@
|
||||
# coding=utf-8
|
||||
"""
|
||||
@Time :2026/7/27
|
||||
@Author :tao.chen
|
||||
"""
|
||||
import httpx
|
||||
from fastapi import FastAPI, Request, Response, HTTPException, Depends, status
|
||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||
from typing import Optional
|
||||
|
||||
app = FastAPI(title="Jupyter Auth & Router Backend")
|
||||
|
||||
RUNTIME_BASE_URL = "http://127.0.0.1:8001"
|
||||
security = HTTPBearer(auto_error=False)
|
||||
|
||||
|
||||
class RuntimeClient:
|
||||
"""与 Runtime 管理服务交互"""
|
||||
|
||||
@staticmethod
|
||||
async def get_workspace(workspace_id: str) -> Optional[dict]:
|
||||
"""通过 action: get 查询单个 workspace 进程信息"""
|
||||
async with httpx.AsyncClient(base_url=RUNTIME_BASE_URL) as client:
|
||||
try:
|
||||
resp = await client.post(
|
||||
"/api/v1/jupyter",
|
||||
json={"action": "get", "workspace_id": workspace_id},
|
||||
timeout=3.0
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
return resp.json()
|
||||
return None
|
||||
except httpx.RequestError:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
async def start_workspace(workspace_id: str) -> dict:
|
||||
"""通过 action: start 启动 workspace 子进程"""
|
||||
async with httpx.AsyncClient(base_url=RUNTIME_BASE_URL) as client:
|
||||
resp = await client.post(
|
||||
"/api/v1/jupyter",
|
||||
json={"action": "start", "workspace_id": workspace_id},
|
||||
timeout=10.0
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
return resp.json()
|
||||
raise HTTPException(status_code=500, detail="Failed to start Jupyter process")
|
||||
|
||||
|
||||
async def get_workspace_from_db(workspace_id: str):
|
||||
"""查 MySQL 数据库校验 workspace 状态与权限(模拟)"""
|
||||
mock_db = {
|
||||
"test1234": {"workspace_id": "test1234", "is_locked": False, "owner_id": "user_001"}
|
||||
}
|
||||
return mock_db.get(workspace_id)
|
||||
|
||||
|
||||
def verify_jwt_token(token: str) -> str:
|
||||
"""校验用户 JWT"""
|
||||
if token == "invalid-token":
|
||||
raise HTTPException(status_code=401, detail="Invalid JWT")
|
||||
return "user_001"
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Auth & Dynamic Route 核心接口
|
||||
# ------------------------------------------------------------------
|
||||
@app.get("/api/v1/auth/jupyter")
|
||||
async def verify_jupyter_access(
|
||||
request: Request,
|
||||
response: Response,
|
||||
auth: Optional[HTTPAuthorizationCredentials] = Depends(security)
|
||||
):
|
||||
workspace_id = request.headers.get("X-Original-Workspace-Id")
|
||||
cookie_token = request.cookies.get("access_token")
|
||||
bearer_token = auth.credentials if auth else None
|
||||
|
||||
token = bearer_token or cookie_token
|
||||
if not token:
|
||||
raise HTTPException(status_code=401, detail="Missing Authentication Token")
|
||||
|
||||
if not workspace_id:
|
||||
raise HTTPException(status_code=400, detail="Missing Workspace ID")
|
||||
|
||||
# 1. 校验用户身份
|
||||
current_user_id = verify_jwt_token(token)
|
||||
|
||||
# 2. 查 MySQL:校验权限与锁定状态
|
||||
ws = await get_workspace_from_db(workspace_id)
|
||||
if not ws:
|
||||
raise HTTPException(status_code=404, detail="Workspace not found")
|
||||
if ws["is_locked"]:
|
||||
raise HTTPException(status_code=403, detail="Workspace is locked")
|
||||
|
||||
# 3. 使用 action: get 查询子进程
|
||||
ws_info = await RuntimeClient.get_workspace(workspace_id)
|
||||
|
||||
# 4. 若未运行/不存在,主动触发 start
|
||||
if not ws_info or ws_info.get("status") != "running":
|
||||
ws_info = await RuntimeClient.start_workspace(workspace_id)
|
||||
|
||||
target_port = ws_info.get("port")
|
||||
jupyter_token = ws_info.get("token")
|
||||
|
||||
if not target_port:
|
||||
raise HTTPException(status_code=500, detail="Jupyter instance missing port configuration")
|
||||
|
||||
# 5. 向 Nginx 返回 Upstream 地址与 Token
|
||||
response.headers["X-Upstream-Addr"] = f"http://127.0.0.1:{target_port}"
|
||||
response.headers["X-Jupyter-Internal-Token"] = jupyter_token or ""
|
||||
|
||||
return {"status": "ok"}
|
||||
Reference in New Issue
Block a user