Luke Granger-Brown
4c4bd46aa8
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.
65 lines
1.5 KiB
Go
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
|
|
}
|