client

package
v0.2.0-rc.1 Latest Latest
Warning

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

Go to latest
Published: Sep 25, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package client is the native Go HTTP client for a Debuglet dispatcher. It runs on the researcher's machine, talks to the dispatcher's existing HTTP API and supports TEST-funded submissions only. It never imports server internals; the wire shapes below mirror the dispatcher's JSON keys.

The guest-side WASI SDK is the separate package pkg/debuglet.

Index

Constants

View Source
const (
	// CodeInvalidRequest is a malformed or incomplete request.
	CodeInvalidRequest = "invalid_request"
	// CodeInvalidPolicy is a policy that cannot be priced or scheduled.
	CodeInvalidPolicy = "invalid_policy"
	// CodeUnknownExecutor names an executor that is not registered.
	CodeUnknownExecutor = "unknown_executor"
	// CodeIntentMismatch is a submission whose debuglets differ from the ones
	// the payment intent was created for.
	CodeIntentMismatch = "intent_mismatch"
	// CodePaymentIncomplete is a submission for a transaction that is not paid.
	CodePaymentIncomplete = "payment_incomplete"
	// CodeUnsupportedPaymentMethod is a payment method the API does not admit.
	CodeUnsupportedPaymentMethod = "unsupported_payment_method"
	// CodePaymentsDisabled is a chain payment method while blockchain payments
	// are disabled.
	CodePaymentsDisabled = "payments_disabled"
	// CodeUnsupportedAPIVersion is APIVersion being unavailable on that server.
	CodeUnsupportedAPIVersion = "unsupported_api_version"
	// CodeUnauthorized is a missing, malformed, expired or revoked credential.
	// It is the failure a client answers by logging in again.
	CodeUnauthorized = "unauthorized"
	// CodeForbidden is an authenticated account that may not perform the
	// operation. Logging in again does not help; another account is needed.
	CodeForbidden = "forbidden"
	// CodeNotFound is a debuglet, user or executor that does not exist.
	CodeNotFound = "not_found"
	// CodeCapacityExhausted is a batch the scheduler cannot admit.
	CodeCapacityExhausted = "capacity_exhausted"
	// CodeCancelRefused is a cancellation the dispatcher did not accept.
	CodeCancelRefused = "cancel_refused"
	// CodeMethodNotAllowed is a method the route does not serve.
	CodeMethodNotAllowed = "method_not_allowed"
	// CodeUnsupportedMediaType is a body representation the route does not read.
	CodeUnsupportedMediaType = "unsupported_media_type"
	// CodePayloadTooLarge is a body beyond the accepted size.
	CodePayloadTooLarge = "payload_too_large"
	// CodeInternal is a failure inside the dispatcher, with no detail exposed.
	CodeInternal = "internal_error"
	// CodeUnavailable is a temporarily unavailable capability.
	CodeUnavailable = "service_unavailable"
)

Documented failure codes of the dispatcher's HTTP API. They are the stable part of an error: a client selects behaviour by comparing HTTPError.Code against these values instead of matching on Message. A dispatcher may add a code within a contract major version, so treat an unknown code as a plain failure of the status it arrived with.

View Source
const (
	// APIVersion is the dispatcher HTTP contract version this SDK is written
	// against, as major.minor. It is announced on every request so that a
	// server implementing an incompatible contract rejects the request
	// explicitly instead of answering a shape the client cannot read. A server
	// written before the contract was versioned ignores the header.
	APIVersion = "1.2"
)
View Source
const StateExited = "RunStateExited"

StateExited is the terminal state string reported by the dispatcher. An exited debuglet with an empty Error succeeded; a nonempty Error is a workload failure.

Variables

This section is empty.

Functions

This section is empty.

Types

type Account

type Account struct {
	ID           string `json:"id"`
	Name         string `json:"name"`
	Role         string `json:"role"`
	AccountKey   string `json:"account_key"`
	RecoveryCode string `json:"recovery_code"`
}

Account is one account together with the credentials an issuing operation returned for it. AccountKey and RecoveryCode are shown by the dispatcher exactly once, at the operation that minted them, and cannot be read back. Treat both as secrets: store them with owner-only permissions and keep them out of logs, command output and receipts.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client talks to one dispatcher endpoint. Create it with New.

func New

func New(endpoint string, options Options) (*Client, error)

New validates endpoint and options and returns a Client. The endpoint is an explicit base URL, optionally with a path prefix that is preserved on every route; plaintext HTTP is accepted only for literal loopback IPs.

func (*Client) Cancel

func (c *Client) Cancel(ctx context.Context, id, executorID string) error

Cancel asks the dispatcher to abort a debuglet on the given executor. A nil error is an acknowledgement, not proof that execution stopped.

func (*Client) Connection

func (c *Client) Connection(ctx context.Context) (ConnectionInfo, error)

Connection reads optional local-executor connection metadata. Older servers may return an HTTPError with status 404; their ordinary HTTP API remains usable.

func (*Client) CreateAccount

func (c *Client) CreateAccount(ctx context.Context, name string) (Account, error)

CreateAccount registers an account and returns its first credentials. They are returned exactly once: the dispatcher stores only their digests. The caller is responsible for storing them where only its user can read them.

func (*Client) Login

func (c *Client) Login(ctx context.Context, accountKey string) (Session, error)

Login exchanges an account key for a session. An empty account key asks a dispatcher that serves the local development profile for a credential for its own local account; every other dispatcher refuses it. The returned Session.Token is what Options.Credential takes.

func (*Client) Logout

func (c *Client) Logout(ctx context.Context) error

Logout revokes the session this client presents. The token is refused from then on, before its own expiry. A client without a credential logs nothing out and reports the dispatcher's authentication failure.

func (*Client) Logs

func (c *Client) Logs(ctx context.Context, id string, options LogOptions) (LogPage, error)

Logs returns one page of a debuglet's stored output.

func (*Client) Nodes

func (c *Client) Nodes(ctx context.Context) ([]Node, error)

Nodes lists the dispatcher's registered executors.

func (*Client) Recover

func (c *Client) Recover(ctx context.Context, recoveryCode string) (Account, error)

Recover consumes a recovery code and returns the replacement credentials of the one account that code belongs to. Every session of that account is revoked by the dispatcher first. A recovery code can name no other account, so recovering never grants ownership of somebody else's.

func (*Client) Status

func (c *Client) Status(ctx context.Context, id string) (State, error)

Status returns the state of one debuglet.

func (*Client) SubmitTEST

func (c *Client) SubmitTEST(ctx context.Context, batch *PreparedBatch) (Submission, error)

SubmitTEST creates a TEST payment intent for the batch and submits it.

func (*Client) Version

func (c *Client) Version(ctx context.Context) (ServerVersion, error)

Version reports the dispatcher's version identities. It is a report, not an ABI negotiation: the request itself carries APIVersion, and a server that cannot serve it rejects the request. A server written before the contract was versioned answers with Version only, leaving the other fields empty.

func (*Client) Whoami

func (c *Client) Whoami(ctx context.Context) (User, error)

Whoami reports the account this client's credential authenticates as. It is the cheapest way to tell a working credential from an expired or revoked one: the latter answers an *HTTPError with CodeUnauthorized.

func (*Client) WithCredential

func (c *Client) WithCredential(token string) (*Client, error)

WithCredential returns a copy of this client that presents the given session token. The endpoint, transport and timeouts are unchanged, so a credential obtained from one dispatcher cannot be attached to another by accident: a different dispatcher means a different Client.

type ConnectionInfo

type ConnectionInfo struct {
	SchemaVersion int    `json:"schema_version"`
	Mode          string `json:"mode"`
	GRPCAddress   string `json:"grpc_address"`
	YamuxAddress  string `json:"yamux_address"`
}

ConnectionInfo describes the control listeners announced by a local dispatcher. It does not grant access or infer control addresses from an HTTP URL.

type HTTPError

type HTTPError struct {
	Method     string
	Path       string
	StatusCode int
	Code       string
	Message    string
}

HTTPError reports a response the client did not accept: any status other than the one expected for the route, including other 2xx codes. Code is the dispatcher's stable failure code, the field to branch on; Message is a bounded, sanitized diagnostic for a human and must not be parsed. A server that sends no documented envelope leaves Code empty. Unrecognized JSON bodies use a generic diagnostic. Recognized auth_key fields and known submission keys are redacted. Path never contains a query or request body.

func (*HTTPError) Error

func (e *HTTPError) Error() string

type LogEntry

type LogEntry struct {
	ID        int64  `json:"id"`
	Timestamp string `json:"timestamp"`
	Output    []byte `json:"output"`
}

LogEntry is one stored output chunk. Output holds the exact guest bytes; Timestamp is the server's opaque string.

type LogOptions

type LogOptions struct {
	After int64
	Limit int64
}

LogOptions selects a log page. After is a cursor (entry ID) that must be >= 0; Limit zero defaults to 100, otherwise it must be within 1..1000.

type LogPage

type LogPage struct {
	State   string     `json:"state"`
	Error   string     `json:"error"`
	After   int64      `json:"after"`
	Logs    []LogEntry `json:"logs"`
	HasMore bool       `json:"has_more"`
}

LogPage is one page of guest output.

type Node

type Node struct {
	ID                     string `json:"id"`
	Ready                  bool   `json:"ready"`
	LastSeen               int64  `json:"last_seen"`
	Version                string `json:"version"`
	TeslaDelaySec          int64  `json:"tesla_delay_sec"`
	TeslaAnchorTimestampNs int64  `json:"tesla_anchor_timestamp_ns"`
	TeslaAnchorKey         []byte `json:"tesla_anchor_key"`
	PricePerBw             int64  `json:"price_per_bw"`
	Currency               string `json:"currency"`
}

Node is one executor as reported by GET executors.

type Options

type Options struct {
	// HTTPClient supplies transport settings. It is cloned, never mutated,
	// and redirects are always rejected. nil uses a fresh client.
	HTTPClient *http.Client
	// RequestTimeout bounds each request including its body read. Zero
	// defaults to 10 s; a negative value is invalid.
	RequestTimeout time.Duration
	// AllowRemoteTEST permits TEST submissions to endpoints other than a
	// literal loopback IP. It is an accident guard, not server authorization:
	// an SSH-forwarded loopback endpoint is still an operator-selected remote
	// service.
	AllowRemoteTEST bool
	// Credential is the session token this client presents on every request,
	// as an Authorization bearer header. It is obtained from Login and belongs
	// to exactly one dispatcher: a Client is bound to one origin and refuses
	// redirects, so a credential never travels to another one. It is never
	// written to a log, an error message or a returned diagnostic. Empty makes
	// unauthenticated requests, which a dispatcher serving the local
	// development profile still accepts.
	Credential string
}

Options configures a Client. The zero value is valid for a loopback endpoint: a fresh HTTP client, a 10 s per-request timeout and no remote TEST submissions.

type Policy

type Policy struct {
	FloorBW     int64    `json:"floor_bw"`
	CeilBW      int64    `json:"ceil_bw"`
	TimeoutMS   int64    `json:"timeout_ms"`
	Addresses   []string `json:"addresses"`
	RequireICMP bool     `json:"require_icmp"`
	ListenUDP   bool     `json:"listen_udp"`
	ListenTCP   bool     `json:"listen_tcp"`
	ListenSCION bool     `json:"listen_scion"`
}

Policy is the network policy requested for a debuglet.

type PreparedBatch

type PreparedBatch struct {
	// contains filtered or unexported fields
}

PreparedBatch is an immutable, validated batch produced by Prepare. The same serialized debuglets array is sent for the payment intent and the submission, so the server's request hash check sees identical values. A zero or nil PreparedBatch is invalid.

func Prepare

func Prepare(requests []Request) (*PreparedBatch, error)

Prepare validates requests and freezes them into one immutable serialized batch used for both submission steps.

type Request

type Request struct {
	// OrderID must be unique within one batch.
	OrderID int64 `json:"order_id"`
	// StartTimestamp is an optional Unix epoch start time.
	StartTimestamp *int64   `json:"start_time,omitempty"`
	ExecutorID     string   `json:"executor_id"`
	Args           []string `json:"args,omitempty"`
	// Wasm is the guest binary; it is transmitted base64-encoded by
	// encoding/json.
	Wasm   []byte `json:"wasm"`
	Policy Policy `json:"policy"`
}

Request describes one debuglet in a batch. Field order and JSON keys match the dispatcher's request model exactly.

type ServerVersion

type ServerVersion struct {
	Version         string   `json:"version"`
	APIVersion      string   `json:"api_version"`
	APIVersions     []string `json:"api_versions"`
	BinaryVersion   string   `json:"binary_version"`
	BinaryRevision  string   `json:"binary_revision"`
	ProtocolVersion string   `json:"protocol_version"`
}

ServerVersion reports a dispatcher's version identities. Version is its configured string, retained from before the HTTP contract was versioned. APIVersion is the HTTP contract the server implements and APIVersions lists the major contract versions it serves; BinaryVersion and BinaryRevision identify the build, and ProtocolVersion is the executor control protocol, which no HTTP client speaks. Every field beyond Version is empty when the server predates contract versioning.

type Session

type Session struct {
	Token     string `json:"token"`
	CSRFToken string `json:"csrf_token"`
	ExpiresAt int64  `json:"expires_at"`
	ID        string `json:"id"`
	Name      string `json:"name"`
	Role      string `json:"role"`
}

Session is an issued session. Token is the bearer credential to put in Options.Credential. CSRFToken is only of interest to a browser client that received the session as a cookie; a native client never needs it. ExpiresAt is Unix seconds.

type State

type State struct {
	State      string `json:"state"`
	Error      string `json:"error"`
	ExecutorID string `json:"executor_id"`
}

State is a debuglet's reported state. Unknown state strings are preserved.

type Submission

type Submission struct {
	IDs           []string `json:"ids"`
	TransactionID string   `json:"transaction_id"`
}

Submission is the result of an accepted TEST submission. IDs are in batch order. No auth key is exposed.

type SubmissionError

type SubmissionError struct {
	Stage          string
	TransactionID  string
	OutcomeUnknown bool
	Err            error
}

SubmissionError reports a failed SubmitTEST. Stage is "intent" or "submit". TransactionID is retained when the intent had already been created. OutcomeUnknown is set conservatively when the submission may have been accepted by the server although no valid response was observed (transport or read failure after sending, malformed success, an unexpected submission 2xx, or a server 5xx); it is uncertainty, not proof of acceptance. A validated pre-send failure or a 4xx response is a rejection with OutcomeUnknown false.

func (*SubmissionError) Code

func (e *SubmissionError) Code() string

Code returns the dispatcher's failure code when the submission failed on a response that carried one, and "" otherwise. It never changes how the outcome itself is classified: OutcomeUnknown stays the only statement about whether the submission may have been accepted.

func (*SubmissionError) Error

func (e *SubmissionError) Error() string

func (*SubmissionError) Unwrap

func (e *SubmissionError) Unwrap() error

type User

type User struct {
	ID   string `json:"id"`
	Name string `json:"name"`
	Role string `json:"role"`
}

User is the account a request authenticated as, as reported by GET me.

Jump to

Keyboard shortcuts

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