Documentation
¶
Overview ¶
Package client provides a standalone HTTP client for the Cachew cache server.
Index ¶
- Constants
- Variables
- func Archive(ctx context.Context, w io.Writer, baseDir string, includePaths []string, ...) error
- func Extract(ctx context.Context, r io.Reader, directory string, threads int) error
- func FormatETag(etag string) (string, error)
- func NewHTTPClient(headerFunc HeaderFunc) *http.Client
- func ParallelGet(ctx context.Context, c RangeReader, key Key, dst io.WriterAt, chunkSize int64, ...) error
- func RawETagFromHeader(etag string) (string, error)
- func ValidateNamespace(name string) error
- func ValidateRawETag(etag string) error
- type CacheWriter
- type Client
- func (c *Client) BaseURL() string
- func (c *Client) Close() error
- func (c *Client) Create(ctx context.Context, key Key, headers http.Header, ttl time.Duration, ...) (CacheWriter, error)
- func (c *Client) Delete(ctx context.Context, key Key) error
- func (c *Client) EnsureGitRefs(ctx context.Context, repoURL string, request EnsureGitRefsRequest) (EnsureGitRefsResponse, error)
- func (c *Client) HTTP() *http.Client
- func (c *Client) Invalidate(ctx context.Context, key Key) error
- func (c *Client) ListNamespaces(ctx context.Context) ([]string, error)
- func (c *Client) Namespace(namespace Namespace) *Client
- func (c *Client) Open(ctx context.Context, key Key, opts ...RequestOption) (io.ReadCloser, http.Header, error)
- func (c *Client) OpenGitBundle(ctx context.Context, bundleURL string) (io.ReadCloser, error)
- func (c *Client) OpenGitLFSSnapshot(ctx context.Context, repoURL string) (*GitSnapshot, error)
- func (c *Client) OpenGitSnapshot(ctx context.Context, repoURL string) (*GitSnapshot, error)
- func (c *Client) OpenGitSnapshotParallel(ctx context.Context, repoURL string, chunkSize int64, concurrency int) (*GitSnapshot, error)
- func (c *Client) Restore(ctx context.Context, key Key, baseDir string, opts ...RestoreOption) (bool, error)
- func (c *Client) Save(ctx context.Context, key Key, baseDir string, paths []string, ...) error
- func (c *Client) Stat(ctx context.Context, key Key, opts ...RequestOption) (http.Header, error)
- func (c *Client) Stats(ctx context.Context) (Stats, error)
- func (c *Client) String() string
- type EnsureGitRefsRequest
- type EnsureGitRefsResponse
- type GitSnapshot
- type HTTPStatusError
- type HeaderFunc
- type Key
- type Namespace
- type RangeOutcome
- type RangeReader
- type RequestOption
- type RequestOptions
- type RestoreOption
- type SaveOption
- type SaveRestoreOption
- type Stats
Constants ¶
const BundleURLHeader = "X-Cachew-Bundle-Url"
BundleURLHeader is the response header on /snapshot.tar.zst that, when present, points at a delta bundle that brings the snapshot up to the mirror's current HEAD.
const ETagKey = "ETag"
ETagKey is the HTTP header key used to store the ETag.
const SnapshotCommitHeader = "X-Cachew-Snapshot-Commit"
SnapshotCommitHeader is the response header on /snapshot.tar.zst that contains the mirror's HEAD SHA at the time the snapshot was generated. An empty value means the snapshot was served cold (no associated mirror) and the caller should freshen the working tree itself.
Variables ¶
var ErrNotModified = errors.New("not modified")
ErrNotModified is returned when an If-None-Match precondition is satisfied, indicating the resource has not changed since the supplied ETag. Over HTTP this corresponds to 304 Not Modified.
var ErrPreconditionFailed = errors.New("precondition failed")
ErrPreconditionFailed is returned when an If-Match precondition is not met. Over HTTP this corresponds to 412 Precondition Failed.
var ErrRangeNotSatisfiable = errors.New("range not satisfiable")
ErrRangeNotSatisfiable is returned when a Range precondition cannot be satisfied against the stored object. Over HTTP this corresponds to 416 Range Not Satisfiable.
ErrStatsUnavailable is returned when a cache backend cannot provide statistics.
Functions ¶
func Archive ¶
func Archive(ctx context.Context, w io.Writer, baseDir string, includePaths []string, excludePatterns []string, threads int) error
Archive writes a tar+zstd stream of the given paths to w. Each entry in includePaths is relative to baseDir and must exist. Exclude patterns use tar's --exclude syntax. threads controls zstd parallelism; 0 uses all CPU cores.
func Extract ¶
Extract decompresses a zstd+tar stream from r into directory, preserving file permissions, ownership, and symlinks. threads controls zstd parallelism; 0 uses all CPU cores.
func FormatETag ¶ added in v0.3.0
FormatETag formats a raw ETag value as a strong HTTP ETag.
func NewHTTPClient ¶
func NewHTTPClient(headerFunc HeaderFunc) *http.Client
NewHTTPClient creates an *http.Client that attaches headerFunc headers to every outgoing request. Useful for callers that need to talk to non-API endpoints (e.g. /git/) with the same auth as the cache client.
The returned client is instrumented with otelhttp so each outgoing request produces a child span and propagates the W3C traceparent header. When no tracer provider is configured, otelhttp falls back to a no-op tracer, so this is cost-free for callers that have not opted in to tracing.
func ParallelGet ¶
func ParallelGet(ctx context.Context, c RangeReader, key Key, dst io.WriterAt, chunkSize int64, concurrency int) error
ParallelGet downloads an object in chunkSize-byte chunks with up to concurrency requests in flight, writing each chunk at its offset via dst.WriteAt. dst may block writes to apply backpressure (e.g. a bounded reordering buffer feeding a stream): chunk dispatch never runs more than 2*concurrency chunks past the oldest incomplete chunk, so a dst window of 2*concurrency*chunkSize is never exceeded and blocked writes always drain.
Chunks are pinned to the discovery response's ETag so a mid-download rewrite is rejected rather than spliced. No ETag, a range-ignoring backend, an object that fits in the first chunk, or concurrency 1 all fall back to a single full read. On error dst is left partially written and must be discarded by the caller.
func RawETagFromHeader ¶ added in v0.3.0
RawETagFromHeader extracts a raw ETag value from a strong HTTP ETag header.
func ValidateNamespace ¶
ValidateNamespace checks that a namespace name is valid.
func ValidateRawETag ¶ added in v0.3.0
ValidateRawETag verifies that etag is an unquoted cache ETag value.
Types ¶
type CacheWriter ¶
type CacheWriter interface {
io.WriteCloser
// Abort discards the in-progress write and releases resources.
// The provided error is recorded as the cause of cancellation.
// The object MUST NOT be made available in the cache after Abort.
Abort(err error) error
}
CacheWriter extends io.WriteCloser with the ability to abort an in-progress cache write. Exactly one of Close or Abort must be called.
Close commits the data to the cache. Abort discards the in-progress write, ensuring the object is never made visible in the cache. Both methods are idempotent after the first call.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is an HTTP client for a Cachew cache server. Its method set mirrors the cache.Cache interface, so it can be used as the transport for a remote cache backend.
func New ¶
func New(baseURL string, headerFunc HeaderFunc) *Client
New creates a Client against the given base URL (e.g. "http://localhost:8080"). If headerFunc is non-nil, its returned headers are added to every outgoing request.
func NewWithHTTPClient ¶
NewWithHTTPClient creates a Client against baseURL using the supplied *http.Client. Callers are responsible for configuring authentication on the supplied client (e.g. via a custom RoundTripper).
func (*Client) Create ¶
func (c *Client) Create(ctx context.Context, key Key, headers http.Header, ttl time.Duration, opts ...RequestOption) (CacheWriter, error)
Create stores a new object in the cache server. The returned CacheWriter must be closed to commit the upload. Call Abort instead of Close to discard the in-progress write and ensure the object is never made visible.
func (*Client) EnsureGitRefs ¶
func (c *Client) EnsureGitRefs(ctx context.Context, repoURL string, request EnsureGitRefsRequest) (EnsureGitRefsResponse, error)
EnsureGitRefs asks the cachew server to ensure its local mirror of repoURL satisfies the request before the caller fetches. The server synchronously fetches from upstream if any requested ref is missing/stale or any requested commit is absent from its object database.
Use this before issuing a git fetch/clone against cachew when fresh refs or specific commits are required and the default ref-check rate-limit window would otherwise allow stale data to be served.
func (*Client) HTTP ¶
HTTP returns the underlying HTTP client, for callers needing to talk to non-API endpoints with the same auth configuration.
func (*Client) Invalidate ¶ added in v0.3.0
Invalidate evicts a stale local copy from the cache server.
func (*Client) ListNamespaces ¶
ListNamespaces requests the namespace list from the server.
func (*Client) Open ¶
func (c *Client) Open(ctx context.Context, key Key, opts ...RequestOption) (io.ReadCloser, http.Header, error)
Open retrieves an object from the cache server. Accepts optional [RequestOption]s such as IfNoneMatch for conditional requests.
func (*Client) OpenGitBundle ¶
OpenGitBundle fetches the bundle pointed at by a BundleURL returned in a previous GitSnapshot response. The caller is responsible for writing the body to a file and applying it via `git pull`/`git fetch`.
func (*Client) OpenGitLFSSnapshot ¶
OpenGitLFSSnapshot fetches the LFS-object snapshot for repoURL. Returns os.ErrNotExist when the server has no LFS snapshot cached.
func (*Client) OpenGitSnapshot ¶
OpenGitSnapshot fetches a working-tree snapshot for repoURL from cachew. The caller is responsible for extracting the returned zstd-compressed tarball (e.g. via the snapshot package). Returns os.ErrNotExist when the server has no snapshot available.
func (*Client) OpenGitSnapshotParallel ¶ added in v0.3.0
func (c *Client) OpenGitSnapshotParallel(ctx context.Context, repoURL string, chunkSize int64, concurrency int) (*GitSnapshot, error)
OpenGitSnapshotParallel downloads the working-tree snapshot for repoURL with up to concurrency concurrent range requests of chunkSize bytes each. It returns as soon as the freshen metadata (Commit, BundleURL) is available, with the download continuing in the background as the caller reads Body, so extraction overlaps the transfer.
The caller must Close the returned GitSnapshot, which cancels any in-flight download. A concurrency of 1 streams a single plain request with no buffering; a server without range support falls back to a single full download. Returns os.ErrNotExist when the server has no snapshot.
func (*Client) Restore ¶
func (c *Client) Restore(ctx context.Context, key Key, baseDir string, opts ...RestoreOption) (bool, error)
Restore downloads the archive stored under key and extracts it into baseDir. Returns (false, nil) on cache miss so callers can populate baseDir and then Save.
func (*Client) Save ¶
func (c *Client) Save(ctx context.Context, key Key, baseDir string, paths []string, opts ...SaveOption) error
Save archives the given paths within baseDir and uploads the tar+zstd stream under key. Any existing object at key is overwritten.
func (*Client) Stat ¶
Stat retrieves headers for an object from the cache server. Accepts optional [RequestOption]s such as IfNoneMatch for conditional requests.
type EnsureGitRefsRequest ¶
type EnsureGitRefsRequest struct {
Refs map[string]string `json:"refs,omitempty"`
Commits []string `json:"commits,omitempty"`
}
EnsureGitRefsRequest specifies what the caller wants present on the server's mirror. At least one of Refs or Commits must be non-empty.
Refs maps each required ref (e.g. "refs/heads/main") to the expected SHA; an empty SHA means "require the ref to exist at any SHA". Commits lists individual commit SHAs that must exist in the mirror's object database, regardless of which ref points at them.
type EnsureGitRefsResponse ¶
type EnsureGitRefsResponse struct {
Refs map[string]string `json:"refs,omitempty"`
MissingCommits []string `json:"missing_commits,omitempty"`
Fetched bool `json:"fetched"`
}
EnsureGitRefsResponse is the response returned by EnsureGitRefs.
Refs contains the resolved local SHA for each requested ref (empty if the ref is still missing on the server after the fetch). MissingCommits lists the requested commits that are still absent from the server's object database. Fetched reports whether the server performed an upstream fetch.
type GitSnapshot ¶
GitSnapshot is a streaming response from OpenGitSnapshot.
Body is the zstd-compressed tarball; the caller must Close it. Commit holds the mirror's HEAD SHA at snapshot time (empty for cold serves). BundleURL, if non-empty, identifies a delta bundle that brings the snapshot up to the mirror's current HEAD; it can be passed to OpenGitBundle.
func (*GitSnapshot) Close ¶
func (s *GitSnapshot) Close() error
Close releases the underlying response body.
type HTTPStatusError ¶
type HTTPStatusError struct {
StatusCode int
}
HTTPStatusError is returned when the server responds with an unexpected HTTP status code. Callers can use errors.As to inspect the status code.
func (*HTTPStatusError) Error ¶
func (e *HTTPStatusError) Error() string
func (*HTTPStatusError) Is ¶
func (e *HTTPStatusError) Is(target error) bool
Is allows errors.Is to match HTTPStatusError against sentinel errors.
type HeaderFunc ¶
HeaderFunc returns headers to attach to each outgoing request.
type Key ¶
type Key [32]byte
Key represents a unique identifier for a cached object.
func HashFiles ¶
HashFiles returns a Key derived from the contents of all regular files matched by the given glob patterns. Patterns use doublestar syntax, so ** matches any number of path segments (e.g. "**/go.sum"). Matches are deduplicated and sorted by path, and each file's path and contents are folded into the digest so that content or path changes invalidate the key. Directories and non-regular matches are skipped. Returns an error if no regular files match any pattern, to avoid silently producing a constant key on typos.
func (*Key) MarshalText ¶
func (*Key) UnmarshalText ¶
type Namespace ¶
type Namespace string
Namespace identifies a logical partition within a cache or metadata store. Valid names start with an alphanumeric character and contain only alphanumerics, hyphens, and underscores.
const DefaultNamespace Namespace = "default"
DefaultNamespace is used when a namespace is not explicitly specified.
func ParseNamespace ¶
ParseNamespace validates and returns a Namespace from a plain string.
func (*Namespace) UnmarshalText ¶
UnmarshalText implements encoding.TextUnmarshaler with validation.
type RangeOutcome ¶
type RangeOutcome int
RangeOutcome classifies how a Range request should be answered.
const ( // RangeFull indicates the full representation should be served (no Range, // an unmatched If-Range, or an unsupported/invalid specifier). RangeFull RangeOutcome = iota // RangePartial indicates a single satisfiable byte range. RangePartial // RangeNotSatisfiable indicates the range lies outside the object. RangeNotSatisfiable )
type RangeReader ¶
type RangeReader interface {
Open(ctx context.Context, key Key, opts ...RequestOption) (io.ReadCloser, http.Header, error)
}
RangeReader is the subset of cache operations ParallelGet needs: a conditional, Range-capable Open. Both *Client and cache.Cache satisfy it.
type RequestOption ¶
type RequestOption func(*RequestOptions)
RequestOption configures conditional request parameters.
func IfNoneMatch ¶
func IfNoneMatch(etag string) RequestOption
IfNoneMatch sets the If-None-Match precondition.
func IfRange ¶
func IfRange(etag string) RequestOption
IfRange sets the If-Range precondition: the Range is only honoured when etag matches the stored ETag, otherwise the full representation is served.
func Range ¶
func Range(start, end int64) RequestOption
Range requests a single half-open byte range [start, end) from Open. A negative end means "to the end of the object" (its Content-Length). For example Range(0, 500) requests the first 500 bytes and Range(0, -1) the whole object. Open returns the matching bytes with a Content-Range header, or ErrRangeNotSatisfiable if the range lies outside the object.
func WithETag ¶ added in v0.3.0
func WithETag(etag string) RequestOption
WithETag sets the raw ETag value to store on Create.
type RequestOptions ¶
type RequestOptions struct {
// IfMatch is the If-Match precondition. Evaluation fails with
// ErrPreconditionFailed if the stored ETag does not match.
IfMatch string
// IfNoneMatch is the If-None-Match precondition. Evaluation reports
// ErrNotModified when the stored ETag matches.
IfNoneMatch string
// Range is a raw HTTP Range header value (e.g. "bytes=0-499"). Only a
// single byte range is supported; multi-range or invalid specifiers are
// ignored and the full representation is served.
Range string
// IfRange gates Range on the stored ETag: the range is only applied when
// IfRange matches the stored ETag, otherwise the full representation is
// served. Only the entity-tag form is supported.
IfRange string
// ETag is the raw ETag value to store on Create. It is formatted as a
// strong HTTP ETag when carried over HTTP or stored in cache metadata.
ETag string
// ETagSet reports whether ETag was explicitly configured.
ETagSet bool
}
RequestOptions holds conditional-request parameters. It is the single representation shared by the client wire protocol, the cache backends, and the server handlers.
func NewRequestOptions ¶
func NewRequestOptions(opts ...RequestOption) RequestOptions
NewRequestOptions applies opts and returns the resulting RequestOptions.
func (RequestOptions) Check ¶
func (o RequestOptions) Check(etag string) error
Check evaluates the preconditions against the stored ETag. It returns ErrNotModified for a satisfied If-None-Match, ErrPreconditionFailed for a failed If-Match, or nil when all preconditions pass.
func (RequestOptions) IfRangeMisses ¶ added in v0.3.0
func (o RequestOptions) IfRangeMisses(etag string) bool
IfRangeMisses reports whether a requested Range is dropped because the If-Range validator does not match etag, in which case the full representation is served in place of the range.
func (RequestOptions) ResolveRange ¶
func (o RequestOptions) ResolveRange(size int64, etag string) (start, length int64, outcome RangeOutcome)
ResolveRange evaluates the Range/If-Range options against an object of the given size and ETag. On RangePartial it returns the [start, start+length) window to serve.
type RestoreOption ¶
type RestoreOption interface {
// contains filtered or unexported methods
}
RestoreOption configures Restore.
type SaveOption ¶
type SaveOption interface {
// contains filtered or unexported methods
}
SaveOption configures Save.
func WithExclude ¶
func WithExclude(patterns ...string) SaveOption
WithExclude adds tar --exclude patterns applied during Save.
func WithExtraHeaders ¶
func WithExtraHeaders(h http.Header) SaveOption
WithExtraHeaders merges additional headers into the upload request.
func WithTTL ¶
func WithTTL(d time.Duration) SaveOption
WithTTL sets the TTL on the uploaded object. Zero (the default) uses the server default.
type SaveRestoreOption ¶
type SaveRestoreOption interface {
SaveOption
RestoreOption
}
SaveRestoreOption configures both Save and Restore.
func WithZstdThreads ¶
func WithZstdThreads(n int) SaveRestoreOption
WithZstdThreads sets zstd parallelism. Zero (the default) uses all CPU cores.
type Stats ¶
type Stats struct {
// Objects is the number of objects currently in the cache.
Objects int64 `json:"objects"`
// Size is the total size of all objects in the cache in bytes.
Size int64 `json:"size"`
// Capacity is the maximum size of the cache in bytes (0 if unlimited).
Capacity int64 `json:"capacity"`
}
Stats contains health and usage statistics for a cache.