Documentation
¶
Overview ¶
Package model holds the pure data types that describe a registry-stats snapshot. Types here carry no behavior beyond JSON struct tags; the tags define the on-disk /data/YYYY-MM-DD.json contract and the HTTP API response shapes, so they MUST stay identical across refactors.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type GhcrStats ¶
type GhcrStats struct {
Package string `json:"package"`
DownloadCount int64 `json:"download_count"`
}
GhcrStats is a GHCR package's scraped download count.
type ImageInfo ¶
type ImageInfo struct {
Architecture string `json:"architecture"`
OS string `json:"os"`
Digest string `json:"digest"`
Size int64 `json:"size"`
}
ImageInfo is a single per-architecture manifest inside a multi-arch tag.
type PullEntry ¶
type PullEntry struct {
Date string
Repo string
PullCount int64
Source RegistrySource
}
PullEntry is a single (date, source, repo, pullCount) record in the pre-computed pull index. Handlers consume these directly instead of iterating every snapshot file per request.
type RegistryEntry ¶
type RegistryEntry struct {
Name string
LastUpdated string
Tags []TagInfo
PullCount int64
DownloadCount int64
}
RegistryEntry is the registry-agnostic Collect() result used by api.RegistrySource implementations. Later steps map it into the per-registry on-disk arrays (docker_hub / ghcr). Zero-value fields are ignored for the registry that doesn't populate them (Tags/PullCount are Docker Hub-only, DownloadCount is GHCR-only).
type RegistryFilter ¶
type RegistryFilter struct {
Only RegistrySource
Set bool
}
RegistryFilter is the typed view of the registry= query parameter. Zero value means "include every registry" (the Grafana default and the behaviour of an unset / $__all / {$__all} / multi-value brace input). When Set is true the filter restricts to Only.
The filter is populated via ParseRegistryFilter so the three handler call sites share one parse of the raw query string (previously each handler re-implemented the brace-stripping dance).
func ParseRegistryFilter ¶
func ParseRegistryFilter(raw string) RegistryFilter
ParseRegistryFilter turns a registry= query value into a typed filter. Accepts the full vocabulary that the pre-refactor stripGrafanaBraces + registryIncludes pair handled:
- "" and "$__all" → include every source (zero value).
- "{$__all}" → include every source (Grafana brace-wrapping).
- "dockerhub", "ghcr" → restrict to that source.
- "{dockerhub}", "{ghcr}" → restrict (brace-wrapped single).
- "{a,b}" (comma inside braces) → include every source. Multi- value braces come from Grafana when the template variable is set to multiple values; the pre-refactor registryIncludes treated any unknown stripped value as "include both", and because {a,b} → "a,b" (unknown as a source name) it fell into the "include both" branch. We preserve that semantics.
- unknown single values → include every source (same fallback).
func (RegistryFilter) Includes ¶
func (f RegistryFilter) Includes(r RegistrySource) bool
Includes reports whether the filter allows entries from r. A zero-value filter (Set == false) includes every source.
type RegistrySource ¶
type RegistrySource uint8
RegistrySource is the typed identity of a container registry that registry-stats scrapes. The zero value (SourceUnknown) represents "registry not classified"; handlers that build carry-forward maps key by RegistrySource + name so a misplaced empty string can never silently collide with a real source. The String() method produces the lowercase on-wire name used in the JSON summary row's `registry` field and in WARN/ERROR log k/v pairs, preserving byte-identical output for Grafana dashboards and Loki alerts.
const ( SourceUnknown RegistrySource = iota SourceDockerHub SourceGHCR )
RegistrySource values. SourceUnknown exists only to catch unset / defaulted values in filter plumbing; production code paths should always hold one of the concrete sources.
func ParseRegistrySource ¶
func ParseRegistrySource(s string) RegistrySource
ParseRegistrySource maps the lowercase on-wire name back to its typed value. Unknown input returns SourceUnknown; callers decide whether that is an error or (for the registry= query param) a "include everything" signal.
func (RegistrySource) MarshalJSON ¶
func (r RegistrySource) MarshalJSON() ([]byte, error)
MarshalJSON renders a RegistrySource as its lowercase name. Today SummaryEntry.Registry stays a plain string on the wire (see the handler rows' `registry` field), so this method is defensive future-proofing for any struct that may embed RegistrySource directly: it keeps the JSON vocabulary consistent.
func (RegistrySource) String ¶
func (r RegistrySource) String() string
String returns the lowercase on-wire name of a RegistrySource. It MUST match the registry= query-parameter vocabulary and the SummaryEntry.Registry JSON field (inviolate: HTTP API surface). SourceUnknown returns "" so callers that write it into a response without checking first surface the mis-classification as an empty field rather than a bogus label.
type RepoRef ¶
RepoRef is an owner/repo pair parsed from env var input. Repo is "*" for wildcard refs that expand at collection time.
type RepoStats ¶
type RepoStats struct {
Repo string `json:"repo"`
LastUpdated string `json:"last_updated"`
Tags []TagInfo `json:"tags"`
PullCount int64 `json:"pull_count"`
}
RepoStats is a Docker Hub repo's pull count plus tag metadata.
type Snapshot ¶
type Snapshot struct {
Timestamp time.Time `json:"timestamp"`
DockerHub []RepoStats `json:"docker_hub,omitempty"`
GHCR []GhcrStats `json:"ghcr,omitempty"`
}
Snapshot is the root on-disk object written once per collection cycle.
func (*Snapshot) Entries ¶
func (s *Snapshot) Entries() iter.Seq2[RegistrySource, SummaryEntry]
Entries yields a flattened stream of (RegistrySource, SummaryEntry) pairs across all registry slices in the snapshot. Zero-download GHCR packages are skipped (a zero scrape is treated as "not applicable"). This centralises the source→slice routing so consumers iterate a uniform stream without knowing the per-registry storage layout.
func (*Snapshot) PullEntries ¶
PullEntries returns PullEntry records for all repos in the snapshot, skipping zero-download GHCR packages. The date parameter is stamped onto each entry (it comes from the caller's storage key, not the snapshot's Timestamp).
type SummaryEntry ¶
SummaryEntry carries the per-registry view that handleSummary needs. filteredPulls also builds on it (summing across registries for the same name).