Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions internal/services/image_processor/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const (
DataTypeStaff DataType = imagepath.TypeStaff
DataTypeBanner DataType = imagepath.TypeBanner
DataTypePoster DataType = imagepath.TypePoster
DataTypeWork DataType = imagepath.TypeWork
)

type Payload struct {
Expand Down
8 changes: 8 additions & 0 deletions internal/services/imagepath/imagepath.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ const (
// fills a phone hero. Both are 2:3 "posters" in the everyday sense, so the
// distinction is: root = whatever the scraper had, /posters/ = the good one.
TypePoster = "Poster"

// TypeWork is a source work's cover -- manga, light novel, novel. Kept under
// its own prefix rather than at the root beside anime because the root is
// keyed by anime id and a work id there would be indistinguishable from one,
// which is exactly the kind of collision this package exists to prevent.
TypeWork = "Work"
)

// For builds the object path for an image record.
Expand Down Expand Up @@ -47,6 +53,8 @@ func For(dataType, id, name string) (string, bool) {
return "/banners/" + key, true
case TypePoster:
return "/posters/" + key, true
case TypeWork:
return "/works/" + key, true
default:
return "", false
}
Expand Down
12 changes: 12 additions & 0 deletions internal/services/imagepath/imagepath_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func TestFor(t *testing.T) {
{"staff", TypeStaff, id, "", "/staff/" + id, true},
{"banner", TypeBanner, id, "", "/banners/" + id, true},
{"poster is its own path, not the root", TypePoster, id, "", "/posters/" + id, true},
{"work", TypeWork, id, "", "/works/" + id, true},

// Name is only a fallback for messages published before producers sent
// ids: in-flight during a rolling deploy, and the retry topic.
Expand Down Expand Up @@ -64,4 +65,15 @@ func TestPosterDoesNotCollideWithAnimeRoot(t *testing.T) {
if root == poster {
t.Fatalf("anime and poster resolved to the same path %q", root)
}

// A work and an anime are different records that could share an id shape.
// If a work ever landed at the root it would overwrite an anime's poster,
// and nothing downstream would report it -- the upload succeeds either way.
work, ok := For(TypeWork, id, "")
if !ok {
t.Fatal("work path not ok")
}
if work == root {
t.Fatalf("work and anime resolved to the same path %q", work)
}
}
Loading