depot/web/fup/fuphttp/metadata.go
Luke Granger-Brown 4c4bd46aa8 fup: factor out metadata retrieval into a separate file
We'll need this for cleanup operations as well. This should likely be factored
out again into an entirely separate package that deals with storage access.
2021-03-21 15:17:46 +00:00

65 lines
1.5 KiB
Go

package fuphttp
import (
"context"
"fmt"
"log"
"strconv"
"time"
"gocloud.dev/blob"
"gocloud.dev/gcerrors"
)
type Metadata struct {
// ExpiresAt is the expiry time of the object.
// May be the zero time, if this object does not expire.
// Stored in expires-at.
ExpiresAt time.Time
// Attributes is the underlying gocloud Attributes.
Attributes *blob.Attributes
}
// metadata retrieves the Metadata for the object.
// Note: if the object is expired, it will delete it.
func metadata(ctx context.Context, bucket *blob.Bucket, filename string) (*Metadata, error) {
attrs, err := bucket.Attributes(ctx, filename)
if err != nil {
return nil, fmt.Errorf("Attributes(%q): %w", filename, err)
}
m := Metadata{
Attributes: attrs,
}
var exp time.Time
if expStr, ok := attrs.Metadata["expires-at"]; ok {
// Check for expiry.
expSec, err := strconv.ParseInt(expStr, 10, 64)
if err != nil {
return nil, fmt.Errorf("parsing expiration %q for %q: %v", expStr, filename, err)
}
exp = time.Unix(expSec, 0)
if exp.Before(time.Now()) {
// This file has expired. Delete it from the backing storage.
err := bucket.Delete(ctx, filename)
switch errorCode(err) {
case gcerrors.NotFound:
// Something probably deleted it before we could get there.
case gcerrors.OK:
// This was fine.
default:
log.Printf("deleting expired file %q: %v", filename, err)
}
return nil, &fupError{
Code: gcerrors.NotFound,
}
}
m.ExpiresAt = exp
}
return &m, nil
}