mirror of
https://github.com/nprasad2077/NBA_Go.git
synced 2026-09-22 22:15:13 +00:00
78 lines
2.5 KiB
Go
78 lines
2.5 KiB
Go
package middleware
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
// CacheStrategy defines caching profiles for different API data mutability tiers
|
|
type CacheStrategy string
|
|
|
|
const (
|
|
// Immutable: For historical completed games, past seasons, and shot charts.
|
|
// Edge TTL: 30 Days | Browser TTL: 1 Day
|
|
Immutable CacheStrategy = "immutable"
|
|
|
|
// SemiDynamic: For daily leaderboards, player season averages, and standings.
|
|
// Edge TTL: 1 Day | Browser TTL: 1 Minute | Stale-While-Revalidate: 10 Minutes
|
|
SemiDynamic CacheStrategy = "semi_dynamic"
|
|
|
|
// Realtime: For active game telemetry, live quarter stats, and fast-updating data.
|
|
// Edge TTL: 10 Seconds | Browser TTL: 5 Seconds | Stale-While-Revalidate: 30 Seconds
|
|
Realtime CacheStrategy = "realtime"
|
|
|
|
// NoCache: For transactional mutations, scrapers, and admin endpoints.
|
|
NoCache CacheStrategy = "no_cache"
|
|
)
|
|
|
|
// EdgeCache injects standardized Cloudflare & HTTP caching headers
|
|
func EdgeCache(strategy CacheStrategy, tags ...string) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
// Only cache idempotent read requests (GET / HEAD)
|
|
if c.Method() != fiber.MethodGet && c.Method() != fiber.MethodHead {
|
|
c.Set("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate")
|
|
c.Set("Pragma", "no-cache")
|
|
c.Set("Expires", "0")
|
|
return c.Next()
|
|
}
|
|
|
|
switch strategy {
|
|
case Immutable:
|
|
// Served directly by Cloudflare US Edge for 30 days without hitting Europe origin
|
|
c.Set("Cache-Control", "public, max-age=86400, s-maxage=2592000, immutable")
|
|
case SemiDynamic:
|
|
// Instant edge delivery; background revalidation over transatlantic backbone
|
|
c.Set("Cache-Control", "public, max-age=60, s-maxage=86400, stale-while-revalidate=600")
|
|
case Realtime:
|
|
c.Set("Cache-Control", "public, max-age=5, s-maxage=10, stale-while-revalidate=30")
|
|
case NoCache:
|
|
c.Set("Cache-Control", "no-store, no-cache, must-revalidate")
|
|
return c.Next()
|
|
}
|
|
|
|
// Cloudflare Cache-Tag header for instantaneous programmatic purge by entity
|
|
if len(tags) > 0 {
|
|
var tagHeader string
|
|
for i, tag := range tags {
|
|
if i > 0 {
|
|
tagHeader += ","
|
|
}
|
|
tagHeader += tag
|
|
}
|
|
c.Set("Cache-Tag", tagHeader)
|
|
}
|
|
|
|
c.Set("Vary", "Accept-Encoding, Origin")
|
|
return c.Next()
|
|
}
|
|
}
|
|
|
|
// ComputeETag generates a weak ETag based on response body bytes for 304 Not Modified optimization
|
|
func ComputeETag(data []byte) string {
|
|
hash := sha256.Sum256(data)
|
|
return fmt.Sprintf(`W/"%s"`, hex.EncodeToString(hash[:8]))
|
|
}
|