Documentation
¶
Overview ¶
Package ipc is the wire layer between a Pilot app (the wallet, for now) and the daemon that hosts it. Length-prefixed JSON envelopes carry requests and replies over any io.ReadWriter — typically a unix-domain socket the daemon hands to the app at spawn time, but anything duplex works (net.Pipe in tests, a TCP connection for remote dev).
The wire is intentionally simple: 4-byte big-endian length + JSON envelope. Mirrors the pilot_header / ipc_envelope split in the architecture graph — framing here, semantics in the envelope.
Index ¶
Constants ¶
const MaxFrameSize = 1 << 20
MaxFrameSize bounds any single envelope. Defends against a malicious or runaway peer that tries to allocate gigabytes by sending a giant length prefix. 1 MiB is comfortably larger than any wallet IPC reply (the biggest is a paginated history slice).
Variables ¶
var ErrFrameTooLarge = errors.New("ipc: frame exceeds max size")
ErrFrameTooLarge is returned by ReadFrame when the length prefix exceeds MaxFrameSize. The connection should be dropped.
var ErrMethodNotFound = errors.New("method not found")
ErrMethodNotFound is returned to a caller when no handler is registered for the requested method.
Functions ¶
func Call ¶
func Call(conn io.ReadWriter, method string, args, result any) error
Call sends one request envelope and waits for the matching reply on the same conn. Synchronous: callers must serialize concurrent Calls on a single conn (one in flight at a time).
If args is nil, the request payload is empty. If result is nil, the reply payload is discarded. Both are otherwise json-marshaled / unmarshaled.
Returns *ErrServerError on EnvErr replies, a wrapped framing error on transport failures, or nil on success.
func Serve ¶
func Serve(ctx context.Context, conn io.ReadWriter, d *Dispatcher) error
Serve reads envelopes from conn in a loop, dispatches each request to the matching handler, and writes the reply. Returns nil on clean EOF (peer closed gracefully between frames) or a non-nil error otherwise.
Single-threaded: one request at a time per connection. If multiple goroutines need to share a connection on the caller side, they must coordinate write order outside this package. For higher fan-out, the daemon opens one Serve per connection in its own goroutine.
Types ¶
type Dispatcher ¶
type Dispatcher struct {
// contains filtered or unexported fields
}
Dispatcher routes method names to handlers. Build once at startup, register all methods, then hand to Serve. Safe to read after setup; not safe to mutate concurrently with Serve.
func (*Dispatcher) Methods ¶
func (d *Dispatcher) Methods() []string
Methods returns the registered method names (for inspection / logging).
func (*Dispatcher) Register ¶
func (d *Dispatcher) Register(method string, h Handler)
Register binds method → handler. A second Register for the same method replaces the first (caller's responsibility to not do that by accident).
type Envelope ¶
type Envelope struct {
Type EnvelopeType `json:"type"`
ReqID string `json:"req_id"`
Method string `json:"method,omitempty"`
AppID string `json:"app_id,omitempty"`
ManifestVersion int `json:"manifest_version,omitempty"`
Payload json.RawMessage `json:"payload,omitempty"`
Error string `json:"error,omitempty"`
}
Envelope is the single message shape on the wire. ReqID is set by the caller and echoed in the reply so a multiplexing client can match.
AppID and ManifestVersion are set by the daemon when it bridges a call from one app to another — handlers can use them for the equivalent of `ipc.context()` (knowing who is calling, under which manifest_version). On a direct connection (no daemon in between) both fields are zero.
type EnvelopeType ¶
type EnvelopeType string
EnvelopeType discriminates the three kinds of envelopes that flow.
const ( // EnvReq is a method call from caller to server. EnvReq EnvelopeType = "req" // EnvReply is a successful return from server to caller. EnvReply EnvelopeType = "reply" // EnvErr is a typed error return; never raw exceptions. EnvErr EnvelopeType = "err" )
type ErrServerError ¶
type ErrServerError struct{ Msg string }
ErrServerError wraps an EnvErr reply from the server side. Callers can `errors.As` to extract the wire-level error string.
func (*ErrServerError) Error ¶
func (e *ErrServerError) Error() string
type Handler ¶
Handler is the server-side function that processes one request envelope. Return either (payload, nil) to send EnvReply, or (nil, err) to send EnvErr with err.Error() as the message.
Handlers should not write to the conn directly — the Serve loop owns the write side. ctx may carry deadlines / cancellation set by Serve.