1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
// Package cache implements caching of GraphQL requests by allowing resolvers to provide hints about their cacheability,
// which can be used by the transport handlers (e.g. HTTP) to provide caching indicators in the response.
package cache
import (
"context"
"fmt"
"time"
)
type ctxKey string
const (
hintsKey ctxKey = "hints"
)
type scope int
// Cache control scopes.
const (
ScopePublic scope = iota
ScopePrivate
)
const (
hintsBuffer = 20
)
// Hint defines a hint as to how long something should be cached for.
type Hint struct {
MaxAge *time.Duration
Scope scope
}
// String resolves the HTTP Cache-Control value of the Hint.
func (h Hint) String() string {
var s string
switch h.Scope {
case ScopePublic:
s = "public"
case ScopePrivate:
s = "private"
}
return fmt.Sprintf("%s, max-age=%d", s, int(h.MaxAge.Seconds()))
}
// TTL defines the cache duration.
func TTL(d time.Duration) *time.Duration {
return &d
}
// AddHint applies a caching hint to the request context.
func AddHint(ctx context.Context, hint Hint) {
c := hints(ctx)
if c == nil {
return
}
c <- hint
}
// Hintable extends the context with the ability to add cache hints.
func Hintable(ctx context.Context) (hintCtx context.Context, hint <-chan Hint, done func()) {
hints := make(chan Hint, hintsBuffer)
h := make(chan Hint)
go func() {
h <- resolve(hints)
}()
done = func() {
close(hints)
}
return context.WithValue(ctx, hintsKey, hints), h, done
}
func hints(ctx context.Context) chan Hint {
h, ok := ctx.Value(hintsKey).(chan Hint)
if !ok {
return nil
}
return h
}
func resolve(hints <-chan Hint) Hint {
var minAge *time.Duration
s := ScopePublic
for h := range hints {
if h.Scope == ScopePrivate {
s = h.Scope
}
if h.MaxAge != nil && (minAge == nil || *h.MaxAge < *minAge) {
minAge = h.MaxAge
}
}
if minAge == nil {
var noCache time.Duration
minAge = &noCache
}
return Hint{MaxAge: minAge, Scope: s}
}
|