feat(storage): implement NAS content storage with read/write capabilities
Build and Push Reader API Image / docker (push) Successful in 1m3s
Build and Push Reader API Image / docker (push) Successful in 1m3s
feat(docker): configure NAS content and EPUB source directories in docker-compose feat(migrations): add tables for SourceAsset, ImportJob, ChapterContentRef, and AssetNovelMapping feat(scripts): create backfill script for populating ChapterContentRef from MongoDB chapters
This commit is contained in:
+4
-1
@@ -121,7 +121,10 @@ async def resolve_current_user(db: AsyncSession, request: Request) -> dict[str,
|
||||
return await _get_user_from_session_cookie(db, request)
|
||||
|
||||
|
||||
async def require_current_user(db: AsyncSession, request: Request) -> dict[str, Any]:
|
||||
async def require_current_user(
|
||||
request: Request,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
) -> dict[str, Any]:
|
||||
user = await resolve_current_user(db, request)
|
||||
if not user:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
@@ -20,6 +20,9 @@ class Settings(BaseSettings):
|
||||
r2_secret_access_key: str = ""
|
||||
r2_bucket_name: str = ""
|
||||
r2_public_base_url: str = ""
|
||||
nas_content_root: str = "./data/content"
|
||||
epub_source_root: str = "./data/epub-source"
|
||||
chapter_content_mode: str = "nas_first" # nas_first | mongo_first
|
||||
|
||||
deepseek_key: str = ""
|
||||
deepseek_model: str = "deepseek-chat"
|
||||
|
||||
+956
-16
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
||||
from app.config import settings
|
||||
|
||||
|
||||
class NasContentStorage:
|
||||
def __init__(self, root_dir: str):
|
||||
self.root = Path(root_dir).resolve()
|
||||
self.root.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def _resolve(self, href: str) -> Path:
|
||||
rel = href.strip().lstrip("/")
|
||||
target = (self.root / rel).resolve()
|
||||
if self.root not in target.parents and target != self.root:
|
||||
raise ValueError("Invalid storage href")
|
||||
return target
|
||||
|
||||
def read_text(self, href: str) -> str:
|
||||
path = self._resolve(href)
|
||||
return path.read_text(encoding="utf-8")
|
||||
|
||||
def write_text(self, href: str, content: str) -> dict[str, str | int]:
|
||||
path = self._resolve(href)
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(content, encoding="utf-8")
|
||||
digest = hashlib.sha256(content.encode("utf-8")).hexdigest()
|
||||
return {"href": href, "sha256": digest, "size": len(content.encode("utf-8"))}
|
||||
|
||||
|
||||
storage = NasContentStorage(settings.nas_content_root)
|
||||
Reference in New Issue
Block a user