Documentation
¶
Overview ¶
Package discovery provides server discovery file management for ToolHive. It writes, reads, and removes a JSON file that advertises a running server so clients (CLI, Studio) can find it without configuration.
Index ¶
- Constants
- func CheckHealth(ctx context.Context, serverURL string, expectedNonce string) error
- func CleanupStale() error
- func FilePath() string
- func HTTPClientForURL(serverURL string) (*http.Client, string, error)
- func ParseNamedPipeURL(rawURL string) (string, error)
- func ParseUnixSocketPath(rawURL string) (string, error)
- func RemoveServerInfo() error
- func ValidateLoopbackURL(rawURL string) error
- func WriteServerInfo(info *ServerInfo) error
- type DiscoverResult
- type ServerInfo
- type ServerState
Constants ¶
const NamedPipePrefix = `\\.\pipe\`
NamedPipePrefix is the Windows named-pipe namespace prefix. The discovery dialer uses it to reconstruct addresses for winio.DialPipeContext, and the API listener (pkg/api) imports it as the canonical definition so the two sides cannot drift.
const (
// NonceHeader is the HTTP header used to return the server nonce.
NonceHeader = "X-Toolhive-Nonce"
)
Variables ¶
This section is empty.
Functions ¶
func CheckHealth ¶
CheckHealth verifies that a server at the given URL is healthy and optionally matches the expected nonce. It supports http://, unix://, and npipe:// URL schemes (npipe:// only resolves on Windows).
func CleanupStale ¶
func CleanupStale() error
CleanupStale removes a stale discovery file. Clients should call this when Discover returns StateStale.
func FilePath ¶
func FilePath() string
FilePath returns the full path to the server discovery file using the default XDG-based directory.
func HTTPClientForURL ¶
HTTPClientForURL returns an HTTP client configured for the given server URL and the base URL to use for requests. For unix:// URLs it creates a client with a Unix socket transport and returns "http://localhost" as the base URL. For npipe:// URLs (Windows only) it dials the named pipe via the platform dialNamedPipe helper. For http:// URLs it validates the host is a loopback address and returns a default client. The returned client has no timeout set; callers should apply their own timeout via context or client.Timeout.
Scheme matching is case-insensitive because url.Parse lowercases the scheme during parsing, so npipe://x and NPIPE://x route through the same arm.
func ParseNamedPipeURL ¶ added in v0.27.1
ParseNamedPipeURL extracts and validates the pipe name from an npipe:// URL and returns the full Windows pipe path (e.g. \\.\pipe\thv-api). The URL shape is strict: npipe://<name> with no path, query, fragment, userinfo, or port. The name itself must match a conservative charset, fit within the 247-char limit imposed by CreateNamedPipeW after the prefix, and must not be one of the legacy reserved Windows device names (CON, NUL, COM1, etc.). The returned path always uses the lowercase form of the name because the pipe namespace is case-insensitive at the kernel layer.
func ParseUnixSocketPath ¶
ParseUnixSocketPath extracts and validates the socket path from a unix:// URL. The expected form is unix:///<absolute-path>; URLs with a non-empty authority (unix://host/path) are rejected because the path component would be ambiguous. On Windows, unix:///C:%5Cpath%5Cthv.sock round-trips back to C:\path\thv.sock by stripping the synthetic leading slash that net/url inserts in front of the drive letter.
func RemoveServerInfo ¶
func RemoveServerInfo() error
RemoveServerInfo removes the server discovery file. It is a no-op if the file does not exist.
func ValidateLoopbackURL ¶
ValidateLoopbackURL checks that an http:// URL points to a loopback address.
func WriteServerInfo ¶
func WriteServerInfo(info *ServerInfo) error
WriteServerInfo atomically writes the server discovery file. It creates the directory if needed, rejects symlinks at the target path, and writes with restricted permissions (0600).
Types ¶
type DiscoverResult ¶
type DiscoverResult struct {
// State is the discovered server state.
State ServerState
// Info is the server information from the discovery file.
// It is nil when State is StateNotFound.
Info *ServerInfo
}
DiscoverResult holds the result of a server discovery attempt.
type ServerInfo ¶
type ServerInfo struct {
// URL is the address where the server is listening.
// For TCP: "http://127.0.0.1:52341"
// For Unix sockets: "unix:///path/to/thv.sock"
URL string `json:"url"`
// PID is the process ID of the running server.
PID int `json:"pid"`
// Nonce is a unique identifier generated at server startup.
// It solves PID reuse: clients verify the nonce via /health to confirm
// the discovery file refers to the expected server instance.
Nonce string `json:"nonce"`
// StartedAt is the UTC timestamp when the server started.
StartedAt time.Time `json:"started_at"`
}
ServerInfo contains the information advertised by a running ToolHive server.
func ReadServerInfo ¶
func ReadServerInfo() (*ServerInfo, error)
ReadServerInfo reads and parses the server discovery file. Returns os.ErrNotExist if the file does not exist.
type ServerState ¶
type ServerState int
ServerState represents the state of a discovered server.
const ( // StateNotFound means no discovery file exists. StateNotFound ServerState = iota // StateRunning means the server is healthy and responding. StateRunning // StateStale means the discovery file exists but the process is dead. StateStale // StateUnhealthy means the process is alive but the server is not responding. StateUnhealthy )
func (ServerState) String ¶
func (s ServerState) String() string
String returns a human-readable representation of the server state.