feat(3D): 휠 방향 반전·회전점 표시 + 3D/등고선 브라우저 보관함
- 휠 위 = 축소로 반전, 커서 지점을 축으로 한 dolly를 공용 유틸에서 직접 처리 - 회전 중심을 작은 구로 표시(돌리는 동안만, 화면상 크기 일정, 항상 위에 그림) - 등고선 렌더 비용 감소: 폴리라인을 주곡선·보조곡선 2덩어리로 병합(드로우콜 424 → 2), 라벨은 카메라가 움직였을 때만 재배치 - common_util_http_cache: 파일 mtime+크기 ETag, If-None-Match 일치 시 304 (preview·contour 적용, 파일이 바뀌면 자동 무효화) - A00_Common/b_asset_cache: IndexedDB 보관함(키 = projectId|url, 값 = 바이트+ETag). 보관본 즉시 사용 후 백그라운드 재검증, 3D는 보관 바이트를 직접 파싱 - 프로젝트 전환 시 타 프로젝트 보관분 삭제, 대시보드→B그룹 이동 시 확정 모델의 3D 프리뷰·등고선(1.0m) 미리 받기(포인트클라우드 제외)
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
"""파일 응답에 브라우저 캐시 검증(ETag)을 붙이는 공통 유틸.
|
||||
|
||||
3D 프리뷰·등고선처럼 한 번 만들면 잘 바뀌지 않는 파일은, 브라우저가 이미 받아 둔 것을
|
||||
그대로 쓰게 해야 새로고침이 빠르다. 그렇다고 무조건 캐시를 믿게 두면 모델을 다시 만들었을 때
|
||||
옛 파일이 계속 보인다.
|
||||
|
||||
그래서 파일의 수정시각·크기로 ETag를 만들어 보내고, 브라우저가 같은 ETag를 들고 오면
|
||||
본문 없이 304만 돌려준다. 파일이 바뀌면 ETag가 저절로 달라져 새 파일을 받는다.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import Request
|
||||
from fastapi.responses import FileResponse, Response
|
||||
|
||||
# 항상 서버에 물어보되(변경 감지), 안 바뀌었으면 본문을 다시 받지 않는다.
|
||||
CACHE_CONTROL = "private, max-age=0, must-revalidate"
|
||||
|
||||
|
||||
def file_etag(path: Path) -> str:
|
||||
"""파일 수정시각·크기로 만든 ETag. 파일이 바뀌면 값이 달라진다."""
|
||||
stat = path.stat()
|
||||
return f'"{int(stat.st_mtime)}-{stat.st_size}"'
|
||||
|
||||
|
||||
def cached_file_response(
|
||||
request: Request,
|
||||
path: Path,
|
||||
media_type: str,
|
||||
filename: str | None = None,
|
||||
) -> Response:
|
||||
"""ETag를 붙인 파일 응답. 브라우저가 가진 것과 같으면 304만 돌려준다."""
|
||||
etag = file_etag(path)
|
||||
headers = {"ETag": etag, "Cache-Control": CACHE_CONTROL}
|
||||
if request.headers.get("if-none-match") == etag:
|
||||
return Response(status_code=304, headers=headers)
|
||||
return FileResponse(path, media_type=media_type, filename=filename, headers=headers)
|
||||
Reference in New Issue
Block a user