A cached source and its variants were served until eviction, so a
changed image at the same URL was never picked up.
Once a source was last checked 24 hours ago, the next request for one
of its images asks upstream with If-None-Match and If-Modified-Since,
from the ETag and Last-Modified it stored. A 304 renews the source and
its variant without a download or a conversion. New bytes replace the
source, and each variant made before them is converted again. A failed
check serves the cached image and puts the URL in the negative cache.
Sources and variants not checked successfully for 30 days are evicted.
A variant file's modification time is its source's check time, so a
hit still makes no database call.
Existing tests change only in call signatures. The test that asserted
two-day-old entries are served without asking upstream is replaced by
the new ones.
Model: opus-5-5
The new package internal/imageproxy holds Proxy, which was imgcache.Service,
with its Config, ImageResponse, CacheStatus and errors. imageproxy.New makes
and registers the counters of upstream fetches and transforms.
internal/imgcache holds the cache only, with its hit and miss counters, and
imgcache.CacheConfig is imgcache.Config. The cache reads and writes each kind
it keeps with one pair of methods: Variant and PutVariant, Source and
PutSource, Failure and PutFailure. Source replaces LookupSource followed by
GetSourceContent. imgcache.go and module.go are gone. The proxy's tests moved
with it. The cache's tests check that the reconciliation pass removes an empty
or cut file and its row. The proxy's tests remove them by hand, then check
that Get fetches or converts again.
Model: opus-5-5
seal.DeriveKeys derives the session hash and block keys, the encrypted URL
key and the CSRF key from the signing key, with their salts declared beside
it, and returns them as one seal.Keys. internal/providers calls it once at
startup and provides the value to the fx graph. The session manager, the
encrypted URL generator and the CSRF protection each take their own key.
session.NewManager, encurl.NewGenerator, newCSRFProtect and handlers.New
return no error, as nothing in them can fail now. Each key is derived as
before, with seal.DeriveKey and the same salt. The signing key itself stays
the HMAC key of signed URLs and the login password. README.md says under
signing_key what it protects.
Model: opus-5-5
The image request now holds only its source and its transform, exactly what
the variant key covers. The /v1/image/ handler checks the allowlist and
verifies the signature itself with Signer.Verify(req, sig, expires). Both
image handlers keep the URL's expiry as a local value for Cache-Control. The
image service holds no signer, allowlist or AllowHTTP, and ValidateRequest is
gone. The fetcher takes the source and builds its URL with Source.URL from its
own AllowHTTP, so no URL string is built and parsed again. chooseAutoFormat
returns the format it chooses instead of writing into the request. The signed
URL format and every route's answers are unchanged.
Model: opus-5-5
The new package internal/providers builds the cache, the fetcher, the
processor, the image service, the session manager and the encrypted URL
generator from the config. pixad's fx graph provides them with
providers.Constructors(), and handlers.New receives them built. The
server tests build the same graph, with only the fetcher's dial function
replaced. database.New opens the database, so these parts can read it
while fx builds them; the cache's stop hook still runs before the
database's.
Each setting's default is declared in internal/config, and
internal/providers works out the default cache_max_bytes. The cache's
MaxBytes is the one value for the disk cache limit, and 0 turns the disk
cache off. The fetcher and the processor take explicit values.
Model: opus-5-5