Files
get_wechat/chatlog_fastAPI/routers/chatlog_proxy.py

94 lines
2.8 KiB
Python

from urllib.parse import quote
import httpx
from fastapi import APIRouter, Request
from fastapi.responses import Response, StreamingResponse
from config import settings
router = APIRouter(tags=["chatlog-proxy"])
HOP_BY_HOP_HEADERS = {
"connection",
"keep-alive",
"proxy-authenticate",
"proxy-authorization",
"te",
"trailers",
"transfer-encoding",
"upgrade",
}
def _copy_headers(headers: httpx.Headers) -> dict[str, str]:
copied: dict[str, str] = {}
for key, value in headers.items():
if key.lower() not in HOP_BY_HOP_HEADERS:
copied[key] = value
return copied
async def _proxy_chatlog(request: Request, upstream_path: str) -> Response:
query = request.url.query
target = f"{settings.chatlog_base_url}{upstream_path}"
if query:
target = f"{target}?{query}"
body = await request.body()
headers = {
key: value
for key, value in request.headers.items()
if key.lower() not in HOP_BY_HOP_HEADERS and key.lower() != "host"
}
async with httpx.AsyncClient(timeout=None, trust_env=False, follow_redirects=True) as client:
upstream = await client.request(
request.method,
target,
content=body if body else None,
headers=headers,
)
response_headers = _copy_headers(upstream.headers)
return StreamingResponse(
iter([upstream.content]),
status_code=upstream.status_code,
media_type=upstream.headers.get("content-type"),
headers=response_headers,
)
@router.api_route("/api/v1/{path:path}", methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"])
async def proxy_api_v1(path: str, request: Request):
return await _proxy_chatlog(request, f"/api/v1/{path}")
async def _proxy_media(kind: str, path: str, request: Request):
safe_path = "/".join(quote(part, safe="") for part in path.split("/"))
return await _proxy_chatlog(request, f"/{kind}/{safe_path}")
@router.api_route("/image/{path:path}", methods=["GET", "POST", "OPTIONS"])
async def proxy_image(path: str, request: Request):
return await _proxy_media("image", path, request)
@router.api_route("/voice/{path:path}", methods=["GET", "POST", "OPTIONS"])
async def proxy_voice(path: str, request: Request):
return await _proxy_media("voice", path, request)
@router.api_route("/video/{path:path}", methods=["GET", "POST", "OPTIONS"])
async def proxy_video(path: str, request: Request):
return await _proxy_media("video", path, request)
@router.api_route("/file/{path:path}", methods=["GET", "POST", "OPTIONS"])
async def proxy_file(path: str, request: Request):
return await _proxy_media("file", path, request)
@router.api_route("/data/{path:path}", methods=["GET", "POST", "OPTIONS"])
async def proxy_data(path: str, request: Request):
return await _proxy_media("data", path, request)