Documentation
¶
Overview ¶
Package discovery is how an app finds the running Studio with no configuration (plan B3): `weft studio` and `weft dev` write a small file, studio.json, naming the Studio they serve, and weft/otel and weft/runtime read it when nothing else names one.
The file is {"url","token","db","pid","started","version"}, mode 0600, written after the listener is bound (so the port in it is the real one) and removed on a clean exit. It lives in the first of:
- ./.weft/, when that directory exists (the local sink's own directory, so a project's Studio is found by that project's apps — after a default `weft studio` it always exists, so run the app from the directory you ran `weft studio` in, or set WEFT_STUDIO_URL);
- $XDG_RUNTIME_DIR/weft/, when XDG_RUNTIME_DIR is set (Linux);
- os.UserCacheDir()/weft/ (macOS, Windows, bare containers).
The writer drops a .gitignore ("*") into ./.weft when there is none, so neither the file nor the token beside the database is committed.
The reader walks the same order and takes the first file it trusts. A file is trusted only when it is a regular file of at most 64 KiB, its url names a loopback host (127.0.0.0/8, ::1, localhost), it is fresh (started less than 24 hours ago) and its pid is alive — and, on unix, it is mode 0600 and owned by the reading user (a file from a git checkout is 0644: never trusted). Anything else is skipped with one Debug line, and the next writer removes it.
Two live Studios never erase each other's file: a writer that displaces another live Studio's file restores it when it exits.
The file is a convenience, never a requirement: WEFT_STUDIO_URL always wins (the reader does not look), WEFT_DISCOVERY=off turns the read off and the write too (Off: weft studio / weft dev write no file), and runtime.Studio(url, tok) / otel.Studio(url, tok) name a Studio in code. weft/otel skips the read when the pipeline names an otel.Studio or an otel.Local, or under otel.NoDiscovery / NoEnv; weft/runtime skips it when the installed pipeline has a Local and no Studio (the README's "When weft/otel reads the file"). The core never imports this package.
Index ¶
Constants ¶
const FileName = "studio.json"
FileName is the discovery file's name in each location.
const MaxAge = 24 * time.Hour
MaxAge is how old a file may be and still be trusted.
Variables ¶
var Dirs = DefaultDirs
Dirs is the location order, writer and reader alike. A variable so a test points every reader and writer of its process at a temporary directory — no test touches the developer's real locations.
Functions ¶
func DefaultDirs ¶
func DefaultDirs() []string
DefaultDirs is the documented order: ./.weft when it exists, then $XDG_RUNTIME_DIR/weft when XDG_RUNTIME_DIR is set, then os.UserCacheDir()/weft. Paths are absolute. ./.weft is relative to the working directory: an app finds a Studio's ./.weft file only when run from the directory that Studio was started in (else WEFT_STUDIO_URL names it).
func Find ¶
Find is the path of a trusted file naming url, "" when no location holds one: how a start checks that the Studio on an address is the one this user's discovery file names (the probe's token, a reuse's missing-file line).
func GuardDir ¶
func GuardDir(dir string)
GuardDir drops a .gitignore ("*") into dir when dir is a .weft directory without one — the project's local data (the database, its token, the discovery file) is never committed by accident. An existing .gitignore is never touched; failures are ignored (the guard is a courtesy, not a gate).
Types ¶
type Info ¶
type Info struct {
// URL is the Studio's base URL, http://host:port (loopback).
URL string `json:"url"`
// Token is the Studio's API token (the file is 0600).
Token string `json:"token"`
// DB is the Studio's SQLite file, absolute; "" for a database with
// no file.
DB string `json:"db"`
// PID is the Studio process's id.
PID int `json:"pid"`
// Started is when the Studio started (RFC 3339 on the wire).
Started time.Time `json:"started"`
// Version is the weft version the Studio runs (version.Runtime).
Version string `json:"version"`
}
Info is the discovery file's content.
func Lookup ¶
Lookup is the reader the app side uses: the first trusted file of the location order, with its path. It does not look when getenv("WEFT_STUDIO_URL") is set (the explicit Studio always wins) or getenv("WEFT_DISCOVERY") is "off". A missing file says nothing; an untrusted one (malformed, stale, not loopback, not 0600 or not this user's) is one Debug line on log (nil: slog.Default()) — observability never changes behaviour, and a leftover file is no news. ok is false when nothing trusted was found.
type Written ¶
type Written struct {
// Path is the file.
Path string
// Info is what was written.
Info Info
// contains filtered or unexported fields
}
Written is a discovery file this process wrote.
func Write ¶
Write writes info to the first location (created 0700 when missing; a .weft directory gets its .gitignore) and returns the handle Remove takes. Untrusted files in every location are removed first — the writer is the one that cleans up. The write is atomic (a temporary file renamed over the old one) and the file is 0600: it carries the token. Another live Studio's file it displaces is restored by Remove. The guarantee is for two live Studios: only the one displaced file is remembered (with three, the first can be dropped), and Remove's check-then-write is not atomic against a third writer.
func (*Written) Refresh ¶
Refresh re-stamps the file's started time with now, while the file is still this Studio's: a Studio running longer than MaxAge stays discoverable (the writer calls it hourly). A missing file — removed by hand, or by another writer's cleanup racing this Studio's rename — is written again, the same content and 0600 atomic rename as Write. A file another Studio has since written is left alone. Nil-safe.
func (*Written) Remove ¶
func (w *Written) Remove()
Remove removes the file when it is still this Studio's (same pid and url) — putting back the live Studio it displaced, if any, its started time re-stamped (that Studio refreshes its own file from then on): of two live Studios, neither erases the other's file. Nil-safe.