Commit Graph
7 Commits
Author SHA1 Message Date
clawbot b73bbde46e Detect a fetched image's format from its bytes once (closes #319)
check / check (push) Canceled after 0s
magic.DetectFormat returns an imagerequest.Format. ValidateMagicBytes
returns the format it checked against the upstream Content-Type. The
cache reads a cached source's format from its file's first bytes, as it
reads a variant's. The proxy hands the format to Process. Process
refuses a format that is not a source format, and input libvips would
load with another loader, such as an SVG passing as AVIF.
Format.MIMEType declares each MIME string once, and the fetcher, the
cache's variant read and the Accept matching use it. magic.MIMEType,
magic.ImageFormat, MIMEToImageFormat, magic's SVG detection,
detectFormat, formatFromString, FormatToMIME and Result.InputFormat are
gone.

Model: opus-5-5
2026-10-26 21:21:39 +01:00
clawbot ac850823f4 Keep cached sources and variants in one FileStore type (closes #318)
check / check (push) Canceled after 0s
imgcache.FileStore is a directory of files named by a hex key, at
<ab>/<cd>/<key>. It writes a file under a temp name, syncs it and renames
it into place. It opens, reports the size of and deletes the file for a
key. The cache keeps its sources in one FileStore and its variants in
another, so ContentStorage and VariantStorage are gone. FileStore has no
Exists: the reconciliation pass checks a variant's file with Size, and the
tests look for the file on disk. Cache.Variant reads the content type from
the file's first bytes itself. storage.go is now filestore.go, and the
unused testdata/red.avif is gone.

Model: opus-5-5
2026-10-26 20:24:33 +01:00
clawbot 17376d885b Split internal/imgcache into the image proxy and the cache (closes #317)
check / check (push) Canceled after 0s
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
2026-10-26 20:00:25 +01:00
clawbot 63690a9ec9 Build the image pipeline in pixad's fx graph (closes #313)
check / check (push) Canceled after 0s
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
2026-10-26 12:28:23 +01:00
clawbot b49d0068df Count hits, misses, fetches and transforms as Prometheus counters (closes #311)
check / check (push) Canceled after 0s
The five counts the cache_stats table held are now Prometheus counters in
memory, as fields of the cache. NewCache makes them and registers them on
the registry it is given. pixad gives it Prometheus' default registry,
which /metrics serves; each test gives it a new one. The Increment methods
add to their cache's counters, so counting makes no database call.

cache_stats, Cache.Stats, Service.Stats, CacheStats and the pending counts
are gone, with their tests. The background goroutine now writes only access
times, and its names say so: StartPendingAccessTimeWrites,
StopPendingAccessTimeWrites and pendingaccesstimes.go. The two stop tests
whose write under way was a count now use access times.

Model: opus-5-5
2026-10-26 10:20:42 +01:00
clawbot 6b19e4c96c Declare only the tables and columns pixa writes and reads (closes #310)
check / check (push) Canceled after 0s
Removes output_content and request_cache, which nothing writes, and every
column that was written but never read: the host, path, query, content_type
and fetched_at of source_content, the content_type and created_at of
variant_content, and the status_code, error_message and fetched_at of
negative_cache.

StoreSource no longer takes the fetch result and LookupSource returns only
the source key. StoreVariant no longer takes a content type and
StoreNegative no longer takes a status code or message, so
extractStatusCode and the status constants, which only fed status_code,
are gone. Reconciliation adopts a variant file without opening it, as its
row no longer records a content type. Tests that set or checked a removed
column follow.

Model: opus-5-5
2026-10-26 09:29:26 +01:00
clawbot 5f9d624d74 Serve a cache hit with no database read or write (closes #309)
check / check (push) Canceled after 0s
A hit opens the variant file and nothing else: its content type comes
from the file's first bytes, and a file in no output format is a miss.
Its access time and count, and the access time of a cached source a
miss uses, go without waiting to one background goroutine that writes
them once a second; each kind of access time waits in a channel of
10,000 that drops the rest. Expired negative cache rows are left to
CleanExpired. The .meta files, metaCache, Lookup and golang-lru go,
with their tests; the two reconciliation walks, identical without the
.meta skip, share one. make bench runs a parallel cache hit benchmark
on the host, outside make check.

Model: opus-5-5
2026-10-21 18:12:55 +02:00