diff --git a/src/backend.go b/src/backend.go index cf2be4e..0ff69d3 100644 --- a/src/backend.go +++ b/src/backend.go @@ -7,6 +7,7 @@ import ( "io" "slices" "strings" + "sync" "time" ) @@ -21,6 +22,10 @@ func splitBlobName(name string) []string { } } +type GetManifestOptions struct { + BypassCache bool +} + type Backend interface { // Retrieve a blob. Returns `reader, size, mtime, err`. GetBlob(ctx context.Context, name string) (reader io.ReadSeeker, size uint64, mtime time.Time, err error) @@ -52,8 +57,40 @@ type Backend interface { CheckDomain(ctx context.Context, domain string) (found bool, err error) } -type GetManifestOptions struct { - BypassCache bool +// Retrieve several manifests. This operation succeeds if all requested manifests could be +// retrieved, and fails otherwise. The returned error is the first error that occurs. +func GetManifests( + backend Backend, ctx context.Context, names []string, opts GetManifestOptions, +) ( + manifests map[string]*Manifest, err error, +) { + type Result struct { + name string + manifest *Manifest + err error + } + + wg := sync.WaitGroup{} + ch := make(chan Result, len(names)) + for _, name := range names { + wg.Go(func() { + manifest, err := backend.GetManifest(ctx, name, opts) + ch <- Result{name, manifest, err} + }) + } + wg.Wait() + close(ch) + + manifests = make(map[string]*Manifest) + for result := range ch { + if result.err == nil { + manifests[result.name] = result.manifest + } else { + err = result.err + break + } + } + return } var backend Backend