The plugin registry — design
Class:
design· Function:registry(usesnothing; used byserve,embed,proxy). The whole-system view isdesign.md; the why isregistry-reasoning.md.
The contract — RepositoryBackendTrait
Defined once in traits/src/lib.rs; every backend implements it. The engine holds backends only as Arc<dyn RepositoryBackendTrait> and dispatches through the vtable — never a concrete-type match on the hot path.
| method | purpose |
name() -> &str |
configured repo name — the routing key |
format() -> ArtifactFormat |
which ecosystem (Rust, Maven3, Docker, …) |
is_writable() -> bool |
znippy-* = read-only; file-* = writable |
fetch(id) -> Option<Vec<u8>> |
resolve an ArtifactId to bytes (direct / gRPC) |
put(id, data) |
store bytes (writable backends only) |
handle_http2_request(suburl, body) -> (status, headers, bytes) |
serve the native HTTP registry protocol |
fetch_many_with_upstreams(upstreams, ids) |
batched fetch + upstream fall-through (default impl) |
Two adjacent contracts complete the picture (traits/src/lib.rs): ConnectorTrait (the agent side — see agent-design) and HolgerObject (a transport-agnostic fetch/put/list/health facade with LocalHolger and RemoteHolger impls). ArtifactFormat::znippy_type_id() pins each format to znippy's DenseUnion discriminant; traits/src/lib.rs tests that the numbers never drift from znippy (the single source of truth).
The config graph & wiring
Config is a directed graph in RON (holger.ron): Repository nodes reference StorageEndpoint and ExposedEndpoint nodes by name. wire_holger() (server/lib/src/lib.rs) resolves it in passes:
- index every node by name into lookup maps;
instantiate_backends()— for each repo,backend_from_config()(server/lib/src/repository.rs) matchesron_repo_type→ a concrete backend struct, boxed asArc<dyn RepositoryBackendTrait>. This match is the registry — the one place that knows the type→backend mapping;- wire each repo's IO to its storage + exposed endpoints;
- reverse-link each exposed endpoint to the repos that write to it;
- build a
FastRoutestable per exposed endpoint.
FastRoutes (server/lib/src/exposed/fast_routes.rs) is the dispatch table: routes are bucketed by the first byte of the repo name into two [usize; 256] arrays, so lookup(name) is O(1) and lock-free on the hot path. The same FastRoutes is shared by the gRPC service and LocalHolger.
The backend families
All backends share the trait and the storage floor; the only per-family code is the ArtifactId→path mapping and the protocol framing.
A · real registry protocol — handle_http2_request synthesizes the index on demand:
| backend | protocol | archive path |
znippy-python |
PEP 503 /simple/ HTML |
packages/{norm}/{file} |
znippy-npm |
packument JSON + tarball | {pkg}/-/{pkg}-{ver}.tgz |
znippy-nuget |
NuGet V3 service + flat-container | {id}/{ver}/{id}.{ver}.nupkg |
znippy-go |
GOPROXY @v/{list,.info,.mod,.zip} |
{module}/@v/{ver}.zip |
znippy-docker |
OCI Registry V2 manifests + blobs | v2/{name}/{manifests|blobs}/{ref} |
znippy-helm |
index.yaml (pre-baked or generated from Chart.yaml) |
{chart}-{ver}.tgz |
znippy-composer |
Composer v2 p2/{vendor}/{pkg}.json |
dist/{vendor}/{pkg}/{ref}.zip |
znippy-rust / file-rust |
Cargo sparse index + config.json |
{crate}-{ver}.crate |
znippy-gem |
RubyGems compact-index | gems/{name}-{ver}.gem |
B · path passthrough — the client knows the layout; holger serves bytes verbatim with content-type sniffing: znippy-{maven, deb, rpm, conda}.
C · native — znippy-package serves znippy's own {name}-{ver}.znippy (GET / lists packages).
file-rust (Cargo sparse) and file-oci (OCI v2 CAS) are the only writable backends; every znippy-* backend is read-only (put() errors) by construction.
Per-backend status
One crate per ecosystem under server/repository/*, all behind the trait. Real protocol today: python, npm, nuget, go, docker, helm, composer, rust, gem (RubyGems compact-index), conda (real generated repodata.json). Path-passthrough: maven, deb, rpm. Writable: file-rust, file-oci. Depth and the exact route tables per backend are enumerated in design.md §6's status table (history) — this file states the current shape.