Documentation
¶
Overview ¶
Package relay maintains fort serve's outbound tunnel to the 028 gateway: one WebSocket to the broker, per-client-session Noise IK handshakes (exec/relay/secure), and sealed HTTP/SSE service against an injected http.Handler — the transport never imports ui (seam: it moves bytes).
Config{URL, Token, Key, MinBackoff}; New(handler, cfg) *Transport; (t *Transport) Run(ctx) error — reconnect loop with exponential backoff (MinBackoff..30s, jittered) until ctx is done.
Per inbound frame:
hs1 -> NewResponder(cfg.Key) for that stream; ReadMessage(payload);
WriteMessage -> reply kind hs2; store Session on completion.
req -> sess.Open -> ReqPayload -> serve:
non-stream: httptest.NewRecorder over the handler; reply res.
stream (Accept: text/event-stream): spawn goroutine with a
cancelable context; a streamWriter ResponseWriter seals+sends a
res{Stream:true} on WriteHeader, then chunk frames on each
Flush; register cancel under (stream,id) for "end".
end -> sess.Open -> id -> cancel that request.
bye -> drop the stream's session + cancel its in-flight requests.
Writes to the socket are serialized with a mutex — and, crucially, each Seal happens under that same lock immediately before its write, so the AEAD nonce order (per session) always matches wire order, which is what the peer decrypts in. A dropped socket cancels every in-flight request and re-dials.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ChunkPayload ¶
type ChunkPayload struct {
ID string `json:"id"`
Data []byte `json:"data,omitempty"`
End bool `json:"end,omitempty"`
}
ChunkPayload is the sealed plaintext of a "chunk" frame (SSE piece).
type Config ¶
type Config struct {
URL string // broker WebSocket URL (e.g. wss://gw/tunnel)
Token string // device token, sent as Authorization: Bearer
Key secure.Keypair // this daemon's pinned static identity
MinBackoff time.Duration // reconnect backoff floor (default 1s)
}
Config configures the outbound tunnel.
type Frame ¶
type Frame struct {
Stream string `json:"stream"`
Kind string `json:"kind"` // hs1|hs2|req|res|chunk|end|bye
B64 string `json:"b64,omitempty"`
}
Frame is the single WebSocket envelope of the gateway wire contract (spec 028). The broker routes on Stream/Kind and never sees inside B64 once a session is sealed.
type ReqPayload ¶
type ReqPayload struct {
ID string `json:"id"`
Method string `json:"method"`
Path string `json:"path"`
Headers map[string]string `json:"headers,omitempty"`
Body []byte `json:"body,omitempty"`
}
ReqPayload is the sealed plaintext of a "req" frame.
type ResPayload ¶
type ResPayload struct {
ID string `json:"id"`
Status int `json:"status"`
Headers map[string]string `json:"headers,omitempty"`
Body []byte `json:"body,omitempty"`
Stream bool `json:"stream,omitempty"` // true => chunks follow
}
ResPayload is the sealed plaintext of a "res" frame.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package secure is Fort's E2E crypto contract for the relay (spec 028): a Noise IK handshake (X25519) between a client and the daemon's pinned static key, then ChaCha20-Poly1305 AEAD framing.
|
Package secure is Fort's E2E crypto contract for the relay (spec 028): a Noise IK handshake (X25519) between a client and the daemon's pinned static key, then ChaCha20-Poly1305 AEAD framing. |