Documentation
¶
Overview ¶
Package updatecheck is the opt-in, once-per-24h "newer nself exists" hint.
Nothing here runs unless NSELF_UPDATE_CHECK=1 (VMI: nothing is sent by default). A background goroutine refreshes a small cache from ping's GET /version at most once per 24 h; the hint itself reads only the cache and never touches the network. Contract: cap:cli.version-nudge.
Index ¶
- Constants
- func Allowed(g Guards) bool
- func DefaultPath() string
- func Hint(g Guards) (string, bool)
- func MaybeStartRefresh(g Guards) <-chan struct{}
- func NewClient() *http.Client
- func Refresh(ctx context.Context, client *http.Client, url string) (string, error)
- func Save(path string, c Cache) error
- type Cache
- type Guards
Constants ¶
const Budget = 250 * time.Millisecond
Budget is the whole-request limit of one refresh.
const EnvOptIn = "NSELF_UPDATE_CHECK"
EnvOptIn is the opt-in switch: the value "1" turns the feature on.
const Interval = 24 * time.Hour
Interval is the minimum time between refreshes and between hints.
const VersionURL = "https://ping.nself.org/version"
VersionURL is ping's release-channel endpoint (contract:ping.release-channel).
Variables ¶
This section is empty.
Functions ¶
func Allowed ¶
Allowed reports whether the feature may run at all: opted in, not JSON mode, no CI marker, stderr is a terminal. Without the opt-in nothing else is read.
func DefaultPath ¶
func DefaultPath() string
DefaultPath returns ~/.nself/cache/update-check.json, or "" when the home directory cannot be resolved (the feature is then off).
func Hint ¶
Hint returns the one-line hint when it is due: allowed, the cached latest is a valid release newer than Current, and no hint was printed within Interval. It reads only the cache and records HintedAt before returning the line; if that record cannot be saved no line is returned, so it never repeats.
func MaybeStartRefresh ¶
func MaybeStartRefresh(g Guards) <-chan struct{}
MaybeStartRefresh starts the background refresh when the feature is allowed and the cache is older than Interval. It never blocks: the returned channel closes when the refresh finishes (nil when none started), and production callers ignore it, so the goroutine is simply abandoned at process exit. A failed refresh keeps the old Latest and records CheckedAt and LastError.
func NewClient ¶
NewClient returns the refresh client: Budget timeout through the httptimeout funnel, compression off so no Accept-Encoding header is sent. The request then carries only Host and User-Agent.
Types ¶
type Cache ¶
type Cache struct {
CheckedAt time.Time `json:"checked_at"`
Latest string `json:"latest"`
LastError string `json:"last_error,omitempty"`
HintedAt time.Time `json:"hinted_at"`
AttemptedAt time.Time `json:"attempted_at"`
}
Cache is the on-disk state at ~/.nself/cache/update-check.json.
CheckedAt is the time of the last refresh attempt (success or failure), so a stale cache is visible to `nself doctor`. LastError is empty after a good refresh. HintedAt is the time the hint was last printed. AttemptedAt is the time a refresh was last started, written before the request goes out, so a refresh cut short by process exit still counts for the retry backoff.
type Guards ¶
type Guards struct {
JSON bool
TTY func() bool
Env func(string) string
Now func() time.Time
Path string
Current string
URL string
Client *http.Client
}
Guards carries everything the feature reads from the outside world, so tests inject a clock, a TTY answer, an environment and a server.
JSON is the recorded JSON mode of the invocation. TTY reports whether stderr is a terminal. Path is the cache file, Current the running version, URL the endpoint and Client the HTTP client (nil means NewClient).