Help us shape the future of Go! Take the 2026 Go Developer Survey

wire

package
v0.6.0 Latest Latest
Warning

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

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

Documentation

Overview

Package wire implements the wire format of the Agent Wire Protocol (AWP): NDJSON framing, the message envelope, the typed messages of SPEC.md sections 6 to 10, Ed25519 key encoding, canonical JSON and signed grants.

The package has no I/O policy of its own. It is shared by the daemon, the tests and anyone who wants to write an AWP peer in Go.

Index

Constants

View Source
const (
	// TMirror carries a copy of one line of a thread the sender is part
	// of. It is reliable like msg: queued, acked by id, replayed on resume
	// (its th is the mirrored thread's, for the seen map).
	TMirror = "mirror"
	// TPrivate asks the receiver not to mirror the thread th. It is
	// reliable like msg.
	TPrivate = "private"
)

Conversation sharing is an extension: an agent may mirror its threads to hosts it names (typically a dashboard), so that they can show those conversations, not only their subjects and states.

The sharing agent announces it: Hello.Shares and Presence.Shares list the hosts it shares with, so the other party of every thread knows. That party can keep a thread out with a private message; the sharer then stops mirroring it and asks its hosts to forget what they have of it.

View Source
const (
	// MaxPresenceBytes caps a signed presence document.
	MaxPresenceBytes = 64 << 10
	// PresenceMaxHops bounds how far a document is forwarded.
	PresenceMaxHops = 8
)

Presence limits.

View Source
const (
	// Version is the protocol major version sent in hello.v.
	Version = 0

	// MaxLine is the largest line a peer accepts, excluding the newline.
	MaxLine = 1 << 20

	// ChunkSize is the recommended chunk payload size before encoding.
	ChunkSize = 256 << 10

	// AuthContext prefixes the byte string signed in auth.
	AuthContext = "awp-auth-v0"
)

Protocol constants.

View Source
const (
	THello     = "hello"
	TAuth      = "auth"
	TResume    = "resume"
	TMsg       = "msg"
	TState     = "state"
	TAck       = "ack"
	TChunk     = "chunk"
	TPing      = "ping"
	TPong      = "pong"
	TBye       = "bye"
	TErr       = "err"
	TGrant     = "grant"
	TIntroduce = "introduce"
)

Message types.

View Source
const (
	ErrBadFrame    = "bad_frame"
	ErrVersion     = "version"
	ErrAuth        = "auth"
	ErrUnsupported = "unsupported"
	ErrForbidden   = "forbidden"
	ErrBlobRefused = "blob_refused"
	ErrTooLarge    = "too_large"
	ErrInternal    = "internal"
)

Error codes from section 9.7.

View Source
const (
	PartText = "text"
	PartCode = "code"
	PartData = "data"
	PartBlob = "blob"
)

Part kinds.

View Source
const (
	StateOpen    = "open"
	StateWorking = "working"
	StateWaiting = "waiting"
	StateDone    = "done"
	StateFailed  = "failed"
	StateClosed  = "closed"
)

Recommended thread states from section 8.1.

View Source
const (
	KeyPattern    = "^ed25519:[A-Za-z0-9_-]{43}$"
	B64URLPattern = "^[A-Za-z0-9_-]+$"
	B64Pattern    = "^[A-Za-z0-9+/]*={0,2}$"
)

Patterns for the encoded fields, as the JSON Schema states them: keys are "ed25519:" and 43 characters of unpadded base64url (section 7.1); nonces and signatures are unpadded base64url; chunk data is standard base64 (section 9.3). Receivers are more liberal (DecodeB64).

View Source
const KeyPrefix = "ed25519:"

KeyPrefix prefixes an encoded Ed25519 public key.

View Source
const TPresence = "presence"

TPresence is the presence extension: a signed summary of what an agent is doing, gossiped across the network so that any connected host can watch it (NOTES.md, "Presence gossip"). It is also the hello cap that asks for it: presence is only sent to peers that list it.

Variables

View Source
var (
	ErrGrantExpired = errors.New("grant expired")
	ErrGrantInvalid = errors.New("invalid grant")
)

Errors from ParseGrant.

View Source
var ErrBadSignature = errors.New("signature does not verify")

ErrBadSignature means a signature did not verify.

View Source
var ErrLineTooLong = errors.New("line exceeds 1 MiB")

ErrLineTooLong means a line exceeded MaxLine (too_large).

View Source
var ErrNotObject = errors.New("line is not a JSON object")

ErrNotObject means a line is not a JSON object (bad_frame).

View Source
var ErrPresenceInvalid = errors.New("invalid presence document")

ErrPresenceInvalid means a presence document failed verification.

Functions

func AuthPayload

func AuthPayload(myHello, peerHello []byte) []byte

AuthPayload is the byte string signed in auth: "awp-auth-v0" || 0x00 || my_hello_line || 0x00 || peer_hello_line.

func Canonical

func Canonical(doc []byte) ([]byte, error)

Canonical re-encodes a JSON document the way section 10.2 defines canonical JSON: object keys sorted, no whitespace, UTF-8. Strings escape only what JSON requires (quote, backslash and control characters, using the short forms \b \f \n \r \t), so the output matches Python's json.dumps(v, sort_keys=True, separators=(",", ":"), ensure_ascii=False). Numbers keep their original text.

func CanonicalValue

func CanonicalValue(v any) ([]byte, error)

CanonicalValue canonicalizes an already decoded value (as produced by a json.Decoder with UseNumber).

func Decode

func Decode(line []byte, v any) error

Decode unmarshals a full line into v (one of the message structs).

func DecodeB64

func DecodeB64(s string) ([]byte, error)

DecodeB64 accepts base64url or standard base64, padded or not. The spec says base64url for keys, nonces and signatures and plain base64 for chunk data, but is silent on padding, so a receiver takes any of them.

func Encode

func Encode(v any) ([]byte, error)

Encode marshals a message to one line, without the trailing newline and without HTML escaping, so that text reads naturally under cat.

func EncodeB64

func EncodeB64(b []byte) string

EncodeB64 is the encoding used for key, nonce and sig fields: unpadded base64url.

func ErrCloses

func ErrCloses(code string) bool

ErrCloses reports whether an err with this code closes the connection. Section 9.7 lists forbidden, unsupported, blob_refused and internal as non-closing. Unknown codes are treated as non-closing too, so a newer peer cannot tear down a connection just by inventing a code.

func ErrCodes added in v0.6.0

func ErrCodes() []string

ErrCodes lists the error codes of section 9.7, in the spec's order.

func Extensions added in v0.6.0

func Extensions() []string

Extensions lists the message types that are not in SPEC.md: this implementation speaks them, peers that do not know them ignore them.

func Fingerprint

func Fingerprint(pub ed25519.PublicKey) string

Fingerprint is the SHA-256 fingerprint of a public key, the way section 13 suggests agents print it in their about text.

func FormatKey

func FormatKey(pub ed25519.PublicKey) string

FormatKey encodes a public key as "ed25519:" + unpadded base64url.

func FormatTime

func FormatTime(t time.Time) string

FormatTime formats t the way awp timestamps are written.

func IDTime

func IDTime(id string) (time.Time, bool)

IDTime returns the timestamp embedded in a ULID, or false if id is not one.

func Nonce

func Nonce(n int) string

Nonce returns n random bytes, base64url encoded.

func Now

func Now() string

Now returns the current time as an RFC 3339 UTC timestamp with millisecond precision.

func ParseKey

func ParseKey(s string) (ed25519.PublicKey, error)

ParseKey decodes an "ed25519:..." public key.

func ParseTime

func ParseTime(s string) (time.Time, error)

ParseTime accepts any RFC 3339 timestamp.

func ShortKey

func ShortKey(key string) string

ShortKey is a short, human-friendly form of an encoded key: the first ten characters of its base64url body.

func SignAuth

func SignAuth(priv ed25519.PrivateKey, myHello, peerHello []byte) string

SignAuth signs the auth transcript from the signer's point of view.

func SignPresence

func SignPresence(priv ed25519.PrivateKey, p *Presence) (json.RawMessage, error)

SignPresence fills in Origin and Sig and returns the document's wire form.

func ThreadStates added in v0.6.0

func ThreadStates() []string

ThreadStates lists the recommended states of section 8.1. Peers may use others.

func VerifyAuth

func VerifyAuth(peer ed25519.PublicKey, sig string, peerHello, myHello []byte) error

VerifyAuth checks the peer's auth signature. From the verifier's side the peer's hello comes first, since the peer signed its own hello first.

Types

type Ack

type Ack struct {
	Envelope
}

Ack says the msg or state named by re is durably received (section 9.2). Acks drive outbox pruning and are not acked themselves.

type Auth

type Auth struct {
	Envelope
	// Sig is the Ed25519 signature, base64url, over "awp-auth-v0" || 0x00 ||
	// my hello line || 0x00 || peer hello line, the lines as sent and
	// received without the newline.
	Sig string `json:"sig" jsonschema:"pattern=^[A-Za-z0-9_-]+$"`
	// Grants are grant objects (section 10.2) the sender presents.
	Grants []json.RawMessage `json:"grants,omitempty"`
}

Auth proves possession of the key sent in hello (section 7.2).

type Bye

type Bye struct {
	Envelope
	// Reason says why, for the log.
	Reason string `json:"reason,omitempty"`
}

Bye is a graceful close (section 9.6). After sending it a peer sends nothing else and closes after the other side's bye or after 5 seconds.

type Chunk

type Chunk struct {
	Envelope
	// Ref names the blob, as the sender chose it.
	Ref string `json:"ref"`
	// N is the chunk index, from 0.
	N int `json:"n" jsonschema:"minimum=0"`
	// Last is true on the final chunk.
	Last bool `json:"last"`
	// Data is the chunk's bytes, standard base64 (B64Pattern; the tag
	// syntax cannot carry the padding).
	Data string `json:"data"`
}

Chunk carries part of a blob (section 9.3). Chunks of one blob arrive in order; chunks of different blobs may interleave. A chunk carries th when the blob belongs to a thread, so that resume replays it like any other threaded message.

type Envelope

type Envelope struct {
	// T is the message type.
	T string `json:"t"`
	// ID is unique per sender. A ULID or UUIDv7 is recommended, so that ids
	// sort by time; resume compares ids as strings.
	ID string `json:"id" jsonschema:"minLength=1"`
	// TS is an RFC 3339 UTC timestamp.
	TS string `json:"ts" jsonschema:"format=date-time"`
	// Th is the thread id. Required for msg, state and ack.
	Th string `json:"th,omitempty"`
	// Re is the id of the message this one responds to.
	Re string `json:"re,omitempty"`
}

Envelope holds the fields every line carries (section 6). The type-specific fields sit beside them at the top level.

func ParseEnvelope

func ParseEnvelope(line []byte) (Envelope, error)

ParseEnvelope decodes the envelope of a line. It fails with ErrNotObject when the line is not a JSON object, which the caller answers with bad_frame.

type Err

type Err struct {
	Envelope
	// Code is the error code.
	Code string `json:"code"`
	// Detail is human readable.
	Detail string `json:"detail,omitempty"`
	// Ref names the blob a blob_refused is about.
	Ref string `json:"ref,omitempty"`
}

Err reports a problem (section 9.7). Whether it closes the connection depends on the code: bad_frame, version, auth and too_large do, unsupported, forbidden, blob_refused and internal do not.

type Grant

type Grant struct {
	Iss   string
	Sub   string
	Caps  []string
	Exp   time.Time
	Nonce string
	Sig   string
	Aud   string // see GrantObject.Aud

	Raw json.RawMessage
}

Grant is a parsed, verified GrantObject. Raw holds the exact object as issued or received; it is what travels on the wire, so fields this implementation does not know about survive and stay covered by the signature.

func MintGrant

func MintGrant(priv ed25519.PrivateKey, sub string, caps []string, exp time.Time, aud string) (*Grant, error)

MintGrant issues a grant from priv to sub. aud, if non-empty, restricts which peer should honor it (see Grant.Aud).

func ParseGrant

func ParseGrant(raw []byte, now time.Time) (*Grant, error)

ParseGrant decodes and verifies a grant: the signature must be iss's over the canonical JSON of the object without sig. If now is non-zero the grant must not have expired at that time.

func (*Grant) Has

func (g *Grant) Has(c string) bool

Has reports whether the grant names capability c.

func (*Grant) Hash

func (g *Grant) Hash() string

Hash identifies a grant by the SHA-256 of its canonical form, signature included.

type GrantMsg

type GrantMsg struct {
	Envelope
	// Grant is the grant object (section 10.2).
	Grant json.RawMessage `json:"grant"`
}

GrantMsg delivers a grant after the handshake (section 10.3).

type GrantObject added in v0.6.0

type GrantObject struct {
	// Iss is the granting key.
	Iss string `json:"iss" jsonschema:"pattern=^ed25519:[A-Za-z0-9_-]{43}$"`
	// Sub is the receiving key.
	Sub string `json:"sub" jsonschema:"pattern=^ed25519:[A-Za-z0-9_-]{43}$"`
	// Caps are the capability strings granted (section 10.1).
	Caps []string `json:"caps"`
	// Exp is when the grant expires, RFC 3339.
	Exp string `json:"exp" jsonschema:"format=date-time"`
	// Nonce makes each grant distinct, base64url.
	Nonce string `json:"nonce" jsonschema:"pattern=^[A-Za-z0-9_-]+$"`
	// Sig is the issuer's signature, base64url.
	Sig string `json:"sig" jsonschema:"pattern=^[A-Za-z0-9_-]+$"`
	// Aud is an extension: when set, only the peer with this key should
	// honor the grant. Introductions use it so that a grant meant for the
	// introduced peer does not also give the recipient powers over the
	// introducer. Peers that do not know the field ignore it, which can
	// only make them honor less, never more, than the spec already says.
	Aud string `json:"aud,omitempty" jsonschema:"pattern=^ed25519:[A-Za-z0-9_-]{43}$"`
}

GrantObject is the wire form of a grant (section 10.2): a signed statement that sub may use caps until exp, honored by iss and by whoever trusts iss. sig is iss's Ed25519 signature over the canonical JSON of the object without sig: keys sorted, no whitespace, UTF-8.

type Hello

type Hello struct {
	Envelope
	// V is the protocol major version. A peer that sees a version it does
	// not speak sends err version and closes.
	V int `json:"v" jsonschema:"minimum=0"`
	// Key is the long-term Ed25519 public key. Its bytes are the peer's
	// identity.
	Key string `json:"key" jsonschema:"pattern=^ed25519:[A-Za-z0-9_-]{43}$"`
	// Name is how the peer calls itself, "harness@host" by convention.
	Name string `json:"name,omitempty"`
	// Nonce is 32 random bytes, base64url. The auth signature covers the
	// whole hello line, nonce included.
	Nonce string `json:"nonce" jsonschema:"pattern=^[A-Za-z0-9_-]+$"`
	// Caps lists the supported message families beyond the mandatory chat
	// and resume: blob, grant, introduce, and any extension.
	Caps []string `json:"caps,omitempty"`
	// About is free text for the other agent's context. It is not
	// authenticated until auth completes.
	About string `json:"about,omitempty"`

	// Addr is an extension: an address at which the sender can be reached,
	// so that either side can reconnect (section 4.3). Peers that do not
	// know it ignore it, as section 5 requires.
	Addr string `json:"addr,omitempty"`

	// Shares is an extension (mirror.go): the keys of the hosts this agent
	// mirrors its conversations to, so the other party knows.
	Shares []string `json:"shares,omitempty"`
}

Hello is the first line each side sends, at once, without waiting for the other (section 7.1).

type IDGen

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

IDGen generates ULIDs that strictly increase, even within one millisecond and even if the wall clock steps backwards (a sandbox restored from a snapshot can do that). Resume compares ids as strings, so monotonicity is what keeps "ids greater than the seen id" meaningful.

func NewIDGen

func NewIDGen() *IDGen

NewIDGen returns a generator. Call Observe with the newest id persisted by a previous run so that ids keep increasing across restarts.

func (*IDGen) New

func (g *IDGen) New() string

New returns the next id.

func (*IDGen) Observe

func (g *IDGen) Observe(id string)

Observe records an id produced earlier (possibly by a previous process) so that New never returns anything smaller.

type IntroPeer

type IntroPeer struct {
	// Key is the introduced peer's public key.
	Key string `json:"key" jsonschema:"pattern=^ed25519:[A-Za-z0-9_-]{43}$"`
	// Name is what the introduced peer calls itself.
	Name string `json:"name,omitempty"`
	// Address is where the introduced peer listens, a hint: the key is the
	// identity.
	Address string `json:"address,omitempty"`
}

IntroPeer identifies the introduced peer.

type Introduce

type Introduce struct {
	Envelope
	// Peer is the introduced peer.
	Peer IntroPeer `json:"peer"`
	// Grant is issued by the introducer to the recipient, for the
	// introduced peer to honor.
	Grant json.RawMessage `json:"grant,omitempty"`
}

Introduce hands the recipient another peer's identity and address plus a grant issued by the introducer (section 10.4). The introduced peer honors the grant only if it trusts the introducer with introduce.

type Message added in v0.6.0

type Message struct {
	T    string
	Type reflect.Type
}

Message pairs a message type with the Go type that holds it.

func Messages added in v0.6.0

func Messages() []Message

Messages lists every message type this package defines, with its Go type: the core messages of SPEC.md first, in the order the spec defines them, then the extensions.

type Mirror

type Mirror struct {
	Envelope
	// Of is the other party of the mirrored thread (the sender is one side).
	Of string `json:"of" jsonschema:"pattern=^ed25519:[A-Za-z0-9_-]{43}$"`
	// OfName is the other party's name.
	OfName string `json:"of_name,omitempty"`
	// Subject is the mirrored thread's subject.
	Subject string `json:"subject,omitempty"`
	// Dir says who wrote Line: "out" the sender, "in" the other party.
	Dir string `json:"dir,omitempty" jsonschema:"enum=out,enum=in"`
	// Line is the original msg or state line, verbatim. A msg's blob parts
	// keep their name, type and size; the file itself is not mirrored.
	Line json.RawMessage `json:"line,omitempty"`
	// Withdraw asks the receiver to delete everything it has of the thread
	// th between the sender and Of.
	Withdraw bool `json:"withdraw,omitempty"`
}

Mirror is an extension: one mirrored line of a thread the sender is part of, or, with Withdraw, a request to forget a mirrored thread. Its th is the mirrored thread's.

type Msg

type Msg struct {
	Envelope
	// Subject is the thread's title, meaningful on its first message.
	Subject string `json:"subject,omitempty"`
	// Parts are the message's pieces, in order.
	Parts []Part `json:"parts"`
}

Msg is one turn in a thread (section 9.1). The first msg with a new th creates the thread.

type Part

type Part struct {
	// K is the part kind: text, code, data or blob.
	K string `json:"k"`
	// Text is the text of a text or code part.
	Text string `json:"text,omitempty"`
	// Lang names a code part's language, as a fenced block would.
	Lang string `json:"lang,omitempty"`
	// Data is a data part's inline JSON.
	Data json.RawMessage `json:"data,omitempty"`
	// Mime is the media type of a data or blob part.
	Mime string `json:"mime,omitempty"`
	// Ref names the blob a blob part refers to, as the chunks carry it.
	Ref string `json:"ref,omitempty"`
	// Name is a blob part's file name.
	Name string `json:"name,omitempty"`
	// Size is a blob part's size in bytes, before encoding.
	Size int64 `json:"size,omitempty" jsonschema:"minimum=0"`
}

Part is one piece of a message. Which fields are meaningful depends on K (PartKinds).

func (Part) MarshalJSON

func (p Part) MarshalJSON() ([]byte, error)

MarshalJSON emits exactly the fields that belong to the part's kind, so a zero-length blob still carries "size":0 and a text part never grows a stray mime.

type PartKind added in v0.6.0

type PartKind struct {
	K        string
	Doc      string
	Required []string
	Optional []string
}

PartKind says which fields a part of one kind carries (section 9.1): Required are always present, Optional only when set. Part.MarshalJSON follows this table, and the JSON Schema is generated from it.

func PartKinds added in v0.6.0

func PartKinds() []PartKind

PartKinds lists the part kinds of section 9.1.

type Ping

type Ping struct {
	Envelope
}

Ping is a liveness probe (section 9.4): sent when idle for 30 seconds by convention; two missed pongs mean the connection is dead.

type Pong

type Pong struct {
	Envelope
}

Pong answers a ping; re names the ping.

type Presence

type Presence struct {
	// Origin is the key of the agent the document describes and is signed by.
	Origin string `json:"origin" jsonschema:"pattern=^ed25519:[A-Za-z0-9_-]{43}$"`
	// Name is the agent's name, as in hello.
	Name string `json:"name,omitempty"`
	// About is the agent's about text, as in hello.
	About string `json:"about,omitempty"`
	// Version is the agent's implementation version.
	Version string `json:"version,omitempty"`
	// Harness is the agent harness: claude, codex, cursor, ...
	Harness string `json:"harness,omitempty"`
	// Model is the model the agent runs on, as it reports it.
	Model string `json:"model,omitempty"`
	// Host is the hostname of the machine the agent runs on.
	Host string `json:"host,omitempty"`
	// Shares lists the keys of the hosts the agent mirrors its
	// conversations to.
	Shares []string `json:"shares,omitempty"`
	// Active is when the agent last did something through awp, to 30
	// seconds, RFC 3339.
	Active string `json:"active,omitempty" jsonschema:"format=date-time"`
	// Waiting says the agent is blocked waiting for a message.
	Waiting bool `json:"waiting,omitempty"`
	// Seq increases with every document the origin signs; a relay keeps the
	// highest it has seen.
	Seq int64 `json:"seq" jsonschema:"minimum=0"`
	// TS is when the document was signed, RFC 3339.
	TS string `json:"ts" jsonschema:"format=date-time"`
	// Peers are the origin's peers.
	Peers []PresencePeer `json:"peers,omitempty"`
	// Threads are the origin's threads.
	Threads []PresenceThread `json:"threads,omitempty"`
	// Outbox counts the origin's queued, unacked messages.
	Outbox int `json:"outbox,omitempty" jsonschema:"minimum=0"`
	// Unread counts the messages the origin has not read.
	Unread int `json:"unread,omitempty" jsonschema:"minimum=0"`
	// Sig is the origin's signature, base64url.
	Sig string `json:"sig,omitempty" jsonschema:"pattern=^[A-Za-z0-9_-]+$"`
}

Presence is what an agent says about itself. It is signed by Origin over the canonical JSON of the document without "sig", like a grant.

func ParsePresence

func ParsePresence(raw []byte) (*Presence, error)

ParsePresence verifies a signed presence document and decodes it.

func (*Presence) Time

func (p *Presence) Time() time.Time

Time parses the document's timestamp.

type PresenceMsg

type PresenceMsg struct {
	Envelope
	// Doc is the signed presence document (Presence), verbatim.
	Doc json.RawMessage `json:"doc"`
	// Hops counts the relays the document has been through; it is not
	// forwarded past PresenceMaxHops.
	Hops int `json:"hops" jsonschema:"minimum=0"`
}

PresenceMsg is an extension: it carries one signed presence document, gossiped to every peer that lists presence in its hello caps. Doc travels unchanged from relay to relay; the envelope and Hops are per hop.

type PresencePeer

type PresencePeer struct {
	// Key is the peer's key.
	Key string `json:"key" jsonschema:"pattern=^ed25519:[A-Za-z0-9_-]{43}$"`
	// Name is the peer's name.
	Name string `json:"name,omitempty"`
	// Up says the peer is connected right now.
	Up bool `json:"up,omitempty"`
	// RTT is the connection's last round trip time in milliseconds, to show
	// latency across the network; 0 if unknown.
	RTT int64 `json:"rtt,omitempty" jsonschema:"minimum=0"`
}

PresencePeer is one of the origin's peers.

type PresenceThread

type PresenceThread struct {
	// Th is the thread id.
	Th string `json:"th"`
	// Peer is the key of the other party.
	Peer string `json:"peer" jsonschema:"pattern=^ed25519:[A-Za-z0-9_-]{43}$"`
	// Subject is the thread's subject.
	Subject string `json:"subject,omitempty"`
	// Mine is the origin's state in the thread.
	Mine string `json:"mine,omitempty"`
	// Theirs is the peer's state, as the origin last heard it.
	Theirs string `json:"theirs,omitempty"`
	// Updated is when the thread last changed, RFC 3339.
	Updated string `json:"updated,omitempty" jsonschema:"format=date-time"`
	// Unread counts the thread's messages the origin has not read.
	Unread int `json:"unread,omitempty" jsonschema:"minimum=0"`
}

PresenceThread is one of the origin's threads.

type Private

type Private struct {
	Envelope
}

Private is an extension: it asks the receiver to keep the thread th out of what it shares with its hosts, and those hosts to forget it.

type Reader

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

Reader reads newline-terminated lines of at most MaxLine bytes.

func NewReader

func NewReader(r io.Reader) *Reader

NewReader returns a Reader over r.

func (*Reader) ReadLine

func (r *Reader) ReadLine() ([]byte, error)

ReadLine returns the next line without its trailing newline. The returned slice is owned by the caller. A final line without a newline is reported as io.ErrUnexpectedEOF, since a well-formed peer always terminates lines.

type Resume

type Resume struct {
	Envelope
	// Seen maps each thread id to the last message id the sender has
	// durably received in it. Empty on a first connection.
	Seen map[string]string `json:"seen"`
}

Resume is sent by both sides after every handshake (section 9.5). The receiver replays its outbox messages the sender has not seen.

type State

type State struct {
	Envelope
	// State is the thread state: open, working, waiting, done, failed or
	// closed by convention; peers may use others.
	State string `json:"state" jsonschema:"example=open,example=working,example=waiting,example=done,example=failed,example=closed"`
	// Note says more, such as why a thread failed.
	Note string `json:"note,omitempty"`
}

State is the sender's view of a thread's soft state (section 8.1). The two sides can disagree.

type Writer

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

Writer writes whole lines. It is safe for concurrent use; each line is written with a single Write call so lines never interleave.

func NewWriter

func NewWriter(w io.Writer) *Writer

NewWriter returns a Writer over w.

func (*Writer) WriteLine

func (w *Writer) WriteLine(line []byte) error

WriteLine writes line followed by a newline.

Jump to

Keyboard shortcuts

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