refactor(handlers): consume port interfaces, wire media+upload assembly (Task 25+26)
- H now holds only small port interfaces (UserStore/LibraryStore/BookStore/ ProgressStore/BookmarkStore/RateLimiter/Scanner/Media/UploadSessions); NewRouter is the composition root distributing *store.Store and *redispkg.R - ports.Media gains EnsurePage; ChaptersOf returns ports.Chapter (media's local duplicate dropped); *media.M now provably satisfies ports.Media; ports.UploadSessions gains LibraryID for root validation before Complete - content.go: duplicated page-index cache + cover self-heal + page extract logic removed in favor of media service — same redis keys, same contract; path traversal check stays in handler (403 semantics preserved) - getLibrary/getLibRow merged into getLib(c, id); idParam helper dedupes :id parsing; isUnique replaced by ports.IsUniqueViolation (Task 28 partial) - main.go assembles media + upload and passes upload.U as scanner Sweeper Full gate green: gofmt, vet, go test -p 1 (real PG+Redis, 0 skip)
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"booklib/internal/bookfile"
|
||||
"booklib/internal/config"
|
||||
"booklib/internal/ports"
|
||||
"booklib/internal/redispkg"
|
||||
)
|
||||
|
||||
@@ -22,6 +23,9 @@ type M struct {
|
||||
rdb *redispkg.R
|
||||
}
|
||||
|
||||
// compile-time proof that *M satisfies the consumer-side interface.
|
||||
var _ ports.Media = (*M)(nil)
|
||||
|
||||
func New(cfg *config.Config, rdb *redispkg.R) *M {
|
||||
return &M{cfg: cfg, rdb: rdb}
|
||||
}
|
||||
@@ -79,7 +83,7 @@ func (m *M) PageIndex(ctx context.Context, bookID int64, size, modTS int64, root
|
||||
}
|
||||
|
||||
// ChaptersOf derives chapters from a page index by grouping pages by parent directory.
|
||||
func (m *M) ChaptersOf(idx []string) []Chapter {
|
||||
func (m *M) ChaptersOf(idx []string) []ports.Chapter {
|
||||
type grp struct {
|
||||
dir string
|
||||
start int
|
||||
@@ -101,9 +105,9 @@ func (m *M) ChaptersOf(idx []string) []Chapter {
|
||||
return nil
|
||||
}
|
||||
titles := make(map[string]int)
|
||||
out := make([]Chapter, len(grps))
|
||||
out := make([]ports.Chapter, len(grps))
|
||||
for i, g := range grps {
|
||||
out[i] = Chapter{Title: path.Base(g.dir), Start: g.start}
|
||||
out[i] = ports.Chapter{Title: path.Base(g.dir), Start: g.start}
|
||||
titles[out[i].Title]++
|
||||
}
|
||||
for i, g := range grps {
|
||||
@@ -114,14 +118,8 @@ func (m *M) ChaptersOf(idx []string) []Chapter {
|
||||
return out
|
||||
}
|
||||
|
||||
// Chapter represents a CBZ chapter.
|
||||
type Chapter struct {
|
||||
Title string `json:"title"`
|
||||
Start int `json:"start"`
|
||||
}
|
||||
|
||||
// EnsurePage extracts a single page to the cache. Returns the cache file path.
|
||||
func (m *M) EnsurePage(bookID int64, size, modTS int64, root, rel string, n int, idx []string) (string, error) {
|
||||
func (m *M) EnsurePage(_ context.Context, bookID int64, size, modTS int64, root, rel string, n int, idx []string) (string, error) {
|
||||
if n >= len(idx) {
|
||||
return "", fmt.Errorf("page %d out of range", n)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user