procplugin

package
v0.1.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package procplugin implements both sides of the process-plugin protocol (docs/SPEC.md §37.4): executables named `ds-<kind>-<name>` on PATH that speak one JSON object per line over stdin and stdout, so a plugin can be written in any language and a Go plugin can be shipped as a process with no extra code.

The host enforces what the plugin is not trusted with: a timeout, a cap on response size, a protocol handshake, and the rule that a resolver reply may contain nothing but existence and a hash. A resolver that returns a value fails here, before anything downstream can see it.

Index

Constants

View Source
const (
	KindPick    = "pick"
	KindResolve = "resolve"
	KindVerb    = "verb"
	KindRecords = "records"
)

Plugin kinds and the executable name pattern `ds-<kind>-<name>`.

View Source
const (
	OpHandshake = "handshake"
	OpPick      = "pick"
	OpResolve   = "resolve"
	OpCheck     = "check"
	OpRender    = "render"
	OpQuery     = "query"
)

Operations.

View Source
const (
	WantExists = "exists"
	WantHash   = "hash"
)

Resolver wants.

View Source
const (
	DefaultTimeout  = 10 * time.Second
	DefaultMaxBytes = 1 << 20
)

Defaults. The timeout is per call; the size cap bounds one response line.

View Source
const Protocol = 1

Protocol is the handshake version. A plugin answering a different number is refused by name, never by misparsing.

Variables

View Source
var (
	ErrNotFound  = errors.New("procplugin: plugin executable not found")
	ErrProtocol  = errors.New("procplugin: protocol mismatch or malformed reply")
	ErrTooLarge  = errors.New("procplugin: reply exceeds the size cap")
	ErrValueLeak = errors.New("procplugin: resolver reply carried more than existence and hash")
	ErrPlugin    = errors.New("procplugin: plugin reported an error")
	ErrTimeout   = errors.New("procplugin: plugin timed out")
)

Errors.

KindValues is the canonical list.

Functions

func Name

func Name(kind, name string) string

Name returns the executable name for a kind and plugin name.

func Serve

func Serve(r io.Reader, w io.Writer, name string, kinds []string, handle Handler) error

Serve is the plugin side: it reads requests from r until EOF, answers the handshake with name and kinds, and delegates everything else to handle. A request the handler cannot serve should return Response{Error: …}.

Types

type Handler

type Handler func(Request) Response

Handler answers plugin-side requests. The handshake is answered by Serve.

type Host

type Host struct {
	Timeout  time.Duration
	MaxBytes int
	LookPath func(name string) (string, error)
	// Args are prepended arguments for every invocation (a test harness
	// re-executing itself needs them; normal plugins take none).
	Args []string
	// Stderr receives the plugin's stderr; nil discards it.
	Stderr io.Writer
}

Host runs plugins. The zero value uses exec.LookPath, DefaultTimeout, and DefaultMaxBytes. LookPath and Args exist so tests and embedders can point at a specific binary; neither is read from the environment by this package.

func (Host) Call

func (h Host) Call(ctx context.Context, executable string, req Request) (Response, error)

Call runs one request against the named plugin executable and returns its reply. Both the handshake and the request are written up front and the process is run to completion, so the exchange has no interleaving to race on; a plugin speaking another protocol is refused before its reply to the operation is read.

func (Host) Pick

func (h Host) Pick(ctx context.Context, format, file, expr string) (Response, error)

Pick asks the `ds-pick-<format>` plugin for a value or range.

func (Host) Records

func (h Host) Records(ctx context.Context, source string, query json.RawMessage) (json.RawMessage, error)

Records asks the `ds-records-<source>` plugin for rows.

func (Host) Resolve

func (h Host) Resolve(ctx context.Context, provider, addr, want string) (exists bool, hash string, err error)

Resolve asks the `ds-resolve-<provider>` plugin whether an address exists and, with WantHash, for its hash. The value itself can never come back.

func (Host) Verb

func (h Host) Verb(ctx context.Context, verb, op string, ref, stateView json.RawMessage) (Response, error)

Verb asks the `ds-<verb>` plugin to check or render a reference.

type Range

type Range struct {
	Start int    `json:"start"`
	End   int    `json:"end"`
	Text  string `json:"text"`
}

Range is a picked line range.

type Request

type Request struct {
	Op       string `json:"op"`
	Protocol int    `json:"protocol,omitempty"`
	// pick
	File string `json:"file,omitempty"`
	Expr string `json:"expr,omitempty"`
	// resolve
	Addr string `json:"addr,omitempty"`
	Want string `json:"want,omitempty"`
	// verb
	Ref       json.RawMessage `json:"ref,omitempty"`
	StateView json.RawMessage `json:"state_view,omitempty"`
	// records
	Query json.RawMessage `json:"query,omitempty"`
}

Request is one host→plugin message. Fields are per operation; unused ones are omitted on the wire.

type Response

type Response struct {
	// handshake
	Protocol int      `json:"protocol,omitempty"`
	Name     string   `json:"name,omitempty"`
	Kinds    []string `json:"kinds,omitempty"`
	// pick
	Value *string `json:"value,omitempty"`
	Range *Range  `json:"range,omitempty"`
	// resolve
	Exists *bool  `json:"exists,omitempty"`
	Hash   string `json:"hash,omitempty"`
	// verb and records
	Findings json.RawMessage `json:"findings,omitempty"`
	Node     json.RawMessage `json:"node,omitempty"`
	Records  json.RawMessage `json:"records,omitempty"`
	// any
	Error string `json:"error,omitempty"`
}

Response is one plugin→host message.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL