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 }