66 lines
1.5 KiB
Go
66 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
|
||
|
}
|