Documentation
¶
Overview ¶
Package githubhttp builds the layered HTTP transport chain used for all GitHub REST API calls: auth → httpcache (ETag + two-tier LRU/disk store) → revalidation suppressor.
The goal is to make repeated per-repo Contents API probes (e.g. by eza --icons listing ~/github.com/<owner>/) effectively free: once warm, each request is served from the in-process LRU without any network I/O, for SuppressDuration after the last hit.
Chain shape (outermost first):
Suppressor ← 5-min window: Cache-Control: only-if-cached, zero network
└─ httpcache.Transport ← RFC-7234 ETag cache, X-From-Cache: 1 on hit
└─ AuthTransport ← token injection + header normalisation
└─ http.DefaultTransport
Index ¶
Constants ¶
const ( DefaultMemCacheMB = 128 DefaultSuppressDur = 5 * time.Minute DefaultMaxCachedURLs = 1000 )
Default cache sizing + suppression window.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AuthTransport ¶
type AuthTransport struct {
Token string
Base http.RoundTripper
Logger *slog.Logger
}
AuthTransport attaches an auth token + normalises response headers so the downstream httpcache layer can actually cache things.
Normalisations (all required by gregjones/httpcache):
- Date header set/refreshed on 304s and any response missing it.
- Vary and X-Varied-* stripped (GitHub returns Vary: Accept, Accept-Encoding which would otherwise partition the cache and defeat it for nearly every request).
- Synthetic ETag injected on 404s so "this doesn't exist" is cacheable (avoids re-probing missing paths).
type Client ¶
type Client struct {
HTTP *http.Client
// Suppressor is nil when Disabled. Its ClearSuppressionCache
// method makes the next request for any URL fall through to the
// httpcache revalidation path instead of the "only-if-cached"
// shortcut.
Suppressor *Suppressor
}
Client is the assembled HTTP client plus the runtime handle the SIGUSR1 handler needs to force-refresh cached data.
type Config ¶
type Config struct {
// Token is the GitHub PAT to attach as `Authorization: token <T>`.
// Empty => anonymous.
Token string
// CacheDir is the disk-cache root (e.g. ~/.cache/ghfs). Empty
// disables the disk tier (in-memory LRU only). Disabled wins
// over both.
CacheDir string
// MemCacheMB is the in-memory LRU budget in MiB. 0 => default.
MemCacheMB int
// SuppressDuration is how long a URL stays "just served from
// cache, don't even revalidate". 0 => default.
SuppressDuration time.Duration
// Disabled skips the entire cache chain (just AuthTransport).
Disabled bool
// Logger receives HTTP request traces (at debug) and cache
// clear notifications (at info). Must be non-nil.
Logger *slog.Logger
}
Config configures New.
type Suppressor ¶
type Suppressor struct {
Base http.RoundTripper
SuppressDuration time.Duration
Logger *slog.Logger
MaxEntries int // 0 => DefaultMaxCachedURLs
// contains filtered or unexported fields
}
Suppressor sits above httpcache. For SuppressDuration after a cache hit on a URL, it replays the request with Cache-Control: only-if-cached — httpcache then serves from storage without ever touching the network (not even an If-None-Match revalidation).
Without this, GitHub will 304 every request with ~30ms RTT, which multiplied by N repos becomes visible to eza --icons.
func (*Suppressor) ClearSuppressionCache ¶
func (r *Suppressor) ClearSuppressionCache()
ClearSuppressionCache forces the next request for every URL to go through revalidation (304 or full response) rather than the only-if-cached shortcut. SIGUSR1 should call this so users can see fresh data without unmounting.