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

proxystatus

package
v1.3.100 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package proxystatus pkg/proxystatus/font.go c4-app-web

Package proxystatus pkg/proxystatus/provider.go c4-app-web

A read-only, self-contained diagnostic page each native mesh proxy serves at a reserved, well-known host through itself — the proxy counterpart of the branded route interstitial (pkg/proxyinterstitial). Hitting one of the reserved hosts through a resolving proxy shows that surface's live state:

Injection model mirrors the resolver's reserved "home" host: the SOCKS5 Dial callback recognizes a status host BEFORE any suffix match / upstream forward, renders the page in-process (nothing is dialed out over the mesh) and splices the rendered HTTP response back to the browser via ServeConn.

MVP scope is READ-ONLY: the three data sections a proxy operator wants when a route misbehaves — recent per-process log lines, route/transport events, and a mux-plot-style per-leg bandwidth/RTT view of the surface's route group (the same RouteGroupMuxInfo telemetry `cli proxy mux plot` renders in the terminal). Route CONTROL (change/select routes, pick a dmsg relay) is left as an explicit, clearly-marked seam — see render.go's control section and the Snapshot doc — so it can be added later without reshaping the wire.

Package proxystatus pkg/proxystatus/render.go c4-app-web

Package proxystatus pkg/proxystatus/render_skywire.go

Package proxystatus pkg/proxystatus/routegraph.go c4-app-web

RouteGraph projects a surface Snapshot's live route-group state into the small node/edge subgraph the status.skysocks page hands to the GPU force-directed view (github.com/0magnet/cosmos-go, reused from pkg/tpviz/wasmgl via the one wasm-visor "netview" blob). It is the graph counterpart of routetree.go's ASCII tree: the SAME Snapshot data, shaped as a graph rather than a tree.

Scope is deliberately SMALL — only the nodes and edges ON the proxy's actual routes: this visor (root), each intermediate hop, and the exit, plus the per-hop transport each leg traverses. It is NOT the whole mesh; an intermediate's other transports are not fetched. A hop PK shared by several legs is ONE node (deduplicated). Edges are colored by their STREAM (tunnel) with the same per-stream accent palette the tree uses, styled active vs standby, and widthed by the leg's live byte-rate.

The engine renders points (no on-canvas text), so a node's FULL public key is never truncated on screen — it rides untruncated in the node's hover tooltip (Tip), with a short hex only as the tooltip's heading. The driver JS (render.go graphGLScript) maps this JSON to cosmos-go's typed-array setData payload (positions seeded, colors as CSS strings, links as index pairs).

Package proxystatus pkg/proxystatus/routetree.go c4-app-web

RouteTree is the single shared adapter that projects a surface Snapshot's live route-group state into a bilateral tree model (pkg/bitree). BOTH the status.skysocks page (+ interstitial) and `skywire cli proxy tree` render from this one model, so the terminal and the page always show the same shape.

Layout (rendered by bitree, styled by each surface's own StyleCell). The root (source PK) is right-anchored over the spine descender, so ignoring the left summary branches it reads as a normal downward tree with the source PK at top in the same PK column as the hops:

	                                         <this visor / source PK>
	                                         │
	R[0] ● 143ms  1.6K↑ 8.1K/s ███░  1.5K↓ 12K/s ██░░ ┬── <exit PK>  [stcpr]  <tpid>  143ms
	R[1] ● 47ms   0.5K↑ 2.0K/s █░░░  0.4K↓  3K/s █░░░ ┴── <hop1 PK>  [sudph]  <tpid>  47ms
	                                                   └── <exit PK>  [stcpr]  <tpid>  88ms

  - Root = this visor (the source PK, taken from any leg's first hop).
  - Each ACTIVE route is a top-level right child; DEAD legs are pruned.
  - The LEFT block of a route is its per-route summary: R[n], a state glyph
    (● active / ○ standby — the caller colors it, no state words), the
    end-to-end ROUTE rtt, then per direction the cumulative bytes (X↑ / Y↓),
    the live goodput RATE (send-rate / recv-rate) and a SHARE bar — this
    route's fraction of the group's aggregate up / down goodput.
  - The RIGHT branch of a route is its hop chain; each hop node's label is the
    peer PK (never truncated) and its trailing columns are [<tp-type>],
    <tpid>, <transport-rtt> — the per-hop TRANSPORT rtt. For a DIRECT (1-hop)
    leg this equals the left ROUTE rtt (same physical link, same live
    measurement); on a multihop leg the near-edge transport rtt and the
    whole-path route rtt differ.

Index

Constants

View Source
const (
	// GlyphActive marks an alive, in-rotation route.
	GlyphActive = "●"
	// GlyphStandby marks an alive but standby (warm spare) route.
	GlyphStandby = "○"
)

Route-state glyphs, used at BOTH multiplexing levels and colored by each surface's StyleCell by detecting which glyph is present:

  • On a LEG's left annotation the glyph stands alone — that leg's own state within its route group (● striping / ○ parked), no state word.
  • On a STREAM-boundary header the glyph is followed by the TUNNEL's role word (Tunnel.Role: "● active" / "○ standby"), because the tunnel's own state is a DIFFERENT fact from its legs' — a standby tunnel's single leg is leg-active inside its own group, which is why a page that drew only leg glyphs showed every tunnel as active.
View Source
const (
	// RoleActive is a tunnel the picker may put streams on.
	RoleActive = "active"
	// RoleStandby is a tunnel held open, kept alive and measured, carrying
	// nothing, so it can be switched in without a route setup.
	RoleStandby = "standby"
)

Tunnel.Role values, as the dialing app labels a route group (pkg/skysocks TunnelRoleActive / TunnelRoleStandby). An empty or unrecognized role is unlabeled — a single-tunnel session or a route group belonging to something else — and renders with no role word at all.

View Source
const (
	// StreamBandGlyph leads a leg's per-stream accent band ("▏sN"); StreamHeaderGlyph
	// marks a stream-boundary node. Exported so the CLI renderer (a different
	// package) can detect them to style the two layers, as it does GlyphActive.
	StreamBandGlyph   = "▏"
	StreamHeaderGlyph = "▚"
)

The two route-multiplexing LAYERS are made visually distinct in the tree:

  • StreamBandGlyph is the per-STREAM accent band prefixed onto every leg summary ("▏s0"), so a leg reads which stream (route group) it belongs to at a glance; the page colors it per-stream, the terminal shows it monochrome.
  • StreamHeaderGlyph marks a STREAM-boundary node on the spine — a different KIND of node than a leg/hop — so the stream (packet-group) layer reads clearly apart from the leg (packet-striping) layer beneath it.

streamAccentCount is how many distinct per-stream accents the palette cycles before wrapping (stream index N → N % streamAccentCount); the page's CSS defines --stream0…--streamN to match.

View Source
const FragmentPath = "/fragment"

FragmentPath serves the live region alone. A page whose WebSocket never opens — one rendered through netscrape, whose frames carry fetches but not sockets — polls it every pollMs instead, so it still updates.

Variables

This section is empty.

Functions

func Host

func Host(s Surface) string

Host returns the reserved status host for a surface ("status.skysocks"), for links (the interstitial's "view status" affordance) and tests.

func Render

func Render(snap Snapshot) []byte

Render returns the full, self-contained HTML status page for snap. All interpolated values are HTML-escaped; the page loads no external resource (matching the proxies' strict no-network serving context).

For the skysocks surface the live region (pills, per-leg mux, events, log) is wrapped in <main id="live"> and kept current by an inline WebSocket script that swaps just that element on each server push — the server-rendered markup is the initial paint, so the page still works with JS/WebSocket unavailable. Other surfaces have no WebSocket endpoint and fall back to a meta refresh, as before.

func RenderFragment

func RenderFragment(snap Snapshot) []byte

RenderFragment renders ONLY the live region — the inner HTML of <main id="live"> (pills, per-leg mux, events, recent log) — with no <html>/<head>/<style> shell. It is the single source of truth for the live markup: Render composes the page shell around it, and the skysocks-client WebSocket handler pushes it verbatim as one TEXT frame so the browser swaps the region in place (el.innerHTML = frame) without a full-page reload. Newlines in the fragment (the <pre> log block) ride through the TEXT frame as-is, so no escaping is needed.

func RouteGraphJSON

func RouteGraphJSON(snap Snapshot) []byte

RouteGraphJSON builds the route subgraph as the JSON the status page embeds in its <script type="application/json" id="rgdata"> and the cosmos-go driver consumes. Dead legs are pruned (matching the tree). Returns a valid, possibly empty ({"nodes":[],"links":[],"sig":""}) document — never nil — so the driver can always parse it.

func RouteTree

func RouteTree(snap Snapshot) *bitree.Node

RouteTree builds the bilateral route-group model for a Snapshot. Dead legs are pruned; the surviving legs are ordered direct-active first, then active multihop, then standby, matching the page's reading order. The returned root is nil-safe to render (bitree.Render handles a childless root).

The two multiplexing LAYERS stack: STREAM level (--tunnels, disjoint route groups) over PACKET level (the mux legs striping one stream's packets). Every stream gets a stream-boundary header node on the spine followed by its own legs. CRUCIALLY the legs are SIBLING spine routes of the header (top-level), not children nested under it — bitree draws the rich left annotation block (R[n], ●/○ state, route-rtt, per-direction ↑/↓ bandwidth + rate + share bars) ONLY for top-level spine routes, so nesting the legs would drop every leg's summary (the #4313 regression this restores).

With MORE THAN ONE stream each leg summary additionally carries that stream's accent band ("▏sN") so which leg belongs to which stream is legible. With a single stream there is nothing to distinguish, so the legs render UNBANDED — the tree reads essentially like the original flat per-leg tree, plus a thin "stream 0 · N legs" header. The per-leg summaries are always present.

func ServeConn

func ServeConn(body []byte) net.Conn

ServeConn returns one end of an in-memory pipe; the other end is fed body as a single HTTP/1.1 response then closed. Nothing is dialed out — the page exists only as seen THROUGH the proxy. The returned conn is handed to go-socks5, which pipes the browser's request in and the response back. Mirrors dmsgweb's serveHomeInProcess so the two reserved in-process hosts behave identically.

func TreeHeader

func TreeHeader() (left, label string, cols []string)

TreeHeader returns the label-header row fields (left group, peer label, trailing-column labels) for a route tree, shaped so bitree can render them as a template row that lines up with the columns of the tree beneath. Only the page uses it; `proxy tree` renders headerless.

func TunnelStandby

func TunnelStandby(t Tunnel) bool

TunnelStandby reports whether a tunnel is labeled standby — held open but carrying no streams. Exported so the route graph (and any other renderer) rules on the tunnel's own state the same way the tree does.

Types

type Accept

type Accept struct {
	Accepted    uint64  `json:"accepted"`
	NoTunnel    uint64  `json:"no_tunnel,omitempty"`
	OpenFailed  uint64  `json:"open_failed,omitempty"`
	Opened      uint64  `json:"opened,omitempty"`
	MaxOpenMS   float64 `json:"max_open_ms,omitempty"`
	LastOpenErr string  `json:"last_open_err,omitempty"`
}

Accept is the SOCKS accept path's accounting — the stage BEFORE a stream is tracked in Streams. Streams starts at handleStream, so a connection that dies at Accept, at picking a tunnel, or at opening a stream on one leaves no row there at all; these counters are what distinguishes "nothing connected" from "everything that connected died before it could be tracked".

Accepted is every connection the listener handed over. NoTunnel counted no live tunnel to put a stream on, OpenFailed opened one and failed, and Opened got a stream and went on to be tracked in Streams. MaxOpenMS is the slowest single open seen, which says whether opens are slow rather than merely failing.

type Alias

type Alias struct {
	Name string `json:"name"`
	PK   string `json:"pk"`
}

Alias is one configured name→PK binding, e.g. "tpd" → the TPD's public key.

type Conn

type Conn struct {
	ID         string `json:"id"`
	Network    string `json:"network,omitempty"`
	LocalPort  int    `json:"local_port,omitempty"`
	RemotePort int    `json:"remote_port,omitempty"`
}

Conn is one active raw forwarded connection through the surface.

type Consumer added in v1.3.98

type Consumer struct {
	// Name is the app name, or "inbound :<port>" for a route group this visor
	// accepted rather than dialed.
	Name    string
	Inbound bool
	Running bool
	Tunnels []Tunnel
}

Consumer is one user of the route plane on the skywire surface: an app that dialed route groups or direct streams, or the visor answering someone else's dial. Tunnels render with the same route tree as a proxy surface.

type DmsgSession

type DmsgSession struct {
	ServerPK string  `json:"server_pk"`
	Protocol string  `json:"protocol,omitempty"` // carrier label (tcp / quic / ws / wt)
	Addr     string  `json:"addr,omitempty"`     // the carrier address the session rides
	Streams  int     `json:"streams"`
	PingMS   float64 `json:"ping_ms,omitempty"`
}

DmsgSession is one established dmsg client session to a dmsg server. PKs are FULL, never truncated. Streams is the session's live stream count; PingMS is the last measured session RTT (0 when never pinged).

type DomainRoute added in v1.3.98

type DomainRoute struct {
	// Suffix is the domain the rule covers, with its subdomains; "*" for
	// the default.
	Suffix string `json:"suffix"`
	// Upstream is the SOCKS5 address hosts matching Suffix leave through,
	// or "direct".
	Upstream string `json:"upstream"`
	// Via names the local app listening on Upstream and whether it runs,
	// empty when none is known.
	Via string `json:"via,omitempty"`
}

DomainRoute is one per-domain upstream rule of the resolving proxies.

type Forward

type Forward struct {
	Port      int    `json:"port"`
	LocalPort int    `json:"local_port,omitempty"`
	Label     string `json:"label,omitempty"`
	Skynet    bool   `json:"skynet,omitempty"`
	DMSG      bool   `json:"dmsg,omitempty"`
	UDP       bool   `json:"udp,omitempty"`
}

Forward is one port this visor exposes to the mesh. Port is the mesh-side port; LocalPort is the loopback port it forwards to.

type Hop

type Hop struct {
	TpID      string
	From      string
	To        string
	TpType    string
	LatencyMS float64
	// ThroughputBps is the hop transport's passively observed peak goodput in
	// bytes/s (transport.Entry.ThroughputBps), 0 when this visor holds no
	// entry for the transport. It is what lets a route that has never carried
	// a byte be given a capacity PRIOR instead of a guess: the first hop is
	// always owned locally, and a deeper hop reports a number only when the
	// visor happens to hold that transport too. RTT says how LONG a path is;
	// this is the only field that says how WIDE it is.
	ThroughputBps float64 `json:"throughput_bps,omitempty"`
}

Hop is one hop of a leg's forward route. From/To are FULL public keys — the status page never truncates them. LatencyMS is the hop's transport RTT where known (first hop owned; single-intermediate far hop derived).

type Layer

type Layer struct {
	Listen string `json:"listen,omitempty"` // SOCKS5 listener the layer binds, e.g. "127.0.0.1:4445"
	Suffix string `json:"suffix,omitempty"` // domain suffix it resolves, e.g. ".dmsg"
	// Upstream is the DOWNSTREAM chain target: the SOCKS5 a non-matching CONNECT
	// is forwarded to (dmsg_web → skynet_web → skysocks-client). Empty when the
	// layer terminates the chain.
	Upstream string `json:"upstream,omitempty"`
	// UpstreamState is an honest, non-probing label for the chain target's
	// liveness — derived from what the visor already knows about the process or
	// runtime behind that address (e.g. "skynet_web running"). Empty when the
	// address belongs to something the visor cannot vouch for; the page then shows
	// the address alone rather than claiming reachability it did not verify.
	UpstreamState string     `json:"upstream_state,omitempty"`
	StartedAt     *time.Time `json:"started_at,omitempty"`
	UptimeSec     int64      `json:"uptime_sec,omitempty"`
	Requests      uint64     `json:"requests"`
	Successful    uint64     `json:"successful"`
	Failed        uint64     `json:"failed"`
	Active        int64      `json:"active"` // requests in flight right now
	LastRequestAt *time.Time `json:"last_request_at,omitempty"`
	LastError     string     `json:"last_error,omitempty"`
}

Layer is the live state of one resolving-proxy layer (dmsg_web on :4445, skynet_web on :4446). Every field is read from what the layer itself already tracks — its Stats counters (uptime, requests, last error) and its config (listener, suffix, upstream) — so nothing here is estimated.

type Leg

type Leg struct {
	Index       int
	TransportID string
	TpType      string
	RemotePK    string
	// LatencyMS is the first-hop transport RTT; RouteLatencyMS is the leg's
	// true end-to-end route latency (all hops). Direct is true for a 1-hop
	// route to the destination, false for a multihop (relayed) leg.
	LatencyMS      float64
	RouteLatencyMS float64
	Direct         bool
	SentBytes      uint64
	RecvBytes      uint64
	// DupBytes is inbound DUPLICATE data (seqs already delivered/buffered when
	// they arrived on this leg) — the peer's spurious retransmits, which ride
	// the fastest leg and otherwise read as payload; RepairBytes is inbound FEC
	// repair frames. Both decompose RecvBytes so a standby leg showing inbound
	// traffic is explainable from the page.
	DupBytes    uint64
	RepairBytes uint64
	Retransmits uint64
	// GoodputBps is this leg's recent goodput — the EWMA of (sent+recv) bytes
	// per second over the page's refresh window (~1s), i.e. the RATE the leg is
	// moving now, distinct from the cumulative SentBytes/RecvBytes counters. 0
	// until a second sample lands. GoodputUpBps/GoodputDownBps split it by
	// direction (send-rate / recv-rate), shown beside the ↑/↓ byte totals and
	// driving the per-route share bars; GoodputBps is their sum.
	GoodputBps     float64
	GoodputUpBps   float64
	GoodputDownBps float64
	Alive          bool
	Standby        bool
	// Source names where a leg that is not this group's own dial came from:
	// a leg the standby-pool arbiter took ("standby :4, re-homed in place").
	// Empty for an ordinary dialed leg.
	Source string `json:"source,omitempty"`
	// Hops is the leg's full forward route (every hop to the destination),
	// full PKs, per-hop transport type + latency where known.
	Hops []Hop
}

Leg is one route in a surface's mux'd route group, decoupled from visor.MuxLegInfo so this package doesn't import pkg/visor (which would be a cycle — the visor implements Provider). Fields mirror the RouteGroupMuxInfo telemetry the `cli proxy mux plot` renderer consumes.

type Names

type Names struct {
	Kind    string  `json:"kind,omitempty"`
	Suffix  string  `json:"suffix,omitempty"`
	Aliases []Alias `json:"aliases,omitempty"`
}

Names describes a layer's name resolution. Kind names the resolver in use; Aliases are the name→PK bindings the layer was configured with (service aliases, the visor's own alias, dmsg-server aliases) — the only resolution state that is actually stored.

type Provider

type Provider interface {
	StatusSnapshot(surface Surface) (Snapshot, error)
}

Provider yields a live Snapshot for a surface. Implemented by the visor (pkg/visor/embedded_proxystatus.go), injected into the resolving-proxy runtimes' Config. A nil Provider disables the status hosts entirely.

type RangeSplit

type RangeSplit struct {
	Enabled         bool   `json:"enabled"`           // feature is on for this client
	ActiveSplits    int64  `json:"active_splits"`     // splits in flight right now
	TotalSplits     uint64 `json:"total_splits"`      // cumulative splits performed
	TotalChunks     uint64 `json:"total_chunks"`      // cumulative range chunks fetched
	TotalBytes      uint64 `json:"total_bytes"`       // cumulative bytes delivered via split
	StreamsPerSplit int    `json:"streams_per_split"` // configured concurrency (streams per split)
	ChunkSize       int64  `json:"chunk_size"`        // bytes per range request
}

RangeSplit is the live range-split summary for the skysocks surface. It is built from the client's atomic counters (pkg/skysocks rangesplit.go), so it is cheap to read at page/watch cadence. ActiveSplits>0 means a splittable download is aggregating across the mesh's tunnels right now; the cumulative totals show it has fired at all and its shape (chunks × streams).

type Snapshot

type Snapshot struct {
	Surface Surface
	App     string // underlying app/logger name (dmsgweb / skynetweb / skysocks-client)
	// SelfPK is this visor's own public key — the route source. Carried explicitly
	// so the tree/graph can label the source and place each leg's first hop even
	// when the legs have no recorded forward-hop path (the router does not always
	// record it for auto/standby legs); treeSrc falls back to this.
	SelfPK     string
	Running    bool  // whether the surface's process/runtime is currently alive
	MuxEnabled bool  // route group has multiplexing enabled
	Legs       []Leg // current per-leg mux state (empty when no active route group)
	// Tunnels is the STREAM-level view: one entry per active route group (a
	// --tunnels stream), each carrying its own PACKET-level mux Legs. The two
	// levels of route multiplexing are stream (tunnels, disjoint route groups)
	// over packet (mux legs striping within a group). When populated the route
	// tree nests tunnel → legs; when empty the tree falls back to the flat Legs
	// list above (a caller that only projects a single route group). Legs mirrors
	// Tunnels[0].Legs for back-compat.
	Tunnels []Tunnel
	// ShapeTunnels is how many ACTIVE tunnels the session's mux.shape target
	// asks for — the k of "<k>x<n>" — and ShapeSource where that target came
	// from: "mux.shape" for an operator-named shape, "auto" (or empty) for the
	// default. The dialing app FOLLOWS k with its own active set: the router
	// can flip a route group's role, but only the app owns the yamux session
	// that puts streams on one (pkg/skysocks reconcileActiveSet).
	ShapeTunnels int    `json:"shape_tunnels,omitempty"`
	ShapeSource  string `json:"shape_source,omitempty"`
	// DisjointRoutes is how many routes to the exit share no intermediate and
	// no first hop: one per intermediate this visor and the exit both hold a
	// transport to, plus the direct transports. 0 until the router has counted
	// them. An auto-sized standby pool (--standby-pool -1) holds this many
	// tunnels, up to pool.size_cap.
	DisjointRoutes int      `json:"disjoint_routes,omitempty"`
	Logs           []string // recent log lines, oldest first
	Events         []string // route/transport events affecting this surface, oldest first
	Streams        []Stream // per-stream detail for the open session (skysocks tunnel), when tracked
	// Accept is the accept path's accounting, which covers the stage BEFORE a
	// connection becomes a row in Streams. Nil until something has been
	// accepted. See the Accept type.
	Accept *Accept `json:"accept,omitempty"`
	// RangeSplit summarizes transparent HTTP range-splitting activity on the
	// surface (skysocks only): whether a split is firing right now and its
	// cumulative shape. Nil when the surface does not range-split (every
	// non-skysocks surface, or a skysocks client with the feature disabled). It
	// makes "is range-split firing" a readable field rather than a log line.
	RangeSplit *RangeSplit `json:"range_split,omitempty"`
	// Layer is the RESOLVING-PROXY layer summary — liveness/uptime, the listener
	// and domain suffix it answers for, its request counters and the downstream
	// SOCKS5 it chains to. Populated for the dmsg_web / skynet_web surfaces, whose
	// interesting state is the layer itself rather than a route group; nil for a
	// surface with no such layer (skysocks, whose tunnel state is Legs/Streams).
	Layer *Layer `json:"layer,omitempty"`
	// Sessions is the dmsg client's established sessions to dmsg servers — the
	// dmsg surface's answer to "what am I actually connected through". Empty for
	// every other surface (they do not relay over dmsg sessions).
	Sessions []DmsgSession `json:"sessions,omitempty"`
	// Names is the layer's name-resolution state: which resolver answers a
	// <name><suffix> lookup and the aliases actually configured on it. There is no
	// lookup CACHE in either resolving proxy today, so no "recent lookups" list is
	// invented here — only the resolution machinery that exists is surfaced.
	Names *Names `json:"names,omitempty"`
	// Forwards is what this visor exposes to the mesh through the surface's
	// forwarding plane (skynet surface: the registered forwarded ports). Empty
	// when nothing is forwarded, or for a surface with no forwarding plane.
	Forwards []Forward `json:"forwards,omitempty"`
	// Conns is the surface's active raw forwarded connections with their metered
	// port pairs — the conn-level view for layers that have no route-group Legs.
	Conns []Conn `json:"conns,omitempty"`
	// ExitOpenTimeouts counts the skysocks client's exit opens that timed out: a
	// stream on a live tunnel whose exit never answered the SOCKS5 greeting, so
	// the browser was handed nothing. Cumulative for the life of the client, and
	// the one failure mode the page reported neither as a leg nor as a stream.
	// Zero (omitted) for every other surface.
	ExitOpenTimeouts uint64 `json:"exit_open_timeouts,omitempty"`
	// Consumers is the skywire surface's content: one entry per app or visor
	// subsystem holding a route group or a direct stream. Empty for every
	// other surface.
	Consumers []Consumer `json:"consumers,omitempty"`
	// DomainRoutes are the resolvers' per-domain upstream rules, last the
	// default every other host takes. Skywire surface only; empty when no
	// rule is set.
	DomainRoutes []DomainRoute `json:"domain_routes,omitempty"`
	Note         string        // optional human note (e.g. why a section is empty)
}

Snapshot is everything a status page renders for one surface. It is a point-in-time projection; the page meta-refreshes to re-fetch, so a stale Snapshot is self-correcting rather than load-bearing.

Extension seam (route control): a future write-capable status page adds a Controls section here (candidate legs, current scheduler mode, selectable dmsg relays) plus a matching mutating method on Provider. The read-only fields below are already shaped so a control UI can render alongside them without a wire change. Keep additions additive.

type Stream

type Stream struct {
	ID          uint32  // yamux stream id
	Target      string  // the CONNECT target host:port the stream carries (never a PK)
	AgeMS       int64   // how long the stream has been open, milliseconds
	SentBytes   uint64  // cumulative bytes browser→exit (up) on this stream
	RecvBytes   uint64  // cumulative bytes exit→browser (down) on this stream
	SentRateBps float64 // smoothed up rate in bytes/sec (EWMA over the refresh window); 0 until a second sample lands
	RecvRateBps float64 // smoothed down rate in bytes/sec (EWMA over the refresh window)
	// LatencyMS is the ROUTE-GROUP latency of the stream's session to the exit,
	// NOT a per-stream RTT — yamux exposes no per-stream round-trip. It is the
	// representative route latency of the surface's live legs, attached to every
	// stream and LABELED as route-group latency by the renderer rather than faked
	// as a per-stream number. 0 when unmeasured.
	LatencyMS float64
}

Stream is one open tunneled stream on the surface's session to the exit — the per-stream detail behind the "N open stream(s)" count. The skysocks-client tracks these locally: id + CONNECT target + age, plus the stream's own up/down byte counters and a smoothed transfer rate. The counters are metered by the splice loop that carries the stream (a counting wrapper on the yamux conn), so they are true per-stream totals, distinct from the route-group-wide sent/recv totals in the mux section.

type Surface

type Surface string

Surface identifies which proxy a status page describes. The string value is the label in the reserved host (status.<surface>) and the human name shown on the page.

const (
	SurfaceDmsg     Surface = "dmsg"
	SurfaceSkynet   Surface = "skynet"
	SurfaceSkysocks Surface = "skysocks"
	SurfaceSkywire  Surface = "skywire"
)

The surfaces that serve a status page. SurfaceSkywire is not one proxy: it is every app and visor subsystem that holds a route or a direct stream.

func Match

func Match(host string) (Surface, bool)

Match reports whether host is one of the reserved status hosts and, if so, which surface it names. host is the raw request host (an optional :port is tolerated and ignored). Matching is case-insensitive and exact on the two labels — "status.skysocks" matches but "x.status.skysocks" and "status" alone do not, so a status host never shadows a real <vhost>.<pk>.<suffix> lookup.

type Tunnel

type Tunnel struct {
	Index      int    // tunnel index in dial order (0-based)
	ExitPK     string // destination exit PK (full, never truncated); same across tunnels
	MuxEnabled bool   // this tunnel's route group has packet-level mux enabled
	Legs       []Leg  // this tunnel's packet-level mux legs
	// Role is "active" (the tunnel carries streams) or "standby" (it is held
	// open, kept alive and measured, carrying nothing, so it can be switched
	// in without a route setup). Empty when the client did not label it — a
	// single-tunnel session, or a route group belonging to something else.
	// It is the local end's own label; an exit cannot know it.
	Role string
	// LegReserve marks a standby group a leg split handed back to the pool: it
	// can be composed back in as a leg but never becomes a tunnel, because no
	// app session runs over it.
	LegReserve bool
	// LocalPort is the route group's LOCAL port — the one name the app, the
	// visor and the bench's carrier.tsv already share for one tunnel (the
	// same port NoteMuxEvent is addressed by). It is what lets the dialing
	// app match a tunnel in this snapshot to its own session rather than
	// trusting the tunnel order. 0 when the visor could not name it.
	// AuditionMS is how long this tunnel has existed. For a STANDBY tunnel it
	// is its audition age: how long the pool has held it open, pinged and
	// measured it without putting a stream on it.
	AuditionMS float64 `json:"audition_ms,omitempty"`
	LocalPort  uint16  `json:"local_port,omitempty"`
	// RemotePort is the route group's FAR-END port. For a leg reserve it is the
	// one name the reserve has (its local port is shared with the tunnel it was
	// split out of): the app adopts a reserve by it (DialOptions.AdoptReservePort).
	RemotePort uint16 `json:"remote_port,omitempty"`
	// OpenStreams is this tunnel's yamux session's current open-stream count
	// (Session.NumStreams), overlaid by the skysocks-client from its own live
	// session — the visor-built base above has no yamux session to read one
	// from. 0 for a standby tunnel (it carries nothing) and for anything the
	// overlay could not match to a live session (LocalPort unknown/0).
	OpenStreams int `json:"open_streams"`
}

Tunnel is one STREAM-level route group — a single --tunnels stream to the exit, carrying its own PACKET-level mux Legs. With --tunnels N there are N tunnels, each auto-steered onto a disjoint first-hop transport; with a single tunnel there is one entry whose Legs are the mux's packet-striped routes.

Jump to

Keyboard shortcuts

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