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

visor

package
v1.3.101 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: AGPL-3.0 Imports: 192 Imported by: 5

Documentation

Overview

Package visor pkg/visor/api.go c3-vis-core

Package visor pkg/visor/api_all_transports.go c3-vis-core

Reader-side helper for the TPD all-transports CXO snapshot. The publisher lives in pkg/deployment/tpd/api/cxo_all_transports_publisher.go and writes JSON-encoded []*transport.Entry to two paths (transports/all/with-self, transports/all/without-self). This helper Acquires the TabCLITransports tab on the CXOSubscriptionManager, reads the requested path's snapshot, and returns the raw JSON body so FetchCXO can serve it to the CLI unchanged.

"Acquire on each call" is intentional and lightweight — the manager's reference counting plus close-grace amortize repeated CLI invocations within ~10s, and a CLI not running once a minute keeps the cycle from running forever.

Package visor pkg/visor/api_app_settings.go

The visor half of the live app-settings surface: a map of tuning knobs per app, held on the proc manager and PULLED by the app on a tick it already runs (pkg/app/appserver/app_settings.go explains why a pull and not a push).

The knobs themselves are opaque here — name → int64, plus name → string for the list ones, exactly as pkg/skysocks/skysettings encodes them. The visor carries them; the app's own registry owns their meaning, their kinds and their defaults, so a knob can be added to the client without touching this file or the wire.

What the visor DOES own is how long a knob lives. It outlives the app process (the proc manager no longer clears the set on stop) and it outlives the visor: every change is written to visorconfig.V1.AppSettings and restored into the store at boot, the way routing.mux_fec is. An operator who set a value gets to keep it until they reset it.

Package visor pkg/visor/api_apps.go c3-vis-core api_apps.go contains app management API methods.

Package visor pkg/visor/api_ar.go c3-vis-core

Package visor pkg/visor/api_browse.go c3-vis-core virtual browser (the native analog of the wasm-visor's skywireVisor.fetchDmsg / fetchClearnet). The same browse.js engine runs in the native hypervisor UI; instead of the wasm JS hooks it calls these over /api/browse/*.

Package visor pkg/visor/api_browse_client.go c3-vis-browse

Package visor pkg/visor/api_browse_jar.go c3-vis-browse

Package visor pkg/visor/api_browse_stream.go c3-vis-browse

Package visor pkg/visor/api_browse_ws.go c3-vis-browse

Package visor pkg/visor/api_config_fields.go c3-vis-core

Field-level editing of the RUNNING visor's config.

Editing skywire-config.json by hand while a visor runs does not work: the visor holds the config in memory and re-marshals the whole struct over the file on every setter that persists (see Visor.SetIsPublic, persistHypervisors, persistRouterKnobs, the launcher app updates, …). Whatever the operator typed into the file is erased at the next flush. The only durable edit is one the visor itself makes.

SetConfigFields is that edit. It addresses a field by its dotted JSON path, validates the value against the visorconfig.V1 struct, and then either

  • hands it to the live setter registered for that path (liveConfigFields below), so the running subsystem picks it up immediately, or
  • writes it into v.conf and flushes, which takes effect on the next start ("restart-required").

Path resolution is reflection over V1's json tags rather than a hand-written field table: the config grows every release, and a table would be stale the week after it was written. The LIVE half is a table, because "a running subsystem can pick this up" is a property of the code, not of the struct — one place to register a new live setter (see liveConfigFields).

Identity is not editable: sk/pk and every *_sk / *secret_key path is refused outright, matching SetRuntimeConfig. Maps another subsystem owns and rewrites wholesale (app_settings, routing.router_app_settings) are refused too, with a pointer at the command that does own them — persisting a value there would be silently overwritten by the owner's next flush.

Package visor pkg/visor/api_config_mirror.go c3-vis-core

Package visor pkg/visor/api_dmsg.go c3-vis-core api_dmsg.go contains DMSG ping, bandwidth, and HTTP API methods.

Package visor pkg/visor/api_dmsg_diag.go c3-vis-core

Package visor pkg/visor/api_fetch_cxo.go c3-vis-core

FetchCXO routes a (feed, path) pair to the matching lazy-on-demand CXO subscriber and returns the cached payload — or a miss reason the CLI's fetch chain can decide what to do with.

Adding a new feed: register a new (subscriber struct, ensure helper, Fetch helper) under pkg/visor/api_*_subscriber.go using the same lazy-on-demand pattern, then add a case to the switch below. The CLI side learns about it through its URL→feed mapping table; nothing in the RPC/marshal layer needs to change.

Package visor pkg/visor/api_host_stats.go c3-vis-core

HostStats — psutil-style resource snapshot of the host the visor is running on. Backs the hypervisor UI's "Resource Monitor" panel; the data shape is meant to be polled at ~1s and graphed.

Counter-style fields (network bytes, GC count, …) are cumulative since boot or process start; the client diffs across polls to derive a rate. Gauge-style fields (CPU%, mem%, RSS) are absolute.

The first call to cpu.Percent(0, …) returns 0 because there's no previous sample to compare against; that's fine — the second call returns a real value, and 1s polling means the "0 on first reading" only shows up briefly during initial paint.

Package visor pkg/visor/api_hypervisors.go c3-vis-core

Package visor pkg/visor/api_local_transport_stats.go c3-vis-core

Local transport-bandwidth read API. The visor's stats tracker (pkg/visor/stats) already keeps a bbolt-backed rollup of every transport's sent/recv counters and latency stats — current snapshot + per-day daily rollups, retained for a configurable window (default 30d). This file exposes that local data through the Visor RPC surface so the hvui's per-visor Bandwidth tab can render it without round-tripping through TPD.

Mirrors what `GET /stats/transports` and `/stats/transports/history` return on the visor's logserver, but reachable via the same hypervisor proxy chain everything else in the hvui uses.

Package visor pkg/visor/api_local_uptime_stats.go c3-vis-core

Local tier-uptime read API. The visor's stats tracker (pkg/visor/stats) keeps a 288-slot-per-day bitmap per tier (process / dmsg / skynet) reflecting which 5-minute slots the visor was observed online. This file exposes that data through the Visor RPC surface so the hvui's per-visor and network-wide Uptime tabs can render it through the same hypervisor proxy chain everything else in the hvui uses — no per-visor logserver HTTP client.

The wire shape mirrors `GET /stats/uptime` on the visor's logserver (a {tier: {date: 288-ascii}} map): the renderer just reads '.' as online, ' ' as offline.

Package visor pkg/visor/api_mux_controls.go c3-vis-core

The visor side of the DIAL-TIME and PER-LEG routing controls: the dial knob set (`skywire cli route settings dial`), the per-leg send-weight override and forward-only leg pin (`skywire cli proxy mux weights` / `proxy mux add --forward-only`), and the negotiated per-group view (`proxy mux negotiated`).

Everything here is one file — the API method, the RPC server method, the RPC client method and the two non-visor API stubs for each control — because the set is one feature and reading it in one place is worth more than filing each half next to its neighbors of the same kind.

The per-leg controls reach the router through router.MuxLegController, an OPTIONAL capability interface, rather than through the Router interface: a source-only (tinygo) router has no route groups to control, and asserting keeps that build compiling without stubs.

Package visor pkg/visor/api_network.go c3-vis-core api_network.go contains network connection, port forwarding, and module reinitialization API methods.

Package visor pkg/visor/api_network_view.go c3-vis-core

NetworkView — server-side combination of service-discovery, transport-discovery, and uptime-tracker data into a per-PK summary, mirroring the table that `skywire cli sd` prints.

Lives at the hypervisor scope (no per-visor binding) because the data is network-wide. Cached for shortLivedCacheTTL on the visor side to absorb the 30s+ poll the UI does, plus any concurrent CLI hits.

Package visor pkg/visor/api_ping.go c3-vis-core api_ping.go contains ping, bandwidth test, and visor test API methods.

Package visor pkg/visor/api_proxies.go c3-vis-core

Runtime status + live enable/disable for the in-process resolving proxies (dmsgweb, skynetweb). Hypervisor UI reads EmbeddedProxies to render its "browser proxy" widget and calls SetEmbeddedProxyEnabled to toggle resolvers without a visor restart.

Design note: toggling only affects the live runtime. The visor config file is NOT rewritten — a restart reverts to whatever Enable says on disk. That keeps runtime toggling a "session-scoped experiment" rather than a destructive operation, and avoids config-file-locking coordination with the config refresh path.

Package visor pkg/visor/api_proxy_tunnel.go

Per-tunnel teardown: close ONE of an app's tunnels and let the app's own standby pool replace it.

`proxy mux rm` cannot do this. It drops a LEG from a route group and the router refuses to take the last one, which is exactly the case a tunnel is — so a bench that wanted one tunnel gone had to cut the underlying transport on the host and take every other route over it down with it. The measurement it produced was therefore never the measurement it asked for.

The tunnel belongs to the APP, not to the visor: only the app knows which of its yamux sessions that route group carries, and only the app can put the replacement into the active set. So this is an op queued on the app's settings channel (pkg/app/appserver/app_settings.go) rather than a router call — the visor resolves the port to a real route group of that app first, so a typo is an error here and not silence five seconds later.

Package visor pkg/visor/api_routing.go c3-vis-core api_routing.go contains routing rule and route group API methods.

Package visor pkg/visor/api_routing_policies.go c3-vis-core surface for the hypervisor UI's routing-policy panel. Walks the router's installed DialHook (when it's a *policy.Hook) and projects its visor-wide default + per-app overrides into a JSON-friendly shape.

Read-only by design — runtime policy installation lives on the SetAppRoutingPolicy path (separate PR). This file only surfaces what's currently configured.

Package visor pkg/visor/api_runtime_config.go c3-vis-core

Whole-config replacement for the visor's on-disk config file. Companion to GetRuntimeConfig: lets the hvui round-trip the config through an editor pane and write the user-edited JSON back to disk.

Validation chain — failure at any step rejects the write:

  1. Strict JSON decode into a fresh visorconfig.V1 with DisallowUnknownFields(), so typos in field names surface instead of silently dropping data.
  2. SK/PK consistency — when both are present the PK must derive from the SK; when only SK is present the visor identity isn't accidentally rotated by an empty PK.
  3. Non-empty config path on the live visor (refuse on STDIN- sourced or in-memory configs).

We deliberately do NOT attempt a hot-reload: the visor's many subsystems (router, app launcher, dmsg client, etc.) hold references to v.conf at startup, so swapping it in-process would leave them stale. Caller must restart the visor for the change to take effect — the hvui surfaces this in the response.

Package visor pkg/visor/api_services.go c3-vis-core api_services.go contains service discovery, health, and configuration API methods.

Package visor pkg/visor/api_skychat.go c3-vis-core

Skychat support — password management + reverse proxy.

The hypervisor UI surfaces skychat as a first-class tab. The browser doesn't talk to skychat directly; it goes through the hypervisor at /api/visors/<pk>/skychat/* which forwards to the skychat app's local HTTP listener. The proxy attaches a per-startup random "internal token" so authenticated hvui sessions bypass any password the user set on the standalone :8001 surface.

Package visor pkg/visor/api_skyenv.go c3-vis-core

Reading and editing /etc/skywire.conf from the running visor.

skywire.json is a derived file: `skywire autoconfig` regenerates it from skywire.conf on every package install and update, and the browser visor does so on every page load. A setting that lives only in the json — which is where SetConfigFields writes — lasts until that next regen. The .conf file is the layer that survives, and until now the only way to edit it was `skywire autoconfig --<flag>` in a shell on the host.

Edits are addressed by autoconfig flag name and go through the same flag→variable table (autoconfigcmd) and the same writer (skyenvfile.Update) as that command, so a setting changed here is byte-for-byte the setting `skywire autoconfig --<flag>` would have written.

Package visor pkg/visor/api_skynet.go c3-vis-core

Package visor pkg/visor/api_state.go c3-vis-core

Package visor pkg/visor/api_state_diag.go c3-vis-api

The `diag` section of `visor state`: the in-process plumbing — router intake, transport read queue and per-transport handlers/pong health, VStream muxes, dmsg session ping health and relay state, Go runtime — that until now could only be inferred from logs. Every value is a cheap read of live counters; the section is built for the default snapshot.

Package visor pkg/visor/api_state_roles.go c3-vis-api

The `roles` section of `visor state`: what this visor is FOR the rest of the network, as opposed to what it is doing for itself. Three answers an operator used to have to assemble from `mdisc entry`, `ss` on the host and the logs:

  • dmsg SERVER — is one running in-process, under which key, on which address, and is it sharing the visor's transport TCP port (#4785/#4787) or bound to one of its own. An own-key server registers in the SAME discovery entry as the visor's client; a config_path server is the standalone dmsg-server service folded into this process on its OWN key.
  • dmsg RELAY, both directions (#4789/#4790/#4791) — the peers this visor nominated as its relays and which of them it is actually attached to (with the carrier), plus the peers attached TO this visor and the streams it is carrying for them against the configured slot cap.
  • TRANSIT — whether this visor refuses to be an intermediate route hop (routing.no_transit, #4788).

Everything here is a cheap read of live counters and config, so the section is part of the default snapshot and is selectable on its own.

Package visor pkg/visor/api_suspend.go

Package visor pkg/visor/api_tpd_metrics_subscriber.go c3-vis-core

Reader-side helper for TPD's network-wide transport metrics feed. The CXO subscription lives in the unified CXOSubscriptionManager (see cxo_subscription_manager.go); this file is a thin facade that AcquireFor's the relevant tab and serves the cached blob.

TPD publishes one leaf per calendar day at "metrics/day/<YYYY-MM-DD>", so a day window is assembled HERE from the N newest leaves — see the pivot/merge pair in pkg/deployment/tpd/store/cxo_metrics_layout.go. Callers still get the single JSON array of store.TransportMetric they always got.

The reader also still understands the previous layout, one leaf per window at "metrics/days/<n>". TPD and visors update independently from the same develop-latest binary on a ~5 minute timer, so a new visor talking to a not-yet-updated TPD is a real state, and it is one visor-side branch rather than a second set of leaves TPD would have to keep publishing.

Pre-task-#134 this file owned its own standalone Subscriber that bound DmsgTPDMetricsCXOPort directly. That subscriber raced with the unified manager for the same DMSG port, causing one of them to fail with "dmsg listen on port 51: port already occupied". The duplication is gone now — there's a single subscriber per CXO port, owned by the manager.

Package visor pkg/visor/api_tpd_perkey_subscriber.go c3-vis-core

Reader-side helper for TPD's per-key feed (perkey/stats): every visor's transports counted by type. The publisher lives in pkg/deployment/tpd/api/cxo_perkey_publisher.go. Served in the exact shape of GET /all-transports/per-key-stats, so a caller of that endpoint takes the feed in its place without knowing which one answered.

Package visor pkg/visor/api_tpd_stats_subscriber.go c3-vis-core

Reader-side helper for TPD's network-aggregate stats feed. The publisher lives in pkg/deployment/tpd/api/cxo_stats_publisher.go and writes three gzipped leaves:

stats/network   the GET /all-transports/stats shape
stats/versions  the GET /version fleet histogram
stats/daily     the GET /metric daily aggregate (~2.7 KB)

Both carry a completeness stamp (observed_at / complete / confidence / trailing peak) that the reader passes through untouched — deciding whether a partial sample is usable is the consumer's call, not the visor's, and stripping the stamp here would recreate exactly the blind spot skycoin/skywire#4513 describes.

The subscription itself lives in the unified CXOSubscriptionManager; this is a thin facade that AcquireFor's TabNetworkStats and serves the cached blob.

Package visor pkg/visor/api_tpd_uptime_subscriber.go c3-vis-core

Reader-side helper for TPD's network-wide visor-uptime feed. The CXO subscription lives in the unified CXOSubscriptionManager (see cxo_subscription_manager.go); this file is a thin facade that AcquireFor's the relevant tab and serves the cached blob.

Pre-task-#134 this file owned its own standalone Subscriber that bound DmsgTPDUptimeCXOPort directly. That subscriber raced with the unified manager for the same DMSG port, causing one of them to fail with "dmsg listen on port 52: port already occupied". The duplication is gone now — there's a single subscriber per CXO port, owned by the manager.

Package visor pkg/visor/api_tps.go c3-vis-core api_tps.go contains embedded Transport Setup Node (TPS) API methods.

Package visor pkg/visor/api_transport.go c3-vis-core api_transport.go contains transport management API methods.

Package visor pkg/visor/api_visor.go c3-vis-core api_visor.go contains visor lifecycle and status API methods.

Package visor pkg/visor/api_visor_cat.go c3-vis-core

VisorCat bridges a remote dmsg / skynet stream to a 127.0.0.1 loopback TCP listener inside the visor process. The CLI dials that loopback and the visor splices the two halves bidirectionally so stdio on the CLI side flows to/from the remote peer without the bytes ever crossing the local RPC channel.

Two modes:

  • dial: the visor opens the outbound stream and waits for the CLI to dial the returned loopback. Useful for the `cli dmsg cat <pk>:<port>` client.
  • listen: the visor binds a one-shot listener on the requested remote port (dmsg + skynet mirror), accepts the first inbound stream, authorizes the peer PK against the dmsgscp whitelist, and splices it to a loopback the CLI dials. Used by `cli dmsg cat listen <port>`.

Listener concurrency is one-shot by design — accepting a second stream into the same stdout would interleave bytes meaninglessly. A persistent server would need its own protocol; we don't have one.

Package visor pkg/visor/api_visor_scp.go c3-vis-core

VisorSCP performs a dmsgscp-protocol file transfer from inside the visor process. The visor has both transports plumbed (dmsg.Client + appnet SkywireNetworker), where a standalone CLI has only the dmsg path. Routing the SCP through the visor lets callers pick either transport without bolting an appnet shim onto the CLI.

Lives in its own file so the dmsgscp / appnet imports stay scoped to one compilation unit.

Package visor pkg/visor/ar_reach_decl.go c3-vis-core

The visor's reachability declaration: the "reach" leaf of its AR-bind feed, which the address resolver folds into its reach feed (see pkg/deployment/ar/arfeed/reach.go). It states what the visor alone can know: its STUN-measured NAT class, which types it serves inbound, and when it last accepted an inbound transport of each.

It is rebuilt on a timer and Put only when its bytes change. Inbound times are rounded to an hour, so a visor accepting transports all day rewrites the leaf at most hourly; between changes the feed heartbeat carries it unchanged.

Package visor pkg/visor/ar_resolve_cxo.go

Address lookups from the address resolver's bindings feed. The visor holds the feed (about 100 KB for the whole network) and answers stcpr, squicr and swtr lookups from it, in microseconds and with no request to the resolver, where GET /resolve costs an authenticated round trip of about 140 ms (measured in pkg/deployment/ar/arpreview).

A miss of any kind falls through to GET /resolve, which stays the authority. The feed trails the resolver's store by its publish window, so an answer may be an address the peer has just left. A peer and type are therefore answered from the feed at most once per fastResolveRepeatAfter: a second lookup inside that window, which usually follows a failed dial, goes to the resolver.

Package visor pkg/visor/autoconnect.go c3-vis-core

Package visor pkg/visor/autoconnect_reach.go c3-vis-core

Autoconnect picks its peers from the address resolver's reach feed: per peer and per transport type, whether a transport is known to work, should work, is untested, or is known to fail (arfeed.Reach.Verdict). Known failures are never dialed; confirmed peers are dialed first; untested ones — visors too old to state anything, bindings not yet probed — get a few dials per cycle so they are not starved, but no more.

Package visor pkg/visor/autotp_cooldown.go

Package visor pkg/visor/browseorigins.go Untagged, dependency-free string work, so the rule it encodes is covered by a test that runs in CI: which app origins a browse origin will accept content from. Getting it wrong does not fail loudly — the browse frame just waits on its interstitial until the handshake times out.

Package visor pkg/visor/conf_cxo.go c3-vis-core

The visor's subscription to the conf service's services feed (published by pkg/deployment/conf/api/cxo_publisher.go on DmsgConfCXOPort). The feed is the deployment's current services config, signed by the conf service's key; when it changes, the new config is applied the same way the hourly dmsg-HTTP refresh applies it (applyDeploymentServices), so the deployment can change its service keys without a release.

The subscription is held, not cycled: the document changes rarely, and the publisher's heartbeat (every 45s) keeps the one connection warm, so a change arrives within the publisher's interval at the cost of no new handshakes. The subscriber's own watchdog re-dials if that heartbeat stops. Until the first connect succeeds, startConfCXOSubscriber retries with backoff; the watchdog only takes over after one.

Package visor pkg/visor/config_refresh.go c3-vis-core

Package visor pkg/visor/csrf.go c3-vis-core

Package visor pkg/visor/cxo_feed_allowlist.go c3-vis-core

Subscriber-allowlist gating for the visor's service-consumed CXO feeds (telemetry stats, tp-list, dmsg-discovery registration). These feeds were historically PUBLIC — a nil SubscriberAllowlist accepts any subscriber, so any peer could subscribe and read the visor's full transport set, undermining the transport-setup-node-mediated access model. This module composes each feed's allowlist and keeps it in sync with the live peer whitelist.

The composed set for a feed is:

v.peerWhitelist  (configured Hypervisors + Pty.Whitelist + own PK)
  ∪ {that feed's consuming-service PK}  (TPD for stats/tp-list,
                                          dmsg-discovery for registration)

The consuming-service PK MUST be present or gating breaks that service: the OnSubscribeRemote hook fires even for the consumer over the visor-initiated announce conn (the check keys off c.PeerID()).

Guard: if BOTH the peer whitelist is empty AND the consumer PK is unknown, the feed is left OPEN (nil allowlist) rather than gated to an empty set that would lock everyone out. When the consumer PK IS known it is always included, even when the peer whitelist is otherwise empty.

Package visor pkg/visor/cxo_subscription_manager.go c3-vis-core

Thin visor-side shim over the reusable pkg/cxo/cxosub cycle-based CXO sync manager. The implementation lives in cxosub, decoupled from *Visor via cxosub.Deps; this file only:

  • re-exports the cxosub types/consts under their historical visor names (CXOFeed, CXOTab, CXOSubscriptionManager, the FeedXxx/TabXxx consts, FeedStatus) so existing callers compile unchanged, and
  • supplies the visor's dependency wiring: the live dmsg client accessor and the feed → (peerPK, port, prefix) resolver that reads service publisher PKs out of the visor config.

The manager's cycle semantics are documented in the cxosub package.

Package visor pkg/visor/cxo_transport_discovery.go c3-vis-core

CXO-aware wrapper around the visor's transport.DiscoveryClient. The only override is GetAllTransports — the network-wide snapshot used by calculateLocalRoutes, autoconnect, the hypervisor's calc tools, and a few RPC paths. Every other DiscoveryClient call (per-edge lookups, registrations, deletes) keeps going to HTTP because the CXO publisher doesn't carry that fan-out and a stale single-edge answer can produce route-setup failures that don't self-correct.

The CXO snapshot is refreshed on the manager's 5min cycle while the feed is held; for read-heavy paths (mux-bw probes, hvui Transports tab, route calc on every Dial) that's tighter than the per-call HTTP fetch was. AcquireFor on each call keeps the cycle alive across bursts via cxoTabCloseGrace.

Package visor pkg/visor/cxo_user_feeds.go c3-vis-core

CXO user-feed registry. Each visor publishes one always-on system feed (the telemetry feed wired up by initStats on skyenv.DmsgCXOPort) and any number of user feeds — distinct CXO TreeStore publishers running on distinct DMSG ports under the visor's PK. Subscribers discover them via the dmsghttp logserver's /feeds endpoint, then connect their CXO subscriber to (visor PK, feed.DmsgPort) directly.

The system feed is reserved at skyenv.DmsgCXOPort. User feeds must pick a different port; collisions with system DMSG ports listed in pkg/skyenv (hypervisor=46, transport-setup=47, http=80, dht=100, etc.) are rejected at registration so a user feed can't shadow a reserved listener.

Package visor pkg/visor/dmsg_lookup_cxo.go c3-vis-core

dmsg-entry LOOKUP over CXO — the consumer/resolver shim that lets a visor's dmsg client resolve a peer's discovery entry from the local CXO clients-by-server snapshot instead of a fresh HTTP-over-dmsg Noise handshake to dmsg-discovery (profiled 76% CPU in handshake crypto). The publish side is dmsg-discovery's ClientsByServerCXOPublisher (DmsgDMSGDClientsByServerCXOPort, 54), which mirrors every client's signed dmsgdisc.Entry into a TreeStore feed under clients-by-server/<server>/<client>/entry. The visor already ingests that feed for the hypervisor's network visualizer; this reuses the same cxosub-managed snapshot as a resolution path.

Wiring: init_dmsg installs the resolver returned here into the dmsg client's discovery client (disc.NewCXOEntryClient), where it fronts the existing HTTP/direct chain for Entry() only. On a hit the peer entry is served with no network round-trip; on ANY miss the wrapped client resolves it over HTTP — "not in my CXO tree" is never "doesn't exist" (see the deployment-services-over-CXO roadmap's back-compat rules).

Provenance: the snapshot comes from exactly one authoritative publisher — the configured dmsg-discovery PK (cxoFeedSpec resolves FeedDMSGDClientsByServer to dmsgdCXOPeer). There is no per-record reporter to police here: dmsg-discovery is the single signer of every entry in the feed, so the feed-PK gate already enforces provenance. The snapshot's own bodies are dmsg-disc-signed dmsgdisc.Entry values.

Lifecycle: cxosub runs the feed as a periodic subscribe → snapshot → unsubscribe cycle (no long-lived subscription), so the orphan- feed reclaim the roadmap calls for is handled by the manager — the visor holds no unbounded CXDS here.

SecKey binding: the cxosub manager subscribes over the visor's single dmsg client (v.dmsgC, keyed to the visor SecKey); there is no second dmsg client and no zero/random keypair (see feedback_never_two_dmsg_clients_same_key).

Package visor pkg/visor/dmsg_over_skynet.go c3-vis-core

"dmsg over skynet transports": serve a .dmsg fetch by reaching the peer's :80 over a skynet transport via the VStreamMux relay (direct → 1-hop relay, route ID 0, PK-addressed, NO route-finder), with dmsg-servers as the only fallback. dmsg is a relay layer — this path never uses a route.

Package visor pkg/visor/dmsg_rpc_transport_oracle.go c3-vis-core

A destination-transport oracle that sources a peer's OWN transports over the always-on visor RPC (skyenv.DmsgVisorRPCPort), plus a composite that layers the general RSN-signed oracle over it. Feeds the RSN-oracle 2-hop route computation (pkg/router/rsn_oracle_routes.go) so the adaptive mux can find disjoint intermediates WITHOUT depending on TPD's (chronically under-filled) view of a busy exit's transports.

Package visor pkg/visor/dmsg_servers_cache.go c3-vis-core

DmsgServersCache persists dmsg-server discovery entries (the "static" PK plus the live `server.address` and metadata) to a JSON file in the visor's local_path. Its purpose is to remember the addresses learned from dmsg-discovery across visor restarts so the bootstrap direct client doesn't have to start from the addresses frozen into skywire.json (which can be months stale).

Read order at startup:

  1. cache file (`<local_path>/dmsg_servers.json`)
  2. main config (`v.conf.Dmsg.Servers` — typically /opt/skywire/skywire.json)

The two are merged: for any PK present in the cache, the cached entry wins; PKs only in the config are kept; PKs only in the cache are also included. This way a server that has rotated its address is reached via the new address without losing PKs the cache hasn't seen yet.

Write trigger: a background loop in initDmsg refreshes the cache from dmsg-discovery once dmsgC is connected, then on a fixed interval. If dmsgd is unreachable, the previous cache contents are kept (no destructive write on transient errors).

Package visor pkg/visor/dmsg_servers_cxo.go

The registered dmsg servers from dmsg discovery's clients-by-server feed, which the visor already holds for its entry lookups. The server cache refreshes from this snapshot and asks dmsg discovery over HTTP only when the feed carries no servers, as a publisher older than the server leaves does.

Package visor pkg/visor/dual_listen.go c3-vis-core

Parity helpers: every port the visor binds on dmsg is also bound on the skywire router (appnet.TypeSkynet) at the same port number. The dmsg listener provides the bootstrap path (works before the router has any transports up); the skynet mirror provides the steady-state path that flows over arbitrary transports (dmsg / stcpr / sudph / etc.) negotiated by the router.

Usage shape across the visor:

dmsgLis, err := v.dmsgC.Listen(port)
if err != nil { return err }
// ... start the dmsg accept loop / server / ServeListener ...
goServeSkynetMirror(ctx, v.conf.PK, port, "label", log,
    func(skyLis net.Listener) {
        // run the same accept logic / server.Serve() on skyLis
    })

Bootstrap order: the skynet networker (appnet.TypeSkynet) is registered during initRouter, which may run *after* this helper is invoked from earlier init steps. The mirror goroutine polls for the networker to register, with exponential backoff capped at 5s, then binds the listener and runs serve. If the context is canceled before the networker shows up, the goroutine exits without binding.

Address-type agnosticism: existing dmsg handlers commonly cast conn.RemoteAddr() to dmsg.Addr to extract the peer PK. Mirrors must use remotePK() instead, which handles both dmsg.Addr and appnet.Addr shapes.

Package visor pkg/visor/embedded_dmsgweb.go c3-vis-core

EmbeddedDmsgWeb is the in-process version of the `skywire dmsg web` utility. It runs a localhost SOCKS5 proxy + HTTP bridge that resolves `.dmsg` (or a configured domain suffix) hostnames by tunneling requests through the visor's own dmsg client.

Why in-process rather than a separate app: running standalone requires spinning up a second dmsg identity with its own sessions, doubling server load for the same PK's worth of connectivity. By sharing the visor's client the resolver piggybacks on sessions that already exist for routing / health / transport probes. This mirrors the setup-node sharing pattern (see embedded_route_setup.go).

Runtime supervision (Start/Stop) is local to this type so the RPC layer can flip resolvers on and off without restarting the visor. Stats live on the struct (not inside pkg/dmsgweb) so counters survive Start→Stop→Start cycles.

Package visor pkg/visor/embedded_proxystatus.go c3-vis-core

visorStatusProvider implements pkg/proxystatus.Provider on top of the visor's existing read APIs, so the resolving proxies (dmsg_web / skynet_web) can serve each surface's reserved in-process status host (http://status.<surface>/).

It is deliberately READ-ONLY and reuses APIs that already exist:

  • logs: Visor.LogsSince(app) — the app's bbolt log store tail
  • mux: Visor.RouteGroupMuxInfo(app) — the same per-leg telemetry the `cli proxy mux plot` renderer consumes
  • running: procManager.ProcByName(app)

Route CONTROL is intentionally out of scope for the MVP; the extension seam lives in pkg/proxystatus (Snapshot doc + the disabled control section). When it lands, a mutating method is added to proxystatus.Provider and implemented here on top of the visor's existing mux-reshape API (AddMuxRoute / RemoveMuxRoute / SetMuxMode), which already exists — no new plumbing.

Package visor pkg/visor/embedded_proxystatus_skywire.go c3-vis-core

The skywire status surface: every app and visor subsystem that holds a route group or a direct stream, each drawn with the same tunnel model as the proxy surfaces.

Package visor pkg/visor/embedded_resolver_local.go c3-vis-core

Publishing a resolving proxy as a LOCAL SERVICE: an app on this visor dials the visor's own PK on the resolver's port and is served in-process over net.Pipe, with no second SOCKS hop on 127.0.0.1 and no port to configure on both sides. See pkg/app/appnet/local_service.go for the table itself.

The port is the resolver's own SOCKS5 port (4445, 4446, …), read as a routing port. Routing ports are a separate space from TCP ports, so there is no collision, and an app that knows which resolver it wants already knows the number. Two resolvers cannot share one, because ValidateResolvers already refuses a duplicate listener port.

A local service is NOT in pkg/visor's ServiceRegistry, which is what handleServerConn dispatches incoming PEER connections from. That distinction is the whole point: a resolver answers for this visor's alias table, mints leaves from its MITM CA and leaves through its exit, so only this visor's own apps may reach it.

Package visor pkg/visor/embedded_resolver_tls.go c3-vis-core

Helpers shared by EmbeddedDmsgWeb and EmbeddedSkynetWeb to wire optional TLS MITM mode onto their underlying runtime configs.

Trust model and threat analysis live in pkg/skynetca; the helpers here only handle the visor-side bookkeeping: load the CA from the configured paths, build a LeafMinter, mutate the runtime config. All errors are non-fatal — when CA load fails the resolver continues to run in non-MITM mode and the caller logs the reason.

Package visor pkg/visor/embedded_resolvers.go c3-vis-core

initEmbeddedResolvers brings up the ADDITIONAL resolving proxies declared by the `resolvers` config list — the ones beyond the dmsg_web / skynet_web primaries that embedded_dmsgweb.go and embedded_skynetweb.go own.

There is no new runtime here. Each entry is projected onto the same DmsgWebConfig / SkynetWebConfig the primaries use and handed to the same EmbeddedDmsgWeb / EmbeddedSkynetWeb type, so an extra resolver is not a second implementation that can drift from the first — it is another instance of the one that already works, with a different listener and, for a dmsg resolver, optionally a different identity.

What IS new is the failure this file has to avoid. The primaries could not collide with each other (4445 vs 4446, fixed), so nothing ever checked. With N resolvers the operator picks the ports, and two SOCKS5 listeners on one port do not both fail loudly: the first binds, the second's Run loop returns "address already in use" into a log line, and the app row still says running. So the port map is validated before anything is constructed, and a resolver that loses a conflict is not constructed at all — with an ERROR naming both claimants.

Package visor pkg/visor/embedded_route_setup.go c3-vis-core

Package visor pkg/visor/embedded_services_cxo.go c3-vis-core

The visor as CXO host for the services it embeds. Visors publish their registration and telemetry feeds on fixed DMSG ports and a service aggregates each feed on the same port, dialing visors back there. A visor that embeds the service holds both ends under one key, and a port takes one listener, so the service's aggregator runs on the visor's own publisher node for that port. The visor's own feed on that node never arrives from a peer, so each Root it publishes is handed to the aggregator in-process.

Package visor pkg/visor/embedded_skymail_bridge.go c3-vis-core

EmbeddedSkymailBridge wraps the pkg/skymailbridge SMTP server so it can be hosted directly inside the visor process — the SMTP-side analog of EmbeddedDmsgWeb / EmbeddedSkynetWeb. The bridge accepts inbound SMTP from a co-located Postfix's transport_map, parses the recipient envelope, and dials peers over the visor's existing dmsg client. No separate app, no second dmsg identity.

Lifecycle mirrors the resolvers exactly: idempotent Start/Stop, running flag, runtime toggle via RPC (SetEmbeddedProxyEnabled("bridge", …)). Standalone deployments (hosts without a full visor) should use cmd/smb instead.

Package visor pkg/visor/embedded_skynetweb.go c3-vis-core

EmbeddedSkynetWeb hosts the `.skynet` resolving proxy inside the visor. Mirrors EmbeddedDmsgWeb's lifecycle (Start/Stop + Stats) but speaks the skynet protocol (route + handshake) instead of DMSG.

Skynet dialing requires establishing a route group — a router-internal operation. This file defines the adapter (routerSkynetDialer) that implements pkg/skynetweb.SkynetDialer on top of router.Router.

Package visor pkg/visor/embedded_tps.go c3-vis-core

Package visor pkg/visor/embedded_wisp.go c3-vis-core

EmbeddedWisp is the in-process Wisp server: the same protocol `skywire cli wisp serve` speaks, bound to the page's virtual loopback instead of an HTTP port.

Why in-process and why vnet. A browser-side Linux guest gets its network by asking a Wisp backend to open connections by name, and the backends such a page normally uses are one central WebSocket somewhere. A visor running in the same tab can be that backend instead, which puts the guest's traffic on a route to a skywire exit. Two things force the shape:

  • websocket.Accept is //go:build !js, so a WebSocket server cannot exist in a tab at all;
  • a service worker cannot intercept ws:// or wss://, so a page-served WebSocket endpoint could not be reached even if one existed.

So the session is framed over a plain conn (wisp.Server.ServeConn) and carried on a vnet port, which page JS reaches with vnet.dial(port). Only a browser-tab visor runs it (initEmbeddedWisp). Natively bottle's vnet is net, which is how the tests bind ordinary loopback and reach it with `wisp.DialConn`.

Egress is the visor's own skysocks-client. Reaching it needs bottle's vnet as the forward dialer: in a tab the proxy's port lives in the page's port table, which net.Dial knows nothing about.

Package visor pkg/visor/execwasm_serve.go c3-vis-api

Package visor pkg/visor/fetchdest.go c3-vis-core

Package visor pkg/visor/flightrec.go c3-vis-core

Package visor pkg/visor/forward_proxy.go c3-vis-core

Package visor pkg/visor/forwarded_ports.go c3-vis-core

ForwardedPorts manages the set of ports that are accessible over skynet and/or DMSG, with per-port metadata (label, description, visibility on the landing page, PK whitelist).

Package visor pkg/visor/gctune_native.go c3-vis-core

Package visor pkg/visor/geo_summary.go c3-vis-core

Package visor pkg/visor/group.go c3-vis-core

Visor-level wrapper around the cmd/apps/skychat/group package. Mirrors pkg/visor/pairing.go in shape: owns one group.Manager (initialized in init_group.go) plus an in-memory ring of recently received messages. RPC clients call GroupCreate / GroupJoin / GroupList / GroupSend / GroupPoll / GroupDelete / GroupLeave; the poll model is the same as PairPoll, so apps that already drain a pair-poll loop can layer on a group-poll loop with the same shape.

Scope (v1, D1 owner-centric):

  • Owners can create groups, invite via link, broadcast messages.
  • Members can join via invite, read messages, leave.
  • Member-side "send" is NOT in v1. Members read only; the owner drives the conversation. Phase-2 (project memo group-chat plan) adds member-side relay via the existing pair-message wire with a group_id tag.

Package visor pkg/visor/gui.go c3-vis-core

Package visor pkg/visor/gui_linux.go c3-vis-core

Package visor pkg/visor/gui_unix.go c3-vis-core

Package visor pkg/visor/helpers.go c3-vis-core Common helper functions to reduce code duplication across the visor package.

Package visor pkg/visor/hostbridge.go c3-vis-wasm

Package visor pkg/visor/hostbridge_dial.go c3-vis-wasm

Package visor pkg/visor/hostbridge_probe_other.go c3-vis-wasm

Package visor pkg/visor/hostbridge_sockets.go c3-vis-wasm

Package visor pkg/visor/hypervisor.go c3-vis-core

Package visor pkg/visor/hypervisor_attached_graph.go c3-vis-api

The hypervisor's attached visors report their transports in the Summary it polls every hypervisorBackgroundPollInterval. AttachedTransportEntries turns that cache into transport entries, so route calculation on the hypervisor's own visor can use those edges without a TPD or route-finder query (#4750).

Package visor pkg/visor/hypervisor_dmsg_ingest.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_admin.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_apps.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_browse.go c3-vis-core The native hypervisor's web surfaces: the Angular dashboard (index.html with its version stamp) and the desk on its own listener, whose browser reaches the mesh and the clearnet through /api/browse* on this visor.

Package visor pkg/visor/hypervisor_handlers_clientlog.go c3-vis-core browser-side error reports from the hypervisor UI.

The hvui installs a global error reporter (a window.onerror / unhandledrejection hook + an Angular ErrorHandler + a console.error/ warn wrapper) that POSTs each client-side error here. The handler writes them to the visor log under the "hvui_client" logger, so an operator debugging a broken UI page (a dead tab, a failed XHR, a thrown change-detection error) can read the browser's errors right in `./local/log/skywire.log` instead of copy-pasting the dev-tools console.

It's intentionally unauthenticated — a broken page (or one that crashes before login) must still be able to report — so it is hardened against abuse of an open log sink: the request body is size-capped, reports are rate-limited, and every field is sanitized (control chars stripped) to prevent log-injection of forged lines.

Package visor pkg/visor/hypervisor_handlers_ctx.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_disc_proxy.go c3-vis-core

Hypervisor-hosted dmsg-discovery proxy.

Visors configured with the hypervisor's HTTP address as their dmsg discovery URL hit these routes. For Entry GETs we check the embedded dmsg server's active client sessions first and synthesize a minimal entry (`DelegatedServers: [H]`) when the requested PK is locally connected; that lets sibling visors dial each other through the hypervisor's relay even when public dmsg-discovery is unreachable. Anything else falls through to the upstream public discovery via a reverse proxy — POSTs (entry registration) included, so non-sibling peers continue to find these visors via the canonical discovery.

`/dmsg-discovery/local/...` mirrors the local-only view for operator inspection (UI / CLI), without the upstream fall-through.

Package visor pkg/visor/hypervisor_handlers_dmsg.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_group.go c3-vis-core

Hypervisor HTTP routes for skychat GROUP chat — the native-visor counterpart to the wasm visor's skychatGroup* JS hooks. These thin handlers bridge the hvui's group panel to the local visor's group RPC surface (ctx.API.Group*), so the same Angular UI drives group chat on a native visor (over HTTP here) and on a wasm visor (over the in-process JS hooks) with no divergence.

Scope: the LOCAL visor only (hv.visorCtx), matching the skychat password + proxy handlers. The group manager runs in the visor process (init_group.go); ctx.API resolves to it. Remote managed visors are out of scope here (a follow-up, same as skychatProxy).

Package visor pkg/visor/hypervisor_handlers_health.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_log.go c3-vis-core Events stream of the local visor's live log, so the HV-UI log window can show the NATIVE visor's server-side log (the wasm visor logs to the browser console and is captured there directly; the native visor's log lives server-side).

Package visor pkg/visor/hypervisor_handlers_mail.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_misc.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_notify.go c3-vis-core

The host-app sink of the notification hub (tier (b), see notifyhub.go): an SSE stream of the notifications apps publish, for a host application that can surface them natively — the Android foreground service posting through per-app notification channels, and later the manager UI's notification bell.

Live-only, no replay: a subscriber sees what arrives while it is connected and nothing else. A reconnecting phone getting a burst of stale "you had a message" toasts is worse than missing them, and the hub's whole contract is best-effort delivery to whoever is listening now.

While at least one subscriber is connected the hub stops posting to the host OS, so a desktop running the Android-style host app doesn't double up. That is derived per publish from the live subscriber set — never cached — so a dropped connection restores the desktop path immediately.

Package visor pkg/visor/hypervisor_handlers_pair.go c3-vis-api

Pre-auth pairing endpoints (#4484 stage 5). A desk tab this hypervisor serves has no session yet; it learns its own standing from GET /pair/status and, as the fallback to `skywire cli visor hv pair`, redeems a one-time code the operator made on the board with POST /pair. Both sit beside /tp/ws, outside the session-auth group; the code is the credential, single-use and revoked after a few wrong attempts.

Package visor pkg/visor/hypervisor_handlers_proxies.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_reachability.go c3-vis-core

HTTP handlers for the per-visor Reachability tab: skywire-route ping (DialPing + Ping + StopPing), dmsg ping (DialDmsgPing + DmsgPing + StopDmsgPing), and a remote /health fetch over dmsg. All three wrap RPC methods that already exist on Visor; this file just exposes them to the UI's HTTP API.

Package visor pkg/visor/hypervisor_handlers_router.go c3-vis-core

Hypervisor HTTP handlers for the unified visor-wide router-knobs resource at GET/PUT /visors/{pk}/router-settings. Backs the hypervisor UI's "Router Settings" panel which gives operators the same knobs the CLI exposes via 'cli proxy start --xxx' (force_local_routes, existing_tp_only, mux_routes, min_hops).

Package visor pkg/visor/hypervisor_handlers_routes.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_routing_tools.go c3-vis-core

HTTP handlers powering the Routing tab's Find + Calculate forms. route-find queries the route-finder service via the visor's configured rfClient. route-calc enumerates routes locally using the same graph machinery the gRPC StreamCalcRoutes uses, but in a bounded-count one-shot form so it fits a JSON HTTP response.

Package visor pkg/visor/hypervisor_handlers_rsn.go c3-vis-core

Per-RSN remote stats fetch for the hvui's Services Health page. Mirrors `skywire-cli route rsn-remote-stats` — for every RSN PK in EffectiveRouteSetupNodes the local visor's DmsgHTTP RPC is used to GET dmsg://<pk>:80/stats, the response is parsed back into a StatsSnapshot and the array is returned to the UI.

Package visor pkg/visor/hypervisor_handlers_skychat.go c3-vis-core

Hypervisor HTTP routes for skychat: password get/set/clear and a reverse proxy to the local skychat HTTP server. The proxy is what backs the hvui's "Chat" tab — the browser talks to the hypervisor (already authenticated), the hypervisor adds the internal-token header and forwards to localhost:<skychat-port>.

Package visor pkg/visor/hypervisor_handlers_skyenv.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_skynet.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_tpd.go c3-vis-core

Network-wide transport metrics proxy for the hvui's Transports home tab. Three fetch strategies are tried in order:

  1. CXO subscriber (instant when fresh) — the visor maintains a long-lived TreeStore subscriber to TPD's metrics-aggregate publisher (see api_tpd_metrics_subscriber.go). When the publisher has pushed a Root for the requested day window the subscriber's local cache returns it immediately, no DMSG round-trip per hvui open.
  2. DMSG-HTTP — bypass the CXO path and ask TPD for /metrics over dmsghttp through the visor's existing DmsgHTTP RPC.
  3. Plain HTTP fallback — last resort when DMSG isn't ready / TPD doesn't publish a DMSG address.

The first strategy that returns 2xx wins; later strategies aren't tried unless the earlier one explicitly missed.

Package visor pkg/visor/hypervisor_handlers_tpd_reduce.go c3-vis-core

Folding TPD's /metrics payload down to what the hvui Transports tab can actually render.

TPD returns one record per transport for the whole mesh, with a daily bandwidth array per record. On the production deployment that is upwards of 180,000 records and over 60 MB of JSON — measured 2026-09-28, and still growing. Proxying it verbatim broke in three places at once:

  • the upstream body was cut off mid-record at ~30s, so the client received HTTP 200 and unparseable JSON;
  • 60 MB exceeded the hypervisor's own 10s WriteTimeout, so the browser got ERR_EMPTY_RESPONSE and the page never loaded at all;
  • and had it arrived, the Angular table renders every row it is given, which wedged the browser's main thread for minutes.

The client only ever displayed a fold of each record — two bandwidth totals from the daily array — sorted by bandwidth, so that fold happens here now. The response carries the full total alongside the capped rows, so the UI can say what it is not showing rather than quietly lying about the size of the mesh.

Package visor pkg/visor/hypervisor_handlers_transports.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_visors.go c3-vis-core

Package visor pkg/visor/hypervisor_handlers_voice.go c3-vis-core

Hypervisor HTTP routes for skychat VOICE calls — the native-visor counterpart to the wasm visor's skychatVoice* JS hooks. These thin handlers bridge the hvui skychat panel to the local visor's voice surface (ctx.API.Voice*), so the SAME Angular UI drives voice on a native visor (over HTTP here) and on a wasm visor (over the in-process JS hooks) with no divergence — mirroring the group + proxy handlers.

Scope: the LOCAL visor only (hv.visorCtx), matching the skychat password + proxy + group handlers. Voice is disabled (ctx.API returns ErrVoiceDisabled) unless the visor was built/started with voice; that surfaces here as 503 so the UI can hide the controls.

Package visor pkg/visor/hypervisor_handlers_voice_audio.go c3-vis-core

The two routes that carry a call's AUDIO between the visor and the app that started it, for a visor whose audio device belongs to that app rather than to itself — Android, where nothing else can work (see pkg/skychat/call/bridge.go and voiceAudioMode in init_voice.go).

POST /skychat/voice/mic      the app's microphone, streamed in
GET  /skychat/voice/speaker  what the calls want played, streamed out

Both carry RAW little-endian int16 PCM, mono, at call.SampleRate — no framing, no JSON, no base64. A voice stream is a continuous 96 KB/s in each direction and every wrapper here would be paid 50 times a second for nothing; the format is fixed on both sides at compile time, so there is nothing to negotiate. The one real cost of that choice is that a wrong sample rate is silent corruption rather than an error, which is why the constant is exported for the app to build its capture and playback from.

**Long-lived, and deliberately so.** A call is minutes; a request per frame would be 50 round trips a second in each direction. Each stream instead re-arms its own deadline as it goes, exactly as the notification SSE stream does — the server's 5 s read / 10 s write timeouts are single deadlines for a whole request, and clearing them outright would leave a wedged peer parked in a syscall forever holding the device.

LOCAL visor only. The bridge is this process's audio device; proxying it to a remote visor would mean shipping someone else's microphone across the mesh through the operator's browser, which is not a thing this route offers.

Package visor pkg/visor/hypervisor_handlers_wallet.go c3-vis-core wallet ("wallet HV-served" mode, docs/design/gui-app-serving-modes.md).

The wallet is the dashboard's #/wallet page: skycoin-web's wallet module compiled into the dashboard, its crypto client-side in skycoin's TinyGo cipher, its wallets in browser storage. The hypervisor serves that cipher and proxies the wallet's node API (wallet/coins, wallet/coin/<index>/…) to the configured backend over the visor's dmsg client: NO skycoin-web process, NO listening port. The same handlers run in the tab's wasm hypervisor, so native == wasm.

When the skycoin-web app runs in this process, wallet/coins and wallet/coin/<index>/… go to it instead, so the same page uses its node settings and its server-side wallet files.

Package visor pkg/visor/hypervisor_hostbridge.go c3-vis-wasm

Package visor pkg/visor/hypervisor_tpviz.go c3-vis-core

Package visor pkg/visor/hypervisor_ws.go c3-vis-core

/ws — the hypervisor API as a message transport.

The Angular UI already routes /api through one seam (SkywireHttpBackend, "the bottom of the Angular HttpClient pipeline"), which today has four backends: same-origin XHR for a visor-served build, a function call into an in-tab wasm visor, a dmsg call for the standalone hypervisor, and dmsg frames to a remote PK. Three of those are message-oriented; the native one is the odd one out, and that asymmetry is what stops the two UI variants converging on a single transport.

This endpoint closes that gap WITHOUT a second API. A frame names a method, a path and a body; the handler replays it through the hypervisor's OWN router, so every route, middleware, permission check and response is byte-identical to the HTTP call it stands in for. There is exactly one implementation of the API — this is a transport, not a parallel surface.

It is deliberately mounted OUTSIDE the /api group: that group's 30s Timeout would kill a long-lived socket. /pty sits outside for the same reason and opts into auth explicitly; this follows it.

Wire format is JSON text frames. `type` is carried from the first version so server-push ("type":"event") can be added later without breaking the request/response contract.

client → server  {"type":"req","id":7,"method":"GET","path":"/api/about","body":null,"headers":{}}
server → client  {"type":"res","id":7,"status":200,"body":"{...}","headers":{"Content-Type":"application/json"}}

Bodies are strings, not base64: the hypervisor API is JSON in and JSON out, and the UI's gateway contract already decodes a text body.

wsReadLimit bounds what a client may SEND; responses are not capped, and some are large — /api/visors-tree-summary is 8.6 MB on a fleet of nine visors, over plain HTTP as much as here. A browser's WebSocket has no read limit so the UI is unaffected, but a Go client must raise coder/websocket's 32 KiB default (SetReadLimit) or the first big response closes the connection.

Package visor pkg/visor/init.go c3-vis-core

This file is the "table of contents" for visor initialization. It declares all init modules, registers them with their dependencies, and provides the shared context helpers used by the init functions spread across the init_*.go files.

Actual initialization logic lives in:

  • init_dmsg.go — DMSG client, ctrl, pty, ping, server latency
  • init_transport.go — Transport manager, STCPR/SUDPH/STCP, address resolver, TPD
  • init_router.go — Router, route setup hooks, embedded route setup, node health
  • init_apps.go — App launcher, CLI/RPC, hypervisors
  • init_services.go — Event broadcaster, uptime, survey, forwarding, ping, UI server

Package visor pkg/visor/init_apps.go c3-vis-core init_apps.go contains app launcher and CLI initialization logic.

Package visor pkg/visor/init_ar_bind_cxo.go c3-vis-core

AR-bind-over-CXO publisher. The visor mirrors its address-resolver bindings — the same stcpr/sudph/quic/wt reachable-address payloads it POSTs to /bind (and re-registers over a fresh dmsg stream every ~90s) — onto a persistent CXO feed on DmsgVisorARBindCXOPort and announces to the AR, which subscribes back and ingests them. This moves the address binding off the timer-driven re-registration, each a fresh dmsg stream with a full Noise handshake (the secp256k1 ECDH handshakeResponder that dominates AR CPU), onto one warm CXO connection.

Once the AR is subscribed and answering, its ingest of the heartbeat Roots refreshes the bindings' TTL and unchanged re-binds skip HTTP. HTTP carries a changed payload, the first bind, and one re-bind after the AR resubscribes on a new conn or stops answering (see cxoKeepaliveHealthy). The publisher is fed by a hook the AR client fires on every successful bind (see addrresolver.BindPublisher), so the CXO leaf always carries the exact LocalAddresses the visor last registered. It is inert until an AR subscribes to the feed.

Package visor pkg/visor/init_coinnode.go c3-vis-core

Brings up fibercoin node discovery (servicedisc.ServiceTypeCoin). For each v.conf.CoinNodes entry the visor:

  1. reverse-proxies the node's local HTTP API over dmsg on the configured DmsgPort (reusing the forwarded-ports infra), so a remote thin-client wallet — including the browser wasm visor over its HTTP-over-dmsg shim — can reach the node's API through the mesh; and
  2. on the SD heartbeat interval, probes the node's /api/v1/health, builds a DETECTED CoinInfo (never operator-claimed), and registers a type=coin SD entry ONLY while the node answers — deregistering when it goes away, so the advertisement is always truthful (no dead entries).

The node itself runs INDEPENDENTLY of the visor (systemd/terminal); the visor never starts or stops it. See docs and project_skycoin_wallet_over_dmsg.

Package visor pkg/visor/init_dmsg.go c3-vis-core init_dmsg.go contains DMSG initialization logic.

Package visor pkg/visor/init_dmsg_relay.go c3-vis-core

dmsg over skynet through this visor (#4484 stage 3). Two halves of one mechanism, both on the visor's single dmsg client:

  • RELAY (accept side): a listener on skyenv.DmsgRelayPort over skynet. A whitelisted peer that dials it gets a server-role dmsg session on this client (dmsg.Client.AcceptRelaySession); its stream requests are carried over this visor's own dmsg server sessions under the PEER's key.
  • CARRIER (dial side): the client's session dialer for skynet:// server addresses. A seeded server entry "skynet://<pk>:70" is dialed as a skywire route to that visor's relay, then wrapped in the usual Noise+yamux dmsg session.

Neither half registers anything in discovery or opens a TCP listener.

Package visor pkg/visor/init_dmsg_relay_local.go c3-vis-core

The LOCAL dmsg relay acceptor: the third pipe into the same relay init_dmsg_relay.go already serves over skynet, and the only one that does not involve the network at all.

It exists for the standalone dmsg client that has to keep its key. The dmsgweb proxy is the case that forced it: it runs beside the visor under a key the survey whitelist knows, so rotating the key is not an option, and yet every one of those processes holds its own sessions to dmsg servers and publishes its own discovery entry — a whole second client's worth of server capacity, per process, on a host that already has a visor with sessions and transports. Attached here it keeps the key, holds exactly one session (to this visor, over a unix socket), publishes nothing, and its streams ride this visor's sessions.

AUTHORIZATION — read dmsg.DmsgLocalRelayConfig's comment for the full model. In short: the unix socket's 0600 mode means the attacher is already running as the visor's user, which is a process that could read the visor's secret key off disk anyway; and the optional allowed_keys list is real authentication, because the dmsg session handshake is Noise XK and proves the attacher holds the secret key for the PK it claims. The loopback listener has no filesystem gate, so it is refused unless allowed_keys is non-empty.

Package visor pkg/visor/init_dmsg_skywire.go c3-vis-core the dmsgpty Host over skynet routes.

Lives in pkg/visor (not pkg/dmsg/dmsgpty) because pkg/app/appnet imports are visor-tier — pushing them down into the dmsgpty package would invert the layering. The dmsgpty package keeps its generic StreamDialer / PKExtractor interfaces (Phase 1/2); this file bridges them to appnet.SkywireNetworker on the visor side.

Phase 3 effect: the dmsgpty Host gains a parallel listener on appnet.SkywireNetworker AND its MultiDialer chain prepends a skynet strategy. `cli dmsg pty start` now rides the visor's already-negotiated transports first; on miss (no route, remote not exposing skynet listener) the chain falls through to the existing dmsg strategy. Backward-compat: every dmsg-only deploy keeps working unchanged because dmsg is the chain's last entry.

Package visor pkg/visor/init_embedded_services.go c3-vis-core

Deployment services running inside the visor. Each block in config.embedded_services is built by its pkg/services factory and mounted under a path prefix on the dmsg HTTP port, next to the log server, so transport-discovery becomes dmsg://<visor pk>:80/tpd/... and is reached the way the visor itself is: one dmsg stream to this key, over any session that reaches it. The service keeps no key, no listener and no dmsg sessions of its own; its CXO aggregators and publishers run on the visor's dmsg client under the visor's key.

Requests over dmsg carry the caller's key in RemoteAddr, which is what the services' whitelists and SW-Sig auth read, so their access rules are unchanged. The nonce path only exists for plain HTTP and is not served here.

Package visor pkg/visor/init_embedded_services_register.go c3-vis-core

Package visor pkg/visor/init_group.go c3-vis-core

Init wiring for the chat-group feed manager. Parallel to init_pairing.go — same shape, same best-effort failure semantics, same close-stack registration. Depends on dmsgC, opens its own bbolt store under v.conf.LocalPath/skychat/groups.db, and resumes any non-terminal group records persisted from a previous run.

Package visor pkg/visor/init_hypervisor_transport.go c3-vis-core

Visor → hypervisor transport auto-upgrade.

The visor's `Hypervisors` config field lists hypervisor PKs the visor reports to. ServeRPCClient establishes a dmsg session to each as the bootstrap RPC channel — that's the "is the hypervisor reachable" signal. Once that session is up, the goroutine started here attempts a direct transport between the visor and the hypervisor too, so subsequent RPC + skypty dials can ride the fast p2p path instead of the dmsg relay.

Ordering rationale:

  1. dmsg session up → hypervisor is alive + reachable through the network.
  2. Attempt every direct carrier this visor can open, in the active preference order (tptypes.PreferenceOrder), stopping at the first that succeeds. dmsg is skipped — it is the relay being escaped, not a destination.

The carrier set is deliberately NOT a fixed pair. It used to be stcpr-then-sudph, which quietly excluded every visor that has neither: a browser visor opens swtr/swsr/webrtc and nothing else, so it never upgraded off the relay at all. Preference is one setting, owned by tptypes and settable at runtime; this loop reads it rather than restating a subset of it.

The transport persists past first creation; the goroutine reconciles every 5 minutes (or after a failed attempt's backoff expires) by re-checking whether a fast transport is still present and re-trying if not.

Stops cleanly when the visor's lifecycle ctx is canceled.

Package visor pkg/visor/init_lan_dmsg.go c3-vis-core

Package visor pkg/visor/init_pairing.go c3-vis-core

Init wiring for the chat-pair feed manager. Mirrors initStats and initCXOUserFeeds: depends on dmsgC, opens its own bbolt store under v.conf.LocalPath/pairing/, and resumes any pairs persisted from a previous run.

The pairing module sits intentionally low in the dependency graph — it doesn't need transports, routes, or the launcher — so the only init-ordering constraint is "after dmsgC."

Package visor pkg/visor/init_registration_cxo.go c3-vis-core

Registration-over-CXO publisher. Runs whenever a dmsg-discovery PK resolves (there is no opt-in flag — earlier comments referenced a Dmsg.RegistrationCXO field that was never added). It publishes this visor's own signed discovery entry as a CXO feed on DmsgDMSGDRegistrationCXOPort and announces to the deployment's dmsg-discovery, which subscribes back and ingests the entry. This moves client-entry registration off the timer-driven HTTP PUT — each a fresh dmsg stream with a full Noise + post-quantum handshake, the load that dominates dmsg-discovery CPU — onto a persistent CXO connection kept warm by the treestore heartbeat.

The entry is published verbatim from the dmsg client's canonical registration path (see EntityCommon.SetEntryPublishHook): the same bytes, sequence and signature dmsg-discovery accepts over HTTP, so the CXO ingest is a drop-in mirror. HTTP PUT is kept alongside as the fallback, so this is safe to enable ahead of the server-side aggregator rollout — it is simply inert until a dmsg-discovery subscribes to the feed.

Package visor pkg/visor/init_router.go c3-vis-core init_router.go contains router initialization logic.

Package visor pkg/visor/init_router_listener.go c3-vis-core

Package visor pkg/visor/init_sd_reg_cxo.go c3-vis-core

SD-registration-over-CXO publisher. The visor mirrors its own service-discovery entries — the type=visor / vpn / skysocks / coin registrations pkg/app/appdisc POSTs to /api/services and re-POSTs every 90s (skyenv.ServiceDiscUpdateInterval) — onto a persistent CXO feed on DmsgVisorSDRegCXOPort, and announces to the service-discovery, which subscribes back and ingests them. This moves the SD heartbeat off the timer-driven re-registration, each a fresh dmsg stream with a full Noise handshake (the secp256k1 handshakeResponder that dominates discovery- service CPU), onto one warm CXO connection.

The feed is inert until an SD subscribes to it. Once the SD is subscribed and answering, its ingest of the heartbeat Roots refreshes the entries' TTL and unchanged heartbeats skip HTTP (servicedisc.KeepaliveSink). HTTP carries a changed entry, the first registration, deletes, and one registration after the SD resubscribes on a new conn or stops answering.

What is published

A visor's service set is per-app and changes when apps start and stop, so the feed carries ONE batched leaf holding the visor's WHOLE current live set, republished on every change:

services        // FrameGzip(v1, JSON []servicedisc.Service)

The entries are verbatim what the SD accepted and echoed back (the clients feed them in through servicedisc.EntrySink), so the ingest is a drop-in mirror of the HTTP register.

Deregistration is ABSENCE, not a tombstone — the same rule SD's own publisher documents (pkg/deployment/sd/api/cxo_publisher.go). A service that stops is simply missing from the next batch, and SD's Redis store expires it on the existing entry TTL. When the set empties, the leaf itself is deleted.

Package visor pkg/visor/init_selfprobe.go c3-vis-core

Package visor pkg/visor/init_services.go c3-vis-core init_services.go contains service initialization logic: health tracking, uptime, survey, forwarding connections, ping listeners, and the UI server.

Package visor pkg/visor/init_skynet_ports.go c3-vis-core

Auto-registers the visor's localhost service ports for skynet forwarding so they're accessible via .skynet URLs (or any skynet client) without manual RegisterTCPPort calls.

Which ports: everything that already listens on localhost and would be useful to reach remotely. The sky-forwarding server (port 57) validates each forwarded port against this list, so only explicitly registered ports are reachable — the access control model is the same as DMSG (PK-authenticated route + noise handshake) just over the routing mesh instead of dmsg servers.

Ports that serve ONLY over DMSG (no localhost listener) like port 136 (route setup RPC) are NOT registered here because there's nothing on localhost to forward to. Making those skynet-accessible would require also binding them on localhost — a separate, larger change.

Package visor pkg/visor/init_stats.go c3-vis-core store into the visor lifecycle.

initStats opens the bbolt store, builds the pull-style probes (transport snapshot, tier states, service states), constructs the Tracker, and registers the Close in the visor's close stack so the store and goroutine drain on shutdown.

Package visor pkg/visor/init_transport.go c3-vis-core init_transport.go contains transport initialization logic.

Package visor pkg/visor/init_udp_forwarding.go c3-vis-core faithful-UDP port forwarding (#2607 stage-4c). The dial/client side lives in appnet (DialPacket). This is the accept side: for every forwarded port marked UDP, the visor registers datagram intent with the router, then a single accept loop drains the datagram siblings the route-setup builds for inbound datagram routes and bridges each to the local UDP service via a UDPBridge.

Package visor pkg/visor/init_uptime.go c3-vis-core service-self uptime recorder. The recorder itself is constructed in run() (so a panic during NewVisor still leaves a session row); this file owns the wireup that connects an existing recorder to the rest of the visor — logserver routes, RPC accessor, close stack — once NewVisor has succeeded.

Package visor pkg/visor/init_voice.go c3-vis-core

Brings up the skychat 1:1 voice-call manager (pkg/skychat/call): it listens for inbound call signaling on skyenv.SkychatVoiceSignalPort over BOTH dmsg AND skynet (same port), and dials outbound calls over whichever network resolves. Media (RTP) rides the signaling conn (a Noise-encrypted skywire transport), never a raw-internet/ICE path — see docs/skychat-voice-rfc.md.

Package visor pkg/visor/lan_dmsg_discovery.go c3-vis-core Auto-discovery of LAN DMSG servers from hypervisors.

Package visor pkg/visor/local_graph.go c3-vis-core

A local graph source is a set of transport entries this visor knows about beyond its own transport manager and the network-wide TPD snapshot. Today the one source is a hypervisor's view of its attached visors (Hypervisor.AttachedTransportEntries, #4750): every attached visor reports its transports in the summary the hypervisor already polls, so route calculation can use those edges without a TPD or route-finder query.

Package visor pkg/visor/memlimit.go c3-vis-core

Package visor pkg/visor/meshproxy.go c3-vis-core meshproxy — the RFC "real-origin" native browse path (see pkg/wasmhv/browseui/RFC-real-origin-browser.md). Instead of the WinBox browser fetching a page and re-implementing the network stack inside a sandboxed opaque srcdoc, this serves mesh (dmsg) sites from a REAL local origin so the BROWSER does native subresource loading, redirects, cookies, WASM, and streaming — skywire only proxies the transport (over dmsg), exactly like pkg/dmsgweb does for a real external browser via SOCKS5. Content flows through THIS visor's own transports; the listeners are loopback-only.

Two origin shapes (BrowseOrigin.Mode), both giving each mesh site its OWN isolated browser origin:

  • "subdomain" (default): ONE listener; each site is the origin <vhost>.<base32pk><suffix> (suffix ".mesh.localhost" resolves to loopback in every target browser, so no public cert is needed; set a real domain + TLS for hosted/https parity). Routed by the Host header.
  • "port": each site gets its OWN 127.0.0.1:<port> origin from a small pool. No DNS/wildcard dependency (works anywhere), weaker isolation (cookies are domain-scoped, not port-scoped). A "portal" on Addr resolves a mesh host to its per-site port via GET /open?host=<resolver-host> → 302.

Optional TLS (BrowseOrigin.TLSCert/TLSKey) serves either mode over HTTPS with a real or locally-trusted cert — for local https parity with the hosted <pk>.<domain> origin (same scheme, secure context, real-domain cookies).

It is a SEPARATE listener from the hypervisor UI (:8000) on purpose: untrusted mesh content must never share an origin with the control surface, and these listeners serve ONLY the reverse proxy — no /api, no UI.

Package visor pkg/visor/node_health.go c3-vis-core

Package visor pkg/visor/notifyhub.go c3-vis-core

The visor-global notification hub — the "where" half of the notification system whose "whether" half lives in each app (see pkg/app/appserver/notify.go).

An app publishes a NotifyReq and stops caring. The hub owns the one decision an app cannot make for itself: which delivery path can actually reach the user right now. It walks a fixed priority chain and stops at the first tier that can deliver, so a single event surfaces exactly once:

(a) an attached UI holding a fresh capability lease — a UI that will really
    put this in front of the user (it also knows what is focused and muted),
    so the hub must not double up. No consumer ships today: the lease is the
    designed-in slot for the hypervisor manager UI's notification bell, and
    it stays false until something calls MarkUICapable.
(b) subscribed host apps — the Android foreground service (and later the
    manager UI) reading the SSE stream, which post native notifications
    through per-app channels.
(c) the host OS notification center via pkg/osnotify — the desktop default.
(d) nothing: on a headless visor (server, router, daemon) there is no UI, no
    subscriber and no desktop session, so the event drops. That is the
    normal case for most of the fleet, not an error.

Why the tiers are ordered this way: each one is strictly "closer" to a user who is actually looking. A capable UI beats a background service beats a desktop toast. Suppression is always DERIVED at publish time (is anyone subscribed right now?), never stored — a cached "phone is attached" flag plus a dropped connection would mute the desktop permanently.

Package visor pkg/visor/options.go c3-vis-core

Package visor pkg/visor/pairing.go c3-vis-core

Visor-level wrapper around the cmd/apps/skychat/pairing package.

The visor owns one pairing.Manager (initialized in init_pairing.go) and an in-memory ring of recently-received messages. RPC clients call PairAdd / PairRemove / PairList to manage their contact list, PairSend to dispatch a message into the corresponding pair feed, and PairPoll to drain inbound messages. The poll model is intentionally simple — long-poll / SSE delivery to apps can layer on later (PR-4) without changing the Visor surface.

Package visor pkg/visor/pairing_hv.go c3-vis-api

Hypervisor pairing (#4484 stage 5). A peer that holds a same-origin transport to this visor (a desk tab the hypervisor serves) or that tried the transport RPC without being whitelisted is a PENDING hypervisor: listed by fingerprint for `skywire cli visor hv pair`, and approved either there or with a one-time code the operator makes on the board and types into the tab. Approval is the existing AddHypervisor path, so the host dials the peer as its hypervisor and lets it drive RPC and pty — and nothing else grants that.

Package visor pkg/visor/peer_whitelist.go c3-vis-core

peerWhitelist is the visor's single source of truth for "which peer PKs may manage this visor". Every management surface consults it live, per-connection: the dmsgpty host, dmsgscp, the /pty web terminal, and the transport-RPC / dmsg-gRPC / dmsg visor-RPC servers. Because they all hold the same mutable reference, a runtime addition propagates to all of them at once.

Transitive trust: a visor configured with hypervisor H connects to H and serves its RPC to it. On accept, H pushes its OWN configured hypervisors to the visor via AddPtyWhitelist, so a super-hypervisor SH that manages H can also reach the visor — trust flows up the hypervisor chain without the operator re-listing SH on every visor.

Package visor pkg/visor/ping.go c3-vis-core

Package visor pkg/visor/policy_loader.go c3-vis-core for routing-policy backends. A single config field (`routing.policy_per_dial`, per-app `routing_policy`, or the runtime `app start --routing-policy <path>` flag) accepts both `.star` (Starlark) and `.wasm` (WASM) artifacts; this helper inspects the path and instantiates the matching Loader, returning the shared policy.Engine interface so callers don't branch on backend.

Package visor pkg/visor/policy_provider.go c3-vis-core implementation of pkg/router/policy.Provider. Surfaces the visor's transport-tracker state, embedded geoip database, service-discovery snapshot, operator-configured trust list, and configured hypervisor PKs to the operator's Starlark routing policy script.

Geo resolution is layered:

  1. SD snapshot (PK→country built from public proxy/vpn/visor entries). Covers multihop intermediates that advertise themselves as a service — without this, every non-neighbor PK would return "??" because the visor has no direct IP for off-path hops. Refreshed on a TTL so it's not in the dial hot path more than once every refreshTTL.
  2. Direct-transport IP → embedded geoip. Catches direct neighbors that don't advertise as a service.
  3. AR-resolve IP → embedded geoip. Catches AR-registered intermediaries that are neither advertised as a service nor directly connected — the common geo-avoid hop. The AR Resolve hits the network, so it runs OFF the dial hot path: a miss fires a single background resolve (deduped) and caches the result (including negatives) per-PK on a TTL; geo-avoid converges over a couple of selections.
  4. "??" — the policy script's filter falls through.

SD snapshot source is the CXO subscription manager (zero network cost when running) with an HTTP fallback (the existing servicesFromHTTP path used by VPNServers/ProxyServers/etc.) when CXO isn't installed or returns empty.

Package visor pkg/visor/profile.go c3-vis-core

The visor half of skychat profiles: read and write this visor's own published identity, and fetch a peer's.

Thin, like pkg/visor/group.go is thin — every rule about what a profile may contain lives in pkg/skychat/profile, and the transport lives on the group manager's describe port. What is here is the RPC-facing shape and the decision of which of the two answers (local store, remote round trip) a given public key deserves.

Package visor pkg/visor/proxied_visor_api.go c3-vis-core

proxiedVisorAPI lets the hypervisor's HTTP layer talk to a visor that isn't directly connected to it — instead reaching it through a sub-hypervisor that is. The hypervisor walks ProxiedVia from HVListVisors output, finds the sub-hypervisor that has the target visor in its own remoteVisors map, and constructs a proxiedVisorAPI that re-routes each VisorAPI method through the sub-hypervisor's HVxxx RPC method (using the target visor's PK as the first arg).

The HVxxx surface on the sub-hypervisor's API is partial — only the ~30 most operator-facing methods have counterparts today. Other methods on proxiedVisorAPI return ErrProxyNotSupported via the embedded proxyDefaultAPI's stubs (generated from api.go's API interface). The hvui falls back to its existing offline-row rendering for fields it can't fetch.

Package visor pkg/visor/proxy_default_api.go c3-vis-core

Generated by /tmp/gen_proxy_stubs.go from pkg/visor/api.go.

proxyDefaultAPI implements the full API interface by returning ErrProxyNotSupported (or the zero value for non-error returns) from every method. proxiedVisorAPI embeds it and overrides the methods that have HVxxx counterparts on the sub-hypervisor's API.

To regenerate after API changes:

go run /tmp/gen_proxy_stubs.go > pkg/visor/proxy_default_api.go

Package visor pkg/visor/pty_forwarding.go c3-vis-pty

Package visor pkg/visor/reach_card.go c3-vis-core

Reach cards: a visor tells peers itself how to dial it. It serves the records the address resolver holds for it, signed, on GET /reach over dmsg and skynet, and a dialer asks the peer for its card before it asks the resolver. The resolver is left telling a visor what to put in its card, and answering for peers that do not serve one.

Package visor pkg/visor/reward_push.go c3-vis-core

Visor-side survey PUSH: periodically send this visor's node-info survey to the reward system over dmsg, so reward eligibility no longer depends on the reward system pulling the survey on its own (online-gated, silent-drop-prone) schedule.

Design: a conditional PUT. Each cycle the visor GETs the sha256 the reward system currently holds for its PK (/node-info/stored-checksum, scoped to the authenticated sender) and only POSTs the full survey when it differs — so a steady-state survey costs one tiny checksum round-trip, and a changed survey (or one the reward system has lost/aged-out) is re-sent. The survey regenerates ~daily (a fresh timestamp), which naturally yields a daily re-assert. The reward system's accept/reject verdict is recorded in v.survey so the hypervisor UI can show reward eligibility (a rejected push → red mark, distinct from the hyphen for no reward address). No-op until a reward address is set and reward_system_dmsg is configured.

Package visor pkg/visor/rewards_ui_native.go c3-vis-core

Package visor pkg/visor/routeviz_embed.go c3-vis-core

Package visor pkg/visor/rpc.go c3-vis-core

Package visor pkg/visor/rpc_apps.go c3-vis-core

Package visor pkg/visor/rpc_ar.go c3-vis-core

Package visor pkg/visor/rpc_bridge.go c3-vis-core

TCP→{dmsg,skynet} bridge for the CLI's `--via <scheme>://<pk>` flow. Multiplexed onto the visor's existing CLI RPC port (v.conf.CLIAddr, default localhost:3435) via cmux: any conn starting with the 6-byte magic bridgeMagic is routed here, everything else falls through to gRPC or net/rpc.

Header (sent by the CLI after cmux matched the magic prefix):

6 bytes — magic ("SKYBRI"). cmux peeks this but doesn't
          consume it, so we read all 42 bytes ourselves.
1 byte  — scheme: 0 = dmsg, 1 = skynet
33 bytes — target visor PK
2 bytes — little-endian uint16. Dmsg port for scheme=0
          (typically DmsgVisorRPCPort = 57). Ignored for
          scheme=1.

Total: 42 bytes.

After header is read, the visor opens the appropriate stream using ITS OWN identity (dmsg client for scheme=0, transport-RPC mux for scheme=1), then bidirectionally io.Copy's between the TCP conn and the stream. CLI's rpc.Client runs on the TCP conn; remote's rpc.Server runs on the other side of the stream; both speak gob, no protocol translation. CLI inherits the visor's whitelist eligibility on the remote without needing its own keypair.

Package visor pkg/visor/rpc_client.go c3-vis-core

Package visor pkg/visor/rpc_client_serve.go c3-vis-core

Package visor pkg/visor/rpc_cxo_feeds.go c3-vis-core

RPC adapter for the CXO user-feed registry. The handlers are thin wrappers over Visor.RegisterCXOFeed / UnregisterCXOFeed / ListCXOFeeds; per-feed lifecycle management lives in cxo_user_feeds.go.

Package visor pkg/visor/rpc_dmsg.go c3-vis-core

Package visor pkg/visor/rpc_embedded_services.go c3-vis-core

Package visor pkg/visor/rpc_group.go c3-vis-core

RPC adapter for the chat-group feed manager. Thin wrappers over the Visor methods in group.go. Mirrors rpc_pairing.go shape.

Package visor pkg/visor/rpc_hostbridge.go c3-vis-wasm

Package visor pkg/visor/rpc_hypervisor_proxy.go c3-vis-core

RPC methods that proxy through the hypervisor's DMSG connections to remote visors. These enable CLI/TUI access to remote visor data without needing direct transport connections.

Package visor pkg/visor/rpc_hypervisors.go c3-vis-core

Package visor pkg/visor/rpc_mail.go c3-vis-core

Package visor pkg/visor/rpc_network.go c3-vis-core

Package visor pkg/visor/rpc_pairing.go c3-vis-core

RPC adapter for the chat-pair feed manager. Thin wrappers over the Visor methods in pairing.go.

Package visor pkg/visor/rpc_ping.go c3-vis-core

Package visor pkg/visor/rpc_profile.go c3-vis-core

RPC adapter for skychat profiles. Thin wrappers over the Visor methods in profile.go. Mirrors rpc_group.go shape.

Package visor pkg/visor/rpc_proxies.go c3-vis-core

Package visor pkg/visor/rpc_routing.go c3-vis-core

Package visor pkg/visor/rpc_services.go c3-vis-core

Package visor pkg/visor/rpc_tps.go c3-vis-core

Package visor pkg/visor/rpc_transport.go c3-vis-core

Package visor pkg/visor/rpc_transport_proxy.go c3-vis-core

TransportRPCProxy enables CLI access to a remote visor's RPC through the local visor's transport. The CLI connects to the local visor (localhost:3435 as usual), calls ProxyRPC with the remote PK, and the local visor opens a VStream to the remote visor over their shared transport. The remote visor serves RPC on that VStream (authenticated via the hypervisor/dmsgpty whitelist).

Usage from CLI:

skywire cli --rpc localhost:3435 visor tp-rpc <remote-pk> <method> [args]

The local visor must: 1. Have a transport to the remote visor 2. Be in the remote visor's hypervisor/dmsgpty whitelist

Package visor pkg/visor/rpc_visor.go c3-vis-core

Package visor pkg/visor/rpc_voice.go c3-vis-core

Package visor pkg/visor/servedversion.go c3-vis-core

Package visor pkg/visor/service_registry.go c3-vis-core

ServiceRegistry maps port numbers to connection handlers so the sky-forwarding server (and future transports) can dispatch incoming connections to the correct service without needing a localhost TCP bounce. Each handler is a function that owns a net.Conn for its lifetime — it reads requests, writes responses, and closes the conn when done.

This replaces the old isPortRegistered / allowed-ports / localhost TCP dial pattern. Registration IS the access control: if a port isn't in the registry, the forwarding server refuses it. Services that shouldn't be exposed (RPC, hypervisor) simply don't register.

Package visor pkg/visor/skymail.go c3-vis-core

The visor's own mailbox (pkg/skymail). It listens for SMTP on port 25 over dmsg and skynet, like every dual-listened visor port, and sends by dialing the recipient visor's port 25 directly: no MTA, no queue, no certificate, so it runs as-is in a browser tab. It is on by default everywhere; the size and age limits keep an open mailbox from filling the storage it lives in. Enable and every limit are live settings (MailSetSettings), kept in settings.json beside the mail.

Package visor pkg/visor/skynet_first_dialer.go c3-vis-core

SkynetFirstUIDialer wraps a dmsg-based dmsgpty UIDialer and tries to reach the peer over the skywire router first. The visor's dmsgpty host already dual-listens on dmsg and skynet at the same port (see init_dmsg_skywire.go's startSkywirePtyListener), so the peer-side accept loops are symmetric — the only thing missing was the hypervisor's dial-side preference for the fast path.

Behavior:

  • Try appnet.DialContext(skynet, peer:port) with a short timeout. Success returns that conn; the pty stream flows over whatever transport the router selected (stcpr / sudph / dmsg).
  • On any error from the skynet dial (no route, networker not registered, timeout), fall back to dmsg.Client.Dial which has been the original behavior.

The skynet path needs a route to the peer, which means the visor has to be sharing a transport with the hypervisor (or vice versa). pkg/visor/init_hypervisor_transport.go's auto-upgrade goroutine establishes that route from the visor side; the hypervisor uses any transport the visor advertised in the address resolver.

Package visor pkg/visor/skynet_relay_dial.go c3-vis-core

Relay tier for the SKYNET dialer (DialSkynet), i.e. `.skynet` hosts only. When there's no direct transport to a destination, reach it through a 1-hop relay — a peer we share a direct (non-dmsg) transport with that also has one to the destination — using VStreamMux.DialThroughRelay (route ID 0, PK-addressed forwarding, no route-finder, no setup-node). It slots between the direct-transport fast path and the existing multihop-route (RF) fallback: direct → relay → route.

This does NOT touch the `.dmsg` path: dmsg is a relay layer and is never route-finder-routed. Making dmsg-addressed / deployment targets reachable via the visor-relay is a separate, relay-only integration (no RF fallback).

Package visor pkg/visor/skynet_relay_graph.go c3-vis-core

Package visor pkg/visor/static_embed.go c3-vis-core

Package visor pkg/visor/status_board.go c3-vis-core

Package visor pkg/visor/survey.go c3-vis-core

Package visor pkg/visor/svc_fetch_cache.go c3-vis-core

Package visor pkg/visor/systray.go c3-vis-core

Package visor pkg/visor/temp_loglevel.go c3-vis-core

Package visor pkg/visor/tpd_announce_stats.go c3-vis-core

Package visor pkg/visor/transport_list.go c3-vis-core

Package visor pkg/visor/transport_list_fetch.go c3-vis-core

Package visor pkg/visor/transport_rpc.go c3-vis-core

TransportRPC serves the visor's RPC interface over skywire transports using VisorRPCPacket (route ID 0) virtual streams. This allows remote management without DMSG or routes — only a direct transport is needed.

Access is controlled by the visor's hypervisor PK whitelist: only PKs listed in the config's `hypervisors` field (or the dmsgpty whitelist) are permitted to open RPC streams.

Package visor pkg/visor/udp_client_forward.go c3-vis-core faithful-UDP port forwarding (#2607 stage-4d). The server side (init_udp_forwarding.go) bridges inbound datagram routes to a local service; this is the mirror: it dials a remote forwarded_ports.udp service via DialPacket and bridges it to a local UDP socket the operator's UDP app talks to.

Package visor pkg/visor/visor.go c3-vis-core

Package visor pkg/visor/voice.go c3-vis-core

Visor-side RPC surface for skychat 1:1 voice (the manager lives in pkg/skychat/call, brought up by init_voice.go). Place a call, hang up, and list active calls; media rides an encrypted skywire transport.

Package visor pkg/visor/voice_ringback.go c3-vis-core

Keeps this visor's ringback tone — what a caller hears while it rings — across restarts. The call manager holds it in memory; this is the copy on disk, beside the rest of the visor's local state.

Package visor pkg/visor/wasmmodule.go c3-vis-core

Package visor pkg/visor/wasmserve.go c3-vis-core

ServeWasm mounts the standalone wasm-visor PWA (the same surface as `skywire cli hv serve`) as an HTTP server. Extracted here so BOTH the CLI command and the visor daemon can serve it from the one binary / one process: `skywire visor --wasm-serve :8443 [--wasm-serve-tls] [--wasm-serve-harness]` brings the harness up alongside the visor, and the operator's rebuild-restart loop re-embeds + re-serves the latest wasm every restart (no separate process to remember).

Package visor pkg/visor/wasmserve_bootreport.go c3-vis-core

Index

Constants

View Source
const (
	StatsKindNetwork  = "network"
	StatsKindVersions = "versions"
	// StatsKindDaily is the GET /metric daily aggregate — per-day
	// bandwidth, latency and by-type breakdown over the published
	// window, newest day first.
	StatsKindDaily = "daily"
)

StatsKindNetwork, StatsKindVersions and StatsKindDaily are the short path names the RPC/CLI layer uses, mirroring tpd-all-transports' with-self / without-self.

View Source
const (
	// CSRFHeaderName is the name of the CSRF header
	CSRFHeaderName = "X-CSRF-Token"

	// CSRFMaxAge is the lifetime of a CSRF token in seconds
	CSRFMaxAge = time.Second * 30
)
View Source
const (
	FeedTPDMetrics           = cxosub.FeedTPDMetrics
	FeedTPDUptime            = cxosub.FeedTPDUptime
	FeedSDServices           = cxosub.FeedSDServices
	FeedDMSGDClientsByServer = cxosub.FeedDMSGDClientsByServer
	FeedTPDAllTransports     = cxosub.FeedTPDAllTransports
	FeedTPDStats             = cxosub.FeedTPDStats
	FeedTPDRouting           = cxosub.FeedTPDRouting
	FeedARReach              = cxosub.FeedARReach
	FeedARBindings           = cxosub.FeedARBindings
	FeedTPDPerKey            = cxosub.FeedTPDPerKey
)

Re-exported feed constants.

View Source
const (
	TabNetworkVisualizer = cxosub.TabNetworkVisualizer
	TabMetrics           = cxosub.TabMetrics
	TabUptime            = cxosub.TabUptime
	TabAutoconnect       = cxosub.TabAutoconnect
	TabCLIServices       = cxosub.TabCLIServices
	TabCLITransports     = cxosub.TabCLITransports
	TabRoutingPolicy     = cxosub.TabRoutingPolicy
	TabDmsgEntryLookup   = cxosub.TabDmsgEntryLookup
	TabNetworkStats      = cxosub.TabNetworkStats
	TabTransportMetrics  = cxosub.TabTransportMetrics
	TabARResolve         = cxosub.TabARResolve
	TabNetworkView       = cxosub.TabNetworkView
)

Re-exported tab constants.

View Source
const (

	// HealthTimeout defines timeout for /health endpoint calls done from hypervisor.
	HealthTimeout = skyenv.HealthTimeout
	// InnerHealthTimeout defines timeout for /health endpoint calls done from visor.
	InnerHealthTimeout = skyenv.InnerHealthTimeout
)
View Source
const (

	// BrowseWSUpgrade names the upgrade the desk asks for.
	BrowseWSUpgrade = "skywire-browse-ws"
)

A page in a real-origin browse frame opens its WebSockets through here: the frame's WebSocket is a stand-in that hands the connection to the desk, which asks this relay to open the real one through the browse proxy. A browser's own WebSocket goes straight to the network from the reader's address — a service worker never sees it.

golang.org/x/net/websocket rather than the vendored coder/websocket: under js/wasm coder/websocket is the BROWSER's WebSocket, the very leak this closes. x/net's is pure Go over whatever net.Conn it is handed.

Between the relay and the desk, each message is a frame: [type u8][length u32 BE][payload].

View Source
const DmsgForwardProxyPort uint16 = 84

DmsgForwardProxyPort is the default dmsg port the clearnet forward-proxy listens on when DmsgWeb.ForwardPort is unset.

View Source
const NotifyAppVisor = "visor"

NotifyAppVisor is the App name the visor stamps on notifications it raises itself, as opposed to relaying for an app. Sinks key their presentation off it (the Android bridge gives it its own, quieter channel), so it is part of the contract rather than a label.

View Source
const PublicServiceDelay = skyenv.PublicAutoconnectInterval

PublicServiceDelay defines the interval for checking service discovery and adding transports to public visors.

View Source
const SuggestedReadDeadline = 30 * time.Second

SuggestedReadDeadline is the per-pump idle ReadFrom deadline. Set by the caller via SetReadDeadline on the skynet PacketConn to give the pump a chance to observe ctx cancellation between reads. Without it a long-lived idle bridge sits forever in ReadFrom and Close has to rely on conn close to unblock — which works but adds a small race window.

Variables

View Source
var (
	// ErrCSRFInvalid is returned when the the CSRF token is in invalid format
	ErrCSRFInvalid = errors.New("invalid CSRF token")
	// ErrCSRFExpired is returned when the csrf token has expired
	ErrCSRFExpired = errors.New("csrf token expired")
)
View Source
var (
	// ErrAlreadyServing is returned when an operation fails due to an operation
	// that is currently running.
	ErrAlreadyServing = errors.New("already serving")

	// ErrTimeout represents a timed-out call.
	ErrTimeout = errors.New("rpc client timeout")
)
View Source
var (
	// ErrVisorNotAvailable represents error for unavailable visor
	ErrVisorNotAvailable = errors.New("no visor available")
	// ErrAppProcNotRunning represents lookup error for App related calls.
	ErrAppProcNotRunning = errors.New("no process of given app is running")
	// ErrProcNotAvailable represents error for unavailable process manager
	ErrProcNotAvailable = errors.New("no process manager available")
	// ErrTrpMangerNotAvailable represents error for unavailable transport manager
	ErrTrpMangerNotAvailable = errors.New("no transport manager available")
	// ErrAppLauncherNotAvailable represents error for unavailable app launcher
	ErrAppLauncherNotAvailable = errors.New("no app launcher available")
	// ErrRouterNotReady represents error for router not yet initialized
	ErrRouterNotReady = errors.New("router not ready")
)
View Source
var CXOFeedFromString = cxosub.FeedFromString

CXOFeedFromString is the inverse of the feed string label. Kept as a visor-package alias for existing callers.

View Source
var CXOFeedString = cxosub.FeedString

CXOFeedString maps a feed constant to its stable string label. Kept as a visor-package alias for existing callers (helpers_test.go round-trips it).

View Source
var ErrDmsgNotReady = errors.New("dmsg client not ready")

ErrDmsgNotReady is returned when the DMSG client is not ready within the timeout.

View Source
var ErrGroupHistoryDisabled = errors.New("grouping: history persistence not enabled")

ErrGroupHistoryDisabled is returned by Visor.GroupHistory / GroupHistoryGroups when persistence is off (the default). Enable by setting Skychat.GroupHistoryDB or the equivalent config knob.

View Source
var ErrGroupNotFound = errors.New("grouping: group not found")

ErrGroupNotFound is returned for an ID the local store doesn't know about. Distinct from a generic error so the CLI can render "no such group" vs a transport-layer failure.

View Source
var ErrGroupingDisabled = errors.New("grouping: manager not initialized")

ErrGroupingDisabled is returned by Visor group methods when the manager isn't initialized (dmsg unavailable at startup, or the bolt store failed to open).

View Source
var ErrNoErrorsCtx = errors.New("errors not set in module initialization context")

ErrNoErrorsCtx is returned when errors channel is not set in module initialization context

View Source
var ErrNoPendingMatch = errors.New("pairing: no pending key matches")

ErrNoPendingMatch is returned when a selection matches no pending key.

View Source
var ErrNoRingback = errors.New("voice: no ringback tone for that call")

ErrNoRingback is returned for an outbound call whose peer's ringback tone is not here — it plays none, or it has not arrived yet.

View Source
var ErrNoVisorInCtx = errors.New("visor not set in module initialization context")

ErrNoVisorInCtx is returned when visor is not set in module initialization context

View Source
var (

	// ErrNotFound is returned when a requested resource is not found.
	ErrNotFound = errors.New("not found")
)
View Source
var ErrPairCodeInvalid = errors.New("pairing: invalid code")

ErrPairCodeInvalid is returned for any code that does not pair: unknown, expired, already used, or revoked. Deliberately one error.

View Source
var ErrPairingDisabled = errors.New("pairing: manager not initialized")

ErrPairingDisabled is returned by Visor pair methods when the pairing manager isn't initialized (dmsg unavailable at startup, or the bolt store failed to open).

View Source
var ErrPolicyHookUnavailable = errors.New("routing-policy hook unavailable")

ErrPolicyHookUnavailable is returned when no router.DialHook is installed — typically because no policy was configured at startup and the runtime swap is the first policy this visor has seen. (Not currently reachable: init_router.go always installs a hook for the runtime-swap path. Reserved for the case where DialHook is explicitly disabled.)

View Source
var ErrProcManagerNotAvailable = errors.New("proc manager not available")

ErrProcManagerNotAvailable is returned when the app settings are asked for on a visor with no proc manager (a hypervisor-only process, or a unit test).

View Source
var ErrProfileDisabled = errors.New("profile: store not initialized")

ErrProfileDisabled is returned when the profile store failed to open, so this visor can neither publish nor persist an identity this run.

Distinct from "no profile set", which is not an error: an empty profile is the normal state of a visor whose operator never opened the dialog.

View Source
var ErrProxyNotSupported = errors.New("operation not supported on proxied visor")

ErrProxyNotSupported is returned by proxiedVisorAPI methods that don't have an HVxxx counterpart on the sub-hypervisor's API. The hypervisor's HTTP layer surfaces this back as a 5xx so the hvui can show "operation not supported for proxied visor" instead of a generic null/empty.

View Source
var ErrRouterNotAvailable = errors.New("router not available")

ErrRouterNotAvailable is returned by RPC handlers that need a router (e.g. SetAppRoutingPolicy) before the visor has finished router init.

View Source
var ErrTPDAllTransportsNotReady = errors.New("tpd all-transports: cxo cache miss")

ErrTPDAllTransportsNotReady is returned when the CXO subscriber has nothing for the requested path yet (no manager, no PK, hasn't synced).

View Source
var ErrTPDMetricsNotReady = errors.New("tpd metrics: cxo cache miss")

ErrTPDMetricsNotReady is returned by FetchTransportMetricsCXO when the local manager has no snapshot for the requested day window yet (manager not initialized, first cycle hasn't completed, or TPD hasn't published anything). Callers should fall back to the HTTP path on this error.

View Source
var ErrTPDPerKeyNotReady = errors.New("tpd per-key: cxo cache miss")

ErrTPDPerKeyNotReady is returned when the per-key feed has nothing fresh to serve. Callers fall through to HTTP.

View Source
var ErrTPDStatsNotReady = errors.New("tpd stats: cxo cache miss")

ErrTPDStatsNotReady is returned when the CXO subscriber has nothing for the requested path yet (no manager, no TPD PK, hasn't synced). Callers treat it as a cache miss and fall through to HTTP.

View Source
var ErrTPDUptimeNotReady = errors.New("tpd uptime: cxo cache miss")

ErrTPDUptimeNotReady is returned by FetchVisorUptimeCXO when the local manager has no snapshot for the requested day window yet (manager not initialized, first cycle hasn't completed, or TPD hasn't published that window). Callers should fall back to the HTTP path on this error.

View Source
var ErrUptimeRecorderUnavailable = errors.New("service-self uptime recorder not configured")

ErrUptimeRecorderUnavailable is returned by UptimeHistory when the recorder failed to open or wasn't wired into the visor (e.g. the LocalPath is unwritable). Callers should distinguish this from a "the recorder ran but has no data yet" empty response.

View Source
var ErrVoiceDisabled = errors.New("voice: disabled (no dmsg)")

ErrVoiceDisabled is returned when the voice manager isn't running (voice needs a dmsg client; see init_voice.go).

Functions

func DialTransportRPC

func DialTransportRPC(mux *transport.VStreamMux, remotePK cipher.PubKey) (*rpc.Client, error)

DialTransportRPC opens a VStream to a remote visor on the visor's shared transport-RPC mux and returns an RPC client connected to it. The mux MUST be the one registered as the transport manager's VisorRPCPacket handler — see the comment on Visor.transportRPCMux for why. The caller is responsible for closing the returned client.

func GenerateSurvey

func GenerateSurvey(v *Visor, log *logging.Logger, routine bool)

GenerateSurvey generates the system survey for reward eligibility verification. The survey is only generated if a valid reward address is set. Does not require root — only needs write access to the visor's local path.

func HypervisorUIFS

func HypervisorUIFS() (fs.FS, error)

HypervisorUIFS returns the embedded Angular hypervisor UI filesystem (the built static/ assets). Exposed for consumers like the standalone-html generator (the since-retired cli hv gen) that need to read index.html + the chunk JS/CSS.

func Run

func Run(parentCtx context.Context, conf *visorconfig.V1, opts Options) error

Run is the exported entry point used by pkg/services/visor. parentCtx becomes the parent of the SignalContext run() builds internally — when the multi-service supervisor cancels its ctx, the visor's signal-derived ctx cancels too and the visor unwinds cleanly.

The standalone command (cmd/skywire-visor/commands) calls it with context.Background().

func RunSystray

func RunSystray(conf *visorconfig.V1, opts Options)

RunSystray runs the visor and its system tray in one process. It needs a desktop session, and returns when the tray quits.

func RunTrayOnly

func RunTrayOnly(rpcAddr string)

RunTrayOnly runs ONLY the system tray — it does NOT start a visor in-process. The tray's controls already talk to the visor purely over its local RPC (rpcClientSystray dials conf.CLIAddr), so decoupling them lets the visor run as an always-on background service (systemd/launchd/Windows service) while the tray is an unprivileged desktop app launched in the user's session. Unlike RunSystray, there is no in-process visor — the tray simply connects to whichever visor is already serving on cli_addr, retrying until it comes up. Selected by `skywire visor --systray-only`.

func ServeBrowseOrigin

func ServeBrowseOrigin(ctx context.Context, cfg BrowseOriginConfig) error

ServeBrowseOrigin runs the browse-origin bootstrap server (RFC §4b, hosted mode): for any Host under Suffix it returns the SW bootstrap shell with __APP_ORIGIN__ and __SUFFIX__ substituted; /browse-sw.js returns the transport SW. Blocking until ctx is canceled.

func ServeRPCClient

func ServeRPCClient(ctx context.Context, log logrus.FieldLogger, tpM *transport.Manager, dmsgC *dmsg.Client, rpcS *rpc.Server, rAddr dmsg.Addr, errCh chan<- error)

ServeRPCClient repetitively dials to a remote hypervisor and serves a RPC server to that address. The dial uses dmsg by default, switching to skynet when an underlying fast transport exists and isn't in cooldown — see dialHypervisorRPC.

func ServeWasm

func ServeWasm(ctx context.Context, cfg WasmServeConfig) error

ServeWasm builds the standalone wasm-visor handler and serves it on cfg.Addr until ctx is canceled. Blocking — run it in a goroutine. Returns an error instead of exiting so the caller (visor daemon or CLI) decides how to react (the daemon logs and continues; the CLI fatals).

func SkynetFirstUIDialer

func SkynetFirstUIDialer(dmsgC *dmsg.Client, rAddr dmsg.Addr) pty.UIDialer

SkynetFirstUIDialer returns a dmsgpty UIDialer that prefers the skywire router for the pty stream and falls back to dmsg. The dmsg client is required as the fallback transport.

func Stop

func Stop()

Stop stops visor and quits GUI app.

func WriteRingback added in v1.3.98

func WriteRingback(w http.ResponseWriter, tone visorapi.VoiceRingback)

WriteRingback serves a ringback tone. The type was chosen by another visor, so it is served as nothing but audio: whitelisted by the call manager, never sniffed, and sandboxed in case anything opens it as a page.

Types

type About

type About struct {
	PubKey        cipher.PubKey   `json:"public_key"` // The hypervisor's public key.
	Build         *buildinfo.Info `json:"build"`
	DmsgConnected bool            `json:"dmsg_connected"` // Whether the DMSG client is connected to servers.
	DmsgSessions  int             `json:"dmsg_sessions"`  // Number of active DMSG server sessions.
}

type Autoconnector

type Autoconnector interface {
	Run(context.Context, *Visor) error
}

Autoconnector continuously tries to connect to services

func MakeConnector

func MakeConnector(conf servicedisc.Config, maxConns int, tm *transport.Manager, dmsgC *dmsg.Client, httpC *http.Client, clientPublicIP string,
	log *logging.Logger, mLog *logging.MasterLogger) Autoconnector

MakeConnector returns a new connector that will try to connect to at most maxConns services

type BrowseClearnetRequest

type BrowseClearnetRequest struct {
	// ExitPK names a skysocks exit to route the fetch through; zero means the
	// visor's default exit (the skysocks-client's server). Ignored when Proxy
	// is set.
	ExitPK cipher.PubKey `json:"exit_pk"`
	// Proxy is "[scheme://]host:port" of a proxy THIS visor dials for the
	// fetch — socks5 (default scheme), socks5h, http or https. It is the one
	// proxy setting a browser has (#4484 stage 6): "vnet:1080" and
	// "localhost:1080" name the visor's own loopback (its skysocks-client),
	// anything else a proxy the visor can reach.
	Proxy  string `json:"proxy,omitempty"`
	Method string `json:"method"`
	URL    string `json:"url"`
	Body   []byte `json:"body,omitempty"`
	// Header is the request headers to send. A POST that cannot declare its
	// Content-Type is a form the origin rejects, so the real-origin browser
	// needs these; before it, every fetch here was a bare GET.
	Header map[string]string `json:"header,omitempty"`
}

BrowseClearnetRequest fetches a CLEARNET url through a skysocks exit over a skywire route (IP-anonymous; the exit does the egress).

type BrowseFetchRequest

type BrowseFetchRequest struct {
	Host   string `json:"host"`
	Port   uint16 `json:"port"`
	Method string `json:"method"`
	Path   string `json:"path"`
	Body   []byte `json:"body,omitempty"`
	// Header is the request headers to send, on either the skynet or the dmsg
	// leg. A form POST to a mesh-hosted site needs its Content-Type just as a
	// clearnet one does.
	Header map[string]string `json:"header,omitempty"`
	// Scheme: "" / "auto" (skynet route first, dmsg-HTTP fallback), "skynet", or
	// "dmsg". A visor serves port 80 over BOTH a skynet mirror and dmsg (see
	// goServeSkynetMirror), so "auto" reaches the same content either way.
	Scheme string `json:"scheme,omitempty"`
}

BrowseFetchRequest fetches a dmsg/skynet site for the HV-UI browser. Host is the resolving-proxy form (NOT dmsg://): a bare PK, "<pk>:<port>", "<pk>.dmsg", a friendly alias like "home.dmsg"/"tpd.dmsg", or "name.skynet" — resolved the same way the visor's resolving SOCKS5 proxy resolves http://name.dmsg.

type BrowseOriginConfig

type BrowseOriginConfig struct {
	Addr    string          // HTTP listen address (loopback; Caddy fronts it)
	VOrigin string          // the visor app origin V, e.g. "https://theskywirenetwork.net"
	Suffix  string          // browse-origin domain suffix (leading dot), e.g. ".haltingstate.net"
	TLS     bool            // usually false — Caddy terminates TLS
	TLSCert string          // optional PEM cert (paired with TLSKey)
	TLSKey  string          // optional PEM key
	Log     *logging.Logger // nil → package default
}

BrowseOriginConfig configures ServeBrowseOrigin — the browse-origin bootstrap server for the hosted two-server model. It serves ONLY the embedded SW bootstrap (and browse-sw.js) for the isolated browse origins B (<pk><Suffix>); it is NEVER in the content path (the registered SW relays every fetch to the visitor's in-tab visor at VOrigin). Front it with Caddy on *.<Suffix>.

type BrowseWebSocketRequest added in v1.3.99

type BrowseWebSocketRequest struct {
	URL       string   // ws:// or wss://
	Proxy     string   // the browse proxy, as for BrowseClearnetRequest
	Origin    string   // the Origin header a browser on the page's real site sends
	Protocols []string // requested subprotocols
}

BrowseWebSocketRequest is one WebSocket a browse frame wants opened.

type CSRFToken

type CSRFToken struct {
	Nonce     []byte
	ExpiresAt time.Time
}

CSRFToken csrf token

type CXOFeed

type CXOFeed = cxosub.Feed

CXOFeed identifies one upstream CXO publisher feed.

type CXOSubscriptionManager

type CXOSubscriptionManager = cxosub.Manager

CXOSubscriptionManager is the visor's alias for cxosub.Manager.

func NewCXOSubscriptionManager

func NewCXOSubscriptionManager(v *Visor, interval time.Duration, log *logging.Logger) *CXOSubscriptionManager

NewCXOSubscriptionManager constructs a manager wired to the visor: the live dmsg client accessor and the visor's feed resolver. interval comes from hypervisor.cxo_subscribe_interval; <= 0 falls back to the cxosub default. log nil falls back to a default package logger.

type CXOTab

type CXOTab = cxosub.Tab

CXOTab identifies a consumer of one or more CXO feeds.

type ConfigFieldDoc

type ConfigFieldDoc struct {
	Path string `json:"path"`
	Desc string `json:"desc"`
}

ConfigFieldDoc is one row of the live-field table, for command help.

func LiveConfigFields

func LiveConfigFields() []ConfigFieldDoc

LiveConfigFields returns the config paths a running visor applies without a restart, sorted by path. `skywire cli config set --help` renders this, so the documented list and the implemented list cannot drift.

type Conn

type Conn struct {
	Addr  dmsg.Addr
	SrvPK cipher.PubKey
	API   visorapi.API
	PtyUI *dmsgPtyUI
}

type ConnHandler

type ConnHandler func(conn net.Conn)

ConnHandler serves a single connection. The handler owns conn for its lifetime — it must close conn when done. Called in its own goroutine by the forwarding server.

func HTTPHandler

func HTTPHandler(h http.Handler) ConnHandler

HTTPHandler returns a ConnHandler that serves an http.Handler on the connection. Each call handles exactly one HTTP connection (which may carry multiple requests via keep-alive). This is the adapter used by HTTP-based DMSG services (port 80 log server, port 81 debug) to register in the handler registry.

type ConnectFn

type ConnectFn func(context.Context, cipher.PubKey) error

ConnectFn provides a way to connect to remote service

type Csrf

type Csrf struct {
	Token string `json:"csrf_token"`
}

type DHTGetIn

type DHTGetIn struct {
	PK   string `json:"pk"`
	Salt string `json:"salt"`
}

type DHTPutIn

type DHTPutIn struct {
	Value []byte `json:"value"`
	Seq   uint64 `json:"seq"`
	Salt  string `json:"salt"`
}

type DHTSyncRequest

type DHTSyncRequest struct {
	RemotePK string `json:"remote_pk"`
	Salt     string `json:"salt"`
}

type DmsgReconnectResult

type DmsgReconnectResult struct {
	SessionsClosed int `json:"sessions_closed"`
}

DmsgReconnectResult reports how many sessions postDmsgReconnect tore down.

type DmsgServersCache

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

DmsgServersCache is a thread-safe map of dmsg-server PK → entry, optionally backed by a JSON file on disk.

func NewDmsgServersCache

func NewDmsgServersCache(filePath string) *DmsgServersCache

NewDmsgServersCache creates a cache backed by the given file. If filePath is empty the cache is in-memory only. If the file exists it is loaded immediately; a missing file is not an error (first run).

func (*DmsgServersCache) All

func (c *DmsgServersCache) All() []*dmsgdisc.Entry

All returns a copy of the cached entries as a slice.

func (*DmsgServersCache) MergePreferringCache

func (c *DmsgServersCache) MergePreferringCache(configured []*dmsgdisc.Entry) []*dmsgdisc.Entry

MergePreferringCache returns a list of dmsg-server entries built by preferring the cached entry for any PK present in the cache, and using the corresponding entry from `configured` for PKs only in the configured list. PKs in the cache but not configured are appended.

Used by the bootstrap path so that on restart the visor connects using the address it last learned from dmsg-discovery, not whatever address was in skywire.json when it was generated.

func (*DmsgServersCache) Replace

func (c *DmsgServersCache) Replace(es []*dmsgdisc.Entry) error

Replace swaps the entire map for the given list and saves. Entries without a Server.Address are dropped. Use this when a refresh returned a complete fresh list — PKs no longer present in dmsgd are pruned. An empty input list is treated as a no-op (callers should check for and skip empty refreshes themselves to avoid destroying the cache during a dmsgd outage).

func (*DmsgServersCache) Set

func (c *DmsgServersCache) Set(e *dmsgdisc.Entry) error

Set replaces the entry for one PK and saves to disk.

type EmbeddedDmsgWeb

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

EmbeddedDmsgWeb holds the runtime state for the visor-hosted dmsgweb resolver. Safe for concurrent Start/Stop calls.

func (*EmbeddedDmsgWeb) Aliases

func (e *EmbeddedDmsgWeb) Aliases() map[string]cipher.PubKey

Aliases returns the name→PK bindings the resolver resolves by name — the canonical service aliases plus this visor's own alias on top, exactly the merge serve() hands to the runtime. The returned map is a copy.

func (*EmbeddedDmsgWeb) IsRunning

func (e *EmbeddedDmsgWeb) IsRunning() bool

IsRunning reports whether the resolver goroutine is currently alive.

func (*EmbeddedDmsgWeb) ListenAddr

func (e *EmbeddedDmsgWeb) ListenAddr() string

ListenAddr returns the SOCKS5 listener the resolver binds, resolved the same way serve() does (loopback default, default port). Read by the status page so it names the listener the browser actually reached it through.

func (*EmbeddedDmsgWeb) SetBind

func (e *EmbeddedDmsgWeb) SetBind(addr string) error

SetBind changes the SOCKS5 bind host and restarts the resolver so it takes effect immediately. "" = loopback (default); "0.0.0.0"/a LAN IP serves the LAN.

func (*EmbeddedDmsgWeb) SetUpstream

func (e *EmbeddedDmsgWeb) SetUpstream(addr string) error

SetUpstream changes the upstream SOCKS5 address and restarts the resolver so the new upstream takes effect immediately.

func (*EmbeddedDmsgWeb) SetUpstreamRules added in v1.3.98

func (e *EmbeddedDmsgWeb) SetUpstreamRules(rules []proxyroute.Rule) error

SetUpstreamRules replaces the per-domain upstream rules and restarts the resolver so they take effect immediately. Pass nil to clear them.

func (*EmbeddedDmsgWeb) Start

func (e *EmbeddedDmsgWeb) Start() error

Start spawns the resolver goroutine. Idempotent: calling Start while already running is a no-op. Returns an error if prerequisites (dmsg client) are missing.

func (*EmbeddedDmsgWeb) Stats

Stats returns a snapshot of cumulative counters (across all Start/Stop cycles).

func (*EmbeddedDmsgWeb) Stop

func (e *EmbeddedDmsgWeb) Stop() error

Stop signals the resolver to shut down and blocks until its goroutine returns. Idempotent.

func (*EmbeddedDmsgWeb) Suffix

func (e *EmbeddedDmsgWeb) Suffix() string

Suffix returns the domain suffix the resolver answers for (".dmsg").

func (*EmbeddedDmsgWeb) Upstream

func (e *EmbeddedDmsgWeb) Upstream() string

Upstream returns the current upstream SOCKS5 address.

func (*EmbeddedDmsgWeb) UpstreamRules added in v1.3.98

func (e *EmbeddedDmsgWeb) UpstreamRules() []proxyroute.Rule

UpstreamRules returns the current per-domain upstream rules.

type EmbeddedRouteSetup

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

EmbeddedRouteSetup holds the state of an embedded Route Setup Node. It uses a separate dmsg client with its own PK/SK identity to: 1. Accept incoming route setup requests from other visors on DmsgSetupPort (36) 2. Dial remote visors to set up routes for the local visor

func (*EmbeddedRouteSetup) CreateRouteGroup

func (ers *EmbeddedRouteSetup) CreateRouteGroup(ctx context.Context, biRt routing.BidirectionalRoute) (routing.EdgeRules, error)

CreateRouteGroup creates a route group by directly calling the setup-node logic. This bypasses the need to dial a remote setup-node over dmsg.

func (*EmbeddedRouteSetup) DmsgClient

func (ers *EmbeddedRouteSetup) DmsgClient() *dmsg.Client

DmsgClient returns the dmsg client used by the embedded route setup-node.

func (*EmbeddedRouteSetup) PK

func (ers *EmbeddedRouteSetup) PK() cipher.PubKey

PK returns the public key of the embedded route setup-node.

func (*EmbeddedRouteSetup) ResetStats

func (ers *EmbeddedRouteSetup) ResetStats()

ResetStats clears all counters and ring buffers on the embedded route setup-node's stats collector. Useful before starting a diagnostic capture window.

func (*EmbeddedRouteSetup) Serve

func (ers *EmbeddedRouteSetup) Serve(ctx context.Context) error

Serve starts the route setup-node listener on DmsgSetupPort. This allows other visors to connect and request route setup.

func (*EmbeddedRouteSetup) Stats

Stats returns the current collector snapshot. Returns a zero-value snapshot if stats are disabled (shouldn't happen in normal use, but keeps the RPC layer simple).

type EmbeddedSkymailBridge

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

EmbeddedSkymailBridge is the runtime state of the in-process SMTP bridge. Field layout intentionally mirrors EmbeddedDmsgWeb to keep the lifecycle code shape uniform.

func (*EmbeddedSkymailBridge) Addr

func (e *EmbeddedSkymailBridge) Addr() string

Addr returns the configured listener address (or the default when empty).

func (*EmbeddedSkymailBridge) IsRunning

func (e *EmbeddedSkymailBridge) IsRunning() bool

IsRunning reports whether the SMTP server goroutine is alive.

func (*EmbeddedSkymailBridge) Mode

func (e *EmbeddedSkymailBridge) Mode() string

Mode returns the configured envelope rewrite mode.

func (*EmbeddedSkymailBridge) Start

func (e *EmbeddedSkymailBridge) Start() error

Start spawns the SMTP server goroutine. Idempotent: calling Start while already running is a no-op. Returns an error if prerequisites (dmsg client) are missing or the listener can't bind.

func (*EmbeddedSkymailBridge) Stop

func (e *EmbeddedSkymailBridge) Stop() error

Stop signals the server to shut down and blocks until the goroutine returns. Idempotent.

type EmbeddedSkynetWeb

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

EmbeddedSkynetWeb holds the runtime state for the visor-hosted skynetweb resolver.

func (*EmbeddedSkynetWeb) Aliases

func (e *EmbeddedSkynetWeb) Aliases() map[string]cipher.PubKey

Aliases returns the name→PK bindings the resolver resolves by name — this visor's own alias. The returned map is a copy.

func (*EmbeddedSkynetWeb) IsRunning

func (e *EmbeddedSkynetWeb) IsRunning() bool

IsRunning reports whether the resolver goroutine is currently alive.

func (*EmbeddedSkynetWeb) ListenAddr

func (e *EmbeddedSkynetWeb) ListenAddr() string

ListenAddr returns the SOCKS5 listener the resolver binds, resolved the same way serve() does (loopback default, default port).

func (*EmbeddedSkynetWeb) SetBind

func (e *EmbeddedSkynetWeb) SetBind(addr string) error

SetBind changes the SOCKS5 bind host and restarts the resolver so it takes effect immediately. "" = loopback (default); "0.0.0.0"/a LAN IP serves the LAN.

func (*EmbeddedSkynetWeb) SetUpstream

func (e *EmbeddedSkynetWeb) SetUpstream(addr string) error

SetUpstream changes the upstream SOCKS5 address and restarts the resolver so the new upstream takes effect immediately. Pass "" to clear the upstream (non-.skynet traffic connects direct).

func (*EmbeddedSkynetWeb) SetUpstreamRules added in v1.3.98

func (e *EmbeddedSkynetWeb) SetUpstreamRules(rules []proxyroute.Rule) error

SetUpstreamRules replaces the per-domain upstream rules and restarts the resolver so they take effect immediately. Pass nil to clear them.

func (*EmbeddedSkynetWeb) Start

func (e *EmbeddedSkynetWeb) Start() error

Start spawns the resolver goroutine. Idempotent.

func (*EmbeddedSkynetWeb) Stats

Stats returns cumulative counters.

func (*EmbeddedSkynetWeb) Stop

func (e *EmbeddedSkynetWeb) Stop() error

Stop cancels the running resolver and waits for it to exit.

func (*EmbeddedSkynetWeb) Suffix

func (e *EmbeddedSkynetWeb) Suffix() string

Suffix returns the domain suffix the resolver answers for (".skynet").

func (*EmbeddedSkynetWeb) Upstream

func (e *EmbeddedSkynetWeb) Upstream() string

Upstream returns the current upstream SOCKS5 address.

func (*EmbeddedSkynetWeb) UpstreamRules added in v1.3.98

func (e *EmbeddedSkynetWeb) UpstreamRules() []proxyroute.Rule

UpstreamRules returns the current per-domain upstream rules.

type EmbeddedWisp

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

EmbeddedWisp holds the runtime state of the in-process Wisp server. Safe for concurrent Start/Stop.

func (*EmbeddedWisp) Addr

func (w *EmbeddedWisp) Addr() string

Addr reports the address the server is bound to, or "" when it is stopped.

func (*EmbeddedWisp) Running

func (w *EmbeddedWisp) Running() bool

Running reports whether the server is bound.

func (*EmbeddedWisp) Start

func (w *EmbeddedWisp) Start() error

Start binds the virtual-loopback port and serves sessions until Stop.

func (*EmbeddedWisp) Stop

func (w *EmbeddedWisp) Stop() error

Stop releases the port. It is safe to call when already stopped.

type ForwardedPorts

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

ForwardedPorts is a thread-safe collection of forwarded port definitions.

func NewForwardedPorts

func NewForwardedPorts(filePath string) *ForwardedPorts

NewForwardedPorts creates a new ForwardedPorts store. If filePath is non-empty, the store loads from and saves to that file.

func (*ForwardedPorts) AllSkynetPorts

func (fp *ForwardedPorts) AllSkynetPorts() []int

AllSkynetPorts returns port numbers that are forwarded over skynet. Used by the old allowed-ports check in the sky-forwarding server.

func (*ForwardedPorts) Deregister

func (fp *ForwardedPorts) Deregister(port int) error

Deregister removes a forwarded port.

func (*ForwardedPorts) Get

func (fp *ForwardedPorts) Get(port int) *visorapi.ForwardedPort

Get returns a copy of a single port definition, or nil.

func (*ForwardedPorts) IsDMSGAllowed

func (fp *ForwardedPorts) IsDMSGAllowed(port int) bool

IsDMSGAllowed checks if the given port is forwarded over DMSG.

func (*ForwardedPorts) IsSkynetAllowed

func (fp *ForwardedPorts) IsSkynetAllowed(port int) bool

IsSkynetAllowed checks if the given port is forwarded over skynet.

func (*ForwardedPorts) IsWhitelisted

func (fp *ForwardedPorts) IsWhitelisted(port int, pk cipher.PubKey) bool

IsWhitelisted checks if the given PK is allowed to access the port. Returns true if the whitelist is empty (open to all) or the PK is in the list.

func (*ForwardedPorts) LandingPageEntries

func (fp *ForwardedPorts) LandingPageEntries() []logserver.ForwardedPortEntry

LandingPageEntries returns entries for the log server landing page. Satisfies logserver.ForwardedPortLister.

func (*ForwardedPorts) LandingPagePorts

func (fp *ForwardedPorts) LandingPagePorts() []visorapi.ForwardedPort

LandingPagePorts returns ports visible on the landing page, sorted.

func (*ForwardedPorts) List

func (fp *ForwardedPorts) List() []visorapi.ForwardedPort

List returns all forwarded ports, sorted by port number.

func (*ForwardedPorts) PortWhitelist

func (fp *ForwardedPorts) PortWhitelist(port int) []cipher.PubKey

PortWhitelist returns the PK whitelist for a given port. An empty slice means the port is accessible to everyone. Satisfies logserver.ForwardedPortLister.

func (*ForwardedPorts) Register

func (fp *ForwardedPorts) Register(p visorapi.ForwardedPort) error

Register adds or updates a forwarded port. Saves to disk if configured.

type GeoData

type GeoData struct {
	CountryCode string  `json:"country_code,omitempty"`
	CountryName string  `json:"country_name,omitempty"`
	RegionCode  string  `json:"region_code,omitempty"`
	RegionName  string  `json:"region_name,omitempty"`
	CityName    string  `json:"city_name,omitempty"`
	Latitude    float64 `json:"latitude,omitempty"`
	Longitude   float64 `json:"longitude,omitempty"`
}

GeoData holds geolocation information for the visor.

func LookupGeo

func LookupGeo(ip string) *GeoData

LookupGeo returns geolocation data for the given IP using the embedded MaxMind GeoLite2-City database. Returns nil if ip is empty or lookup fails. No network round-trip — replaces the previous HTTP call to the configured ip.skycoin.com geoip service.

type GroupHistoryFetcher

type GroupHistoryFetcher interface {
	// ListByGroup returns up to limit most recent messages for the
	// named group, newest last. Limit <= 0 returns all stored.
	ListByGroup(groupID string, limit int) ([]visorapi.GroupMessage, error)
	// ListGroupBefore returns up to limit messages strictly older than
	// `before`, newest last — the backward page cursor that lets a
	// client walk a large channel's backlog a chunk at a time instead
	// of pulling all of it to show anything. A zero `before` means
	// "from the newest", so it doubles as the first page.
	ListGroupBefore(groupID string, before time.Time, limit int) ([]visorapi.GroupMessage, error)
	// Groups returns the set of group IDs that have any stored
	// messages — useful for operator inspection ('cli skychat group
	// history --list-groups' style introspection).
	Groups() ([]string, error)
	// ListGroupSince returns every stored message for the named
	// group with TS strictly after `since`, oldest first. Powers the
	// gRPC StreamGroupMessages history-fallback path that backfills
	// a reconnecting subscriber whose disconnect gap is longer than
	// the in-memory inbox ring can cover.
	ListGroupSince(groupID string, since time.Time) ([]visorapi.GroupMessage, error)
}

GroupHistoryFetcher is the read side of the group history store. Wired in init_group.go as an adapter around skychat/history.BoltStore when persistence is enabled. nil when disabled — callers must nil-check and return ErrGroupHistoryDisabled.

type HVMuxArgs

type HVMuxArgs struct {
	PK cipher.PubKey
	N  int
}

type Health

type Health struct {
	Status int `json:"status"`
	*visorapi.HealthInfo
}

type HealthCheckable

type HealthCheckable interface {
	Health(ctx context.Context) (int, error)
}

HealthCheckable resource returns its health status as an integer that corresponds to HTTP status code returned from the resource 200 codes correspond to a healthy resource

type Hypervisor

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

func NewHypervisor

func NewHypervisor(config visorconfig.HypervisorConfig, visor *Visor, dmsgC *dmsg.Client) (*Hypervisor, error)

func (*Hypervisor) AddMockData

func (hv *Hypervisor) AddMockData(config MockConfig) error

func (*Hypervisor) AttachedTransportEntries

func (hv *Hypervisor) AttachedTransportEntries() ([]*transport.Entry, time.Time)

AttachedTransportEntries is the hypervisor's LocalGraphSource: the transports of every attached visor seen within attachedGraphStaleAfter, setup transports excluded, deduplicated by ID (both ends of an edge between two attached visors report it). The returned time advances only when the set of IDs changes.

func (*Hypervisor) AuthEnabled

func (hv *Hypervisor) AuthEnabled() bool

AuthEnabled reports whether the web UI currently requires a login.

func (*Hypervisor) Disable

func (hv *Hypervisor) Disable() error

func (*Hypervisor) DisableUI

func (hv *Hypervisor) DisableUI() error

DisableUI stops just the web UI; the DMSG-RPC listener, managed-visor tracking, and `hv ls` keep working.

func (*Hypervisor) Enable

func (hv *Hypervisor) Enable(ctx context.Context) error

Enable starts the hypervisor: the DMSG-RPC listener + managed-visor tracking (the secure, whitelist-gated surface that backs `hv ls`) always, and the web UI unless UIDisable is set. The UI can be toggled independently afterward via EnableUI/DisableUI without affecting the RPC/tracking.

func (*Hypervisor) EnableUI

func (hv *Hypervisor) EnableUI() error

EnableUI starts just the web UI, leaving the DMSG-RPC/tracking untouched. Requires the hypervisor to be enabled.

func (*Hypervisor) HTTPHandler

func (hv *Hypervisor) HTTPHandler() http.Handler

func (*Hypervisor) IsEnabled

func (hv *Hypervisor) IsEnabled() bool

func (*Hypervisor) IsUIServing

func (hv *Hypervisor) IsUIServing() bool

IsUIServing reports whether the web UI HTTP server is currently serving.

func (*Hypervisor) ServeRPC

func (hv *Hypervisor) ServeRPC(ctx context.Context, dmsgPort uint16) error

func (*Hypervisor) SetAuth

func (hv *Hypervisor) SetAuth(enable bool) error

SetAuth turns the web UI's login requirement on or off at runtime.

EnableAuth is read while the router is BUILT, not per request, so setting the flag alone changes nothing on a server that is already serving. The change takes effect by rebuilding the mux, which is what this does: only the HTTP listener is cycled, in the same way EnableUI/DisableUI cycle it. The DMSG-RPC listener, managed-visor tracking and `hv ls` are untouched, and so is the visor — this is the "without restarting the visor" path.

Sessions do not survive the switch (the router, and with it the session middleware, is new), so a browser tab open on the UI has to be reloaded.

type LANDmsgServer

type LANDmsgServer struct {
	Server        *dmsg.Server
	PK            cipher.PubKey
	SK            cipher.SecKey
	Address       string // "ip:port" the server is listening on (LAN-routable)
	PublicAddress string // operator-set WAN-routable "host:port" (empty when not configured)
	Port          int    // actual port (useful when port 0 was configured)
}

LANDmsgServer holds the state of an embedded LAN DMSG server.

type LocalGraphSource

type LocalGraphSource func() ([]*transport.Entry, time.Time)

LocalGraphSource returns transport entries and a version: a time that advances only when the returned set changes, so a cache keyed on it rebuilds exactly then and not otherwise.

type LogsRes

type LogsRes struct {
	LastLogTimestamp string   `json:"last_log_timestamp"`
	Logs             []string `json:"logs"`
}

type MockConfig

type MockConfig struct {
	Visors            int
	MaxTpsPerVisor    int
	MaxRoutesPerVisor int
	EnableAuth        bool
}

type NetworkViewEntry

type NetworkViewEntry = netview.Entry

NetworkViewEntry / NetworkViewResponse are the network-view table types. They live in the dependency-free pkg/visor/netview leaf (so the wasm-visor can build the same view without importing pkg/visor, which doesn't compile for js/wasm) and are aliased here for the rest of pkg/visor that consumes them.

type NodeHealthTracker

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

NodeHealthTracker computes health status of TPS and RSN nodes on demand, behind a short TTL cache. It re-seeds its node set from the supplied providers on every recompute so runtime config_refresh changes are picked up. Results feed the api_tps UI panel RPCs only; the real transport/route dial path does not depend on this.

func NewNodeHealthTracker

func NewNodeHealthTracker(dmsgC *dmsg.Client, log *logging.Logger, tpsProvider, rsnProvider func() []cipher.PubKey) *NodeHealthTracker

NewNodeHealthTracker creates a new on-demand health tracker. The providers are invoked on every recompute to (re)seed the node set.

func (*NodeHealthTracker) GetRSNHealth

func (nht *NodeHealthTracker) GetRSNHealth() []visorapi.NodeHealth

GetRSNHealth returns health status for all RSN nodes.

func (*NodeHealthTracker) GetRSNNodesSorted

func (nht *NodeHealthTracker) GetRSNNodesSorted() []cipher.PubKey

GetRSNNodesSorted returns RSN nodes sorted by health (healthy first, then by latency).

func (*NodeHealthTracker) GetTPSHealth

func (nht *NodeHealthTracker) GetTPSHealth() []visorapi.NodeHealth

GetTPSHealth returns health status for all TPS nodes.

func (*NodeHealthTracker) GetTPSNodesSorted

func (nht *NodeHealthTracker) GetTPSNodesSorted() []cipher.PubKey

GetTPSNodesSorted returns TPS nodes sorted by health (healthy first, then by latency).

func (*NodeHealthTracker) Start

func (nht *NodeHealthTracker) Start(ctx context.Context)

Start records the base context used for on-demand checks. It no longer runs a background ticker — health is computed lazily when an api_tps RPC asks for it (see ensureFresh). Kept for lifecycle symmetry.

type NotifyHub

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

NotifyHub fans user-facing notifications out to whichever sink can reach the user. Safe for concurrent use; every method is non-blocking.

func NewNotifyHub

func NewNotifyHub(log logrus.FieldLogger) *NotifyHub

NewNotifyHub constructs an empty hub with the host-OS sink wired up. log may be nil; it only carries the per-publish trace.

func (*NotifyHub) MarkUICapable

func (h *NotifyHub) MarkUICapable(capable bool)

MarkUICapable refreshes (capable) or clears (!capable) the attached-UI capability lease. Nothing calls it yet — it is the seam the hypervisor manager UI's notification bell will heartbeat on, mirroring skychat's POST /notify-capable.

The lease means "a UI that will ACTUALLY surface this to the user is attached", not merely "a UI is connected": a backgrounded mobile WebView can show nothing, so it must stop heartbeating or it would silence the native path (01_playbook.md Step 4a).

func (*NotifyHub) Publish

func (h *NotifyHub) Publish(n appserver.NotifyReq)

Publish routes n to the first tier that can deliver it (see the file header). Never blocks: it runs on the publishing app's single RPC serve goroutine, so stalling here would stall that app's Dial/Write/Read too.

func (*NotifyHub) Subscribe

func (h *NotifyHub) Subscribe(capacity int) (<-chan appserver.NotifyReq, func() uint64)

Subscribe returns a receive-only channel of notifications plus a cancel func that closes it and reports how many events were dropped for this subscriber. Cancel is idempotent and MUST be called (the SSE handler defers it) or the subscriber leaks and keeps suppressing the host-OS sink forever.

func (*NotifyHub) SubscriberCount

func (h *NotifyHub) SubscriberCount() int

SubscriberCount reports how many host apps are currently subscribed.

type Options

type Options struct {
	// LoadConfig reads the config again for Visor.Reload. When nil the visor
	// cannot reload, because it was handed a config it has no source for.
	LoadConfig func() (*visorconfig.V1, error)

	// LogLevel overrides the config's log level when set.
	LogLevel string
	// PprofMode is one of cpu, mem, mutex, block, trace or http; empty is off.
	PprofMode string
	// PprofAddr is where the http pprof mode listens.
	PprofAddr string

	// Hypervisors are public keys added to the config's remote hypervisors.
	Hypervisors []string
	// NoHypervisors drops the config's remote hypervisors.
	NoHypervisors bool
	// LaunchBrowser opens the hypervisor UI once the visor is up.
	LaunchBrowser bool
	// NoCSRF stops the hypervisor UI from requiring a CSRF token on
	// requests that change state.
	NoCSRF bool

	// DmsgServer pins the visor to one dmsg server public key.
	DmsgServer string
	// DmsgServerAddr dials DmsgServer at this host:port instead of asking
	// discovery for it.
	DmsgServerAddr string
	// DmsgServerMaxAttempts is how many failed connects to the pinned server
	// end startup. Zero means 5.
	DmsgServerMaxAttempts int

	// StoreLog also writes the log to <local_path>/log/skywire.log.
	StoreLog bool
	// LogJSON also writes structured JSON lines next to it (needs StoreLog).
	LogJSON bool
	// ForceColor colors the log even when it is not a terminal.
	ForceColor bool
}

Options are the settings a visor process starts with that are not part of its config file: command-line overrides and where logs go. The zero value runs the visor exactly as its config says.

type PairStatus

type PairStatus struct {
	PK          cipher.PubKey `json:"pk"`
	Fingerprint string        `json:"fingerprint"`
	Paired      bool          `json:"paired"`
	Pending     bool          `json:"pending"`
}

PairStatus is the pre-auth view a tab gets of its own standing.

type PingMsg

type PingMsg struct {
	Timestamp time.Time
	PingPk    cipher.PubKey
	Data      []byte
}

PingMsg is used to calculate the ping to a remote visor

type PingRouteRef

type PingRouteRef struct {
	PK    cipher.PubKey
	Index int
}

PingRouteRef identifies a specific route to a peer. Index 0 is the primary/legacy route used by single-route callers; aux routes (1..N-1) are added by callers that establish multiple parallel routes to the same target — currently only `cli visor ping mux-bw`, future mux-aware proxies will join.

The route map is keyed by this struct rather than by bare PK so that N parallel DialPing calls to the same peer can coexist without overwriting each other's conn / route hops. Legacy single-route callers stay PK-only via PingRoutePrimary(pk) or by leaving PingConfig.RouteIndex at its zero value.

func PingRoutePrimary

func PingRoutePrimary(pk cipher.PubKey) PingRouteRef

PingRoutePrimary returns the PingRouteRef for the primary route to a peer. Call sites that don't care about multi-route semantics pass this — keeps the existing single-route fast path unambiguous.

func (PingRouteRef) String

func (r PingRouteRef) String() string

String renders as "<pk>#<index>" — useful for logs and the rpc-grpc dmsg-port handler's per-route debug output.

type PingSizeMsg

type PingSizeMsg struct {
	Size     int  `json:"size"`
	EchoFull bool `json:"echo_full,omitempty"` // If true, server echoes full payload for bandwidth testing
}

PingSizeMsg contains the size of the PingMsg to be sent

type RPC

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

func (*RPC) ARSelfInfo

func (r *RPC) ARSelfInfo(_ *struct{}, out *visorapi.ARSelfRegistration) (err error)

ARSelfInfo returns the visor's own AR registration (STCPR + SUDPH).

func (*RPC) ActiveRoutes

func (r *RPC) ActiveRoutes(_ *struct{}, out *[]visorapi.AppRouteStatus) (err error)

ActiveRoutes returns all active routes with app associations and live stats

func (*RPC) AddApp

func (r *RPC) AddApp(in *visorapi.SetAppAddIn, _ *struct{}) (err error)

AddApp add app to config

func (*RPC) AddHypervisor

func (r *RPC) AddHypervisor(in *cipher.PubKey, _ *struct{}) (err error)

func (*RPC) AddMuxRoute

func (r *RPC) AddMuxRoute(in *visorapi.MuxRouteInput, _ *struct{}) (err error)

AddMuxRoute adds a mux route to an app's active connection

func (*RPC) AddMuxRouteForward

func (r *RPC) AddMuxRouteForward(in *visorapi.MuxRouteInput, _ *struct{}) (err error)

AddMuxRouteForward adds a forward-only leg over the caller-supplied route.

func (*RPC) AddPtyWhitelist

func (r *RPC) AddPtyWhitelist(in *visorapi.AddPtyWhitelistIn, _ *struct{}) (err error)

AddPtyWhitelist is the RPC gateway for Visor.AddPtyWhitelist.

func (*RPC) AddTransport

func (r *RPC) AddTransport(in *visorapi.AddTransportIn, out *visorapi.TransportSummary) (err error)

AddTransport creates a transport for the visor.

func (*RPC) App

func (r *RPC) App(appName *string, reply *appserver.AppState) (err error)

App returns App registered on the Visor.

func (*RPC) AppDirectStreams

func (r *RPC) AppDirectStreams(in *string, out *[]transport.VStreamInfo) (err error)

AppDirectStreams retrieves the live direct (0-hop) streams for the named app.

func (*RPC) AppHelp

func (r *RPC) AppHelp(in *visorapi.AppNameIn, reply *string) (err error)

AppHelp returns the captured `<binary> --help` output for an app.

func (*RPC) ApproveHypervisor

func (r *RPC) ApproveHypervisor(sel *string, out *cipher.PubKey) (err error)

ApproveHypervisor approves a pending key by public key or fingerprint.

func (*RPC) Apps

func (r *RPC) Apps(_ *struct{}, reply *[]*appserver.AppState) (err error)

Apps returns list of Apps registered on the Visor.

func (*RPC) BandwidthTest

func (r *RPC) BandwidthTest(conf visorapi.BandwidthTestConfig, out *visorapi.BandwidthResult) (err error)

BandwidthTest performs a bandwidth test over skywire route.

func (*RPC) CXORefreshFeed

func (r *RPC) CXORefreshFeed(args *visorapi.CXORefreshArgs, out *visorapi.FeedStatus) (err error)

CXORefreshFeed forces a synchronous re-subscribe + first-Root + walk for the named feed. See Visor.CXORefreshFeed for semantics.

func (*RPC) CXOStatus

func (r *RPC) CXOStatus(_ *struct{}, out *[]visorapi.FeedStatus) (err error)

CXOStatus exposes the CXO subscription manager's per-feed state for `skywire cli visor cxo status`. See Visor.CXOStatus for semantics.

func (*RPC) CheckAREntry

func (r *RPC) CheckAREntry(pk *string, out *[]string) (err error)

CheckAREntry checks if a PK is registered in the address resolver.

func (*RPC) ClearMuxWeights

func (r *RPC) ClearMuxWeights(in *visorapi.MuxWeightsInput, out *router.MuxWeightsView) (err error)

ClearMuxWeights releases a per-leg weight pin.

func (*RPC) ClearSkychatPassword

func (r *RPC) ClearSkychatPassword(oldPassword *string, _ *struct{}) (err error)

ClearSkychatPassword removes the skychat password (gate goes off).

func (*RPC) ConnectRawTCP

func (r *RPC) ConnectRawTCP(in *visorapi.ConnectIn, out *uuid.UUID) (err error)

ConnectRawTCP creates a raw TCP connection with the remote visor

func (*RPC) CutAppTunnel

func (r *RPC) CutAppTunnel(in *visorapi.CutAppTunnelIn, seq *uint64) (err error)

CutAppTunnel closes one of an app's tunnels by its route group port.

func (*RPC) DMSGServers

func (r *RPC) DMSGServers(_ *struct{}, out *[]visorapi.DMSGServerInfo) (err error)

DMSGServers returns list of connected DMSG servers with latencies

func (*RPC) DeleteApp

func (r *RPC) DeleteApp(in *visorapi.AppNameIn, _ *struct{}) (err error)

DeleteApp removes an app entry from the launcher config (and stops it first if running).

func (*RPC) DeleteRewardAddress

func (r *RPC) DeleteRewardAddress(_ *struct{}, _ *struct{}) (err error)

DeleteRewardAddress deletes the reward.txt

func (*RPC) DeregisterApp

func (r *RPC) DeregisterApp(procKey *appcommon.ProcKey, _ *struct{}) (err error)

DeregisterApp de registers a App with provided proc key.

func (*RPC) DeregisterService

func (r *RPC) DeregisterService(in *visorapi.DeregisterServiceIn, out *struct{}) (err error)

DeregisterService deregisters services from service discovery

func (*RPC) DeregisterTCPPort

func (r *RPC) DeregisterTCPPort(port *int, _ *struct{}) (err error)

DeregisterTCPPort deregisters the local port that can be accessed by remote visors

func (*RPC) DialDmsgPing

func (r *RPC) DialDmsgPing(pk *cipher.PubKey, _ *struct{}) (err error)

DialDmsgPing dials to a remote visor over dmsg for ping.

func (*RPC) DialDmsgPingViaServer

func (r *RPC) DialDmsgPingViaServer(in *visorapi.DialDmsgPingViaServerIn, _ *struct{}) (err error)

DialDmsgPingViaServer dials to a remote visor over dmsg via a specific server.

func (*RPC) DialPing

func (r *RPC) DialPing(conf visorapi.PingConfig, _ *struct{}) (err error)

DialPing dials to the ping module using the provided pk as a hop.

func (*RPC) DialUDPForward

func (r *RPC) DialUDPForward(in *visorapi.UDPForwardIn, _ *struct{}) (err error)

DialUDPForward starts a client-side faithful-UDP forward (#2607).

func (*RPC) DisableHypervisor

func (r *RPC) DisableHypervisor(persist *bool, _ *struct{}) (err error)

DisableHypervisor stops the hypervisor HTTP server and disconnects remote visors. If persist is true, the change is also written to the config file.

func (*RPC) DisableHypervisorUI

func (r *RPC) DisableHypervisorUI(persist *bool, _ *struct{}) (err error)

DisableHypervisorUI stops only the hypervisor web UI; the DMSG-RPC listener, managed-visor tracking, and hv ls keep working. Persists when persist is true.

func (*RPC) DisconnectRawTCP

func (r *RPC) DisconnectRawTCP(id *uuid.UUID, _ *struct{}) (err error)

DisconnectRawTCP breaks the raw TCP connection with the given id

func (*RPC) DiscoverTransportByID

func (r *RPC) DiscoverTransportByID(id *uuid.UUID, out *transport.Entry) (err error)

DiscoverTransportByID obtains available transports via the transport discovery via a given transport ID.

func (*RPC) DiscoverTransportsByPK

func (r *RPC) DiscoverTransportsByPK(pk *cipher.PubKey, out *[]*transport.Entry) (err error)

DiscoverTransportsByPK obtains available transports via the transport discovery via given public key.

func (*RPC) DmsgBandwidthTest

func (r *RPC) DmsgBandwidthTest(conf visorapi.BandwidthTestConfig, out *visorapi.BandwidthResult) (err error)

DmsgBandwidthTest performs a bandwidth test over dmsg.

func (*RPC) DmsgConnectAll

func (r *RPC) DmsgConnectAll(_ *struct{}, out *visorapi.DmsgConnectAllResult) (err error)

DmsgConnectAll reaches every dmsg server in discovery and ensures a session to each.

func (*RPC) DmsgConverge

func (r *RPC) DmsgConverge(carriers *[]string, out *visorapi.DmsgConvergeResult) (err error)

DmsgConverge optionally sets the dmsg carrier preference (empty = leave as-is) and runs one carrier-convergence pass on the main dmsg client.

func (*RPC) DmsgHTTP

func (r *RPC) DmsgHTTP(req *visorapi.DmsgHTTPRequest, out *visorapi.DmsgHTTPResponse) (err error)

func (*RPC) DmsgPing

func (r *RPC) DmsgPing(conf visorapi.PingConfig, out *[]time.Duration) (err error)

DmsgPing pings over dmsg connection.

func (*RPC) DmsgPingOnce

func (r *RPC) DmsgPingOnce(conf visorapi.PingConfig, out *time.Duration) (err error)

DmsgPingOnce performs a single ping over dmsg connection.

func (*RPC) DmsgPortHits

func (r *RPC) DmsgPortHits(_ *struct{}, out *[]dmsg.PortHit) (err error)

DmsgPortHits returns inbound dmsg stream requests that hit a local port with no listener (dmsg error 306), keyed by (src PK, dst port).

func (*RPC) DmsgPorterDiag

func (r *RPC) DmsgPorterDiag(_ *struct{}, out *netutil.EphemeralDiagResult) (err error)

DmsgPorterDiag returns detailed diagnostics of the RSN's ephemeral port entries.

func (*RPC) DmsgPorterReset

func (r *RPC) DmsgPorterReset(_ *struct{}, out *visorapi.DmsgPorterStatus) (err error)

DmsgPorterReset frees all ephemeral port reservations.

func (*RPC) DmsgPorterStats

func (r *RPC) DmsgPorterStats(_ *struct{}, out *visorapi.DmsgPorterStatus) (err error)

DmsgPorterStats returns ephemeral port reservation counts.

func (*RPC) DmsgProbe

func (r *RPC) DmsgProbe(req *visorapi.DmsgProbeRequest, out *bool) (err error)

DmsgProbe checks dmsg reachability of a remote PK on a given port.

func (*RPC) DmsgProbeReason

func (r *RPC) DmsgProbeReason(req *visorapi.DmsgProbeRequest, out *visorapi.DmsgProbeReasonResponse) (err error)

DmsgProbeReason checks dmsg reachability and reports the failure reason.

func (*RPC) DmsgProbeViaServer

func (r *RPC) DmsgProbeViaServer(req *visorapi.DmsgProbeViaServerRequest, out *bool) (err error)

DmsgProbeViaServer probes dmsg reachability forced through a specific server.

func (*RPC) DmsgPtyExec

func (r *RPC) DmsgPtyExec(args *visorapi.DmsgPtyExecArgs, out *pty.CommandExecResult) (err error)

DmsgPtyExec runs a one-shot command on a remote visor via the embedded dmsgpty host (see Visor.DmsgPtyExec).

func (*RPC) DmsgReconnect

func (r *RPC) DmsgReconnect(_ *struct{}, out *int) (err error)

DmsgReconnect forces DMSG session reconnection.

func (*RPC) DmsgSessions

func (r *RPC) DmsgSessions(_ *struct{}, out *visorapi.DmsgClientSessions) (err error)

DmsgSessions returns the current dmsg session state of every dmsg client running inside the visor.

func (*RPC) DmsgSetMinSessions

func (r *RPC) DmsgSetMinSessions(in *int, _ *struct{}) (err error)

DmsgSetMinSessions updates the minimum DMSG session count.

func (*RPC) DoCustomSetting

func (r *RPC) DoCustomSetting(in *visorapi.SetAppMapIn, _ *struct{}) (err error)

DoCustomSetting set custom setting to apps arguments

func (*RPC) EmbeddedProxies

func (r *RPC) EmbeddedProxies(_ *struct{}, out *visorapi.EmbeddedProxiesStatus) (err error)

EmbeddedProxies returns the runtime state of the in-process resolving proxies. See Visor.EmbeddedProxies for semantics.

func (*RPC) EmbeddedServiceControl added in v1.3.100

func (r *RPC) EmbeddedServiceControl(in *visorapi.EmbeddedServiceControlArgs, _ *struct{}) (err error)

EmbeddedServiceControl stops, starts or restarts an embedded service.

func (*RPC) EnableHypervisor

func (r *RPC) EnableHypervisor(persist *bool, _ *struct{}) (err error)

EnableHypervisor starts the hypervisor HTTP server and DMSG listener. If persist is true, the change is also written to the config file.

func (*RPC) EnableHypervisorUI

func (r *RPC) EnableHypervisorUI(persist *bool, _ *struct{}) (err error)

EnableHypervisorUI starts only the hypervisor web UI; the DMSG-RPC listener and managed-visor tracking are unaffected. Persists when persist is true.

func (*RPC) FetchCXO

func (r *RPC) FetchCXO(args *visorapi.FetchCXOArgs, out *visorapi.FetchCXOResult) (err error)

FetchCXO probes the visor's lazy-on-demand CXO subscriber for the requested (feed, path) and returns the cached payload or a miss reason. Used by the CLI's FetchServiceURL to add a CXO step at the front of the RPC→DMSG→HTTP chain — when the visor already has a fresh subscription the CLI can skip the network round-trip entirely.

func (*RPC) FetchServiceData

func (r *RPC) FetchServiceData(in *visorapi.FetchServiceDataIn, out *[]byte) (err error)

FetchServiceData proxies a GET request to a deployment service.

func (*RPC) GetAppConnectionsSummary

func (r *RPC) GetAppConnectionsSummary(appName *string, out *[]appserver.ConnectionSummary) (err error)

GetAppConnectionsSummary returns connections stats for the app.

func (*RPC) GetAppError

func (r *RPC) GetAppError(appName *string, out *string) (err error)

GetAppError gets app runtime error.

func (*RPC) GetAppSettings

func (r *RPC) GetAppSettings(appName *string, out *visorapi.AppSettings) (err error)

GetAppSettings returns the live tuning knobs held for an app.

func (*RPC) GetAppStats

func (r *RPC) GetAppStats(appName *string, out *appserver.AppStats) (err error)

GetAppStats gets app runtime statistics.

func (*RPC) GetCalculateRoutes

func (r *RPC) GetCalculateRoutes(_ *struct{}, out *bool) (err error)

GetCalculateRoutes gets calculate_routes from visor's routing config

func (*RPC) GetConfigPath

func (r *RPC) GetConfigPath(_ *struct{}, out *string) (err error)

GetConfigPath returns the filesystem path the visor loaded its config from.

func (*RPC) GetDmsgPingServerPK

func (r *RPC) GetDmsgPingServerPK(pk *cipher.PubKey, out *cipher.PubKey) (err error)

GetDmsgPingServerPK returns the DMSG server PK used for a ping connection.

func (*RPC) GetIsPublic

func (r *RPC) GetIsPublic(_ *struct{}, out *bool) (err error)

GetIsPublic returns whether the visor is configured as public.

func (*RPC) GetMinHops

func (r *RPC) GetMinHops(_ *struct{}, out *uint16) (err error)

GetMinHops returns the visor's configured routing.min_hops value.

func (*RPC) GetPersistentTransports

func (r *RPC) GetPersistentTransports(_ *struct{}, out *[]transport.PersistentTransports) (err error)

GetPersistentTransports gets persistent_transports from visor's routing config

func (*RPC) GetPreferredDmsgServer

func (r *RPC) GetPreferredDmsgServer(remotePK *cipher.PubKey, out *cipher.PubKey) (err error)

GetPreferredDmsgServer returns the lowest-latency DMSG server shared with a remote visor.

func (*RPC) GetRSNHealth

func (r *RPC) GetRSNHealth(_ *struct{}, out *[]visorapi.NodeHealth) (err error)

func (*RPC) GetRemoteDmsgServers

func (r *RPC) GetRemoteDmsgServers(pk *cipher.PubKey, out *[]cipher.PubKey) (err error)

GetRemoteDmsgServers returns the DMSG servers a remote visor is connected to.

func (*RPC) GetRewardAddress

func (r *RPC) GetRewardAddress(_ *struct{}, out *string) (err error)

GetRewardAddress reads the reward address from reward.txt

func (*RPC) GetRouteSetupNodesSorted

func (r *RPC) GetRouteSetupNodesSorted(_ *struct{}, out *[]cipher.PubKey) (err error)

func (*RPC) GetRouterDialSettings

func (r *RPC) GetRouterDialSettings(_ *struct{}, out *visorapi.RouterDialSettings) (err error)

GetRouterDialSettings returns the live dial-time router knobs.

func (*RPC) GetRouterSettings

func (r *RPC) GetRouterSettings(_ *struct{}, out *visorapi.RouterSettings) (err error)

GetRouterSettings returns the unified runtime router knobs.

func (*RPC) GetRuntimeConfig

func (r *RPC) GetRuntimeConfig(_ *struct{}, out *[]byte) (err error)

GetRuntimeConfig returns the visor's running config as JSON.

func (*RPC) GetTPSHealth

func (r *RPC) GetTPSHealth(_ *struct{}, out *[]visorapi.NodeHealth) (err error)

func (*RPC) GetTransportLogs

func (r *RPC) GetTransportLogs(days *int, out *[]visorapi.TransportLogEntry) (err error)

GetTransportLogs returns transport log entries from the last N days.

func (*RPC) GetTransportSetupNodes

func (r *RPC) GetTransportSetupNodes(_ *struct{}, out *[]cipher.PubKey) (err error)

func (*RPC) GetTransportSetupNodesSorted

func (r *RPC) GetTransportSetupNodesSorted(_ *struct{}, out *[]cipher.PubKey) (err error)

func (*RPC) GoroutineDump

func (r *RPC) GoroutineDump(_ *struct{}, out *string) (err error)

GoroutineDump returns every goroutine's stack (pprof debug=2 text).

func (*RPC) GroupAddMember

func (r *RPC) GroupAddMember(req *visorapi.GroupAddMemberRequest, out *visorapi.GroupInfo) (err error)

GroupAddMember extends the allowlist + persisted member list.

func (*RPC) GroupApproveJoin

func (r *RPC) GroupApproveJoin(req *visorapi.GroupPeerRequest, out *visorapi.GroupInfo) (err error)

GroupApproveJoin admits a queued requester.

func (*RPC) GroupAskAgain

func (r *RPC) GroupAskAgain(id *string, out *visorapi.GroupInfo) (err error)

GroupAskAgain re-submits a declined join request (the UI's "ask again").

func (*RPC) GroupBanMember

func (r *RPC) GroupBanMember(req *visorapi.GroupPeerRequest, out *visorapi.GroupInfo) (err error)

GroupBanMember bars a peer from the group.

func (*RPC) GroupCatalog

func (r *RPC) GroupCatalog(host *cipher.PubKey, out *visorapi.GroupCatalogResponse) (err error)

GroupCatalog asks a visor what groups and channels it publishes. A zero host means this visor.

func (*RPC) GroupCreate

func (r *RPC) GroupCreate(req *visorapi.GroupCreateArgs, out *visorapi.GroupCreateResponse) (err error)

GroupCreate constructs a new owner-side group on this visor and returns the persisted info + the invite link.

func (*RPC) GroupDelete

func (r *RPC) GroupDelete(id *string, _ *struct{}) (err error)

GroupDelete tears down an owner-side group.

func (*RPC) GroupDemoteAdmin

func (r *RPC) GroupDemoteAdmin(req *visorapi.GroupPromoteAdminRequest, out *visorapi.GroupInfo) (err error)

GroupDemoteAdmin revokes roster authority from PK on the named group. Refuses to demote the founder (immutable recovery anchor).

func (*RPC) GroupDenyJoin

func (r *RPC) GroupDenyJoin(req *visorapi.GroupPeerRequest, _ *struct{}) (err error)

GroupDenyJoin declines a queued request.

func (*RPC) GroupFileKey

func (r *RPC) GroupFileKey(req *visorapi.GroupFileKeyArgs, out *visorapi.GroupFileKeyResult) (err error)

GroupFileKey returns the per-file keys that seal and open one group attachment. The group key itself is not part of the response — see Visor.GroupFileKey.

On the exposure: anyone who can reach this RPC can already call GroupPoll, which hands back decrypted message bodies, so a per-file attachment key grants strictly less than what the same caller has. What the scoping does buy is that the answer cannot be replayed against any OTHER file, or against the group's message history.

func (*RPC) GroupGet

func (r *RPC) GroupGet(id *string, out *visorapi.GroupInfo) (err error)

GroupGet returns one group's info by ID.

func (*RPC) GroupHistory

func (r *RPC) GroupHistory(req *visorapi.GroupHistoryRequest, out *[]visorapi.GroupMessage) (err error)

GroupHistory returns persisted group messages for a given group. Returns ErrGroupHistoryDisabled when persistence is off — operators enable it via Skychat.GroupHistoryDB in the visor config. Unlike GroupPoll (which drains the in-memory ring), this RPC reads from disk and survives visor restarts.

func (*RPC) GroupHistoryGroups

func (r *RPC) GroupHistoryGroups(_ *struct{}, out *[]string) (err error)

GroupHistoryGroups returns every group ID that has stored messages. Returns ErrGroupHistoryDisabled when persistence is off.

func (*RPC) GroupHistoryPage

func (r *RPC) GroupHistoryPage(req *visorapi.GroupHistoryPageArgs, out *[]visorapi.GroupMessage) (err error)

GroupHistoryPage is GroupHistory with a backward cursor — up to Limit messages strictly older than Before, newest last. A zero Before asks for the newest page, so the first request and every "older, please" request have the same shape.

func (*RPC) GroupInvite

func (r *RPC) GroupInvite(id *string, out *string) (err error)

GroupInvite returns a freshly-encoded invite link for an owner-side group.

func (*RPC) GroupJoin

func (r *RPC) GroupJoin(req *visorapi.GroupJoinArgs, out *visorapi.GroupInfo) (err error)

GroupJoin accepts an invite link and registers a member-side record.

func (*RPC) GroupJoinRequests

func (r *RPC) GroupJoinRequests(id *string, out *[]visorapi.GroupJoinRequest) (err error)

GroupJoinRequests returns the admission queue for a group.

func (*RPC) GroupLeave

func (r *RPC) GroupLeave(id *string, _ *struct{}) (err error)

GroupLeave is the member-side counterpart of GroupDelete.

func (*RPC) GroupList

func (r *RPC) GroupList(_ *struct{}, out *[]visorapi.GroupInfo) (err error)

GroupList returns every persisted group on this visor.

func (*RPC) GroupMuteMember

func (r *RPC) GroupMuteMember(req *visorapi.GroupPeerRequest, out *visorapi.GroupInfo) (err error)

GroupMuteMember restricts a peer from posting.

func (*RPC) GroupPoll

func (r *RPC) GroupPoll(req *visorapi.GroupPollRequest, out *[]visorapi.GroupMessage) (err error)

GroupPoll drains inbound group messages with TS strictly after Since.

func (*RPC) GroupPromoteAdmin

func (r *RPC) GroupPromoteAdmin(req *visorapi.GroupPromoteAdminRequest, out *visorapi.GroupInfo) (err error)

GroupPromoteAdmin grants roster authority to PK on the named group. Callable by any existing admin on this visor.

func (*RPC) GroupRefreshMeta

func (r *RPC) GroupRefreshMeta(id *string, out *visorapi.GroupInfo) (err error)

GroupRefreshMeta re-reads a group's display metadata from its founding visor.

func (*RPC) GroupRemoveMember

func (r *RPC) GroupRemoveMember(req *visorapi.GroupPeerRequest, out *visorapi.GroupInfo) (err error)

GroupRemoveMember evicts a peer from the roster.

func (*RPC) GroupResolve

func (r *RPC) GroupResolve(req *visorapi.GroupResolveArgs, out *visorapi.GroupResolveResult) (err error)

GroupResolve reports what a skychat address points at — a person, or a group/channel and what joining it involves.

func (*RPC) GroupRotateKey

func (r *RPC) GroupRotateKey(id *string, out *visorapi.GroupInfo) (err error)

GroupRotateKey mints a new key for an encrypted group and distributes it to every current member, sealed per member.

func (*RPC) GroupSend

func (r *RPC) GroupSend(req *visorapi.GroupSendArgs, _ *struct{}) (err error)

GroupSend publishes one message into the named group's feed. Owner-side only in v1.

func (*RPC) GroupSetJoinPoW

func (r *RPC) GroupSetJoinPoW(req *visorapi.GroupJoinPoWRequest, out *visorapi.GroupInfo) (err error)

GroupSetJoinPoW sets how much proof of work a join request must carry.

func (*RPC) GroupSetListed

func (r *RPC) GroupSetListed(req *visorapi.GroupSetListedRequest, out *visorapi.GroupInfo) (err error)

GroupSetListed publishes or un-publishes a group in this visor's discovery catalog.

func (*RPC) GroupSetMeta

func (r *RPC) GroupSetMeta(req *visorapi.GroupSetMetaArgs, out *visorapi.GroupInfo) (err error)

GroupSetMeta updates a group's display metadata (name and/or picture).

func (*RPC) GroupSetPeerBackfill

func (r *RPC) GroupSetPeerBackfill(req *visorapi.GroupPeerBackfillRequest, out *visorapi.GroupInfo) (err error)

GroupSetPeerBackfill sets the group's backfill-from-any-member policy.

func (*RPC) GroupSetReadOnly

func (r *RPC) GroupSetReadOnly(req *visorapi.GroupReadOnlyRequest, out *visorapi.GroupInfo) (err error)

GroupSetReadOnly suspends or resumes posting for non-admins.

func (*RPC) GroupUnbanMember

func (r *RPC) GroupUnbanMember(req *visorapi.GroupPeerRequest, out *visorapi.GroupInfo) (err error)

GroupUnbanMember lifts a ban.

func (*RPC) GroupUnmuteMember

func (r *RPC) GroupUnmuteMember(req *visorapi.GroupPeerRequest, out *visorapi.GroupInfo) (err error)

GroupUnmuteMember lifts a posting restriction.

func (*RPC) GroupUnsend

func (r *RPC) GroupUnsend(req *visorapi.GroupUnsendArgs, _ *struct{}) (err error)

GroupUnsend deletes a message the local visor published, by UnixNano TS.

func (*RPC) GrowMuxFromPool

func (r *RPC) GrowMuxFromPool(in *visorapi.MuxRouteInput, out *int) (err error)

GrowMuxFromPool grows an app's tunnel by `legs` legs taken from its standby pool

func (*RPC) GrowMuxRoute

func (r *RPC) GrowMuxRoute(in *visorapi.MuxRouteInput, out *int) (err error)

GrowMuxRoute adds disjoint legs to an app's active rg up to a target count

func (*RPC) HVAddTransport

func (r *RPC) HVAddTransport(in *visorapi.HVAddTransportArgs, out *visorapi.TransportSummary) (err error)

HVAddTransport creates a new transport on a remote visor.

func (*RPC) HVDeregisterTCPPort

func (r *RPC) HVDeregisterTCPPort(in *visorapi.HVTCPPortArgs, _ *struct{}) (err error)

HVDeregisterTCPPort deregisters a skynet TCP port on a remote visor.

func (*RPC) HVDmsgConnectAll

func (r *RPC) HVDmsgConnectAll(pk *cipher.PubKey, out *visorapi.DmsgConnectAllResult) (err error)

HVDmsgConnectAll triggers connect-all on a remote visor.

func (*RPC) HVDmsgSessions

func (r *RPC) HVDmsgSessions(pk *cipher.PubKey, out *visorapi.DmsgClientSessions) (err error)

HVDmsgSessions returns the per-client dmsg sessions snapshot of a remote visor.

func (*RPC) HVEmbeddedProxies

func (r *RPC) HVEmbeddedProxies(pk *cipher.PubKey, out *visorapi.EmbeddedProxiesStatus) (err error)

HVEmbeddedProxies returns embedded resolving proxy status from a remote visor.

func (*RPC) HVListDirectVisors

func (r *RPC) HVListDirectVisors(_ *struct{}, out *[]visorapi.HVVisorEntry) (err error)

HVListDirectVisors returns summaries of visors DIRECTLY connected to this hypervisor (no sub-hypervisor merging). Powers the tree builder's per-sub-hypervisor section.

func (*RPC) HVListForwardedPorts

func (r *RPC) HVListForwardedPorts(pk *cipher.PubKey, out *[]visorapi.ForwardedPort) (err error)

HVListForwardedPorts returns forwarded ports on a remote visor.

func (*RPC) HVListTCPPorts

func (r *RPC) HVListTCPPorts(pk *cipher.PubKey, out *[]int) (err error)

HVListTCPPorts returns registered skynet TCP ports on a remote visor.

func (*RPC) HVListVisors

func (r *RPC) HVListVisors(_ *struct{}, out *[]visorapi.HVVisorEntry) (err error)

HVListVisors returns summaries of all visors connected to this hypervisor.

func (*RPC) HVListVisorsTree

func (r *RPC) HVListVisorsTree(_ *struct{}, out *visorapi.HVVisorTree) (err error)

HVListVisorsTree returns the structured tree of hypervisor sections for the UI's main node list.

func (*RPC) HVLogsSince

func (r *RPC) HVLogsSince(in *visorapi.HVLogsArgs, out *[]string) (err error)

HVLogsSince fetches recent app logs from a remote visor.

func (*RPC) HVRegisterForwardedPort

func (r *RPC) HVRegisterForwardedPort(in *visorapi.HVForwardedPortArgs, _ *struct{}) (err error)

HVRegisterForwardedPort registers a forwarded port on a remote visor.

func (*RPC) HVRegisterTCPPort

func (r *RPC) HVRegisterTCPPort(in *visorapi.HVTCPPortArgs, _ *struct{}) (err error)

HVRegisterTCPPort registers a skynet TCP port on a remote visor.

func (*RPC) HVReload

func (r *RPC) HVReload(pk *cipher.PubKey, _ *struct{}) (err error)

HVReload reloads a remote visor.

func (*RPC) HVRemoveRoutingRule

func (r *RPC) HVRemoveRoutingRule(in *visorapi.HVRoutingRuleArgs, _ *struct{}) (err error)

HVRemoveRoutingRule deletes a routing rule on a remote visor.

func (*RPC) HVRemoveTransport

func (r *RPC) HVRemoveTransport(in *visorapi.HVTransportArgs, _ *struct{}) (err error)

HVRemoveTransport deletes a transport on a remote visor.

func (*RPC) HVServiceHealth

func (r *RPC) HVServiceHealth(pk *cipher.PubKey, out *[]visorapi.ServiceHealthEntry) (err error)

HVServiceHealth returns deployment service health for a remote visor.

func (*RPC) HVSetAutoStart

func (r *RPC) HVSetAutoStart(in *visorapi.HVAutostartArgs, _ *struct{}) (err error)

HVSetAutoStart toggles autostart on a remote visor.

func (*RPC) HVSetCalculateRoutes

func (r *RPC) HVSetCalculateRoutes(in *visorapi.HVCalcRoutesArgs, _ *struct{}) (err error)

HVSetCalculateRoutes toggles calculate_routes on a remote visor.

func (*RPC) HVSetDmsgSessionsCount

func (r *RPC) HVSetDmsgSessionsCount(in *visorapi.HVDmsgSessionsArgs, out *visorapi.DmsgConnectAllResult) (err error)

HVSetDmsgSessionsCount persists sessions_count and triggers connect-all on a remote visor.

func (*RPC) HVSetEmbeddedProxyEnabled

func (r *RPC) HVSetEmbeddedProxyEnabled(in *visorapi.HVProxyArgs, _ *struct{}) (err error)

HVSetEmbeddedProxyEnabled flips a resolver on or off on a remote visor.

func (*RPC) HVSetEmbeddedProxyUpstream

func (r *RPC) HVSetEmbeddedProxyUpstream(in *visorapi.HVProxyArgs, _ *struct{}) (err error)

HVSetEmbeddedProxyUpstream sets a resolver's SOCKS5 fallthrough on a remote visor.

func (*RPC) HVSetMinHops

func (r *RPC) HVSetMinHops(in *visorapi.HVMinHopsArgs, _ *struct{}) (err error)

HVSetMinHops sets min_hops on a remote visor.

func (*RPC) HVSetPublicAutoconnect

func (r *RPC) HVSetPublicAutoconnect(in *visorapi.HVAutoconnectArgs, _ *struct{}) (err error)

HVSetPublicAutoconnect toggles public_autoconnect on a remote visor.

func (*RPC) HVSetRewardAddress

func (r *RPC) HVSetRewardAddress(in *visorapi.HVRewardArgs, out *string) (err error)

HVSetRewardAddress sets the reward address on a remote visor.

func (*RPC) HVShutdown

func (r *RPC) HVShutdown(pk *cipher.PubKey, _ *struct{}) (err error)

HVShutdown shuts down a remote visor.

func (*RPC) HVStartApp

func (r *RPC) HVStartApp(in *visorapi.HVAppArgs, _ *struct{}) (err error)

HVStartApp starts an app on a remote visor.

func (*RPC) HVStopApp

func (r *RPC) HVStopApp(in *visorapi.HVAppArgs, _ *struct{}) (err error)

HVStopApp stops an app on a remote visor.

func (*RPC) HVUpdateForwardedPort

func (r *RPC) HVUpdateForwardedPort(in *visorapi.HVForwardedPortArgs, _ *struct{}) (err error)

HVUpdateForwardedPort updates a forwarded port on a remote visor.

func (*RPC) HVVisorSummary

func (r *RPC) HVVisorSummary(pk *cipher.PubKey, out *visorapi.Summary) (err error)

HVVisorSummary returns a detailed summary of a specific remote visor.

func (*RPC) Health

func (r *RPC) Health(_ *struct{}, out *visorapi.HealthInfo) (err error)

func (*RPC) HostBridgeConnect added in v1.3.101

func (r *RPC) HostBridgeConnect(url *string, _ *struct{}) (err error)

HostBridgeConnect connects the visor to a host bridge.

func (*RPC) HostBridgeDisconnect added in v1.3.101

func (r *RPC) HostBridgeDisconnect(_ *struct{}, _ *struct{}) (err error)

HostBridgeDisconnect ends the session to the host bridge.

func (*RPC) HostBridgeForward added in v1.3.101

func (r *RPC) HostBridgeForward(in *visorapi.HostBridgeForwardArgs, out *visorapi.HostBridgeForward) (err error)

HostBridgeForward forwards a port of the bridge's host to the visor.

func (*RPC) HostBridgeStatus added in v1.3.101

func (r *RPC) HostBridgeStatus(_ *struct{}, out *visorapi.HostBridgeStatus) (err error)

HostBridgeStatus reports the session to the host bridge.

func (*RPC) HostBridgeUnforward added in v1.3.101

func (r *RPC) HostBridgeUnforward(host *string, _ *struct{}) (err error)

HostBridgeUnforward stops a forward.

func (*RPC) HostStats

func (r *RPC) HostStats(_ *struct{}, out *visorapi.HostStatsInfo) (err error)

HostStats returns a host-level resource snapshot (CPU%, memory, disk, network, plus the visor process slice). Backs the hypervisor UI's Resource Monitor panel.

func (*RPC) IsDMSGClientReady

func (r *RPC) IsDMSGClientReady(_ *struct{}, out *bool) (err error)

IsDMSGClientReady return status of dmsg client

func (*RPC) IsHypervisorAuthEnabled

func (r *RPC) IsHypervisorAuthEnabled(_ *struct{}, out *bool) (err error)

IsHypervisorAuthEnabled returns whether the hypervisor web UI requires a login.

func (*RPC) IsHypervisorEnabled

func (r *RPC) IsHypervisorEnabled(_ *struct{}, out *bool) (err error)

IsHypervisorEnabled returns whether the hypervisor is currently serving.

func (*RPC) IsHypervisorUIServing

func (r *RPC) IsHypervisorUIServing(_ *struct{}, out *bool) (err error)

IsHypervisorUIServing returns whether the hypervisor web UI is serving.

func (*RPC) IsStartupComplete

func (r *RPC) IsStartupComplete(_ *struct{}, out *bool) (err error)

Health returns health information about the visor IsStartupComplete returns whether the visor has finished initializing all modules.

func (*RPC) IsSuspended

func (r *RPC) IsSuspended(_ *struct{}, out *bool) (err error)

IsSuspended reports whether the visor is currently suspended.

func (*RPC) KillApp

func (r *RPC) KillApp(name *string, _ *struct{}) (err error)

KillApp kill App with provided name.

func (*RPC) ListCXOFeeds

func (r *RPC) ListCXOFeeds(_ *struct{}, out *[]logserver.CXOFeedEntry) (err error)

ListCXOFeeds returns the current set of feeds (system + user). Mirrors what the dmsghttp logserver exposes at /feeds for out-of-band discovery.

func (*RPC) ListForwardedPorts

func (r *RPC) ListForwardedPorts(_ *struct{}, out *[]visorapi.ForwardedPort) (err error)

ListForwardedPorts returns all forwarded ports with metadata.

func (*RPC) ListRawTCP

func (r *RPC) ListRawTCP(_ *struct{}, out *map[uuid.UUID]*appnet.RawTCPForwardConn) (err error)

ListRawTCP returns all the ongoing raw TCP skyforwarding connections

func (*RPC) ListTCPPorts

func (r *RPC) ListTCPPorts(_ *struct{}, out *[]int) (err error)

ListTCPPorts lists all the local por that can be accessed by remote visors

func (*RPC) ListUDPForwards

func (r *RPC) ListUDPForwards(_ *struct{}, out *[]int) (err error)

ListUDPForwards lists active client-side faithful-UDP forwards.

func (*RPC) LocalTransportStats

func (r *RPC) LocalTransportStats(_ *struct{}, out *visorapi.LocalTransportStatsResponse) (err error)

LocalTransportStats returns the visor's local per-transport bandwidth + latency rollup from the bbolt stats store.

func (*RPC) LocalUptimeStats

func (r *RPC) LocalUptimeStats(args *visorapi.LocalUptimeArgs, out *visorapi.LocalUptimeResponse) (err error)

LocalUptimeStats returns the visor's tier-uptime bitmaps from the bbolt stats store — process / dmsg / skynet, 5-minute resolution for the requested window. Mirror of /stats/uptime on the logserver, reachable through the hypervisor RPC chain so the hvui can fetch it without per-visor HTTP calls.

func (*RPC) LogsSince

func (r *RPC) LogsSince(in *visorapi.AppLogsRequest, out *[]string) (err error)

LogsSince returns all logs from an specific app since the timestamp

func (*RPC) MailAttachment

func (r *RPC) MailAttachment(in *visorapi.MailAttachmentRequest, out *skymail.AttachmentData) (err error)

MailAttachment decodes one attachment. See Visor.MailAttachment.

func (*RPC) MailDelete

func (r *RPC) MailDelete(in *visorapi.MailMessageRequest, _ *struct{}) (err error)

MailDelete removes one message. See Visor.MailDelete.

func (*RPC) MailList

func (r *RPC) MailList(folder *string, out *[]skymail.Summary) (err error)

MailList lists a folder. See Visor.MailList.

func (*RPC) MailRaw

func (r *RPC) MailRaw(in *visorapi.MailMessageRequest, out *[]byte) (err error)

MailRaw returns one message as stored. See Visor.MailRaw.

func (*RPC) MailRead

func (r *RPC) MailRead(in *visorapi.MailMessageRequest, out *skymail.Rendered) (err error)

MailRead renders one message. See Visor.MailRead.

func (*RPC) MailSend

func (r *RPC) MailSend(in *skymail.Outgoing, out *skymail.SendResult) (err error)

MailSend sends a message. See Visor.MailSend. A send that reached no recipient still answers with its per-recipient reasons: net/rpc drops the reply of a call that returns an error, and the reasons are the useful part, so only a failure with no result is returned as one.

func (*RPC) MailSetSettings

func (r *RPC) MailSetSettings(in *visorapi.MailSettingsWire, _ *struct{}) (err error)

MailSetSettings changes the mailbox settings. See Visor.MailSetSettings.

func (*RPC) MailSetWhitelist

func (r *RPC) MailSetWhitelist(in *[]cipher.PubKey, _ *struct{}) (err error)

MailSetWhitelist replaces the mailbox whitelist. See Visor.MailSetWhitelist.

func (*RPC) MailStatus

func (r *RPC) MailStatus(_ *struct{}, out *visorapi.MailStatus) (err error)

MailStatus reports the mailbox state. See Visor.MailStatus.

func (*RPC) MuxWeights

func (r *RPC) MuxWeights(in *visorapi.MuxWeightsInput, out *router.MuxWeightsView) (err error)

MuxWeights reports the per-leg weights and scheduler mode in force.

func (*RPC) NetworkView

func (r *RPC) NetworkView(_ *struct{}, out *visorapi.NetworkViewResponse) (err error)

NetworkView returns the SD/TPD/UT-aggregated network table that `cli sd` prints. Backs the hypervisor UI's Network tab.

func (*RPC) NewPairCode

func (r *RPC) NewPairCode(ttl *time.Duration, out *visorapi.PairCode) (err error)

NewPairCode mints a one-time pairing code.

func (*RPC) Overview

func (r *RPC) Overview(_ *struct{}, out *visorapi.Overview) (err error)

Overview provides a overview of the AppNode.

func (*RPC) PairAdd

func (r *RPC) PairAdd(req *visorapi.PairAddRequest, _ *struct{}) (err error)

PairAdd creates a pair record and brings up the local publisher / subscriber.

func (*RPC) PairDelete

func (r *RPC) PairDelete(req *visorapi.PairDeleteRequest, _ *struct{}) (err error)

PairDelete retracts a previously sent message from the pair feed.

func (*RPC) PairList

func (r *RPC) PairList(_ *struct{}, out *[]visorapi.PairInfo) (err error)

PairList returns every persisted pair (pending / active / revoked).

func (*RPC) PairMarkActive

func (r *RPC) PairMarkActive(peerPK *cipher.PubKey, _ *struct{}) (err error)

PairMarkActive promotes a pending pair to active.

func (*RPC) PairPoll

func (r *RPC) PairPoll(req *visorapi.PairPollRequest, out *[]visorapi.PairMessage) (err error)

PairPoll drains inbound pair messages with TS strictly after Since.

func (*RPC) PairRemove

func (r *RPC) PairRemove(peerPK *cipher.PubKey, _ *struct{}) (err error)

PairRemove tears down the pair and marks the record revoked.

func (*RPC) PairSend

func (r *RPC) PairSend(req *visorapi.PairSendRequest, out *string) (err error)

PairSend publishes one message into the pair feed, replying with the new message's id so the caller can later retract it.

func (*RPC) PendingHypervisors

func (r *RPC) PendingHypervisors(_ *struct{}, out *[]visorapi.PendingHypervisor) (err error)

PendingHypervisors lists peers waiting to be approved as hypervisors.

func (*RPC) Ping

func (r *RPC) Ping(conf visorapi.PingConfig, out *[]time.Duration) (err error)

Ping pings the connected route via DialPing.

func (*RPC) PingOnce

func (r *RPC) PingOnce(conf visorapi.PingConfig, out *time.Duration) (err error)

PingOnce performs a single ping on the connected route.

func (*RPC) Ports

func (r *RPC) Ports(_ *struct{}, out *map[string]visorapi.PortDetail) (err error)

Ports return list of all ports used by visor services and apps

func (*RPC) ProfileFetch

func (r *RPC) ProfileFetch(pk *cipher.PubKey, out *visorapi.Profile) (err error)

ProfileFetch asks the visor at pk who it is. A zero key means this visor.

func (*RPC) ProfileGet

func (r *RPC) ProfileGet(_ *struct{}, out *visorapi.Profile) (err error)

ProfileGet returns what this visor publishes about itself.

func (*RPC) ProfileSet

func (r *RPC) ProfileSet(req *visorapi.ProfileSetArgs, out *visorapi.Profile) (err error)

ProfileSet writes this visor's published profile and returns the stored result.

func (*RPC) ProxyServers

func (r *RPC) ProxyServers(vc *visorapi.FilterServersIn, out *[]servicedisc.Service) (err error)

ProxyServers gets available socks5 proxy servers from service discovery URL

func (*RPC) PublicAutoconnectStatus

func (r *RPC) PublicAutoconnectStatus(_ *struct{}, out *bool) (err error)

PublicAutoconnectStatus returns whether public autoconnect is running

func (*RPC) RecentAppLog

func (r *RPC) RecentAppLog(in *visorapi.RecentAppLogRequest, out *[]string) (err error)

RecentAppLog returns the recent app-scoped route/transport events + log lines captured in the log broadcaster's per-app ring.

func (*RPC) RegisterApp

func (r *RPC) RegisterApp(procConf *appcommon.ProcConfig, reply *appcommon.ProcKey) (err error)

RegisterApp registers a App with provided proc config.

func (*RPC) RegisterCXOFeed

func (r *RPC) RegisterCXOFeed(req *visorapi.RegisterCXOFeedRequest, _ *struct{}) (err error)

RegisterCXOFeed creates a new user-published CXO TreeStore feed listening on dmsgPort under the visor's PK. The feed is reachable from any peer that subscribes to (visor PK, dmsgPort) over DMSG.

func (*RPC) RegisterForwardedPort

func (r *RPC) RegisterForwardedPort(p *visorapi.ForwardedPort, _ *struct{}) (err error)

RegisterForwardedPort registers a port with full metadata.

func (*RPC) RegisterTCPPort

func (r *RPC) RegisterTCPPort(port *int, _ *struct{}) (err error)

RegisterTCPPort registers the local port to be accessed by remote visors

func (*RPC) RehomeTunnelLeg

func (r *RPC) RehomeTunnelLeg(in *visorapi.MuxRehomeInput, _ *struct{}) (err error)

RehomeTunnelLeg adopts a standby tunnel's chain into an active one as a leg.

func (*RPC) ReinitiateModule

func (r *RPC) ReinitiateModule(module string, _ *struct{}) (err error)

ReinitiateModule reinitiate/restart modules

func (*RPC) Reload

func (r *RPC) Reload(_ *struct{}, _ *struct{}) (err error)

Reload reloads the config - without restarting the visor

func (*RPC) RemoteVisors

func (r *RPC) RemoteVisors(_ *struct{}, out *[]string) (err error)

RemoteVisors return connected remote visors

func (*RPC) RemoveAllHypervisors

func (r *RPC) RemoveAllHypervisors(_ *struct{}, out *int) (err error)

RemoveAllHypervisors tears down every runtime-added hypervisor connection on this visor. Returns the count disconnected.

func (*RPC) RemoveAllTransports

func (r *RPC) RemoveAllTransports(_ *struct{}, _ *struct{}) (err error)

RemoveAllTransports removes all Transports from the visor.

func (*RPC) RemoveHypervisor

func (r *RPC) RemoveHypervisor(in *cipher.PubKey, _ *struct{}) (err error)

RemoveHypervisor tears down a runtime-added hypervisor connection by PK. Idempotent: succeeds with nil if the PK is not currently a runtime-added hypervisor on this visor (covers double-rm, rm of a config-loaded hypervisor, and rm of an already-disconnected PK).

func (*RPC) RemoveMuxRoute

func (r *RPC) RemoveMuxRoute(in *visorapi.MuxRouteInput, _ *struct{}) (err error)

RemoveMuxRoute removes a mux route from an app's active connection

func (*RPC) RemoveRoutingRule

func (r *RPC) RemoveRoutingRule(key *routing.RouteID, _ *struct{}) (err error)

RemoveRoutingRule removes a RoutingRule based on given RouteID key.

func (*RPC) RemoveTransport

func (r *RPC) RemoveTransport(tid *uuid.UUID, _ *struct{}) (err error)

RemoveTransport removes a Transport from the visor.

func (*RPC) ResetRouteSetupStats

func (r *RPC) ResetRouteSetupStats(_ *struct{}, _ *struct{}) (err error)

func (*RPC) RestartApp

func (r *RPC) RestartApp(name *string, _ *struct{}) (err error)

RestartApp restarts App with provided name.

func (*RPC) Resume

func (r *RPC) Resume(_ *struct{}, _ *struct{}) (err error)

Resume re-runs the module graph to bring a suspended visor back online.

func (*RPC) RouteGroupMuxInfo

func (r *RPC) RouteGroupMuxInfo(in *string, out *[]visorapi.MuxRouteGroupInfo) (err error)

RouteGroupMuxInfo retrieves per-mux-leg counters for active rg's tagged with the named app.

func (*RPC) RouteGroupMuxNegotiated

func (r *RPC) RouteGroupMuxNegotiated(in *string, out *[]router.MuxNegotiated) (err error)

RouteGroupMuxNegotiated reports per-group negotiated values.

func (*RPC) RouteGroups

func (r *RPC) RouteGroups(_ *struct{}, out *[]visorapi.RouteGroupInfo) (err error)

RouteGroups retrieves routegroups via rules of the routing table.

func (*RPC) RouteSetupStats

func (r *RPC) RouteSetupStats(_ *struct{}, out *setupmetrics.StatsSnapshot) (err error)

func (*RPC) RoutingPolicies

func (r *RPC) RoutingPolicies(_ *struct{}, out *visorapi.RoutingPoliciesSummary) (err error)

RoutingPolicies returns the installed routing-policy summary (visor-wide default + per-app overrides) for the hypervisor UI.

func (*RPC) RoutingRule

func (r *RPC) RoutingRule(key *routing.RouteID, rule *routing.Rule) (err error)

RoutingRule obtains a routing rule of given RouteID.

func (*RPC) RoutingRules

func (r *RPC) RoutingRules(_ *struct{}, out *[]routing.Rule) (err error)

RoutingRules obtains all routing rules of the RoutingTable.

func (*RPC) RoutingStats

func (r *RPC) RoutingStats(_ *struct{}, out *routing.RoutingTableStats) (err error)

RoutingStats retrieves this visor's routing-table observability counters.

func (*RPC) RuntimeLogs

func (r *RPC) RuntimeLogs(_ *struct{}, out *string) (err error)

RuntimeLogs returns the visor's accumulated runtime log buffer. Used by the hypervisor UI's "view logs" action and the `skywire cli visor logs` command.

func (*RPC) RuntimeLogsSince

func (r *RPC) RuntimeLogsSince(since *int64, out *visorapi.RuntimeLogsDelta) (err error)

RuntimeLogsSince returns only entries whose log_line is strictly greater than since. Used by the hypervisor UI for diff-based live tailing. Caller passes the previous response's Latest as `since`.

func (*RPC) RuntimeStats

func (r *RPC) RuntimeStats(_ *struct{}, out *visorapi.RuntimeStatsInfo) (err error)

RuntimeStats returns Go runtime statistics for the visor process.

func (*RPC) SaveRoutingRule

func (r *RPC) SaveRoutingRule(in *routing.Rule, _ *struct{}) (err error)

SaveRoutingRule saves a routing rule.

func (*RPC) ServiceHealth

func (r *RPC) ServiceHealth(_ *struct{}, out *[]visorapi.ServiceHealthEntry) (err error)

ServiceHealth checks all deployment services.

func (*RPC) SetAppAddress

func (r *RPC) SetAppAddress(in *visorapi.SetAppStringIn, _ *struct{}) (err error)

SetAppAddress sets addr flag for the app

func (*RPC) SetAppArgs

func (r *RPC) SetAppArgs(in *visorapi.SetAppArgsIn, _ *struct{}) (err error)

SetAppArgs replaces the entire Args slice on an app.

func (*RPC) SetAppDetailedStatus

func (r *RPC) SetAppDetailedStatus(in *visorapi.SetAppStatusIn, _ *struct{}) (err error)

SetAppDetailedStatus sets app's detailed status.

func (*RPC) SetAppEnv

func (r *RPC) SetAppEnv(in *visorapi.SetAppEnvIn, _ *struct{}) (err error)

SetAppEnv sets/replaces/deletes a single KEY=value entry on an app's environment.

func (*RPC) SetAppEnvBatch

func (r *RPC) SetAppEnvBatch(in *visorapi.SetAppEnvBatchIn, _ *struct{}) (err error)

SetAppEnvBatch is the multi-key counterpart to SetAppEnv.

func (*RPC) SetAppEnvFull

func (r *RPC) SetAppEnvFull(in *visorapi.SetAppEnvFullIn, _ *struct{}) (err error)

SetAppEnvFull replaces the entire Env slice on an app.

func (*RPC) SetAppError

func (r *RPC) SetAppError(in *visorapi.SetAppErrorIn, _ *struct{}) (err error)

SetAppError sets app's error.

func (*RPC) SetAppKillswitch

func (r *RPC) SetAppKillswitch(in *visorapi.SetAppBoolIn, _ *struct{}) (err error)

SetAppKillswitch sets killswitch flag for the app

func (*RPC) SetAppLauncherMode

func (r *RPC) SetAppLauncherMode(in *visorapi.SetAppLauncherModeIn, _ *struct{}) (err error)

SetAppLauncherMode persists the launcher-mode preference for an app.

func (*RPC) SetAppNetworkInterface

func (r *RPC) SetAppNetworkInterface(in *visorapi.SetAppNetworkInterfaceIn, _ *struct{}) (err error)

SetAppNetworkInterface sets network interface for the app.

func (*RPC) SetAppPK

func (r *RPC) SetAppPK(in *visorapi.SetAppPKIn, _ *struct{}) (err error)

SetAppPK sets PK for the app.

func (*RPC) SetAppRoutingPolicy

func (r *RPC) SetAppRoutingPolicy(in *visorapi.SetAppRoutingPolicyIn, _ *struct{}) (err error)

SetAppRoutingPolicy installs (or clears, when Path is empty / "none") a per-app routing-policy override at runtime. Backend dispatched by file extension; the running app picks up the change on its next dial.

func (*RPC) SetAppSecure

func (r *RPC) SetAppSecure(in *visorapi.SetAppBoolIn, _ *struct{}) (err error)

SetAppSecure sets secure flag for the app

func (*RPC) SetAppSettings

func (r *RPC) SetAppSettings(in *visorapi.SetAppSettingsIn, out *visorapi.AppSettings) (err error)

SetAppSettings replaces the live tuning knobs held for an app.

func (*RPC) SetAppWhitelist

func (r *RPC) SetAppWhitelist(in *visorapi.SetAppWhitelistIn, _ *struct{}) (err error)

SetAppWhitelist sets the connection whitelist for skysocks / vpn-server.

func (*RPC) SetAutoStart

func (r *RPC) SetAutoStart(in *visorapi.SetAutoStartIn, _ *struct{}) (err error)

SetAutoStart sets auto-start settings for an app.

func (*RPC) SetCalculateRoutes

func (r *RPC) SetCalculateRoutes(enabled *bool, _ *struct{}) (err error)

SetCalculateRoutes sets calculate_routes in visor's routing config

func (*RPC) SetConfigFields

func (r *RPC) SetConfigFields(fields *map[string]json.RawMessage, out *[]visorapi.ConfigFieldChange) (err error)

SetConfigFields applies a field-by-field edit to the running visor's config. Live where a live setter is registered for the path, on-disk (restart-required) otherwise. See api_config_fields.go.

func (*RPC) SetDmsgSessionsCount

func (r *RPC) SetDmsgSessionsCount(count *int, out *visorapi.DmsgConnectAllResult) (err error)

SetDmsgSessionsCount updates the persisted sessions_count in the visor config and triggers a one-shot connect-all so the running dmsg client reaches the new target immediately.

func (*RPC) SetEmbeddedProxyBind

func (r *RPC) SetEmbeddedProxyBind(req *visorapi.SetEmbeddedProxyBindRequest, _ *struct{}) (err error)

SetEmbeddedProxyBind sets a resolver's SOCKS5 bind host (and persists it).

func (*RPC) SetEmbeddedProxyEnabled

func (r *RPC) SetEmbeddedProxyEnabled(req *visorapi.SetEmbeddedProxyEnabledRequest, _ *struct{}) (err error)

SetEmbeddedProxyEnabled toggles a resolver (dmsg/skynet) on or off at runtime without editing the config file.

func (*RPC) SetEmbeddedProxyUpstream

func (r *RPC) SetEmbeddedProxyUpstream(req *visorapi.SetEmbeddedProxyUpstreamRequest, _ *struct{}) (err error)

SetEmbeddedProxyUpstream changes the upstream SOCKS5 address for a resolver.

func (*RPC) SetExistingTPOnly

func (r *RPC) SetExistingTPOnly(enabled *bool, _ *struct{}) (err error)

SetExistingTPOnly sets whether to only use existing transports for routing

func (*RPC) SetForceLocalRoutes

func (r *RPC) SetForceLocalRoutes(enabled *bool, _ *struct{}) (err error)

SetForceLocalRoutes sets whether to skip the route finder and use local route calculation

func (*RPC) SetHypervisorAuth

func (r *RPC) SetHypervisorAuth(in *visorapi.SetHypervisorAuthIn, _ *struct{}) (err error)

SetHypervisorAuth turns the hypervisor web UI's login requirement on or off at runtime, cycling only the UI's HTTP listener. Persists when Persist is set.

func (*RPC) SetHypervisorPassword

func (r *RPC) SetHypervisorPassword(in *visorapi.HypervisorPasswordChangeIn, _ *struct{}) (err error)

SetHypervisorPassword changes the hypervisor UI admin password. Local-only RPC; the HTTP session check that /api/change-password enforces is intentionally absent here.

func (*RPC) SetHypervisorPasswordForce

func (r *RPC) SetHypervisorPasswordForce(in *visorapi.HypervisorPasswordChangeIn, _ *struct{}) (err error)

SetHypervisorPasswordForce sets the hypervisor UI admin password without the old one (reset / first-time set). Local-only RPC; same privileged-local rationale as SetHypervisorPassword. OldPassword in the request is ignored.

func (*RPC) SetIsPublic

func (r *RPC) SetIsPublic(isPublic *bool, _ *struct{}) (err error)

SetIsPublic sets the is_public field in the visor config and flushes.

func (*RPC) SetLANDmsgServer

func (r *RPC) SetLANDmsgServer(info visorapi.LANDmsgServerInfo, out *bool) (err error)

SetLANDmsgServer is called by the hypervisor to push LAN DMSG server info to this visor.

func (*RPC) SetMinHops

func (r *RPC) SetMinHops(n *uint16, _ *struct{}) (err error)

SetMinHops sets min_hops in visor's routing config

func (*RPC) SetMuxCap

func (r *RPC) SetMuxCap(n *int, _ *struct{}) (err error)

SetMuxCap sets the adaptive mux active-width ceiling (aggregation ceiling)

func (*RPC) SetMuxDirection

func (r *RPC) SetMuxDirection(in *visorapi.MuxDirectionInput, _ *struct{}) (err error)

SetMuxDirection pins or releases the unidirectional direction mapping on all of an app's active directional route groups

func (*RPC) SetMuxMode

func (r *RPC) SetMuxMode(mode *string, _ *struct{}) (err error)

SetMuxMode sets the weight distribution mode for mux transport selection

func (*RPC) SetMuxStandby

func (r *RPC) SetMuxStandby(n *int, _ *struct{}) (err error)

SetMuxStandby sets the adaptive mux warm-standby reserve pool size

func (*RPC) SetMuxWeights

func (r *RPC) SetMuxWeights(in *visorapi.MuxWeightsInput, out *router.MuxWeightsView) (err error)

SetMuxWeights pins per-leg send weights on an app's route group.

func (*RPC) SetMuxWidth

func (r *RPC) SetMuxWidth(n *int, _ *struct{}) (err error)

SetMuxWidth sets the adaptive mux steady active download width (the floor)

func (*RPC) SetPersistentTransports

func (r *RPC) SetPersistentTransports(pTs *[]transport.PersistentTransports, _ *struct{}) (err error)

SetPersistentTransports sets persistent_transports in visor's routing config

func (*RPC) SetPublicAutoconnect

func (r *RPC) SetPublicAutoconnect(pAc *bool, _ *struct{}) (err error)

SetPublicAutoconnect sets public_autoconnect in visor's routing config

func (*RPC) SetRewardAddress

func (r *RPC) SetRewardAddress(p string, out *string) (err error)

SetRewardAddress sets the reward address and privacy setting in reward.txt

func (*RPC) SetRouterDialSettings

func (r *RPC) SetRouterDialSettings(s *visorapi.RouterDialSettings, _ *struct{}) (err error)

SetRouterDialSettings applies dial-time router knobs.

func (*RPC) SetRouterSettings

func (r *RPC) SetRouterSettings(s *visorapi.RouterSettings, _ *struct{}) (err error)

SetRouterSettings sets the unified runtime router knobs.

func (*RPC) SetRuntimeConfig

func (r *RPC) SetRuntimeConfig(rawJSON *[]byte, _ *struct{}) (err error)

SetRuntimeConfig validates rawJSON and writes it to the visor's on-disk config file. Visor restart is required for the change to take effect; this RPC does NOT trigger one.

func (*RPC) SetSTCPAddr

func (r *RPC) SetSTCPAddr(in *visorapi.SetSTCPAddrIn, _ *struct{}) (err error)

SetSTCPAddr injects an STCP PK table entry at runtime.

func (*RPC) SetSkychatPassword

func (r *RPC) SetSkychatPassword(in *visorapi.SkychatPasswordChangeIn, _ *struct{}) (err error)

SetSkychatPassword sets / changes the skychat password.

func (*RPC) SetSkyenv

func (r *RPC) SetSkyenv(edits *visorapi.SkyenvEdits, out *visorapi.SkyenvState) (err error)

SetSkyenv edits /etc/skywire.conf the way `skywire autoconfig --<flag>` does.

func (*RPC) Shutdown

func (r *RPC) Shutdown(_ *struct{}, _ *struct{}) (err error)

Shutdown shuts down visor.

func (*RPC) SkychatHTTP added in v1.3.100

func (r *RPC) SkychatHTTP(in *visorapi.SkychatHTTPIn, out *visorapi.SkychatHTTPOut) (err error)

SkychatHTTP serves one request to the local skychat app.

func (*RPC) SkychatLocalAddr

func (r *RPC) SkychatLocalAddr(_ *struct{}, out *string) (err error)

SkychatLocalAddr returns the host:port skychat is bound to.

func (*RPC) SkychatPasswordIsSet

func (r *RPC) SkychatPasswordIsSet(_ *struct{}, out *bool) (err error)

SkychatPasswordIsSet reports whether a password is currently set.

func (*RPC) Skyenv

func (r *RPC) Skyenv(_ *struct{}, out *visorapi.SkyenvState) (err error)

Skyenv returns the visor's /etc/skywire.conf settings. See api_skyenv.go.

func (*RPC) SkynetHTTP

func (r *RPC) SkynetHTTP(req *visorapi.SkynetHTTPRequest, out *visorapi.SkynetHTTPResponse) (err error)

SkynetHTTP performs an HTTP request over skynet using the visor's router.

func (*RPC) SkynetProbe

func (r *RPC) SkynetProbe(req *visorapi.DmsgProbeRequest, out *bool) (err error)

SkynetProbe probes reachability of a remote PK:port over skynet.

func (*RPC) StartApp

func (r *RPC) StartApp(in *visorapi.StartAppIn, _ *struct{}) (err error)

StartApp start App with provided name.

func (*RPC) StartPublicAutoconnect

func (r *RPC) StartPublicAutoconnect(_ *struct{}, _ *struct{}) (err error)

StartPublicAutoconnect starts the public autoconnect routine

func (*RPC) StartSkysocksClient

func (r *RPC) StartSkysocksClient(pk string, _ *struct{}) (err error)

StartSkysocksClient starts SkysocksClient App

func (*RPC) StartUIServer

func (r *RPC) StartUIServer(addr *string, _ *struct{}) (err error)

StartUIServer starts the embedded UI server.

func (*RPC) StartVPNClient

func (r *RPC) StartVPNClient(in *visorapi.StartVPNClientIn, _ *struct{}) (err error)

StartVPNClient starts VPNClient App

func (*RPC) StateSnapshot

func (r *RPC) StateSnapshot(_ *struct{}, out *visorapi.StateSnapshot) (err error)

StateSnapshot provides a curated, secrets-free snapshot of the visor's live runtime state (see StateSnapshot in api_state.go).

func (*RPC) StateSnapshotProjected

func (r *RPC) StateSnapshotProjected(in *visorapi.StateSnapshotReq, out *visorapi.StateSnapshot) (err error)

StateSnapshotProjected builds only the requested subtree(s) of the snapshot server-side, so a `--select mux` call skips the expensive transports build. See StateSnapshotProjected in api_state.go.

func (*RPC) StopAllPings

func (r *RPC) StopAllPings(_ *struct{}, out *visorapi.StopAllPingsOut) (err error)

StopAllPings stops all active ping connections.

func (*RPC) StopApp

func (r *RPC) StopApp(name *string, _ *struct{}) (err error)

StopApp stops App with provided name.

func (*RPC) StopDmsgPing

func (r *RPC) StopDmsgPing(pk *cipher.PubKey, _ *struct{}) (err error)

StopDmsgPing stops the dmsg ping conn.

func (*RPC) StopPing

func (r *RPC) StopPing(pk *cipher.PubKey, _ *struct{}) (err error)

StopPing stops the ping conn.

func (*RPC) StopPublicAutoconnect

func (r *RPC) StopPublicAutoconnect(_ *struct{}, _ *struct{}) (err error)

StopPublicAutoconnect stops the public autoconnect routine

func (*RPC) StopSkysocksClients

func (r *RPC) StopSkysocksClients(_ *struct{}, _ *struct{}) (err error)

StopSkysocksClients stops all SkysocksClient Apps

func (*RPC) StopUDPForward

func (r *RPC) StopUDPForward(localPort *int, _ *struct{}) (err error)

StopUDPForward stops a client-side faithful-UDP forward by local port.

func (*RPC) StopUIServer

func (r *RPC) StopUIServer(_ *struct{}, _ *struct{}) (err error)

StopUIServer stops the embedded UI server.

func (*RPC) StopVPNClient

func (r *RPC) StopVPNClient(name *string, _ *struct{}) (err error)

StopVPNClient stops VPNClient App

func (*RPC) Summary

func (r *RPC) Summary(_ *struct{}, out *visorapi.Summary) (err error)

Summary provides an extra summary of the AppNode.

func (*RPC) Suspend

func (r *RPC) Suspend(_ *struct{}, _ *struct{}) (err error)

Suspend tears down all network subsystems, keeping the local RPC alive.

func (*RPC) TPSAddTransport

func (r *RPC) TPSAddTransport(in *visorapi.TPSAddTransportIn, out *visorapi.TPSTransportResponse) (err error)

TPSAddTransport adds a transport on a target visor using the embedded TPS.

func (*RPC) TPSExternalAddTransport

func (r *RPC) TPSExternalAddTransport(in *visorapi.TPSExternalAddTransportIn, out *visorapi.TPSTransportResponse) (err error)

TPSExternalAddTransport requests transport setup via an external TPS.

func (*RPC) TPSExternalGetTransports

func (r *RPC) TPSExternalGetTransports(in *visorapi.TPSExternalGetTransportsIn, out *[]visorapi.TPSTransportResponse) (err error)

TPSExternalGetTransports gets transports from a target visor via an external TPS.

func (*RPC) TPSExternalHealthCheck

func (r *RPC) TPSExternalHealthCheck(tpsPK *cipher.PubKey, _ *struct{}) (err error)

TPSExternalHealthCheck dials an external TPS over dmsg and performs a health check.

func (*RPC) TPSGetTransports

func (r *RPC) TPSGetTransports(targetPK *cipher.PubKey, out *[]visorapi.TPSTransportResponse) (err error)

TPSGetTransports gets transports from a target visor using the embedded TPS.

func (*RPC) TPSRemoveTransport

func (r *RPC) TPSRemoveTransport(in *visorapi.TPSRemoveTransportIn, _ *struct{}) (err error)

TPSRemoveTransport removes a transport on a target visor using the embedded TPS.

func (*RPC) TPSStatus

func (r *RPC) TPSStatus(_ *struct{}, out *visorapi.TPSStatus) (err error)

TPSStatus returns the status of the embedded TPS.

func (*RPC) TestProxy

func (r *RPC) TestProxy(conf visorapi.ProxyTestConfig, out *[]visorapi.ProxyTestResult) (err error)

TestProxy tests proxy servers by connecting through them.

func (*RPC) TestVisor

func (r *RPC) TestVisor(conf visorapi.PingConfig, out *[]visorapi.TestResult) (err error)

TestVisor trying to test viosr by pinging to public visor.

func (*RPC) Transport

func (r *RPC) Transport(in *uuid.UUID, out *visorapi.TransportSummary) (err error)

Transport obtains a Transport Summary of Transport of given Transport ID.

func (*RPC) TransportRPCCall

func (r *RPC) TransportRPCCall(req *visorapi.TransportRPCCallRequest, out *json.RawMessage) (err error)

TransportRPCCall dials a remote visor's transport RPC and calls the specified method. The local visor acts as a proxy — it opens a VStream over an existing transport to the remote visor and forwards the RPC. The remote visor must have this visor's PK in its hypervisor/dmsgpty whitelist.

Thin RPC handler: delegates to v.TransportRPCCall so the mux-sharing and error-handling logic stays in one place (rpc_transport_proxy.go). See the comment there for why we use a shared mux.

func (*RPC) TransportTypes

func (r *RPC) TransportTypes(_ *struct{}, out *[]string) (err error)

TransportTypes lists all transport types supported by the Visor.

func (*RPC) Transports

func (r *RPC) Transports(in *visorapi.TransportsIn, out *[]*visorapi.TransportSummary) (err error)

Transports lists Transports of the Visor and provides a summary of each.

func (*RPC) UIServerStatus

func (r *RPC) UIServerStatus(_ *struct{}, out *visorapi.UIServerStatus) (err error)

UIServerStatus returns the status of the UI server.

func (*RPC) UnregisterCXOFeed

func (r *RPC) UnregisterCXOFeed(name *string, _ *struct{}) (err error)

UnregisterCXOFeed stops the named user feed (no-op for unknown names). The reserved system feed name "stats" cannot be removed.

func (*RPC) UpdateForwardedPort

func (r *RPC) UpdateForwardedPort(p *visorapi.ForwardedPort, _ *struct{}) (err error)

UpdateForwardedPort updates metadata for an existing forwarded port.

func (*RPC) Uptime

func (r *RPC) Uptime(_ *struct{}, out *float64) (err error)

Uptime returns for how long the visor has been running in seconds

func (*RPC) UptimeHistory

func (r *RPC) UptimeHistory(in *visorapi.UptimeHistoryArgs, out *visorapi.UptimeHistoryResponse) (err error)

UptimeHistory returns the visor's session-level uptime history (one row per process incarnation, version-tagged) plus optionally today's 5-minute slot bitmap. Surfaces ErrUptimeRecorderUnavailable when the recorder isn't wired so the CLI can render a clear "(recorder unavailable)" instead of an empty list.

func (*RPC) VPNServers

func (r *RPC) VPNServers(vc *visorapi.FilterServersIn, out *[]servicedisc.Service) (err error)

VPNServers gets available public VPN server from service discovery URL

func (*RPC) VisorCat

func (r *RPC) VisorCat(req *visorapi.VisorCatRequest, out *visorapi.VisorCatResponse) (err error)

VisorCat opens or accepts a peer stream over the chosen transport and bridges it to a 127.0.0.1 loopback the CLI dials to splice stdio. See api_visor_cat.go.

func (*RPC) VisorSCP

func (r *RPC) VisorSCP(req *visorapi.VisorSCPRequest, out *bool) (err error)

VisorSCP runs a dmsgscp transfer to the peer using the visor's own dmsg.Client / appnet so the caller can pick either transport without an appnet shim on its side. See api_visor_scp.go.

func (*RPC) VoiceActive

func (r *RPC) VoiceActive(_ *struct{}, out *[]string) (err error)

VoiceActive replies with the ids of active calls.

func (*RPC) VoiceAnswer

func (r *RPC) VoiceAnswer(callID *string, _ *struct{}) (err error)

VoiceAnswer accepts a ringing inbound call by id.

func (*RPC) VoiceCall

func (r *RPC) VoiceCall(peer *cipher.PubKey, callID *string) (err error)

VoiceCall places a 1:1 voice call to the given peer PK; replies with the call id.

func (*RPC) VoiceCallAudio

func (r *RPC) VoiceCallAudio(callID *string, out *visorapi.VoiceAudioSnapshot) (err error)

VoiceCallAudio replies with the recent sent + received PCM of a call.

func (*RPC) VoiceDecline

func (r *RPC) VoiceDecline(callID *string, _ *struct{}) (err error)

VoiceDecline rejects a ringing inbound call by id.

func (*RPC) VoiceDial

func (r *RPC) VoiceDial(peer *cipher.PubKey, out *string) (err error)

VoiceDial places a call and replies with its id, without waiting.

func (*RPC) VoiceDialRingback added in v1.3.98

func (r *RPC) VoiceDialRingback(callID *string, out *visorapi.VoiceRingback) (err error)

VoiceDialRingback replies with the ringback tone of an outbound call's peer.

func (*RPC) VoiceDialing

func (r *RPC) VoiceDialing(_ *struct{}, out *[]visorapi.VoiceDialingInfo) (err error)

VoiceDialing replies with the calls this visor is placing.

func (*RPC) VoiceHangup

func (r *RPC) VoiceHangup(callID *string, _ *struct{}) (err error)

VoiceHangup ends an active call by id.

func (*RPC) VoiceIncoming

func (r *RPC) VoiceIncoming(_ *struct{}, out *[]string) (err error)

VoiceIncoming replies with the ringing inbound calls awaiting an answer.

func (*RPC) VoiceMute

func (r *RPC) VoiceMute(req *visorapi.VoiceMuteReq, _ *struct{}) (err error)

VoiceMute toggles the mic (send) and speaker (playback) mute of an active call.

func (*RPC) VoiceRingback added in v1.3.98

func (r *RPC) VoiceRingback(_ *struct{}, out *visorapi.VoiceRingback) (err error)

VoiceRingback replies with this visor's own ringback tone.

func (*RPC) VoiceSetRingback added in v1.3.98

func (r *RPC) VoiceSetRingback(in *visorapi.VoiceRingback, _ *struct{}) (err error)

VoiceSetRingback sets (or, with no data, clears) this visor's ringback tone. The tone is not logged: it is up to a megabyte of audio.

type RSNRemoteStat

type RSNRemoteStat struct {
	PK       cipher.PubKey               `json:"pk"`
	Snapshot *setupmetrics.StatsSnapshot `json:"snapshot,omitempty"`
	Error    string                      `json:"error,omitempty"`
	// Status from the RSN's HTTP response (only set when Snapshot is
	// nil and Error is empty — i.e. unexpected 2xx body that didn't
	// parse, or non-2xx with no error message).
	Status int `json:"status,omitempty"`
}

RSNRemoteStat is the per-RSN entry returned by /api/route-setup-nodes/stats. Either Snapshot or Error is set; both being absent means the RSN returned a non-2xx status with no body.

type ServiceInfo

type ServiceInfo struct {
	Port  uint16 `json:"port"`
	Label string `json:"label"`
}

Services returns a snapshot of all registered (port, label) pairs.

type ServiceRegistry

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

ServiceRegistry is a thread-safe port → handler map. The zero value is not usable; call NewServiceRegistry.

func NewServiceRegistry

func NewServiceRegistry() *ServiceRegistry

NewServiceRegistry returns a ready-to-use registry.

func (*ServiceRegistry) Get

func (r *ServiceRegistry) Get(port uint16) (ConnHandler, bool)

Get returns the handler for port, or (nil, false) if unregistered.

func (*ServiceRegistry) List

func (r *ServiceRegistry) List() []ServiceInfo

List returns all registered services as a sorted snapshot.

func (*ServiceRegistry) ListPublic

func (r *ServiceRegistry) ListPublic() []logserver.ServiceEntry

ListPublic returns non-hidden services. Satisfies the logserver.ServiceLister interface for the /services catalog.

func (*ServiceRegistry) Ports

func (r *ServiceRegistry) Ports() []uint16

Ports returns all registered port numbers, sorted ascending.

func (*ServiceRegistry) Register

func (r *ServiceRegistry) Register(port uint16, label string, handler ConnHandler)

Register adds a handler for port. Overwrites any existing handler on the same port (last writer wins — matches the "latest init module" semantics of the visor startup sequence).

func (*ServiceRegistry) RegisterHidden

func (r *ServiceRegistry) RegisterHidden(port uint16, label string, handler ConnHandler)

RegisterHidden adds a handler that is forwarded but NOT shown in the /services catalog. Use for services that should be accessible to PK-authenticated peers but not advertised publicly.

func (*ServiceRegistry) SelfDial

func (r *ServiceRegistry) SelfDial(port uint16) (net.Conn, error)

SelfDial returns a client-side net.Conn whose peer is the handler registered on port, served in-process over net.Pipe — no transport, no dmsg/skynet hop, no loopback. Used by the embedded resolving proxies to short-circuit a request destined for THIS visor's own PK instead of dialing out over the network back to self (which dmsg does not loopback and which is 202-prone). Errors if no handler is registered on port. The caller owns the returned conn and must close it; the handler goroutine exits when its end closes.

func (*ServiceRegistry) SelfDialAs

func (r *ServiceRegistry) SelfDialAs(port uint16, remotePK cipher.PubKey) (net.Conn, error)

SelfDialAs is SelfDial but stamps the server-end conn's RemoteAddr with remotePK (as a dmsg.Addr, which stringifies to "<pk>:<port>") so the in-process handler sees a noise-authenticated-equivalent caller identity.

Used by the embedded resolving proxies' self-loopback path: a request for THIS visor's own PK is served in-process over net.Pipe (no transport, no remote PK), which would otherwise render as anonymous on the landing page. Stamping the visor's OWN PK — which is always on its own landing-page whitelist — makes the self view authenticated, because local self-access through one's own proxy is inherently authorized. Only the SERVER end is stamped (the side the handler reads RemoteAddr from); the returned client end is unchanged. The port stamped into the addr is informational only — the landing-page whitelist check keys off the PK host part.

func (*ServiceRegistry) Unregister

func (r *ServiceRegistry) Unregister(port uint16)

Unregister removes the handler for port. No-op if not registered.

type StatusMessage

type StatusMessage struct {
	Text    string
	IsError bool
}

StatusMessage defines a status of visor update.

type TPSGetTransportsRequest

type TPSGetTransportsRequest struct {
	TargetPK cipher.PubKey
}

TPSGetTransportsRequest is input for GetTransports RPC via external TPS.

type TPSGetTransportsResponse

type TPSGetTransportsResponse struct {
	Transports []TPSSetupResponse
}

TPSGetTransportsResponse is the response for GetTransports via external TPS.

type TPSHealthCheckArgs

type TPSHealthCheckArgs struct{}

TPSHealthCheckArgs is empty input for health check.

type TPSHealthCheckReply

type TPSHealthCheckReply struct {
	Status string
}

TPSHealthCheckReply is the health check response.

type TPSRPCGateway

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

TPSRPCGateway handles RPC requests from remote visors wanting transport setup.

func (*TPSRPCGateway) AddTransport

func (g *TPSRPCGateway) AddTransport(req *TPSSetupRequest, reply *TPSSetupResponse) error

AddTransport handles transport setup requests from remote visors.

func (*TPSRPCGateway) GetTransports

GetTransports retrieves transport list from a target visor.

func (*TPSRPCGateway) HealthCheck

func (g *TPSRPCGateway) HealthCheck(_ *TPSHealthCheckArgs, reply *TPSHealthCheckReply) error

HealthCheck tests if the TPS is responsive.

func (*TPSRPCGateway) RemoveTransport

func (g *TPSRPCGateway) RemoveTransport(_ *TPSRemoveTransportRequest, _ *struct{}) error

RemoveTransport is blocked for remote callers - only allowed via local RPC.

type TPSRemoveTransportRequest

type TPSRemoveTransportRequest struct {
	TargetPK cipher.PubKey
	ID       uuid.UUID
}

TPSRemoveTransportRequest is input for RemoveTransport RPC.

type TPSSetupRequest

type TPSSetupRequest struct {
	TargetPK cipher.PubKey
	RemotePK cipher.PubKey
	Type     string
}

TPSSetupRequest is input for AddTransport RPC via external TPS.

type TPSSetupResponse

type TPSSetupResponse struct {
	ID     uuid.UUID
	Local  cipher.PubKey
	Remote cipher.PubKey
	Type   string
}

TPSSetupResponse is the response for AddTransport via external TPS.

type TransportRPCProxyReply

type TransportRPCProxyReply struct {
	Result []byte `json:"result"` // JSON-encoded RPC result
	Error  string `json:"error,omitempty"`
}

TransportRPCProxyReply is the response from the TransportRPCProxy RPC method.

type TransportRPCProxyRequest

type TransportRPCProxyRequest struct {
	RemotePK cipher.PubKey `json:"remote_pk"`
	Method   string        `json:"method"`
	Args     []byte        `json:"args"` // JSON-encoded RPC args
}

TransportRPCProxyRequest is the request for the TransportRPCProxy RPC method.

type TransportRPCServer

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

TransportRPCServer serves the visor's RPC over transport virtual streams.

func NewTransportRPCServer

func NewTransportRPCServer(
	log *logging.Logger,
	rpcServer *rpc.Server,
	whitelist pty.Whitelist,
	mux *transport.VStreamMux,
) *TransportRPCServer

NewTransportRPCServer creates a transport-level RPC server. rpcServer is the visor's existing RPC server (same one that serves localhost). whitelist is the visor's shared peer whitelist — consulted live per accept, so runtime transitive additions take effect without a restart.

mux MUST be the same VStreamMux that's registered as the transport manager's VisorRPCPacket handler (via tm.SetVisorRPCHandler) AND is used by TransportRPCCall's outbound dial path. The transport manager only routes VisorRPCPacket frames to a single handler; dial-side muxes that aren't that handler never receive responses and hang. Caller (initApps in init_apps.go) is responsible for creating the mux once and threading it through both the server (here) and the Visor struct so dial paths use it too.

func (*TransportRPCServer) Close

func (s *TransportRPCServer) Close() error

Close stops the server.

func (*TransportRPCServer) Serve

func (s *TransportRPCServer) Serve()

Serve starts accepting and serving RPC connections. Blocks until Close.

func (*TransportRPCServer) SetRejectedHook

func (s *TransportRPCServer) SetRejectedHook(f func(cipher.PubKey))

SetRejectedHook installs the callback run for each refused peer.

type UDPBridge

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

UDPBridge bidirectionally pumps datagrams between a local net.PacketConn (typically *net.UDPConn bound to the forwarded port's local TCP port — UDP using the same number) and a skynet- side net.PacketConn (typically a *router.DatagramRouteGroup).

Closing the bridge (via Close) cancels the pump goroutines and closes both conns. Closing either end externally also stops the bridge cleanly — ReadFrom on a closed conn surfaces an error, the corresponding pump goroutine exits, and the second pump is canceled via the bridge's context.

func NewUDPBridge

func NewUDPBridge(local, skynet net.PacketConn, cfg UDPBridgeConfig) *UDPBridge

NewUDPBridge constructs a bridge. The bridge does NOT start pumping until Start is called — gives the caller a chance to wire any pre-start state (e.g. a fixed localPeer for an outbound-initiated forward).

func (*UDPBridge) Close

func (b *UDPBridge) Close() error

Close stops the pumps and closes both conns. Idempotent.

func (*UDPBridge) SetLocalPeer

func (b *UDPBridge) SetLocalPeer(addr net.Addr)

SetLocalPeer pre-pins the local UDP peer (the address of the app sending to our local port). Used for outbound-initiated forwards where we know the local app's source up-front. For inbound-initiated forwards leave this unset; the first local ReadFrom captures it automatically.

func (*UDPBridge) Start

func (b *UDPBridge) Start()

Start launches the two pump goroutines and returns immediately. Idempotent — second call is a no-op.

func (*UDPBridge) Wait

func (b *UDPBridge) Wait()

Wait blocks until both pumps have exited. Close-then-Wait is the canonical shutdown sequence.

type UDPBridgeConfig

type UDPBridgeConfig struct {
	// BufSize is the per-pump scratch buffer size. Sized to fit
	// the largest expected datagram; 65535 covers any UDP payload
	// the local socket can deliver.
	BufSize int

	// Logger overrides the default.
	Logger *logging.Logger
}

UDPBridgeConfig tunes the bridge. Zero values use defaults.

type Visor

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

Visor provides messaging runtime for Apps by setting up all necessary connections and performing messaging gateway functions.

func NewVisor

func NewVisor(ctx context.Context, conf *visorconfig.V1, opts Options, logBcast *logging.Broadcaster, logStore logstore.Store) (*Visor, bool)

NewVisor constructs new Visor. logBcast (the master-logger Broadcaster hook) and logStore (the in-memory runtime-log ring) are created and attached to the loggers by the caller; both are installed on the Visor BEFORE module init so the RPC log surfaces (--verbose stream + RuntimeLogs/RuntimeLogsSince) work while the visor is still starting up — the RPC binds during module init, so wiring these afterward left a window where a log query hit a nil field and segfaulted the process. Both may be nil (e.g. tests); all readers nil-guard.

func (*Visor) ARSelfInfo

func (v *Visor) ARSelfInfo() (*visorapi.ARSelfRegistration, error)

ARSelfInfo returns the visor's own cached AR registration. Reads the in-memory cache populated by the refresh loop — no HTTP round-trip.

func (*Visor) ActiveRoutes

func (v *Visor) ActiveRoutes() ([]visorapi.AppRouteStatus, error)

ActiveRoutes implements API. Returns all active routes with their app associations and live stats.

func (*Visor) AddApp

func (v *Visor) AddApp(appName, binaryName string) error

AddApp implement API.

func (*Visor) AddHypervisor

func (v *Visor) AddHypervisor(hvPK cipher.PubKey) error

AddHypervisor adds a remote hypervisor PK and connects to it at runtime. The PK is written to the config's hypervisors list (see persistHypervisors), so the connection survives a restart, and on a package install it is mirrored into HYPERVISORPKS in skywire.conf so the next `skywire autoconfig` run (every package update) keeps it.

func (*Visor) AddMuxRoute

func (v *Visor) AddMuxRoute(appName string, fwd, rev []routing.Hop, rgPort uint16) error

AddMuxRoute implements API. Adds a leg over the caller-supplied route to the app's active rg. The hop lists have the same shape 'cli route calc' emits, so the natural workflow is

skywire cli route calc <peer-pk> --json | skywire cli proxy mux-add

rgPort disambiguates when the app has multiple concurrent rg's — the rg's own port as 'mux info' prints it (desc.dst_port), or its src_port; 0 auto-picks when there's exactly one. Auto-pick a disjoint route on the visor side is deferred — callers pick the route explicitly for now.

func (*Visor) AddMuxRouteForward

func (v *Visor) AddMuxRouteForward(appName string, fwd, rev []routing.Hop, rgPort uint16) error

AddMuxRouteForward implements API. AddMuxRoute with the reverse direction dropped: the leg adds UPSTREAM send capacity only.

func (*Visor) AddPtyWhitelist

func (v *Visor) AddPtyWhitelist(pks []cipher.PubKey) error

AddPtyWhitelist merges PKs into the live shared whitelist, extending pty + RPC trust to peers a connected hypervisor vouches for (its own hypervisors). Idempotent. Every mutation is logged with full PKs for audit. Implements API.

func (*Visor) AddTransport

func (v *Visor) AddTransport(remote cipher.PubKey, tpType string, timeout time.Duration, label string, noRegister bool, _ bool) (*visorapi.TransportSummary, error)

AddTransport implements API.

func (*Visor) AllRouteGroupMuxInfo

func (v *Visor) AllRouteGroupMuxInfo() ([]visorapi.MuxRouteGroupInfo, error)

AllRouteGroupMuxInfo implements API. Returns per-mux-leg counters for EVERY active route group on the visor, regardless of app — the whole-runtime view surfaced in `cli visor state`. Same transcription as RouteGroupMuxInfo, only without the app filter.

func (*Visor) App

func (v *Visor) App(appName string) (*appserver.AppState, error)

App implements API.

func (*Visor) AppDirectStreams

func (v *Visor) AppDirectStreams(appName string) ([]transport.VStreamInfo, error)

AppDirectStreams implements API. Reports the live direct (0-hop) streams the AppDirectMux holds for appName, which is where a proxy session goes when the dial is shortcut-eligible (min_hops <= 1 and no per-dial --mux). Those sessions build no route group by design, so RouteGroupMuxInfo is empty for them and every "what route is this using?" surface came up blank on a working proxy. Empty appName reports every app's streams.

func (*Visor) AppHelp

func (v *Visor) AppHelp(appName string) (string, error)

AppHelp returns the `--help` output for the named app. Three resolution paths to cover the launcher's three app shapes:

  1. In-process registered app (launcher.RegisterApp("skysocks", …)) with args like ["app", "skysocks", …] → exec the running skywire binary with the leading non-flag args + "--help" (i.e. "skywire app skysocks --help").

  2. Embedded cobra subcommand of skywire (skycoin daemon, skycoin web) with args like ["skycoin", "daemon", …] → same pattern: "skywire skycoin daemon --help".

  3. External standalone binary at <BinPath>/<Binary> → exec the file directly with --help.

Cached per resolved (exec, args-prefix); invalidated by the running skywire binary's mtime so a rebuild surfaces fresh help.

func (*Visor) ApproveHypervisor

func (v *Visor) ApproveHypervisor(sel string) (cipher.PubKey, error)

ApproveHypervisor implements API: sel is a public key, or a fingerprint (or unique prefix) of a pending key. Approval is AddHypervisor.

func (*Visor) Apps

func (v *Visor) Apps() ([]*appserver.AppState, error)

Apps implements API.

func (*Visor) BandwidthTest

func (v *Visor) BandwidthTest(conf visorapi.BandwidthTestConfig) (visorapi.BandwidthResult, error)

BandwidthTest implements API. Performs a bandwidth test over a skywire route by sending and receiving data for the specified duration.

func (*Visor) BrowseClearnet

func (v *Visor) BrowseClearnet(req BrowseClearnetRequest) (*visorapi.SkynetHTTPResponse, error)

BrowseClearnet originates a route group to the skysocks server, runs SOCKS5 over a yamux stream, and performs the HTTP(S) request — TLS terminates here (system cert pool), so the exit only relays ciphertext for https.

func (*Visor) BrowseFetch

func (v *Visor) BrowseFetch(req BrowseFetchRequest) (*visorapi.SkynetHTTPResponse, error)

BrowseFetch performs the request over skynet and/or dmsg per Scheme, returning the response in the shared SkynetHTTPResponse shape.

func (*Visor) BrowseWebSocket added in v1.3.99

func (v *Visor) BrowseWebSocket(ctx context.Context, req BrowseWebSocketRequest) (*websocket.Conn, error)

BrowseWebSocket opens req.URL through req.Proxy, sending the jar's cookies for that site as a browser would.

func (*Visor) CXOFeedStates

func (v *Visor) CXOFeedStates() []visorapi.CXOFeedState

func (*Visor) CXORefreshFeed

func (v *Visor) CXORefreshFeed(args visorapi.CXORefreshArgs) (*visorapi.FeedStatus, error)

CXORefreshFeed forces a fresh subscribe → first-Root → walk cycle on the named feed and blocks until it succeeds or the timeout expires. The returned FeedStatus reflects the snapshot *after* the sync attempt, so the operator can tell at a glance whether the publisher is reachable.

func (*Visor) CXOStatus

func (v *Visor) CXOStatus() ([]visorapi.FeedStatus, error)

CXOStatus returns the per-feed snapshot/refcount/last-sync/last-err state of the in-memory CXO subscription manager. Used by `skywire cli visor cxo status` so operators can see why a feed is missing data (cycle never started? publisher unreachable? snapshot genuinely empty?).

Returns an empty slice when the manager hasn't been initialized (e.g. visor still has no DMSG client). Errors only for genuine internal failures; "no feeds yet" is not an error.

func (*Visor) CXOSubMgr

func (v *Visor) CXOSubMgr() *CXOSubscriptionManager

CXOSubMgr returns the visor's manager, constructing it lazily on first use. Returns nil when the visor has no DMSG client (early startup, or DMSG disabled). Callers treat nil as "no manager; fall through to whatever non-CXO source you'd otherwise use" — every method on a nil receiver is a safe no-op.

func (*Visor) CheckAREntry

func (v *Visor) CheckAREntry(pk string) ([]string, error)

CheckAREntry checks if a public key is registered in the address resolver. Returns the transport types the visor is registered for (e.g., ["stcpr", "sudph"]) without revealing its IP address.

func (*Visor) ClearMuxWeights

func (v *Visor) ClearMuxWeights(appName string, rgPort uint16) (router.MuxWeightsView, error)

ClearMuxWeights implements API. Releases an explicit weight pin, returning the group to the ECF scheduler every mux is built with.

func (*Visor) ClearSkychatPassword

func (v *Visor) ClearSkychatPassword(oldPassword string) error

ClearSkychatPassword removes the password file and re-launches skychat without --password-file so the gate goes back to off.

func (*Visor) ClearTempLogLevel added in v1.3.100

func (v *Visor) ClearTempLogLevel() logserver.LogLevelStatus

ClearTempLogLevel implements logserver.LogLevelController.

func (*Visor) Close

func (v *Visor) Close() error

Close safely stops spawned Apps and Visor.

func (*Visor) ConfiguredHypervisors

func (v *Visor) ConfiguredHypervisors() []cipher.PubKey

ConfiguredHypervisors implements logserver.RelatedNodesProvider. It returns the PKs of the hypervisors this visor is configured to be managed by (v.conf.Hypervisors).

func (*Visor) ConnectRawTCP

func (v *Visor) ConnectRawTCP(network string, remotePK cipher.PubKey, remotePort, localPort int) (uuid.UUID, error)

ConnectRawTCP implements API. Establishes a raw TCP port forwarding connection over skywire. The network parameter selects the transport:

  • "skynet" (default; empty string treated as skynet) — dials the remote visor's sky-forwarding server, handshakes the requested remote port, and pipes a local TCP listener to the resulting stream. Routes traverse the routing layer.
  • "dmsg" — opens a DMSG stream directly to (remotePK, remotePort) and pipes a local TCP listener to it. Requires the remote visor to be running a DMSG forwarder for that port. Independent of the routing layer.

Returns the forwarder's ID; pass to DisconnectRawTCP to tear down.

func (*Visor) CutAppTunnel

func (v *Visor) CutAppTunnel(appName string, rgPort uint16) (uint64, error)

CutAppTunnel closes exactly one of appName's tunnels — the one whose route group port is rgPort, as `proxy mux info` prints it (desc.dst_port) — and returns the sequence of the queued op. The app applies it on its next settings pull (one tunnel.probe_interval, 5 s by default) and its pool replaces the tunnel from standby.

func (*Visor) DMSGServers

func (v *Visor) DMSGServers() ([]visorapi.DMSGServerInfo, error)

DMSGServers returns list of connected DMSG servers with their latencies. Servers are sorted by latency (lowest first). Servers with latency 0 have not been measured yet.

func (*Visor) DeleteApp

func (v *Visor) DeleteApp(appName string) error

DeleteApp implements API. Stops the running proc (if any), then removes the app entry from the launcher config and flushes the updated config to disk. Returns an error if the app doesn't exist or the proc fails to stop cleanly.

func (*Visor) DeleteRewardAddress

func (v *Visor) DeleteRewardAddress() error

DeleteRewardAddress implements API.

func (*Visor) DeregisterApp

func (v *Visor) DeregisterApp(procKey appcommon.ProcKey) error

DeregisterApp implements API.

func (*Visor) DeregisterService

func (v *Visor) DeregisterService(pks []cipher.PubKey, serviceType string) error

DeregisterService deregisters the specified public keys from service discovery. This requires the visor's public key to be whitelisted as a network monitor in the service discovery. serviceType must be one of: "vpn", "visor", "skysocks" (or "proxy")

func (*Visor) DeregisterTCPPort

func (v *Visor) DeregisterTCPPort(localPort int) error

DeregisterTCPPort implements API.

func (*Visor) DiagSnapshot

func (v *Visor) DiagSnapshot() *visorapi.DiagSnapshot

DiagSnapshot builds the diag section. Every part is best-effort on a partially initialized visor: a missing subsystem leaves its field nil.

func (*Visor) DialDmsgPing

func (v *Visor) DialDmsgPing(pk cipher.PubKey) error

DialDmsgPing implements API. Dials a remote visor over dmsg for ping. It prefers to use the lowest-latency DMSG server that both visors share.

func (*Visor) DialDmsgPingViaServer

func (v *Visor) DialDmsgPingViaServer(pk cipher.PubKey, serverPK cipher.PubKey) error

DialDmsgPingViaServer implements API. Dials a remote visor over dmsg via a specific server.

func (*Visor) DialDmsgRPC

func (v *Visor) DialDmsgRPC(pk cipher.PubKey) (net.Conn, error)

DialDmsgRPC implements API. Dials a remote visor's gRPC/RPC port over DMSG. Returns a net.Conn that can be used to create a gRPC client.

func (*Visor) DialPing

func (v *Visor) DialPing(conf visorapi.PingConfig) error

DialPing implements API.

func (*Visor) DialUDPForward

func (v *Visor) DialUDPForward(remotePK cipher.PubKey, remotePort, localPort int) error

DialUDPForward opens a faithful-UDP forward: it DialPackets to remotePK:remotePort (which must be a forwarded_ports.udp service on the peer) and binds a local UDP socket on localPort, bridging the two. The operator's UDP app then talks to 127.0.0.1:localPort and its datagrams reach the remote service (and replies come back). Runs until StopUDPForward(localPort) or visor shutdown.

func (*Visor) DisableHypervisor

func (v *Visor) DisableHypervisor() error

DisableHypervisor implements API.

func (*Visor) DisableHypervisorPersist

func (v *Visor) DisableHypervisorPersist(persist bool) error

DisableHypervisorPersist disables the hypervisor and optionally persists to config.

func (*Visor) DisableHypervisorUIPersist

func (v *Visor) DisableHypervisorUIPersist(persist bool) error

DisableHypervisorUIPersist stops the hypervisor web UI but keeps the DMSG-RPC listener, managed-visor tracking, and `hv ls` running. Optionally persists.

func (*Visor) DisconnectRawTCP

func (v *Visor) DisconnectRawTCP(id uuid.UUID) error

DisconnectRawTCP implements API.

func (*Visor) DiscoverTransportByID

func (v *Visor) DiscoverTransportByID(id uuid.UUID) (*transport.Entry, error)

DiscoverTransportByID implements API.

func (*Visor) DiscoverTransportsByPK

func (v *Visor) DiscoverTransportsByPK(pk cipher.PubKey) ([]*transport.Entry, error)

DiscoverTransportsByPK implements API.

func (*Visor) DmsgBandwidthTest

func (v *Visor) DmsgBandwidthTest(conf visorapi.BandwidthTestConfig) (visorapi.BandwidthResult, error)

DmsgBandwidthTest implements API. Performs a bandwidth test over dmsg by sending and receiving data for the specified duration.

func (*Visor) DmsgConnectAll

func (v *Visor) DmsgConnectAll() (*visorapi.DmsgConnectAllResult, error)

DmsgConnectAll enumerates every dmsg server in discovery and ensures the visor's dmsg client has an active session to each one. This is a one-shot action intended for RSN / TPS visors that need to reach arbitrary destinations without relying on phase-3 new-session dials during route setup. It does not mutate the visor's configured sessions_count — for persistent behavior use SetDmsgSessionsCount with 0 (connect to all) or edit sessions_count in the visor config.

func (*Visor) DmsgConverge

func (v *Visor) DmsgConverge(carriers []string) (*visorapi.DmsgConvergeResult, error)

DmsgConverge optionally sets the main dmsg client's ordered carrier preference (empty = leave as-is) and runs one carrier-convergence pass, re-dialing each server session onto the most-preferred carrier it currently advertises. Returns the effective preference, how many sessions converged, and the resulting per-session carriers.

func (*Visor) DmsgHTTP

DmsgHTTP implements API. Performs an HTTP request over dmsg using the visor's dmsg client.

func (*Visor) DmsgPing

func (v *Visor) DmsgPing(conf visorapi.PingConfig) ([]time.Duration, error)

DmsgPing implements API. Measures round-trip time over dmsg connection.

Mutex scope: same pattern as the skynet-side Ping — hold dmsgPing.mu only for the map lookup, release before wire I/O. Lets concurrent DmsgPing calls on different PKs proceed in parallel instead of serializing through one global lock.

func (*Visor) DmsgPingOnce

func (v *Visor) DmsgPingOnce(conf visorapi.PingConfig) (time.Duration, error)

DmsgPingOnce implements API. Performs a single ping over dmsg connection.

See DmsgPing for mutex-scoping rationale.

func (*Visor) DmsgPingOnceWithEcho

func (v *Visor) DmsgPingOnceWithEcho(conf visorapi.PingConfig, echoFull bool) (bytesSent, bytesReceived uint64, latency time.Duration, err error)

DmsgPingOnceWithEcho performs a single dmsg ping with optional full echo. Returns bytes sent, bytes received, latency, and error. If echoFull is true, server echoes full payload (for bandwidth testing).

See DmsgPing for mutex-scoping rationale.

func (*Visor) DmsgPingViaServer

func (v *Visor) DmsgPingViaServer(conf visorapi.PingConfig, serverPK cipher.PubKey) ([]time.Duration, error)

DmsgPingViaServer implements API. Performs a ping through a specific DMSG server. This is a convenience method that handles dial, ping, and cleanup.

func (*Visor) DmsgPortHits

func (v *Visor) DmsgPortHits() []dmsg.PortHit

DmsgPortHits implements API. Returns inbound dmsg stream requests that hit a local port with no listener (dmsg error 306), keyed by (src PK, dst port).

func (*Visor) DmsgPorterDiag

func (v *Visor) DmsgPorterDiag() (*netutil.EphemeralDiagResult, error)

DmsgPorterDiag returns detailed diagnostic information about ephemeral port reservations in the embedded RSN's DMSG client porter.

func (*Visor) DmsgPorterReset

func (v *Visor) DmsgPorterReset() (*visorapi.DmsgPorterStatus, error)

DmsgPorterReset frees all ephemeral port reservations on the main and embedded RSN DMSG clients. Returns the number of ports freed.

func (*Visor) DmsgPorterStats

func (v *Visor) DmsgPorterStats() (*visorapi.DmsgPorterStatus, error)

DmsgPorterStats returns the current ephemeral port reservation counts for the main and embedded RSN DMSG clients.

func (*Visor) DmsgProbe

func (v *Visor) DmsgProbe(pk cipher.PubKey, port uint16) (bool, error)

DmsgProbe checks whether a remote PK is reachable on a given dmsg port by performing a DialStream + immediate Close. The noise handshake completing confirms end-to-end reachability. Returns true if reachable.

func (*Visor) DmsgProbeReason

func (v *Visor) DmsgProbeReason(pk cipher.PubKey, port uint16) (reachable bool, reason string, err error)

DmsgProbeReason is DmsgProbe with the failure reason kept. Unreachable is a result, not an RPC error, so the reason comes back as a string and the error return stays reserved for the RPC itself — callers that only want the boolean keep using DmsgProbe. reason is "" when reachable.

func (*Visor) DmsgProbeViaServer

func (v *Visor) DmsgProbeViaServer(pk cipher.PubKey, port uint16, serverPK cipher.PubKey) (bool, error)

DmsgProbeViaServer probes dmsg reachability of pk:port forced through a specific dmsg server (serverPK), for per-server reachability diagnosis. Returns true if reachable via that server.

func (*Visor) DmsgPtyExec

func (v *Visor) DmsgPtyExec(args visorapi.DmsgPtyExecArgs) (*pty.CommandExecResult, error)

DmsgPtyExec runs a one-shot command on the remote visor identified by args.RemotePK using this visor's embedded dmsgpty host. Skips the host's CLI control listener (the unix socket / TCP loopback that the standalone dmsgpty-cli connects to) — the caller already holds an authenticated RPC connection to this visor, so the permission gate is the visor RPC, not the dmsgpty CLI socket.

Trust model upstream of this is the visor RPC's auth (whoever can reach :3435). Trust model downstream is unchanged: the remote dmsgpty host enforces its whitelist on the dmsg stream this visor opens; the remote sees this visor's PK as the peer.

func (*Visor) DmsgReconnect

func (v *Visor) DmsgReconnect() (int, error)

DmsgReconnect forces all DMSG sessions to close and reconnect.

func (*Visor) DmsgServerHealth added in v1.3.100

func (v *Visor) DmsgServerHealth() *httputil.DmsgServerHealth

DmsgServerHealth is the load of the dmsg server this visor runs, or nil.

func (*Visor) DmsgSessionCount added in v1.3.100

func (v *Visor) DmsgSessionCount() int

DmsgSessionCount is the visor's sessions with dmsg servers.

func (*Visor) DmsgSessions

func (v *Visor) DmsgSessions() (*visorapi.DmsgClientSessions, error)

DmsgSessions enumerates all dmsg clients running inside the visor and returns the server PKs each one has an active session with. Covers the main visor dmsg client, the embedded route setup node's dmsg client (if configured), and the embedded transport setup node's dmsg client (if configured). Each of these runs under a DIFFERENT identity/key and maintains its OWN session set, so checking `visor info` alone does not tell you whether the RSN or TPS is actually reaching the network.

func (*Visor) DmsgSetMinSessions

func (v *Visor) DmsgSetMinSessions(n int) error

DmsgSetMinSessions updates the minimum DMSG session count at runtime.

func (*Visor) DoCustomSetting

func (v *Visor) DoCustomSetting(appName string, customSetting map[string]any) error

DoCustomSetting implents API.

func (*Visor) EmbeddedProxies

func (v *Visor) EmbeddedProxies() (*visorapi.EmbeddedProxiesStatus, error)

EmbeddedProxies reports runtime state for every in-process resolver. Both fields are populated when configured — UI layers want to show "disabled" as distinct from "absent" so operators can tell the difference between "resolver present but toggled off" and "config section missing".

func (*Visor) EmbeddedServiceControl added in v1.3.100

func (v *Visor) EmbeddedServiceControl(name, action string) error

EmbeddedServiceControl stops, starts or restarts the embedded service named name. Only a service under its own key runs apart from the visor; a mounted one lives and dies with it.

func (*Visor) EnableHypervisor

func (v *Visor) EnableHypervisor() error

EnableHypervisor implements API.

func (*Visor) EnableHypervisorPersist

func (v *Visor) EnableHypervisorPersist(persist bool) error

EnableHypervisorPersist enables the hypervisor and optionally persists to config.

func (*Visor) EnableHypervisorUIPersist

func (v *Visor) EnableHypervisorUIPersist(persist bool) error

EnableHypervisorUIPersist starts the hypervisor web UI (RPC/tracking unaffected) and optionally persists the change.

func (*Visor) FetchAllTransportEntries

func (v *Visor) FetchAllTransportEntries(ctx context.Context) ([]*transport.Entry, error)

FetchAllTransportEntries pulls every transport from the configured TPD client AND merges in the local transport manager's view. The TPD bulk endpoint can lag behind reality (its cache is async-refreshed), so a transport this visor has actively negotiated may not be present yet. The local transport manager is authoritative for "what this visor can actually dial right now"; merging avoids missed 1-hop routes in calc responses while the BFS depth limit + streaming output bound memory.

Dedup is by transport ID — TPD's view is preferred when it has a matching entry (it carries label/QoS metadata the local view lacks).

func (*Visor) FetchAllTransportsCXO

func (v *Visor) FetchAllTransportsCXO(_ bool) ([]byte, error)

FetchAllTransportsCXO returns the network's transport list as JSON, from TPD's routing feed — the same list route calculation uses. withSelf is kept for the callers that pass it: self-loops are not transports anyone routes over, and neither feed variant carries them any more. Caller treats the not-ready error as a cache miss and falls through to HTTP.

func (*Visor) FetchCXO

func (v *Visor) FetchCXO(args visorapi.FetchCXOArgs) (*visorapi.FetchCXOResult, error)

FetchCXO implements API.

func (*Visor) FetchServiceData

func (v *Visor) FetchServiceData(service, path string) ([]byte, error)

FetchServiceData fetches data from a deployment service endpoint via the visor's configured URLs. service is one of: tpd, ut, sd, ar, rf, dmsgd. path is the URL path (e.g., "/all-transports/stats").

DMSG-HTTP is preferred whenever the service has a dmsg URL configured — it is the default service transport and a dmsg-only visor has no HTTP URL at all. Plain HTTP is used only as the dual-config fallback or the http-only path.

func (*Visor) FetchTPDPerKeyCXO added in v1.3.100

func (v *Visor) FetchTPDPerKeyCXO() ([]byte, time.Time, error)

FetchTPDPerKeyCXO returns the /all-transports/per-key-stats body from the per-key feed and the time of the leaf it came from, or ErrTPDPerKeyNotReady.

func (*Visor) FetchTPDStatsCXO

func (v *Visor) FetchTPDStatsCXO(kind string) ([]byte, time.Time, error)

FetchTPDStatsCXO returns the JSON body for one aggregate — (bytes, lastRootAt, nil) on a hit, (nil, zero, ErrTPDStatsNotReady) when the feed has nothing to serve it from.

The publisher republishes every ~12s, so lastRootAt doubles as a liveness signal: a root much older than that means the subscription, not the network, went quiet.

func (*Visor) FetchTransportMetricsCXO

func (v *Visor) FetchTransportMetricsCXO(days int) ([]byte, time.Time, error)

FetchTransportMetricsCXO returns the metrics blob for the given day window as a single JSON array of store.TransportMetric — (bytes, lastRootAt, nil) on a hit, (nil, zero, ErrTPDMetricsNotReady) when the feed has nothing to serve it from.

`days` may be any positive count; it is satisfied from however many day leaves TPD is currently publishing (30 at present), so asking for more days than exist returns the days that do.

func (*Visor) FetchVisorUptimeCXO

func (v *Visor) FetchVisorUptimeCXO(days int) ([]byte, time.Time, error)

FetchVisorUptimeCXO returns the cached visor-uptime blob for the given day window. (bytes, lastRootAt, nil) on a hit; (nil, zero, ErrTPDUptimeNotReady) when the cache has nothing for that path yet.

`days` should be one of the values the TPD publisher writes (currently 1, 7, 30); other values always miss because the publisher doesn't write them.

func (*Visor) GetAppConnectionsSummary

func (v *Visor) GetAppConnectionsSummary(appName string) ([]appserver.ConnectionSummary, error)

GetAppConnectionsSummary implements API.

func (*Visor) GetAppError

func (v *Visor) GetAppError(appName string) (string, error)

GetAppError implements API.

func (*Visor) GetAppSettings

func (v *Visor) GetAppSettings(appName string) (visorapi.AppSettings, error)

GetAppSettings returns the live tuning knobs held for appName.

func (*Visor) GetAppStats

func (v *Visor) GetAppStats(appName string) (appserver.AppStats, error)

GetAppStats implements API.

func (*Visor) GetCalculateRoutes

func (v *Visor) GetCalculateRoutes() (bool, error)

GetCalculateRoutes gets calculate_routes routing config of visor

func (*Visor) GetConfigPath

func (v *Visor) GetConfigPath() (string, error)

GetConfigPath returns the filesystem path the visor loaded its config from. Returns "stdin" when the config was read from stdin or supplied via --config-arg; returns an empty string if the path was never set.

func (*Visor) GetDmsgPingServerPK

func (v *Visor) GetDmsgPingServerPK(pk cipher.PubKey) (cipher.PubKey, error)

GetDmsgPingServerPK implements API. Returns the DMSG server PK used for a ping connection.

func (*Visor) GetIsPublic

func (v *Visor) GetIsPublic() bool

GetIsPublic returns the current is_public config setting.

func (*Visor) GetLastRouteCalcTime

func (v *Visor) GetLastRouteCalcTime() time.Duration

GetLastRouteCalcTime returns the time spent calculating the last local route.

func (*Visor) GetMinHops

func (v *Visor) GetMinHops() (uint16, error)

GetMinHops returns the visor's configured routing.min_hops value.

func (*Visor) GetNetworkTypes

func (v *Visor) GetNetworkTypes() []string

GetNetworkTypes returns the network types used by the visor.

func (*Visor) GetPersistentTransports

func (v *Visor) GetPersistentTransports() ([]transport.PersistentTransports, error)

GetPersistentTransports returns the visor's configured persistent_transports.

func (*Visor) GetPingRoute

func (v *Visor) GetPingRoute(pk cipher.PubKey) []cipher.PubKey

GetPingRoute returns the route hops for the primary ping connection to a peer (RouteIndex 0). For aux routes in a mux-set use GetPingRouteAt(ref).

func (*Visor) GetPingRouteAt

func (v *Visor) GetPingRouteAt(ref PingRouteRef) []cipher.PubKey

GetPingRouteAt returns the route hops for a specific ping route.

func (*Visor) GetPingRouteDetails

func (v *Visor) GetPingRouteDetails(pk cipher.PubKey) []router.RouteHopInfo

GetPingRouteDetails returns detailed route information for the PRIMARY ping connection to a peer (RouteIndex 0), including transport IDs and types for each hop. For aux routes use GetPingRouteDetailsAt(ref).

func (*Visor) GetPingRouteDetailsAt

func (v *Visor) GetPingRouteDetailsAt(ref PingRouteRef) []router.RouteHopInfo

GetPingRouteDetailsAt returns detailed route information for a specific ping route. Used by mux-aware callers (mux-bw) to surface the hops of each parallel route — the primary-keyed accessor can't distinguish among them.

func (*Visor) GetPreferredDmsgServer

func (v *Visor) GetPreferredDmsgServer(remotePK cipher.PubKey) (cipher.PubKey, error)

GetPreferredDmsgServer returns the lowest-latency DMSG server that both the local and remote visor are connected to. Returns empty PK if no common server found.

func (*Visor) GetRSNHealth

func (v *Visor) GetRSNHealth() ([]visorapi.NodeHealth, error)

GetRSNHealth returns health status for all configured RSN nodes.

func (*Visor) GetRemoteDmsgServers

func (v *Visor) GetRemoteDmsgServers(pk cipher.PubKey) ([]cipher.PubKey, error)

GetRemoteDmsgServers implements API. Gets the DMSG servers a remote visor is connected to.

func (*Visor) GetRewardAddress

func (v *Visor) GetRewardAddress() (string, error)

GetRewardAddress implements API.

func (*Visor) GetRouteSetupNodesSorted

func (v *Visor) GetRouteSetupNodesSorted() ([]cipher.PubKey, error)

GetRouteSetupNodesSorted returns RSN nodes sorted by health (healthy first, then by latency).

func (*Visor) GetRouterDialSettings

func (v *Visor) GetRouterDialSettings() (visorapi.RouterDialSettings, error)

GetRouterDialSettings implements API. Reads the live dial-time knobs.

func (*Visor) GetRouterSettings

func (v *Visor) GetRouterSettings() (visorapi.RouterSettings, error)

GetRouterSettings returns the current runtime values of the four router knobs. MinHops and MuxRoutes are written to Routing.* and seeded back into the router at boot, so they survive a restart; ForceLocalRoutes / ExistingTPOnly are runtime-only, mirroring the CLI's behavior. Surviving a restart is not the same as surviving a config regen — of these, only MinHops has a skywire.conf field (MINHOPS) and is preserved by `config gen -r`.

func (*Visor) GetRuntimeConfig

func (v *Visor) GetRuntimeConfig() ([]byte, error)

GetRuntimeConfig returns the visor's running config as JSON bytes with the secret key redacted — it never leaves the process via this view (matching the browser wasm-visor). The PK is kept but is not editable on save; see SetRuntimeConfig, which preserves and re-injects the real SK.

func (*Visor) GetSkysocksClientAddress

func (v *Visor) GetSkysocksClientAddress() string

GetSkysocksClientAddress get PK address of server set on skysocks-client

func (*Visor) GetTPSHealth

func (v *Visor) GetTPSHealth() ([]visorapi.NodeHealth, error)

GetTPSHealth returns health status for all configured TPS nodes.

func (*Visor) GetTransportCounts

func (v *Visor) GetTransportCounts() (stcpr, sudph int)

GetTransportCounts returns the count of STCPR and SUDPH transports (excluding "user" labeled). Retained for backward compatibility; GetTransportTypeCounts reports every live transport type.

func (*Visor) GetTransportLatencyByRemotePK

func (v *Visor) GetTransportLatencyByRemotePK(remotePK cipher.PubKey) float64

GetTransportLatencyByRemotePK returns the smoothed average RTT in milliseconds for the local managed transport to remotePK, or 0 if no such transport exists or its latency is not yet sampled.

Used by the ping-tree streaming RPC's UseTransportLatency fast-path: at level-1 (direct neighbors) the visor already has continuously-sampled transport-level RTT; re-pinging would duplicate work without adding signal. Returning 0 lets the caller fall back to a live ping when the transport doesn't yet have measurements (e.g. just-established).

O(N) over local transports. Stops on first match. Callers should not invoke per-packet — this is intended for the BFS level-1 pass where N is the direct-neighbor count.

func (*Visor) GetTransportLogs

func (v *Visor) GetTransportLogs(days int) ([]visorapi.TransportLogEntry, error)

GetTransportLogs implements API. Returns one entry per (transport, day) for the last N UTC days, drawn from the bbolt-backed stats store. The on-disk CSV transport log was retired — see pkg/transport/log.go and pkg/visor/stats. Each entry's RecvBytes/SentBytes is the within-day delta (matches the historical CSV semantics, where the per-day file accumulated bytes from a zero-anchored start-of-day baseline). Timestamp is the start of the UTC day, expressed as a Unix epoch second.

func (*Visor) GetTransportSetupNodes

func (v *Visor) GetTransportSetupNodes() ([]cipher.PubKey, error)

GetTransportSetupNodes returns the whitelisted transport setup node public keys.

func (*Visor) GetTransportSetupNodesSorted

func (v *Visor) GetTransportSetupNodesSorted() ([]cipher.PubKey, error)

GetTransportSetupNodesSorted returns TPS nodes sorted by health (healthy first, then by latency).

func (*Visor) GetTransportTypeCounts

func (v *Visor) GetTransportTypeCounts() map[string]int

GetTransportTypeCounts returns a count of live transports keyed by their actual network type (excluding "user" labeled). The key set is derived from the transports present rather than a hardcoded subset, so every current and future transport type (stcpr, sudph, stcp, dmsg, squicr, swsr, swtr, webrtc, …) is represented.

func (*Visor) GetVPNClientAddress

func (v *Visor) GetVPNClientAddress() string

GetVPNClientAddress get PK address of server set on vpn-client

func (*Visor) GoroutineDump

func (v *Visor) GoroutineDump() (string, error)

GoroutineDump implements API: every goroutine's stack in the pprof debug=2 text format. For builds with no pprof listener (a visor in a browser tab): the CLI's `visor goroutines` falls back to it.

func (*Visor) GroupAddMember

func (v *Visor) GroupAddMember(id string, pk cipher.PubKey) (visorapi.GroupInfo, error)

GroupAddMember extends the allowlist + persisted member list. Owner-side only.

func (*Visor) GroupApproveJoin

func (v *Visor) GroupApproveJoin(id string, pk cipher.PubKey) (visorapi.GroupInfo, error)

GroupApproveJoin admits a queued requester. Admin-only.

func (*Visor) GroupAskAgain

func (v *Visor) GroupAskAgain(id string) (visorapi.GroupInfo, error)

GroupAskAgain re-submits a join request an admin has DECLINED — the UI's "ask again" action. Everything is derived from the stored record, so the caller passes only the group id; the request pays the same PoW and rate-limit gates as a first ask (see group.Manager.AskAgain).

func (*Visor) GroupBanMember

func (v *Visor) GroupBanMember(id string, pk cipher.PubKey) (visorapi.GroupInfo, error)

GroupBanMember bars a peer from the group. Admin-only.

func (*Visor) GroupCatalog

func (v *Visor) GroupCatalog(host cipher.PubKey) ([]visorapi.GroupCatalogEntry, bool, error)

GroupCatalog asks a visor what groups and channels it publishes.

Answered locally when host is this visor, so an operator can see their own listing exactly as others would without a network round trip.

func (*Visor) GroupCreate

func (v *Visor) GroupCreate(args visorapi.GroupCreateArgs) (visorapi.GroupInfo, string, error)

GroupCreate constructs a new owner-side group on this visor. Returns the persisted info and the invite link so the operator can hand the link out.

func (*Visor) GroupDelete

func (v *Visor) GroupDelete(id string) error

GroupDelete tears down an owner-side group and marks it revoked.

func (*Visor) GroupDemoteAdmin

func (v *Visor) GroupDemoteAdmin(id string, pk cipher.PubKey) (visorapi.GroupInfo, error)

GroupDemoteAdmin removes pk from the group's explicit Admins set. Refuses to demote the founder (immutable recovery anchor). Other admins can demote each other freely — the assumption is that admins trust each other by virtue of having been promoted.

func (*Visor) GroupDenyJoin

func (v *Visor) GroupDenyJoin(id string, pk cipher.PubKey) error

GroupDenyJoin declines a queued request. Admin-only.

func (*Visor) GroupFileKey

GroupFileKey returns the keys that seal and open one attachment of a group — derived per file, so the group key itself stays in the visor.

The chat app calls this on both sides of an attachment's life: once to seal a file it is about to publish, and once per file it needs to render or serve. See the group package's filekey.go for the derivation and cmd/apps/skychat/commands/filecrypt.go for the container.

func (*Visor) GroupGet

func (v *Visor) GroupGet(id string) (visorapi.GroupInfo, error)

GroupGet returns the info for a specific group, or ErrGroupNotFound.

Populates SubscriberAlive the same way GroupList does — without this, single-group queries (`cli skychat group info <id>`) always reported subscriber_alive=false regardless of the live session state, because toInfo doesn't reach into the session map. The list path was already correct; the single-group path silently dropped the field. Surfaced as a misleading symptom during the agent-coordination work today: persisted last_message_at would advance while subscriber_alive stayed false, and we kept chasing that as a session-state divergence when really it was the RPC shape leaving the field unpopulated.

func (*Visor) GroupHistory

func (v *Visor) GroupHistory(groupID string, limit int) ([]visorapi.GroupMessage, error)

GroupHistory returns up to limit most recent persisted messages for the named group. Persistence is opt-in (see init_group.go's history store wiring); when disabled, returns ErrGroupHistoryDisabled. Mirrors GroupPoll's RPC shape but reads from disk instead of the in-memory ring buffer — operators can recover messages across visor restarts.

func (*Visor) GroupHistoryGroups

func (v *Visor) GroupHistoryGroups() ([]string, error)

GroupHistoryGroups lists every group ID that has stored messages. Returns ErrGroupHistoryDisabled when persistence is off.

func (*Visor) GroupHistoryPage

func (v *Visor) GroupHistoryPage(args visorapi.GroupHistoryPageArgs) ([]visorapi.GroupMessage, error)

GroupHistoryPage is GroupHistory with a backward cursor: up to Limit messages strictly older than Before, newest last.

A zero Before asks for the newest page, so a client's first call and its subsequent "older, please" calls are the same request with the oldest timestamp it holds filled in. That is the whole mechanism behind reading a channel's backlog in chunks — see history.Store.ListGroupBefore.

func (*Visor) GroupInvite

func (v *Visor) GroupInvite(id string) (string, error)

GroupInvite returns a freshly-encoded invite link for an owner-side group. Members get an error (only owners can issue invites in D1).

func (*Visor) GroupJoin

func (v *Visor) GroupJoin(args visorapi.GroupJoinArgs) (visorapi.GroupInfo, error)

GroupJoin accepts an invite link OR a short skychat:// group address, registers a member-side record, and opens the subscriber. Returns the info on the joined group.

An address route costs one extra round trip (the describe) before the join proper; a link goes straight to the join. Both converge on Manager.RequestJoin, so admission policy, proof of work and rate limiting are identical either way — the address is a shorter way to name the group, not a shortcut past its door.

func (*Visor) GroupJoinRequests

func (v *Visor) GroupJoinRequests(id string) ([]visorapi.GroupJoinRequest, error)

GroupJoinRequests returns the admission queue for a group, newest first. Includes decided entries so callers can show history; filter on Status == "pending" for the actionable set.

func (*Visor) GroupLeave

func (v *Visor) GroupLeave(id string) error

GroupLeave is the member-side counterpart of Delete.

func (*Visor) GroupList

func (v *Visor) GroupList() ([]visorapi.GroupInfo, error)

GroupList returns every persisted group on this visor. The SubscriberAlive field is populated from the live session map — the only API surface where that's needed (the chat-app's /status renders per-group health from this).

func (*Visor) GroupMuteMember

func (v *Visor) GroupMuteMember(id string, pk cipher.PubKey) (visorapi.GroupInfo, error)

GroupMuteMember restricts a peer from posting. Admin-only.

func (*Visor) GroupPoll

func (v *Visor) GroupPoll(since time.Time) ([]visorapi.GroupMessage, error)

GroupPoll drains messages with TS > since. Mirrors PairPoll.

func (*Visor) GroupPromoteAdmin

func (v *Visor) GroupPromoteAdmin(id string, pk cipher.PubKey) (visorapi.GroupInfo, error)

GroupPromoteAdmin adds pk to the group's Admins set. Callable by any existing admin (founder implicitly, or any explicit Admins entry). Returns the updated info — surfacing Admins so the caller can confirm the grant landed.

func (*Visor) GroupRefreshMeta

func (v *Visor) GroupRefreshMeta(id string) (visorapi.GroupInfo, error)

GroupRefreshMeta re-reads a group's display metadata from its founding visor and returns the (possibly updated) info. Best-effort: an unreachable founder returns the local record unchanged rather than an error, because the caller is a UI opening a chat, and the founder being asleep is not a problem the person opening it can act on.

func (*Visor) GroupRemoveMember

func (v *Visor) GroupRemoveMember(id string, pk cipher.PubKey) (visorapi.GroupInfo, error)

GroupRemoveMember evicts a peer from the roster. Admin-only. A kick, not a ban — the peer may ask to rejoin.

func (*Visor) GroupResolve

GroupResolve says what a skychat address points at: a person, or a group/channel and what joining it involves.

This is what lets one input field accept anything a user can hold. A bare public key is answered locally — a key naming a person and a key hosting a channel are the same string, so only the address's shape can distinguish them, and a DM needs no permission to open. A group address is answered from this visor's own store when it already knows the group, and otherwise by asking the host.

func (*Visor) GroupRotateKey

func (v *Visor) GroupRotateKey(id string) (visorapi.GroupInfo, error)

GroupRotateKey mints a new key for an encrypted group and hands it to every current member, each copy sealed to that member's own PK. Admin-only.

Eviction rotates on its own; this is the operator-driven case — a key believed leaked, or tidying up after someone left out of band. Errors for a plaintext group, which has no key to rotate.

func (*Visor) GroupSend

func (v *Visor) GroupSend(args visorapi.GroupSendArgs) error

GroupSend publishes a message into the named group's feed. Owners write directly; members open a dmsg stream to the owner's relay listener and submit, the owner re-publishes with sender attribution preserved. Either way the sender's own subscriber renders the message back into its inbox so the UX is consistent across roles.

Bounded with a 30s context: a dead owner shouldn't hang an RPC caller forever. Members get a clean dial-timeout error they can surface to the operator.

func (*Visor) GroupSetJoinPoW

func (v *Visor) GroupSetJoinPoW(id string, bits uint8) (visorapi.GroupInfo, error)

GroupSetJoinPoW sets how much proof of work a join request must carry, in leading zero bits. Zero turns the price off. Admin-only.

The lever for a group being flooded: public keys are free, so this is what makes each identity cost measurable CPU. Local to this visor — see skychatgroup.Record.JoinPoWBits.

func (*Visor) GroupSetListed

func (v *Visor) GroupSetListed(id string, listed bool) (visorapi.GroupInfo, error)

GroupSetListed publishes (or un-publishes) a group in this visor's discovery catalog. Admin-only, and local rather than gossiped — it says what this visor answers questions about, not what the group is.

func (*Visor) GroupSetMeta

func (v *Visor) GroupSetMeta(args visorapi.GroupSetMetaArgs) (visorapi.GroupInfo, error)

GroupSetMeta updates a group's display metadata — name, picture, or both. Founder-only (the manager enforces it): members mirror the founding visor's record and re-learn these fields from it, so an edit anywhere else would only un-happen.

func (*Visor) GroupSetPeerBackfill

func (v *Visor) GroupSetPeerBackfill(id string, enabled bool) (visorapi.GroupInfo, error)

GroupSetPeerBackfill decides whether any online member may serve this group's history and messages to a joiner, or only admins. Admin-only.

Enabled (the default) is what keeps a group readable while its admins are offline; disabled restores the admins-only topology and the group goes dark whenever no admin is up.

func (*Visor) GroupSetReadOnly

func (v *Visor) GroupSetReadOnly(id string, readOnly bool) (visorapi.GroupInfo, error)

GroupSetReadOnly suspends (or resumes) posting for every non-admin. Admin-only.

func (*Visor) GroupUnbanMember

func (v *Visor) GroupUnbanMember(id string, pk cipher.PubKey) (visorapi.GroupInfo, error)

GroupUnbanMember lifts a ban. The peer must ask to join again.

func (*Visor) GroupUnmuteMember

func (v *Visor) GroupUnmuteMember(id string, pk cipher.PubKey) (visorapi.GroupInfo, error)

GroupUnmuteMember lifts a posting restriction. Admin-only.

func (*Visor) GroupUnsend

func (v *Visor) GroupUnsend(args visorapi.GroupUnsendArgs) error

GroupUnsend deletes a message the local visor published to the group, by its UnixNano timestamp. Only the sender can remove their own message; the deletion propagates to subscribers via CXO snapshot-diff.

func (*Visor) GrowMuxFromPool

func (v *Visor) GrowMuxFromPool(appName string, legs, minHops int, rgPort uint16) (int, error)

GrowMuxFromPool implements API. Grows the app's tunnel by `legs` additional mux legs, built on the routes of the app's STANDBY tunnels to the same exit instead of discovered from scratch, with today's route-finder grow as the fallback for whatever the pool cannot cover (see pool_legs.go). rgPort disambiguates concurrent rg's exactly as AddMuxRoute does. Returns the number of legs actually added.

func (*Visor) GrowMuxRoute

func (v *Visor) GrowMuxRoute(appName string, target, minHops int, rgPort uint16) (int, error)

GrowMuxRoute implements API. Adds disjoint legs to the app's active rg until it has `target` total legs (or route planning can no longer find a disjoint path), for failover redundancy. minHops floors the added legs' hop count so a multihop mux grows with multihop legs. rgPort disambiguates concurrent rg's by dst_port or src_port (0 auto-picks when exactly one is active). Returns the number of legs actually added.

func (*Visor) HVAddTransport

func (v *Visor) HVAddTransport(pk, remote cipher.PubKey, tpType, label string, timeout time.Duration) (*visorapi.TransportSummary, error)

HVAddTransport creates a new transport on the visor identified by pk.

func (*Visor) HVDeregisterTCPPort

func (v *Visor) HVDeregisterTCPPort(pk cipher.PubKey, port int) error

HVDeregisterTCPPort deregisters a skynet TCP port on the visor identified by pk.

func (*Visor) HVDmsgConnectAll

func (v *Visor) HVDmsgConnectAll(pk cipher.PubKey) (*visorapi.DmsgConnectAllResult, error)

HVDmsgConnectAll triggers a one-shot connect-all on the visor identified by pk.

func (*Visor) HVDmsgSessions

func (v *Visor) HVDmsgSessions(pk cipher.PubKey) (*visorapi.DmsgClientSessions, error)

HVDmsgSessions returns the per-client dmsg sessions snapshot for the visor identified by pk. Locally — short-circuits to the in-process visor; remotely — forwards over the hypervisor proxy.

func (*Visor) HVEmbeddedProxies

func (v *Visor) HVEmbeddedProxies(pk cipher.PubKey) (*visorapi.EmbeddedProxiesStatus, error)

HVEmbeddedProxies returns embedded resolving proxy status on the visor identified by pk.

func (*Visor) HVListDirectVisors

func (v *Visor) HVListDirectVisors() ([]visorapi.HVVisorEntry, error)

HVListDirectVisors returns summaries of visors DIRECTLY connected to this hypervisor — does NOT walk sub-hypervisors. Used by the tree builder to query each sub-hypervisor's own direct visors without pulling its already-flattened sub-merge.

Local visor is included first (with IsLocal=true) when this visor has the hypervisor flag enabled, matching HVListVisors's shape.

func (*Visor) HVListForwardedPorts

func (v *Visor) HVListForwardedPorts(pk cipher.PubKey) ([]visorapi.ForwardedPort, error)

HVListForwardedPorts returns the configured forwarded ports on the visor identified by pk.

func (*Visor) HVListTCPPorts

func (v *Visor) HVListTCPPorts(pk cipher.PubKey) ([]int, error)

HVListTCPPorts returns the registered skynet TCP ports on the visor identified by pk.

func (*Visor) HVListVisors

func (v *Visor) HVListVisors() ([]visorapi.HVVisorEntry, error)

HVListVisors returns summaries of all visors connected to this hypervisor.

func (*Visor) HVListVisorsTree

func (v *Visor) HVListVisorsTree() (*visorapi.HVVisorTree, error)

pairs), its table renders once. Per-section query timeout (10s) bounds wall time regardless of depth.

Currently 1 level deep (local + direct sub-hypervisors). Walking transitively to depth N would need a request-scoped visited-set on the wire so each hop knows what NOT to recurse into; out-of-scope for v1.

func (*Visor) HVLogsSince

func (v *Visor) HVLogsSince(pk cipher.PubKey, since time.Time, appName string) ([]string, error)

HVLogsSince returns app logs since the given timestamp on the visor identified by pk.

func (*Visor) HVRegisterForwardedPort

func (v *Visor) HVRegisterForwardedPort(pk cipher.PubKey, p visorapi.ForwardedPort) error

HVRegisterForwardedPort registers a forwarded port on the visor identified by pk.

func (*Visor) HVRegisterTCPPort

func (v *Visor) HVRegisterTCPPort(pk cipher.PubKey, port int) error

HVRegisterTCPPort registers a skynet TCP port on the visor identified by pk.

func (*Visor) HVReload

func (v *Visor) HVReload(pk cipher.PubKey) error

HVReload reloads the visor identified by pk.

func (*Visor) HVRemoveRoutingRule

func (v *Visor) HVRemoveRoutingRule(pk cipher.PubKey, key routing.RouteID) error

HVRemoveRoutingRule deletes a routing rule on the visor identified by pk.

func (*Visor) HVRemoveTransport

func (v *Visor) HVRemoveTransport(pk cipher.PubKey, tid uuid.UUID) error

HVRemoveTransport deletes a transport on the visor identified by pk.

func (*Visor) HVServiceHealth

func (v *Visor) HVServiceHealth(pk cipher.PubKey) ([]visorapi.ServiceHealthEntry, error)

HVServiceHealth returns deployment service health entries for the visor identified by pk.

func (*Visor) HVSetAutoStart

func (v *Visor) HVSetAutoStart(pk cipher.PubKey, appName string, autostart bool) error

HVSetAutoStart toggles autostart for an app on the visor identified by pk.

func (*Visor) HVSetCalculateRoutes

func (v *Visor) HVSetCalculateRoutes(pk cipher.PubKey, enable bool) error

HVSetCalculateRoutes toggles calculate_routes on the visor identified by pk.

func (*Visor) HVSetDmsgSessionsCount

func (v *Visor) HVSetDmsgSessionsCount(pk cipher.PubKey, count int) (*visorapi.DmsgConnectAllResult, error)

HVSetDmsgSessionsCount persists the dmsg sessions_count and triggers connect-all on the visor identified by pk.

func (*Visor) HVSetEmbeddedProxyEnabled

func (v *Visor) HVSetEmbeddedProxyEnabled(pk cipher.PubKey, kind string, enable bool) error

HVSetEmbeddedProxyEnabled enables/disables an embedded proxy ("dmsg" or "skynet") on the visor identified by pk.

func (*Visor) HVSetEmbeddedProxyUpstream

func (v *Visor) HVSetEmbeddedProxyUpstream(pk cipher.PubKey, kind, addr string) error

HVSetEmbeddedProxyUpstream sets the SOCKS5 upstream for an embedded proxy on the visor identified by pk.

func (*Visor) HVSetMinHops

func (v *Visor) HVSetMinHops(pk cipher.PubKey, hops uint16) error

HVSetMinHops sets the routing min_hops on the visor identified by pk.

func (*Visor) HVSetPublicAutoconnect

func (v *Visor) HVSetPublicAutoconnect(pk cipher.PubKey, enable bool) error

HVSetPublicAutoconnect toggles public_autoconnect on the visor identified by pk.

func (*Visor) HVSetRewardAddress

func (v *Visor) HVSetRewardAddress(pk cipher.PubKey, addr string) (string, error)

HVSetRewardAddress sets the reward address on the visor identified by pk. Returns the resulting config string from the visor.

func (*Visor) HVShutdown

func (v *Visor) HVShutdown(pk cipher.PubKey) error

HVShutdown shuts down the visor identified by pk.

func (*Visor) HVStartApp

func (v *Visor) HVStartApp(pk cipher.PubKey, appName string) error

HVStartApp starts an app on the visor identified by pk.

func (*Visor) HVStopApp

func (v *Visor) HVStopApp(pk cipher.PubKey, appName string) error

HVStopApp stops an app on the visor identified by pk.

func (*Visor) HVUpdateForwardedPort

func (v *Visor) HVUpdateForwardedPort(pk cipher.PubKey, p visorapi.ForwardedPort) error

HVUpdateForwardedPort updates a forwarded port on the visor identified by pk.

func (*Visor) HVVisorSummary

func (v *Visor) HVVisorSummary(pk cipher.PubKey) (*visorapi.Summary, error)

HVVisorSummary returns detailed info about a specific remote visor.

func (*Visor) Health

func (v *Visor) Health() (*visorapi.HealthInfo, error)

Health implements API.

func (*Visor) HostBridgeConnect added in v1.3.101

func (v *Visor) HostBridgeConnect(url string) error

HostBridgeConnect connects to the bridge at url, replacing any session, and keeps redialing it until HostBridgeDisconnect. The URL is saved in the config, so the visor reconnects at boot.

func (*Visor) HostBridgeDisconnect added in v1.3.101

func (v *Visor) HostBridgeDisconnect() error

HostBridgeDisconnect ends the session and its forwards, and removes them from the config.

func (*Visor) HostBridgeForward added in v1.3.101

func (v *Visor) HostBridgeForward(host, local string) (visorapi.HostBridgeForward, error)

HostBridgeForward listens on host on the bridge's host and passes each connection to local, an address the visor can dial. The forward is kept across reconnects and saved in the config.

func (*Visor) HostBridgeStatus added in v1.3.101

func (v *Visor) HostBridgeStatus() (visorapi.HostBridgeStatus, error)

HostBridgeStatus reports the session and its forwards.

func (*Visor) HostBridgeUnforward added in v1.3.101

func (v *Visor) HostBridgeUnforward(host string) error

HostBridgeUnforward stops the forward from host.

func (*Visor) HostStats

func (v *Visor) HostStats() (*visorapi.HostStatsInfo, error)

HostStats implements API. Best-effort: a probe failure on one subsystem (e.g., disk usage on an unusual mount layout) doesn't take down the whole call — that field is left at its zero value.

func (*Visor) IsDMSGClientReady

func (v *Visor) IsDMSGClientReady() (bool, error)

IsDMSGClientReady return availability of dsmg client

func (*Visor) IsHypervisorAuthEnabled

func (v *Visor) IsHypervisorAuthEnabled() bool

IsHypervisorAuthEnabled reports whether the hypervisor web UI requires a login right now. False when this visor runs no hypervisor.

func (*Visor) IsHypervisorEnabled

func (v *Visor) IsHypervisorEnabled() bool

IsHypervisorEnabled implements API.

func (*Visor) IsHypervisorUIServing

func (v *Visor) IsHypervisorUIServing() bool

IsHypervisorUIServing implements API. Reports whether the web UI is serving.

func (*Visor) IsPublicAutoconnectRunning

func (v *Visor) IsPublicAutoconnectRunning() bool

IsPublicAutoconnectRunning returns whether public autoconnect is running.

func (*Visor) IsStartupComplete

func (v *Visor) IsStartupComplete() bool

IsStartupComplete implements API.

func (*Visor) IsSuspended

func (v *Visor) IsSuspended() (bool, error)

IsSuspended reports whether the visor is currently suspended.

func (*Visor) KillApp

func (v *Visor) KillApp(appName string) error

KillApp implements API.

func (*Visor) ListCXOFeeds

func (v *Visor) ListCXOFeeds() []logserver.CXOFeedEntry

ListCXOFeeds implements logserver.CXOFeedsLister. Returns the system telemetry feed plus every user-registered feed, sorted by port for stable output.

func (*Visor) ListForwardedPorts

func (v *Visor) ListForwardedPorts() ([]visorapi.ForwardedPort, error)

ListForwardedPorts returns all forwarded ports with metadata.

func (*Visor) ListRawTCP

func (v *Visor) ListRawTCP() (map[uuid.UUID]*appnet.RawTCPForwardConn, error)

ListRawTCP implements API.

func (*Visor) ListTCPPorts

func (v *Visor) ListTCPPorts() ([]int, error)

ListTCPPorts implements API (legacy — returns port numbers only).

func (*Visor) ListUDPForwards

func (v *Visor) ListUDPForwards() ([]int, error)

ListUDPForwards returns the local ports with active client-side UDP forwards.

func (*Visor) LocalPK

func (v *Visor) LocalPK() cipher.PubKey

LocalPK returns this visor's public key. Used by gRPC handlers that need to default the source PK on calc-route style requests.

func (*Visor) LocalTransportStats

func (v *Visor) LocalTransportStats() (*visorapi.LocalTransportStatsResponse, error)

LocalTransportStats returns every per-transport record from the local stats store, sorted busiest-first. Returns an empty slice (no error) when the stats subsystem isn't initialized — the hvui then surfaces "no data" rather than an error.

func (*Visor) LocalUptimeStats

func (v *Visor) LocalUptimeStats(args visorapi.LocalUptimeArgs) (*visorapi.LocalUptimeResponse, error)

LocalUptimeStats returns the visor's tier-uptime bitmaps over the requested window. Returns an empty Tiers map (no error) when the stats subsystem isn't initialized so the hvui surfaces "no data" rather than an error.

func (*Visor) LogLevelStatus added in v1.3.100

func (v *Visor) LogLevelStatus() logserver.LogLevelStatus

LogLevelStatus implements logserver.LogLevelController.

func (*Visor) LogsSince

func (v *Visor) LogsSince(timestamp time.Time, appName string) ([]string, error)

LogsSince implements API.

func (*Visor) MailAttachment

func (v *Visor) MailAttachment(folder, id string, n int) (*skymail.AttachmentData, error)

MailAttachment implements visorapi.API.

func (*Visor) MailDelete

func (v *Visor) MailDelete(folder, id string) error

MailDelete implements visorapi.API.

func (*Visor) MailList

func (v *Visor) MailList(folder string) ([]skymail.Summary, error)

MailList implements visorapi.API.

func (*Visor) MailRaw

func (v *Visor) MailRaw(folder, id string) ([]byte, error)

MailRaw implements visorapi.API.

func (*Visor) MailRead

func (v *Visor) MailRead(folder, id string) (*skymail.Rendered, error)

MailRead implements visorapi.API.

func (*Visor) MailSend

func (v *Visor) MailSend(msg skymail.Outgoing) (*skymail.SendResult, error)

MailSend implements visorapi.API.

func (*Visor) MailSetSettings

func (v *Visor) MailSetSettings(u visorapi.MailSettingsUpdate) error

MailSetSettings implements visorapi.API: it applies at once and is kept in the mailbox's settings.json, which survives a restart and, in a browser tab, a reload.

func (*Visor) MailSetWhitelist

func (v *Visor) MailSetWhitelist(pks []cipher.PubKey) error

MailSetWhitelist implements visorapi.API.

func (*Visor) MailStatus

func (v *Visor) MailStatus() (*visorapi.MailStatus, error)

MailStatus implements visorapi.API.

func (*Visor) ManagedVisors

func (v *Visor) ManagedVisors() []cipher.PubKey

ManagedVisors implements logserver.RelatedNodesProvider. It returns the PKs of the visors this node manages as a hypervisor — the same connected set as `hv ls`. Empty when this node is not acting as a hypervisor (v.conf.Hypervisor nil), so the landing page only shows the managed-visors section for a node that actually IS a hypervisor. Reads v.remoteVisors lock-free, matching the existing RemoteVisors() accessor.

func (*Visor) MasterLogger

func (v *Visor) MasterLogger() *logging.MasterLogger

MasterLogger returns the underlying master logger (currently contained in visor config).

func (*Visor) MuxWeights

func (v *Visor) MuxWeights(appName string, rgPort uint16) (router.MuxWeightsView, error)

MuxWeights implements API. Reports the group's scheduler mode and, when it is the explicit one, the per-leg weights in force.

func (*Visor) NetworkView

func (v *Visor) NetworkView() (*visorapi.NetworkViewResponse, error)

NetworkView returns the combined SD/TPD/UT view, served from a short-lived cache. Cache is invalidated on miss/expiry; concurrent callers during a refetch share the new result. The error return is reserved for future use (e.g., reporting that *all* upstream services were unreachable); today the underlying compute never returns an error — partial fetches yield partial tables.

func (*Visor) NetworkViewRefresh

func (v *Visor) NetworkViewRefresh() (*visorapi.NetworkViewResponse, error)

NetworkViewRefresh forces re-aggregation regardless of cache age. Used by the UI's manual-refresh button.

func (*Visor) NewPairCode

func (v *Visor) NewPairCode(ttl time.Duration) (visorapi.PairCode, error)

NewPairCode implements API: a one-time code a tab can present to be approved without the CLI seeing its fingerprint.

func (*Visor) Notify

func (v *Visor) Notify(title, body, tag string)

Notify raises a notification from the VISOR itself — a transport that went down, a peer that came back, an update that landed — as opposed to relaying one an app published.

It exists so that adding a notification is one line at the place that already knows the thing happened, with no plumbing: the hub picks the tier that can reach the user, and every sink (a phone, the desktop notification center, a future manager-UI bell) already handles an event it has never seen before.

tag groups related notifications so a newer one replaces its predecessor — pass a stable string per subject (a peer's key, a service name) and leave it empty for one-offs that should stack. Nil-safe and non-blocking, like the hub.

func (*Visor) NotifyHub

func (v *Visor) NotifyHub() *NotifyHub

NotifyHub exposes the visor's notification hub. Nil-safe: a bare &Visor{} (test fixtures) has no hub.

func (*Visor) Overview

func (v *Visor) Overview() (*visorapi.Overview, error)

Overview implements API.

func (*Visor) PairAdd

func (v *Visor) PairAdd(peerPK cipher.PubKey) error

PairAdd creates a pair record for peerPK, brings up the local publisher (allowlist=[peerPK]) and a subscriber dialing peerPK at the deterministic pair-publisher port. The peer must independently call PairAdd on its own visor for the connection to actually succeed; until then the subscriber sits idle.

Idempotent — calling PairAdd for an existing peer returns nil.

func (*Visor) PairDelete

func (v *Visor) PairDelete(peerPK cipher.PubKey, id string) error

PairDelete retracts a message we previously sent to peerPK, naming it by the id PairSend returned. The retraction is published onto the pair feed, so it reaches the peer even if they are offline right now — delete-for-everyone over CXO, matching what a chat-delete envelope does over a framed DM conn.

func (*Visor) PairList

func (v *Visor) PairList() ([]visorapi.PairInfo, error)

PairList returns a snapshot of every persisted pair (pending / active / revoked).

func (*Visor) PairMarkActive

func (v *Visor) PairMarkActive(peerPK cipher.PubKey) error

PairMarkActive transitions a previously-added pair from pending → active. Called by the initiator's skychat when the peer's pair-ack arrives, signaling that both sides have publishers up and the user-visible status should reflect a confirmed pair.

No-op if the record is already active. Returns an error when pairing is disabled or no record exists for peerPK.

func (*Visor) PairPoll

func (v *Visor) PairPoll(since time.Time) ([]visorapi.PairMessage, error)

PairPoll returns inbound pair messages with TS strictly after `since`. Pass time.Time{} (zero) to retrieve the entire current inbox window. Messages older than the inbox capacity are dropped silently — clients that want guaranteed delivery should poll often enough that the window doesn't roll over between polls.

func (*Visor) PairRemove

func (v *Visor) PairRemove(peerPK cipher.PubKey) error

PairRemove tears down the pair (closing publisher + subscriber) and marks the record revoked. The bbolt record is preserved for audit; future tooling may add hard-purge.

func (*Visor) PairSend

func (v *Visor) PairSend(peerPK cipher.PubKey, text string) (string, error)

PairSend publishes one message to peerPK's pair feed and returns the new message's id — the same id the peer will see on it, so the caller can later retract it with PairDelete. Returns ErrNotFound if peerPK isn't a registered pair.

func (*Visor) PairStatusOf

func (v *Visor) PairStatusOf(pk cipher.PubKey) PairStatus

PairStatusOf reports whether pk is paired (trusted) or pending.

func (*Visor) PairWithCode

func (v *Visor) PairWithCode(pk cipher.PubKey, code string) error

PairWithCode approves pk if code is an outstanding one-time code.

func (*Visor) PendingHypervisors

func (v *Visor) PendingHypervisors() ([]visorapi.PendingHypervisor, error)

PendingHypervisors implements API: the peers waiting to be approved.

func (*Visor) Ping

func (v *Visor) Ping(conf visorapi.PingConfig) ([]time.Duration, error)

Ping implements API. Measures round-trip time by sending ping data and waiting for an echo response.

The ping.mu lock protects v.ping.conns (a map) and is released before any wire I/O so concurrent Ping/PingOnceWithEcho calls on DIFFERENT PingRouteRefs (the mux-bw N-routes scenario) don't serialize through one global mutex. The contract for callers using the same RouteRef from multiple goroutines remains "serialize externally" — the conn itself is a net.Conn and the ping protocol's size→ack→data→echo handshake assumes a single writer/reader pair per call. StopPing concurrent with this method's wire I/O will close the conn; the resulting Read/Write errors are caller-visible (and surfaced via MuxRouteFailure for mux-bw — see #2756) rather than indefinite-block.

func (*Visor) PingOnce

func (v *Visor) PingOnce(conf visorapi.PingConfig) (time.Duration, error)

PingOnce implements API. Performs a single ping and returns the round-trip time.

See Ping for the mutex-scoping rationale — same pattern: hold ping.mu only for the map lookup, do wire I/O without the lock.

func (*Visor) PingOnceWithEcho

func (v *Visor) PingOnceWithEcho(conf visorapi.PingConfig, echoFull bool) (bytesSent, bytesReceived uint64, latency time.Duration, err error)

PingOnceWithEcho performs a single ping with optional full echo. Returns bytes sent, bytes received, latency, and error. If echoFull is true, server echoes full payload (for bandwidth testing).

HOT PATH for mux-bw bandwidth measurements. Previously held ping.mu for the entire wire roundtrip (~287ms at 2-hop with 32 KB payloads), which globally serialized all N parallel pump goroutines through one mutex — bytes-aggregate-across-N didn't scale and per-route avg stayed pinned at ~351 kbps even though peak per-call could hit ~1.7 Mbps. After PR #2761, the lock is held only for the conns-map lookup; wire I/O on the chosen conn runs unlocked, letting N pump goroutines on DIFFERENT PingRouteRefs run truly in parallel. See Ping doc comment for the conn-lifecycle contract.

The entire call is bounded by a single 10s conn.SetDeadline at entry (cleared on return). Previously each of the 4 wire steps (write size, read ack, write ping, read echo) had its own 30s deadline, so a single stuck step could hang up to 30s — racing the mux-bw pumpCtx's default 30s duration and causing the pump to suppress the resulting MuxRouteFailure event (task #131). 10s gives the pump 3+ failed iterations within its window so a stuck-route error reliably reaches the consumer.

func (*Visor) PinnedProxyExit

func (v *Visor) PinnedProxyExit() string

PinnedProxyExit returns the skysocks-client --srv key the CONFIG carried at boot, or "" when the client did not autostart on a pinned exit. It is the operator's choice, recorded before anything can re-point the app, so a consumer can tell a configured exit from one the visor or the operator switched to later.

func (*Visor) Ports

func (v *Visor) Ports() (map[string]visorapi.PortDetail, error)

Ports return list of all ports used by visor services and apps

func (*Visor) ProfileFetch

func (v *Visor) ProfileFetch(pk cipher.PubKey) (visorapi.Profile, error)

ProfileFetch asks the visor at pk who it is.

A zero key, or this visor's own, is answered from the local store — the same courtesy GroupCatalog gives an operator inspecting their own listing, and the reason a UI can use one call for both.

A peer that does not answer is NOT an error to the caller's user: every call site has the public key itself as a perfectly good fallback. It is still returned as an error here so the caller can tell "reachable, says nothing" from "could not ask", which are different things to show.

func (*Visor) ProfileGet

func (v *Visor) ProfileGet() (visorapi.Profile, error)

ProfileGet returns what this visor publishes about itself.

An unset profile is reported as an empty one with the key and address filled in, not as an error: those two fields are what the "my address" dialog needs, and they are true whether or not a name was ever set.

func (*Visor) ProfileSet

func (v *Visor) ProfileSet(args visorapi.ProfileSetArgs) (visorapi.Profile, error)

ProfileSet writes this visor's published profile and returns what was actually stored — normalization may have trimmed the name, and the caller should show the user what their peers will see rather than what they typed.

func (*Visor) ProxyServers

func (v *Visor) ProxyServers(version, country string) ([]servicedisc.Service, error)

ProxyServers gets available proxy servers — CXO snapshot first, HTTP service-discovery fallback.

func (*Visor) PublicAutoconnectStatus

func (v *Visor) PublicAutoconnectStatus() (bool, error)

PublicAutoconnectStatus returns whether public autoconnect is currently running

func (*Visor) PublicVisors

func (v *Visor) PublicVisors(version, country string) ([]servicedisc.Service, error)

PublicVisors gets available public visors — CXO snapshot first, HTTP service-discovery fallback.

func (*Visor) ReachCardBody added in v1.3.100

func (v *Visor) ReachCardBody() ([]byte, error)

ReachCardBody is this visor's signed reach card, built from its own address resolver records.

func (*Visor) RecentAppEvents

func (v *Visor) RecentAppEvents(appName string, minLevel logrus.Level) (events, logs []logging.Record)

RecentAppEvents returns the recent app-scoped route/transport events and log lines captured for appName by the log broadcaster's per-app ring, filtered to entries at least as severe as minLevel. Both slices are oldest-first. Returns empty slices (not an error) when nothing has been captured.

func (*Visor) RecentAppLog

func (v *Visor) RecentAppLog(appName, level string) ([]string, error)

RecentAppLog implements API. It returns the recent app-scoped route/transport events + log lines captured for appName by the log broadcaster's per-app ring, merged into one time-ordered slice and formatted as visor log lines. level is the minimum severity ("trace".."error"; empty defaults to "debug").

func (*Visor) RecentAppLogMerged

func (v *Visor) RecentAppLogMerged(appName string, minLevel logrus.Level) []logging.Record

RecentAppLogMerged returns the recent events+logs for appName merged into one time-ordered slice (oldest first), filtered to entries at least as severe as minLevel. This is the "reading the log" view `cli proxy log` prints.

func (*Visor) RegisterApp

func (v *Visor) RegisterApp(procConf appcommon.ProcConfig) (appcommon.ProcKey, error)

RegisterApp implements API.

func (*Visor) RegisterCXOFeed

func (v *Visor) RegisterCXOFeed(name string, dmsgPort uint16, description string) error

RegisterCXOFeed creates and starts a user CXO feed under name on dmsgPort. Idempotent on (name, port) — registering an existing feed returns nil without re-creating it. Conflicts (same name with a different port, or a port collision with another feed/system port) return errors.

func (*Visor) RegisterForwardedPort

func (v *Visor) RegisterForwardedPort(p visorapi.ForwardedPort) error

RegisterForwardedPort registers a port with full metadata.

func (*Visor) RegisterTCPPort

func (v *Visor) RegisterTCPPort(localPort int) error

RegisterTCPPort implements API (legacy — wraps RegisterForwardedPort with skynet-only defaults).

func (*Visor) RehomeTunnelLeg

func (v *Visor) RehomeTunnelLeg(appName string, targetPort, standbyPort uint16) error

RehomeTunnelLeg implements API. Moves the STANDBY tunnel's whole built chain into the ACTIVE tunnel as one more mux leg, in place, with no setup-node dial. Both tunnels belong to appName and must join the same peer.

On success the app is told its standby tunnel was CONSUMED rather than lost, so it drops it from the pool without the redial backoff reset and pool fill a death triggers. The op lands on the app's next settings pull.

func (*Visor) ReinitiateModule

func (v *Visor) ReinitiateModule(module string) error

ReinitiateModule implements API.

func (*Visor) Reload

func (v *Visor) Reload() error

Reload implements API.

func (*Visor) RemoteVisors

func (v *Visor) RemoteVisors() ([]string, error)

RemoteVisors return list of connected remote visors

func (*Visor) RemoveAllHypervisors

func (v *Visor) RemoveAllHypervisors() (int, error)

RemoveAllHypervisors tears down every runtime-added hypervisor connection. Returns the count of hypervisors that were disconnected.

func (*Visor) RemoveAllTransports

func (v *Visor) RemoveAllTransports() error

RemoveAllTransports implements API

func (*Visor) RemoveHypervisor

func (v *Visor) RemoveHypervisor(hvPK cipher.PubKey) error

RemoveHypervisor tears down a runtime-added hypervisor connection by PK. Only succeeds for hypervisors that were added via AddHypervisor — config-loaded hypervisors take a different code path and don't enter v.hypervisorCancels. Idempotent: returns nil if the PK isn't currently a runtime-added hypervisor.

The connection's goroutine, on cancel, runs its deferred delete of hvPK from both connectedHypervisors and hypervisorCancels — so by the time RemoveHypervisor returns, the visor's view of "connected hypervisors" no longer includes hvPK.

func (*Visor) RemoveMuxRoute

func (v *Visor) RemoveMuxRoute(appName string, tpID uuid.UUID, rgPort uint16) error

RemoveMuxRoute implements API. Drops the leg over the given transport from the app's active rg; rgPort disambiguates as in AddMuxRoute.

func (*Visor) RemoveRoutingRule

func (v *Visor) RemoveRoutingRule(key routing.RouteID) error

RemoveRoutingRule implements API.

func (*Visor) RemoveTransport

func (v *Visor) RemoveTransport(tid uuid.UUID) error

RemoveTransport implements API.

func (*Visor) ResetRouteSetupStats

func (v *Visor) ResetRouteSetupStats() error

ResetRouteSetupStats clears all counters and ring buffers on the embedded Route Setup Node's stats collector.

func (*Visor) RestartApp

func (v *Visor) RestartApp(appName string) error

RestartApp implements API.

func (*Visor) Resume

func (v *Visor) Resume() error

Resume re-runs the module graph to bring a suspended visor fully back online. The local CLI RPC surface was never torn down (cliLocalUp), so initCLI only re-creates its dmsg/transport-bound surfaces. Idempotent: Resume on a running visor is a no-op.

func (*Visor) RolesSnapshot

func (v *Visor) RolesSnapshot() *visorapi.RolesSnapshot

RolesSnapshot builds the roles section. Cheap and best-effort: a not-yet-initialized dmsg client or config leaves the corresponding role zero-valued rather than failing.

func (*Visor) RouteGroupMuxInfo

func (v *Visor) RouteGroupMuxInfo(appName string) ([]visorapi.MuxRouteGroupInfo, error)

RouteGroupMuxInfo implements API. Returns per-mux-leg byte/packet/ latency counters for every active route group tagged with the named app. The visor's router holds the rg's; we just transcribe the internal MuxInfo into the wire-friendly visor-level shape.

func (*Visor) RouteGroupMuxNegotiated

func (v *Visor) RouteGroupMuxNegotiated(appName string) ([]router.MuxNegotiated, error)

RouteGroupMuxNegotiated implements API. Per-group negotiated capabilities and the send-window shape in effect.

func (*Visor) RouteGroups

func (v *Visor) RouteGroups() (rgs []visorapi.RouteGroupInfo, err error)

func (*Visor) RouteSetupStats

func (v *Visor) RouteSetupStats() (*setupmetrics.StatsSnapshot, error)

RouteSetupStats returns a snapshot of the embedded Route Setup Node's request statistics. Returns an error if no embedded RSN is running on this visor (i.e. route_setup_sk is not configured).

func (*Visor) RoutingPolicies

func (v *Visor) RoutingPolicies() (*visorapi.RoutingPoliciesSummary, error)

RoutingPolicies projects the router's installed DialHook into a summary the hypervisor UI can render. Returns an empty summary (with no default + empty PerApp) when no hook is installed or the installed hook isn't a *policy.Hook.

func (*Visor) RoutingRule

func (v *Visor) RoutingRule(key routing.RouteID) (routing.Rule, error)

RoutingRule implements API.

func (*Visor) RoutingRules

func (v *Visor) RoutingRules() ([]routing.Rule, error)

RoutingRules implements API.

func (*Visor) RoutingStats

func (v *Visor) RoutingStats() (routing.RoutingTableStats, error)

RouteGroups implements API. Returns one entry per active route group on the visor, with the descriptor, hop path, and initiator flag.

The previous implementation walked v.router.Rules() looking for Reverse rules and then dereferenced the matching forward rule via NextRouteID(). Reverse (Consume) rules don't carry a NextRouteID, so the lookup always failed and this function returned an empty list. We now drive directly off the router's active route-group set (rgsNs) via ActiveRouteStatuses, which already holds the descriptor, hops, and initiator flag. RoutingStats implements API. Returns this visor's routing-table observability counters (live rule count, route-ID high-water, per-type breakdown). On a relay these are how the soak harness detects rule/reserved-ID leaks.

func (*Visor) RuntimeLogs

func (v *Visor) RuntimeLogs() (string, error)

RuntimeLogs returns visor runtime logs

func (*Visor) RuntimeLogsSince

func (v *Visor) RuntimeLogsSince(since int64) (visorapi.RuntimeLogsDelta, error)

RuntimeLogsSince returns only entries whose log_line is strictly greater than since. Used for diff-based live tailing of the runtime-logs buffer; pass the previous response's Latest as `since` to fetch only the new entries since the last poll.

func (*Visor) RuntimeStats

func (v *Visor) RuntimeStats() (*visorapi.RuntimeStatsInfo, error)

RuntimeStats implements API.

func (*Visor) SaveRoutingRule

func (v *Visor) SaveRoutingRule(rule routing.Rule) error

SaveRoutingRule implements API.

func (*Visor) ServeMeshProxy

func (v *Visor) ServeMeshProxy(ctx context.Context, cfg *visorconfig.BrowseOriginConfig, aliases map[string]cipher.PubKey) error

ServeMeshProxy runs the browse-origin listener(s) until ctx is done, dispatched by cfg.Mode ("subdomain" default, or "port"). aliases maps friendly labels to PKs (same set the dmsgweb resolver uses).

func (*Visor) ServiceHealth

func (v *Visor) ServiceHealth() ([]visorapi.ServiceHealthEntry, error)

ServiceHealth checks the health of all configured deployment services.

Each service URL is probed over the same transport the visor is configured to use: URLs with a dmsg:// scheme go through the visor's DMSG client, http/https URLs go through the default HTTP transport. This matches the visor's actual traffic path, so the dashboard reflects the reachability the visor itself experiences (not a separate probe path).

Entries are returned in a stable order (HTTP/DMSG services first, then DMSG servers sorted by PK, then route setup nodes, then transport setup nodes). Network checks within each group run in parallel so the total response time is dominated by the slowest single check.

The following are probed:

  • Services: Config Service, Transport Discovery, DMSG Discovery, Address Resolver, Route Finder, Service Discovery (each via GET {base}/health, dmsg:// or http://)
  • DMSG servers: one entry per server the visor currently has an active session with; latency comes from the visor's measured dmsg latency table
  • Route Setup Nodes: one entry per PK in EffectiveRouteSetupNodes; health is determined by whether the DMSG discovery entry has a non-empty DelegatedServers list (RSN/TPS don't serve HTTP /health over DMSG, so discovery registration is the health signal)
  • Transport Setup Nodes: same scheme as RSN

func (*Visor) SetAppAddress

func (v *Visor) SetAppAddress(appName string, address string) error

SetAppAddress implements API.

func (*Visor) SetAppArgs

func (v *Visor) SetAppArgs(appName string, args []string) error

SetAppArgs replaces the entire Args slice on the named app. Used by the universal app-settings panel where the operator edits args as a shell-string; the caller (HTTP handler / CLI) is responsible for tokenizing.

func (*Visor) SetAppDNS

func (v *Visor) SetAppDNS(appName string, dnsAddr string) error

SetAppDNS implements API.

func (*Visor) SetAppDetailedStatus

func (v *Visor) SetAppDetailedStatus(appName, status string) error

SetAppDetailedStatus implements API.

func (*Visor) SetAppEnv

func (v *Visor) SetAppEnv(appName, key, value string) error

SetAppEnv implements API. Sets / replaces / deletes a KEY=value entry on the named app's environment. Empty value deletes.

func (*Visor) SetAppEnvBatch

func (v *Visor) SetAppEnvBatch(appName string, env map[string]string) error

SetAppEnvBatch is the multi-key counterpart to SetAppEnv. Single config flush + launcher reset for the whole batch.

func (*Visor) SetAppEnvFull

func (v *Visor) SetAppEnvFull(appName string, env []string) error

SetAppEnvFull replaces the entire Env slice on the named app. Counterpart to SetAppArgs for environment vars; the per-key SetAppEnv RPC is still available for targeted mutation.

func (*Visor) SetAppError

func (v *Visor) SetAppError(appName, appErr string) error

SetAppError implements API.

func (*Visor) SetAppKillswitch

func (v *Visor) SetAppKillswitch(appName string, killswitch bool) error

SetAppKillswitch implements API.

func (*Visor) SetAppLauncherMode

func (v *Visor) SetAppLauncherMode(appName, mode string) error

SetAppLauncherMode persists the launcher-mode preference for an app entry. Empty clears the override; "internal" / "external" pin the mode. Honored by StartApp on the next start.

func (*Visor) SetAppNetworkInterface

func (v *Visor) SetAppNetworkInterface(appName, netifc string) error

SetAppNetworkInterface implements API.

func (*Visor) SetAppPK

func (v *Visor) SetAppPK(appName string, pk cipher.PubKey) error

SetAppPK implements API.

func (*Visor) SetAppRoutingPolicy

func (v *Visor) SetAppRoutingPolicy(appName, path string) error

SetAppRoutingPolicy installs (or clears) a per-app routing policy at runtime. Backend is dispatched by file extension — `.wasm` uses the WASM loader, anything else (including the inline-Starlark form) uses the Starlark loader. The swap is live: the running app picks up the new policy on its next dial, no restart required.

path == "" or "none" clears the per-app entry, falling the app back to the visor-wide policy (or no policy if none is configured).

Returns ErrRouterNotAvailable when called before router initialization completes.

func (*Visor) SetAppSecure

func (v *Visor) SetAppSecure(appName string, isSecure bool) error

SetAppSecure implements API.

func (*Visor) SetAppSettings

func (v *Visor) SetAppSettings(appName string, vals map[string]int64, text map[string]string) (visorapi.AppSettings, error)

SetAppSettings replaces the whole intended knob set for appName and returns the state that results, so a caller sees the new version without a second round-trip. Empty or nil maps are a full reset: a knob the maps do not name goes back to the value the app compiled with.

PERSISTED. The set is written to the visor config, so it survives both the app stopping and the visor restarting — the two silent resets that made every bench sweep re-apply itself. `proxy settings --reset` sends empty maps, which clears the app here and drops its entry from the config; the version counter still MOVES, so the running app learns of the reset on its next pull rather than keeping what it already installed.

func (*Visor) SetAppWhitelist

func (v *Visor) SetAppWhitelist(appName, whitelist string) error

SetAppWhitelist implements API. Updates the comma-separated PK whitelist that gates incoming connections on skysocks / vpn-server. Empty value means "open to all authenticated peers" — same semantics as omitting the flag.

Replaces the older SetAppPassword: the apps no longer recognize a --passcode flag, so updating that arg was a silent no-op (or worse, would prevent the app from starting if the flag definition was tightened).

func (*Visor) SetAutoStart

func (v *Visor) SetAutoStart(appName string, autoStart bool) error

SetAutoStart implements API.

func (*Visor) SetCalculateRoutes

func (v *Visor) SetCalculateRoutes(enabled bool) error

SetCalculateRoutes sets calculate_routes routing config of visor

func (*Visor) SetConfigFields

func (v *Visor) SetConfigFields(fields map[string]json.RawMessage) ([]visorapi.ConfigFieldChange, error)

SetConfigFields validates every requested field against the visorconfig.V1 struct and then applies them: live where a live setter is registered for the path, otherwise into the config file for the next start. Validation is done for ALL fields before ANY is applied, so a typo in the third argument does not leave the first two half-applied.

Returns one ConfigFieldChange per field, sorted by path.

func (*Visor) SetDmsgSessionsCount

func (v *Visor) SetDmsgSessionsCount(count int) (*visorapi.DmsgConnectAllResult, error)

SetDmsgSessionsCount updates the visor's dmsg.sessions_count setting (written to skywire-config.json so it survives restart — but not a config regen, which rebuilds the json from /etc/skywire.conf; set MINDMSGSESS there to make it durable on an autoconfig-managed host) and immediately attempts to maximize current session count if the new value is higher or zero (zero = connect to all available servers).

Note: the live dmsg.Client's MinSessions is not currently mutable at runtime — the change takes full effect on next visor restart. The DmsgConnectAll one-shot is invoked inline so the visor reaches the desired connectivity immediately in addition to persisting the change.

func (*Visor) SetEmbeddedProxyBind

func (v *Visor) SetEmbeddedProxyBind(kind, addr string) error

SetEmbeddedProxyBind changes the SOCKS5 bind host for a resolving proxy at runtime AND persists it (proxy_addr + enable) to the visor config, so it survives a restart — the way to make a board a `.dmsg`/`.skynet` LAN gateway without a config-file edit. Pass "" for loopback (the default) or "0.0.0.0"/a LAN IP to serve the LAN. Note: a subsequent `skywire autoconfig` regenerates the config from skywire.conf and would reset this; on autoconfig-managed hosts, set DMSGWEBADDR in skywire.conf instead.

func (*Visor) SetEmbeddedProxyEnabled

func (v *Visor) SetEmbeddedProxyEnabled(kind string, enable bool) error

SetEmbeddedProxyEnabled starts or stops a resolver at runtime. kind is case-insensitive "dmsg" or "skynet". If the resolver was never constructed (no config section), it is constructed on-the-fly with defaults so `proxies set dmsg on` works from a fresh visor without editing the config file.

func (*Visor) SetEmbeddedProxyUpstream

func (v *Visor) SetEmbeddedProxyUpstream(kind, addr string) error

SetEmbeddedProxyUpstream changes the upstream SOCKS5 address for a resolving proxy at runtime. The resolver is restarted to apply the change. Pass "" to clear the upstream.

func (*Visor) SetExistingTPOnly

func (v *Visor) SetExistingTPOnly(enabled bool) error

SetExistingTPOnly implements API. Sets whether to only use existing transports for routing (no new transport creation).

func (*Visor) SetForceLocalRoutes

func (v *Visor) SetForceLocalRoutes(enabled bool) error

SetForceLocalRoutes implements API. Sets whether to skip the route finder and use local route calculation.

func (*Visor) SetHypervisorAuthPersist

func (v *Visor) SetHypervisorAuthPersist(enable, persist bool) error

SetHypervisorAuthPersist turns the hypervisor web UI's login requirement on or off without restarting the visor, and optionally writes it to the config. Only the UI's HTTP listener is cycled; see Hypervisor.SetAuth.

func (*Visor) SetHypervisorPassword

func (v *Visor) SetHypervisorPassword(oldPassword, newPassword string) error

SetHypervisorPassword changes the hypervisor UI's "admin" account password. Mirrors the /api/change-password endpoint without the HTTP session check — RPC is local-only and already privileged. Returns an error when this visor isn't hosting a hypervisor.

func (*Visor) SetHypervisorPasswordForce

func (v *Visor) SetHypervisorPasswordForce(newPassword string) error

SetHypervisorPasswordForce sets the hypervisor UI's "admin" account password WITHOUT the old one, creating the account if none exists. For the local privileged RPC path (skywire cli visor hv passwd --force): forgotten-password reset, or a first-time set from the CLI. Returns an error when this visor isn't hosting a hypervisor.

func (*Visor) SetIsPublic

func (v *Visor) SetIsPublic(isPublic bool) error

SetIsPublic sets is_public config of visor and flushes the config.

func (*Visor) SetLANDmsgServer

func (v *Visor) SetLANDmsgServer(info visorapi.LANDmsgServerInfo) error

SetLANDmsgServer is called by the hypervisor (via RPC) to inform this visor about the hypervisor's embedded DMSG server. The visor connects to it (LAN address first, public fallback if set) and saves both entries to config so future restarts can reach the server without depending on a fresh push.

func (*Visor) SetLocalGraphSource

func (v *Visor) SetLocalGraphSource(src LocalGraphSource)

SetLocalGraphSource installs (or with nil, removes) the local graph source.

func (*Visor) SetLogBroadcaster

func (v *Visor) SetLogBroadcaster(b *logging.Broadcaster)

SetLogBroadcaster wires the visor with the master logger's Broadcaster hook. Stored on the Visor so the gRPC adapter can forward Subscribe calls through to it.

func (*Visor) SetLogstore

func (v *Visor) SetLogstore(store logstore.Store)

SetLogstore sets visor runtime logstore

func (*Visor) SetMinHops

func (v *Visor) SetMinHops(in uint16) error

SetMinHops sets min_hops routing config of visor

func (*Visor) SetMuxCap

func (v *Visor) SetMuxCap(n int) error

SetMuxCap implements API. Sets the hard ceiling on adaptive mux active width (the aggregation ceiling) at runtime — the adaptive engine reads it on the next tick of every route group, so it takes effect live without a restart.

This drives the process-global preset atomic. For a preset:* (wasm) policy the value now reaches the sandboxed wazero guest via the decide/tick input wire (the host stamps it, the guest applies it before dispatch — see pkg/router/policy/wasm), so the reported applied value is honest for the wasm path too, not only the native/wasm-visor in-process path (#4325).

func (*Visor) SetMuxDirection

func (v *Visor) SetMuxDirection(appName, mode string) error

SetMuxDirection implements API. Pins (or releases) the unidirectional direction→leg-class mapping on ALL of the app's active directional route groups — a proxy session can hold several concurrent rg's (one per SOCKS5 connection), and pinning only one would leave the others' controllers free to diverge. mode is "auto" (release — the flip controller resumes on both ends), "default" (initiator sends on the direct leg / download rides the multihop mux) or "flipped" (the swapped mapping). Each rg signals the pin to its peer over the wire; against an old peer the pin is best-effort local-only.

func (*Visor) SetMuxMode

func (v *Visor) SetMuxMode(mode string) error

SetMuxMode implements API. Sets the weight distribution mode for mux transport selection. Runtime-only: held in the router, never written to the config, lost on restart. There is no skywire.conf field for it.

func (*Visor) SetMuxStandby

func (v *Visor) SetMuxStandby(n int) error

SetMuxStandby implements API. Sets the warm-standby reserve pool size — the number of full-duplex spare legs the adaptive default holds parked for instant, dip-free promotion (decideAdaptive requests Mux = width + standby). Takes effect on the next dial (the requested Mux width) and tick. Clamped to >= 1; pulls cap (and width) down if they would exceed the new pool. Reaches wasm presets via the input wire (see SetMuxCap).

func (*Visor) SetMuxWeights

func (v *Visor) SetMuxWeights(appName string, weights map[string]float64, rgPort uint16) (router.MuxWeightsView, error)

SetMuxWeights implements API. Pins the app's route group to operator-supplied per-leg send weights, keyed by the leg's first-hop transport id. rgPort disambiguates concurrent rg's exactly as AddMuxRoute does.

func (*Visor) SetMuxWidth

func (v *Visor) SetMuxWidth(n int) error

SetMuxWidth implements API. Sets the steady active download width (the floor the adaptive engine converges to when idle) at runtime. Takes effect live. Clamped to [1, cap]; reaches wasm presets via the input wire (see SetMuxCap).

func (*Visor) SetPersistentTransports

func (v *Visor) SetPersistentTransports(pTps []transport.PersistentTransports) error

SetPersistentTransports replaces the visor's persistent_transports list — in the transport manager's cache and in skywire-config.json, so it survives a restart. Not a config regen: `skywire autoconfig` rebuilds the json from /etc/skywire.conf, which has no field for persistent_transports.

func (*Visor) SetPublicAutoconnect

func (v *Visor) SetPublicAutoconnect(pAc bool) error

SetPublicAutoconnect sets public_autoconnect config of visor

func (*Visor) SetRewardAddress

func (v *Visor) SetRewardAddress(p string) (string, error)

SetRewardAddress implements API. The durable store is <local_path>/reward.txt, not skywire-config.json — the in-memory conf field below is never flushed, and reward.txt sits outside the generated json, so the address survives both a restart and a config regen. REWARDSKYADDR in skywire.conf sets it at gen time.

func (*Visor) SetRouterDialSettings

func (v *Visor) SetRouterDialSettings(s visorapi.RouterDialSettings) error

SetRouterDialSettings implements API. Applies every field the caller set; a zero field is left alone (see RouterDialSettings). A refused value — the accessors validate — is reported rather than silently dropped, and the settings applied before it stay applied: the caller asked for each one independently.

func (*Visor) SetRouterSettings

func (v *Visor) SetRouterSettings(s visorapi.RouterSettings) error

SetRouterSettings is the unified setter behind PUT /visors/{pk}/router-settings. Each field is applied via the existing per-knob setter so the same persistence rules apply. Returns an error mid-way if any setter fails; partial application is possible — UI surfaces should re-fetch on error.

func (*Visor) SetRuntimeConfig

func (v *Visor) SetRuntimeConfig(rawJSON []byte) error

SetRuntimeConfig validates and writes the visor's on-disk config. The visor is NOT hot-reloaded; the operator must restart the process for the new config to take effect.

func (*Visor) SetSTCPAddr

func (v *Visor) SetSTCPAddr(pk cipher.PubKey, addr string) error

SetSTCPAddr injects an STCP PK table entry at runtime, mapping a public key to a TCP address. This allows creating STCP transports to visors not preconfigured in the STCP config.

func (*Visor) SetSkychatPassword

func (v *Visor) SetSkychatPassword(oldPassword, newPassword string) error

SetSkychatPassword writes a salted SHA256 hash of newPassword to the visor's skychat-password file and ensures the skychat app is launched with --password-file pointing at it. If a password is currently set, oldPassword must verify against it. Mirrors the hypervisor's ChangePassword shape.

func (*Visor) SetSkyenv

func (v *Visor) SetSkyenv(req visorapi.SkyenvEdits) (visorapi.SkyenvState, error)

SetSkyenv implements visorapi.API.

func (*Visor) SetTempLogLevel added in v1.3.100

func (v *Visor) SetTempLogLevel(level logrus.Level, ttl time.Duration) (logserver.LogLevelStatus, error)

SetTempLogLevel implements logserver.LogLevelController. Setting a level while one is already in force replaces its level and ttl but keeps the original base.

func (*Visor) SetTransportPreference

func (v *Visor) SetTransportPreference(order []string) error

SetTransportPreference installs the transport-type priority order and writes it to routing.transport_preference, so it survives a restart — but not a config regen: `skywire autoconfig` rebuilds the json from /etc/skywire.conf, which has no field for it. An empty slice reverts to the built-in default. Every name must be a known transport type — a silently-dropped typo would leave the caller believing a preference is in force that isn't.

func (*Visor) SetUptimeRecorder

func (v *Visor) SetUptimeRecorder(r *serviceuptime.Recorder)

SetUptimeRecorder attaches a serviceuptime.Recorder to the visor. Idempotent re-attach is a no-op (first writer wins). Wires:

  • the running recorder onto the logserver so /uptime/* routes surface live data over HTTP.

The recorder's keepalive lifecycle is owned by the caller; this method only stores the handle and registers it with surfaces that need to read from it.

func (*Visor) Shutdown

func (v *Visor) Shutdown() error

Shutdown implements API.

func (*Visor) SkychatHTTP added in v1.3.100

func (v *Visor) SkychatHTTP(in visorapi.SkychatHTTPIn) (visorapi.SkychatHTTPOut, error)

SkychatHTTP is SkychatProxy for callers over RPC, such as the CLI when skychat runs portless.

func (*Visor) SkychatLocalAddr

func (v *Visor) SkychatLocalAddr() (string, error)

SkychatLocalAddr returns the host:port the visor's skychat is configured to bind. Used by the UI to show / link the standalone surface. Empty when skychat isn't configured on this visor.

func (*Visor) SkychatPasswordIsSet

func (v *Visor) SkychatPasswordIsSet() (bool, error)

SkychatPasswordIsSet reports whether a non-empty password file exists for the skychat app on this visor.

func (*Visor) SkychatProxy

func (v *Visor) SkychatProxy(method, path string, query string, headers http.Header, body io.Reader) (int, http.Header, []byte, error)

SkychatProxy proxies a request to the local skychat HTTP server. Returns the response status, headers and body. Used by the hypervisor's /api/visors/<pk>/skychat/* mount.

path must be the suffix after "/skychat/" (e.g. "sse", "history/peers"). The proxy attaches the internal token so the password gate is bypassed for in-process hvui calls.

func (*Visor) Skyenv

func (v *Visor) Skyenv() (visorapi.SkyenvState, error)

Skyenv implements visorapi.API.

func (*Visor) SkynetHTTP

SkynetHTTP performs an HTTP request over skynet using the visor's router.

func (*Visor) SkynetProbe

func (v *Visor) SkynetProbe(pk cipher.PubKey, port uint16) (bool, error)

SkynetProbe probes reachability of pk:port over skynet (skywire's routed p2p transports) by dialing a route to the destination and closing it. A completed dial (route setup + connection) means reachable. Returns true if reachable.

func (*Visor) SnapshotGroupHistoryAfter

func (v *Visor) SnapshotGroupHistoryAfter(groupID string, since time.Time) []visorapi.GroupMessage

SnapshotGroupHistoryAfter returns persisted group messages with TS > since from the durable history sink (if configured). Powers the gRPC streaming handler's history-fallback path: when a subscriber's reconnect gap is longer than the in-memory inbox ring (groupInboxCap = 256 messages) can cover, the handler falls through to this method to backfill from bbolt. The two sources are merged + dedup'd at the handler layer.

Returns nil + nil error when no history sink is configured (operator hasn't set GroupHistoryDB), an unknown group, or no messages newer than `since`. nil-vs-empty is not distinguished; callers treat both as "no history backfill available, stick with inbox-only".

Filter contract matches SnapshotGroupMessagesAfter: strict greater-than (TS > since). The handler's lastSentNs dedup depends on it.

func (*Visor) SnapshotGroupMessagesAfter

func (v *Visor) SnapshotGroupMessagesAfter(since time.Time) []visorapi.GroupMessage

SnapshotGroupMessagesAfter returns the ring-buffered group inbox snapshot of messages with TS > since. Used by the gRPC streaming handler to replay events that landed during a client's reconnect window — the CLI tracks the last-seen timestamp and the server drains anything newer from the buffer before entering the live dispatch loop. Returns nil when grouping is disabled.

Filter contract: strict greater-than (TS > since). The streaming handler's lastSentNs dedup assumes this — a >= filter would quietly reintroduce duplicate cursor-message delivery. Do not relax to >= without auditing every caller.

Buffer size bounds the replay depth; see groupInboxCap. A client that's been disconnected longer than the buffer turnover will see only the most recent groupInboxCap messages, not the full gap. Same limitation as PairPoll/snapshotAfter.

func (*Visor) StartApp

func (v *Visor) StartApp(appName string) error

StartApp implements API. Resolves the launcher mode from the AppConfig.LauncherMode field if set, falling back to the visor's default. StartAppWithMode("") matches; StartAppWithMode(<explicit>) still wins per-call.

func (*Visor) StartAppWithMode

func (v *Visor) StartAppWithMode(appName, launcherMode string) error

StartAppWithMode implements API with launcher mode override. launcherMode can be "internal", "external", or "" for default behavior.

func (*Visor) StartPublicAutoconnect

func (v *Visor) StartPublicAutoconnect() error

StartPublicAutoconnect starts public autoconnect if not already running.

func (*Visor) StartSkysocksClient

func (v *Visor) StartSkysocksClient(serverKey string) error

StartSkysocksClient implements API.

func (*Visor) StartUIServer

func (v *Visor) StartUIServer(addr string) error

StartUIServer starts the embedded UI server on the specified address. If addr is empty, uses the configured LocalAddr or defaults to localhost:8081.

func (*Visor) StartVPNClient

func (v *Visor) StartVPNClient(pk cipher.PubKey) error

StartVPNClient implements API.

func (*Visor) StartVPNClientWithMode

func (v *Visor) StartVPNClientWithMode(pk cipher.PubKey, launcherMode string) error

StartVPNClientWithMode implements API with launcher mode override.

func (*Visor) StateSnapshot

func (v *Visor) StateSnapshot() (*visorapi.StateSnapshot, error)

StateSnapshot assembles the full runtime StateSnapshot (every default section). It is StateSnapshotProjected(nil).

func (*Visor) StateSnapshotProjected

func (v *Visor) StateSnapshotProjected(fields []string) (*visorapi.StateSnapshot, error)

StateSnapshotProjected assembles the runtime StateSnapshot, building ONLY the sections named in fields (see the StateSelect* keys). A nil/empty fields slice builds the full default snapshot (proxy stays opt-in). This is the efficiency win behind `cli visor state --select`: `--select mux` skips the ~307 KB transports build entirely, so a 1 s mux watch is cheap.

Each requested section is best-effort and never panics on a not-yet- initialized subsystem; failures are recorded in Notes. Secrets are never included (see the StateSnapshot type doc). At + Suspended are always populated (both cheap).

func (*Visor) StopAllPings

func (v *Visor) StopAllPings() (int, []string, error)

StopAllPings stops all active ping connections and cleans up their routes. Returns the number of connections stopped, error messages, and any fatal error.

func (*Visor) StopApp

func (v *Visor) StopApp(appName string) error

StopApp implements API.

func (*Visor) StopDmsgPing

func (v *Visor) StopDmsgPing(pk cipher.PubKey) error

StopDmsgPing implements API.

func (*Visor) StopPing

func (v *Visor) StopPing(pk cipher.PubKey) error

StopPing implements API.

Tears down ALL routes to the given peer (every PingRouteRef whose PK matches). Callers that want to tear down a single route in a mux-set must use StopPingRoute(ref) instead. The legacy semantics (single PK = single connection) are preserved for the common case where no aux routes exist.

func (*Visor) StopPingRoute

func (v *Visor) StopPingRoute(ref PingRouteRef) error

StopPingRoute closes a single route in a mux-set without touching the other parallel routes to the same peer. Used by `cli visor ping mux-bw` when one of N parallel routes fails mid-pump and we want to keep the others alive, and by future mux-aware proxies that want to drop one leg of a multi-route session.

Returns nil if the ref doesn't match any known conn (idempotent — safe to call from cleanup paths that aren't sure whether the route was ever established).

func (*Visor) StopPublicAutoconnect

func (v *Visor) StopPublicAutoconnect() error

StopPublicAutoconnect stops public autoconnect if running.

func (*Visor) StopSkysocksClients

func (v *Visor) StopSkysocksClients() error

StopSkysocksClients implements API.

func (*Visor) StopUDPForward

func (v *Visor) StopUDPForward(localPort int) error

StopUDPForward tears down a client-side UDP forward by its local port.

func (*Visor) StopUIServer

func (v *Visor) StopUIServer() error

StopUIServer stops the embedded UI server if running.

func (*Visor) StopVPNClient

func (v *Visor) StopVPNClient(appName string) error

StopVPNClient implements API.

func (*Visor) SubscribeGroupMessages

func (v *Visor) SubscribeGroupMessages(capacity int) (<-chan visorapi.GroupMessage, func() uint64)

SubscribeGroupMessages registers a live subscriber on the visor's group inbox. Every message delivered to the inbox from this point forward is fanned out to the returned channel (bounded; bursts past capacity are dropped and counted via the cancel-returned uint64).

Powers the gRPC StreamGroupMessages handler — the long-lived streaming replacement for the net/rpc GroupPoll loop. Backlog (messages already buffered in the ring at subscribe time) is NOT replayed by this method; callers that want that should call SnapshotGroupMessagesAfter alongside Subscribe (the streaming handler does exactly that to replay missed events on reconnect).

Returns nil channel + a no-op cancel when grouping is disabled on this visor (e.g. early init or tests).

func (*Visor) SubscribeLogs

func (v *Visor) SubscribeLogs(f logging.Filter, capacity int) (<-chan *logrus.Entry, func() uint64)

SubscribeLogs subscribes to log entries matching the filter. Wraps the broadcaster so callers don't need a direct handle. Returns nil channel + nil cancel when the broadcaster is not installed (e.g. tests).

func (*Visor) SubscribeNotifications

func (v *Visor) SubscribeNotifications(capacity int) (<-chan appserver.NotifyReq, func() uint64)

SubscribeNotifications registers a host-app subscriber on the visor's hub, mirroring SubscribeLogs. Returns a nil channel when there is no hub so callers can answer "unavailable" rather than panic.

func (*Visor) Summary

func (v *Visor) Summary() (*visorapi.Summary, error)

Summary implements API.

func (*Visor) Suspend

func (v *Visor) Suspend() error

Suspend makes the visor quiescent WITHOUT stopping the process: it tears down every network subsystem (transports, routing, apps, dmsg, autoconnect, AR/TPD registration, the reward heartbeat, and the dmsg/transport-bound RPC surfaces) but keeps the local CLI RPC listener alive so Resume can arrive. The node stops earning, routing, and serving apps and drops off dmsg discovery, while remaining controllable on CLIAddr. It is the privilege-free alternative to stopping the service manager unit. Idempotent: a second Suspend is a no-op.

func (*Visor) TPSAddTransport

func (v *Visor) TPSAddTransport(targetPK, remotePK cipher.PubKey, tpType string) (*visorapi.TPSTransportResponse, error)

TPSAddTransport uses the embedded TPS to add a transport on a target visor.

func (*Visor) TPSExternalAddTransport

func (v *Visor) TPSExternalAddTransport(tpsPK, targetPK, remotePK cipher.PubKey, tpType string) (*visorapi.TPSTransportResponse, error)

TPSExternalAddTransport dials an external TPS over dmsg and requests transport setup.

func (*Visor) TPSExternalGetTransports

func (v *Visor) TPSExternalGetTransports(tpsPK, targetPK cipher.PubKey) ([]visorapi.TPSTransportResponse, error)

TPSExternalGetTransports dials an external TPS over dmsg and requests transport list.

func (*Visor) TPSExternalHealthCheck

func (v *Visor) TPSExternalHealthCheck(tpsPK cipher.PubKey) error

TPSExternalHealthCheck dials an external TPS over dmsg and performs a health check.

func (*Visor) TPSGetTransports

func (v *Visor) TPSGetTransports(targetPK cipher.PubKey) ([]visorapi.TPSTransportResponse, error)

TPSGetTransports uses the embedded TPS to get transports from a target visor.

func (*Visor) TPSRemoveTransport

func (v *Visor) TPSRemoveTransport(targetPK cipher.PubKey, tpID uuid.UUID) error

TPSRemoveTransport uses the embedded TPS to remove a transport on a target visor.

func (*Visor) TPSStatus

func (v *Visor) TPSStatus() (*visorapi.TPSStatus, error)

TPSStatus returns the status of the embedded Transport Setup Node.

func (*Visor) TestProxy

func (v *Visor) TestProxy(conf visorapi.ProxyTestConfig) ([]visorapi.ProxyTestResult, error)

TestProxy tests proxy servers by connecting through them and fetching a test URL

func (*Visor) TestVisor

func (v *Visor) TestVisor(conf visorapi.PingConfig) ([]visorapi.TestResult, error)

TestVisor trying to test visor

func (*Visor) Transport

func (v *Visor) Transport(tid uuid.UUID) (*visorapi.TransportSummary, error)

Transport implements API.

func (*Visor) TransportListBody added in v1.3.100

func (v *Visor) TransportListBody() ([]byte, string, error)

TransportListBody is this visor's own live transport list, signed by it. It implements logserver.TransportListProvider.

func (*Visor) TransportRPCCall

func (v *Visor) TransportRPCCall(remotePK cipher.PubKey, method string, args json.RawMessage) (json.RawMessage, error)

TransportRPCCall proxies an RPC call to a remote visor over a transport VStream. args is optional JSON-encoded RPC arguments; nil means no-arg call.

Uses v.transportRPCMux — the SAME VStreamMux that's registered as the transport manager's VisorRPCPacket handler. Sharing this mux between accept and dial paths is required: the manager only routes inbound VisorRPCPacket frames to one handler, and dial-side response frames have to land in the same streams map that opened the stream. Creating a separate mux for the dial path (as the previous DialTransportRPC implementation did) left outbound streams unable to receive responses and every tp-rpc call timed out indefinitely.

func (*Visor) TransportTypes

func (v *Visor) TransportTypes() ([]string, error)

TransportTypes implements API.

func (*Visor) Transports

func (v *Visor) Transports(typeFilters []string, pks []cipher.PubKey, logs bool) ([]*visorapi.TransportSummary, error)

Transports implements API.

func (*Visor) UIServerStatus

func (v *Visor) UIServerStatus() (*visorapi.UIServerStatus, error)

UIServerStatus returns the current status of the UI server.

func (*Visor) UnregisterCXOFeed

func (v *Visor) UnregisterCXOFeed(name string) error

UnregisterCXOFeed stops a previously-registered user feed. Removing the system feed by name is rejected. Unknown names are a no-op (idempotent).

func (*Visor) UpdateForwardedPort

func (v *Visor) UpdateForwardedPort(p visorapi.ForwardedPort) error

UpdateForwardedPort updates metadata for an existing forwarded port.

func (*Visor) Uptime

func (v *Visor) Uptime() (float64, error)

Uptime implements API.

func (*Visor) UptimeHistory

UptimeHistory implements API. Reads from the service-self uptime recorder's bbolt store. Returns ErrUptimeRecorderUnavailable when the recorder isn't wired (recorder open failed at startup or the visor is running without LocalPath access).

func (*Visor) UptimeRecorder

func (v *Visor) UptimeRecorder() *serviceuptime.Recorder

UptimeRecorder returns the wired recorder, or nil if SetUptimeRecorder was never called (e.g. recorder open failed at startup). RPC and inspection paths should nil-check.

func (*Visor) VPNServers

func (v *Visor) VPNServers(version, country string) ([]servicedisc.Service, error)

VPNServers gets available public VPN servers — CXO snapshot first, HTTP service-discovery fallback.

func (*Visor) VisorCat

VisorCat opens or accepts a remote stream and returns the loopback the CLI should dial. The accept-and-splice work runs in a background goroutine so the RPC returns immediately — the CLI's loopback dial completes the bridge.

Error categories:

  • Validation: bad mode / transport / missing remote_pk on dial → wrapped errors the CLI surfaces verbatim.
  • Dial: dmsg not ready, skynet networker not yet registered, remote unreachable.
  • Listen: dmsg.Listen / appnet.ListenContext failures, whitelist rejection of the first peer.

func (*Visor) VisorSCP

func (v *Visor) VisorSCP(req visorapi.VisorSCPRequest) error

VisorSCP runs a dmsgscp transfer to req.RemotePK:req.Port over req.Transport ("dmsg" or "skynet"), uploading or downloading per req.Direction. The local-filesystem path req.LocalPath is read or written by THIS visor process — operators running the CLI against a different visor see that visor's filesystem, not the caller's.

Error categories:

  • Validation: bad PK / direction / transport / empty paths → wrapped errors with stable prefixes the CLI can surface.
  • Dial: dmsg session not ready, or skynet networker not yet registered when initRouter raced this call.
  • Protocol: the dmsgscp.Client surface returns the same fmt.Errorf-wrapped sentinels the standalone client does.

func (*Visor) VoiceActive

func (v *Visor) VoiceActive() ([]string, error)

VoiceActive returns the ids of active calls.

func (*Visor) VoiceAnswer

func (v *Visor) VoiceAnswer(callID string) error

VoiceAnswer accepts a ringing inbound call by id (explicit-answer mode, when real audio is enabled).

func (*Visor) VoiceAudioBridge

func (v *Visor) VoiceAudioBridge() *skycall.Bridge

VoiceAudioBridge returns the host-app audio device this visor is using, or nil when it opens a device of its own (or has none). The local API's voice audio routes are served only when this is non-nil.

func (*Visor) VoiceCall

func (v *Visor) VoiceCall(peer cipher.PubKey) (string, error)

VoiceCall places a 1:1 voice call to peer over the mesh and returns the new call id. Blocks until the callee accepts or declines, or until the ring budget elapses; the media session then runs in the background until Hangup.

func (*Visor) VoiceCallAudio

func (v *Visor) VoiceCallAudio(callID string) (sent, recv []int16, err error)

VoiceCallAudio returns the most recent buffered sent + received PCM for an active call (only when the visor runs with real audio, which taps call audio). The CLI polls this to draw a live two-panel spectrogram.

func (*Visor) VoiceDecline

func (v *Visor) VoiceDecline(callID string) error

VoiceDecline rejects a ringing inbound call by id.

func (*Visor) VoiceDial

func (v *Visor) VoiceDial(peer cipher.PubKey) (string, error)

VoiceDial places a 1:1 voice call and returns its id at once, without waiting for an answer. The ring then runs in the background and the caller follows it through VoiceDialing / VoiceActive, canceling with VoiceHangup.

This is the one an HTTP handler wants: both surfaces that place calls cap a request below the ring budget, so a blocking VoiceCall could never return the id it produced. See call.Manager.Dial.

func (*Visor) VoiceDialRingback added in v1.3.98

func (v *Visor) VoiceDialRingback(callID string) (visorapi.VoiceRingback, error)

VoiceDialRingback returns the ringback tone the peer of an outbound call plays, once it has arrived.

func (*Visor) VoiceDialing

func (v *Visor) VoiceDialing() ([]visorapi.VoiceDialingInfo, error)

VoiceDialing returns the calls being placed right now.

It was deliberately kept OFF the API interface, on the grounds that a caller's own dial state is of no use to a remote operator. True, but it is of use to the UI beside this visor, and skychat reaches the visor through this interface — so the one surface that most needs it was the one that could not have it. The consequence was not cosmetic: an outbound call that is still ringing has no id anywhere the desktop UI can see, and the hang-up button works off an id, so a call could be placed and not called off. The phone could, through the hypervisor's own route; the desktop could not.

The hypervisor route still answers empty for a REMOTE visor, so what a remote operator can see is unchanged by this.

func (*Visor) VoiceHangup

func (v *Visor) VoiceHangup(callID string) error

VoiceHangup ends an active call by id.

func (*Visor) VoiceIncoming

func (v *Visor) VoiceIncoming() ([]string, error)

VoiceIncoming returns the ringing inbound calls awaiting an answer, each formatted as "<call-id> from <peer-pk>".

func (*Visor) VoiceMute

func (v *Visor) VoiceMute(callID string, mic, speaker bool) error

VoiceMute toggles the mic (send) and speaker (playback) mute of an active call. mic silences what the peer hears from us; speaker silences what we hear from the peer.

func (*Visor) VoiceRingback added in v1.3.98

func (v *Visor) VoiceRingback() (visorapi.VoiceRingback, error)

VoiceRingback returns this visor's own ringback tone.

func (*Visor) VoiceSetRingback added in v1.3.98

func (v *Visor) VoiceSetRingback(t visorapi.VoiceRingback) error

VoiceSetRingback sets the tone callers hear while this visor rings, and keeps it for the next start; empty data clears it.

type VisorTreeResponse

type VisorTreeResponse struct {
	Sections []VisorTreeSection `json:"sections"`
}

VisorTreeResponse wraps the tree sections for the UI's main node list endpoint.

type VisorTreeSection

type VisorTreeSection struct {
	HypervisorPK cipher.PubKey      `json:"hypervisor_pk"`
	ViaChain     []cipher.PubKey    `json:"via_chain,omitempty"`
	Visors       []visorapi.Summary `json:"visors"`
	SubError     string             `json:"sub_error,omitempty"`
}

VisorTreeSection is one hypervisor's section in the tree response. Same shape as HVVisorTreeNode in the visor RPC, but rehydrates each HVVisorEntry into the richer Summary the UI's table already knows how to render. Visor entries replicate across sections by design; sections themselves dedup.

type WasmLink struct{ Name, URL string }

WasmLink is a site linked from the served page.

type WasmServeConfig

type WasmServeConfig struct {
	Addr     string // HTTP listen address (e.g. ":8443")
	TLS      bool   // serve HTTPS (self-signed localhost cert, or TLSCert/TLSKey if set)
	TLSCert  string // optional cert file (PEM) — a locally-trusted *.mesh.localhost cert (mkcert) so B-origin iframes load without a per-host accept; empty = built-in self-signed
	TLSKey   string // optional key file (PEM), paired with TLSCert
	Harness  bool   // mount the /ctl/* operator control bridge (DEV ONLY)
	Password string // optional access-password gate
	// BrowseSuffix is the browse-origin domain suffix (leading dot), e.g.
	// ".mesh.localhost" (local) or ".haltingstate.net" (hosted). Empty →
	// ".mesh.localhost".
	BrowseSuffix string
	// BrowseOriginAddr, when set, ALSO serves the browse-origin SW bootstrap on a
	// SECOND listener at this address (the same process serves V on Addr and the
	// isolated browse origins B here). A hosted deploy fronts this with Caddy on
	// *.<BrowseSuffix>. Empty = off (local mode host-routes B on the V listener).
	BrowseOriginAddr string
	// VOrigin is the PUBLIC origin of the visor app V (e.g.
	// "https://theskywirenetwork.net") that B's bootstrap postMessages to — used
	// only with BrowseOriginAddr behind a proxy. Empty = derive from Addr (local).
	VOrigin string
	// ExecWasmPath serves the skywire command module from that file at
	// /skywire.wasm. Empty means the module installed beside the binary.
	ExecWasmPath string

	// DeskHelpTerminal opens a second terminal that has already run
	// `skywire --help`. Off by default: it costs a whole extra Go/wasm runtime
	// of the full binary, permanently — see deskWasmBootOpts.
	DeskHelpTerminal bool
	// DeskDocsPort runs `skywire doc serve` on this virtual-loopback port.
	// 0 (default) = off, for the same reason.
	DeskDocsPort int
	// BootReportFile keeps the boot reports desks post (wasmserve_bootreport.go)
	// as JSON lines, moved to <file>.1 at 1 MiB. Empty keeps them only in the log.
	BootReportFile string
	// Links are shown under the boot message as plain anchors, so a crawler finds
	// the deployment's other sites before any script runs.
	Links []WasmLink
	Log   *logging.Logger // nil → package default
	// contains filtered or unexported fields
}

WasmServeConfig configures ServeWasm. Mirrors the `hv serve` flags.

Source Files

Directories

Path Synopsis
Package dmsgtracker pkg/visor/dmsgtracker/dmsg_tracker.go c3-vis-core
Package dmsgtracker pkg/visor/dmsgtracker/dmsg_tracker.go c3-vis-core
Package logserver pkg/visor/logserver/api.go c3-vis-core
Package logserver pkg/visor/logserver/api.go c3-vis-core
landingpage
Package landingpage pkg/visor/logserver/landingpage/landingpage.go c3-vis-core http://<pk>.dmsg/ (and skywire.dmsg → the visor's own PK).
Package landingpage pkg/visor/logserver/landingpage/landingpage.go c3-vis-core http://<pk>.dmsg/ (and skywire.dmsg → the visor's own PK).
Package logstore pkg/visor/logstore/logstore.go c3-vis-core
Package logstore pkg/visor/logstore/logstore.go c3-vis-core
Package netview pkg/visor/netview/netview.go c3-vis-core
Package netview pkg/visor/netview/netview.go c3-vis-core
Package rewardconfig pkg/visor/rewardconfig/reward.go c3-vis-core
Package rewardconfig pkg/visor/rewardconfig/reward.go c3-vis-core
Package rpcgrpc pkg/visor/rpcgrpc/client.go c3-vis-core
Package rpcgrpc pkg/visor/rpcgrpc/client.go c3-vis-core
Package stats pkg/visor/stats/bitmap.go c3-vis-core
Package stats pkg/visor/stats/bitmap.go c3-vis-core
Package usermanager pkg/visor/usermanager/user.go c3-vis-core
Package usermanager pkg/visor/usermanager/user.go c3-vis-core
Package visorapi pkg/visor/visorapi/api.go c3-vis-core
Package visorapi pkg/visor/visorapi/api.go c3-vis-core
Package visorconfig pkg/visor/visorconfig/args.go c3-vis-core
Package visorconfig pkg/visor/visorconfig/args.go c3-vis-core
Package visorcore pkg/visor/visorcore/autoconnect.go c3-vis-core
Package visorcore pkg/visor/visorcore/autoconnect.go c3-vis-core
Package visorinit pkg/visor/visorinit/module.go c3-vis-core
Package visorinit pkg/visor/visorinit/module.go c3-vis-core

Jump to

Keyboard shortcuts

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