Documentation
¶
Overview ¶
Package visorapi pkg/visor/visorapi/api.go c3-vis-core
Package visorapi pkg/visor/visorapi/args.go c3-vis-core
Package visorapi pkg/visor/visorapi/client.go c3-vis-core
Package visorapi pkg/visor/visorapi/cxo.go c3-vis-core
Package visorapi pkg/visor/visorapi/dmsg.go c3-vis-core
Package visorapi pkg/visor/visorapi/doc.go c3-vis-core
Package visorapi is the visor's RPC contract: the API interface, the types its methods take and return, and the net/rpc client that implements it against a running visor.
It exists so that callers of a visor (the CLI, apps, services) can depend on the contract without linking the visor itself. pkg/visor implements API and serves it; nothing here imports pkg/visor.
Package visorapi pkg/visor/visorapi/group.go c3-vis-core
Package visorapi pkg/visor/visorapi/hostbridge.go c3-vis-wasm
Package visorapi pkg/visor/visorapi/hypervisor.go c3-vis-core
Package visorapi pkg/visor/visorapi/local.go c3-vis-core
Package visorapi pkg/visor/visorapi/mail.go c3-vis-core
Package visorapi pkg/visor/visorapi/mock.go c3-vis-core
Package visorapi pkg/visor/visorapi/pairing.go c3-vis-core
Package visorapi pkg/visor/visorapi/routing.go c3-vis-core
Package visorapi pkg/visor/visorapi/services.go
Package visorapi pkg/visor/visorapi/state.go c3-vis-core
Package visorapi pkg/visor/visorapi/stats.go c3-vis-core
Package visorapi pkg/visor/visorapi/voice.go c3-vis-core
Index ¶
- Constants
- Variables
- func HypervisorFingerprint(pk cipher.PubKey) string
- func RegisterLocalAPI(api API)
- func SkyenvSecret(key string) bool
- func UnregisterLocalAPI(api API)
- type API
- type ARSelfEntry
- type ARSelfRegistration
- type AddPtyWhitelistIn
- type AddTransportIn
- type AppLogsRequest
- type AppNameIn
- type AppRouteStatus
- type AppSettings
- type Apps
- type BandwidthResult
- type BandwidthTestConfig
- type CXO
- type CXOFeedState
- type CXORefreshArgs
- type Chat
- type ConfigFieldChange
- type ConnectIn
- type CurrentLeafStats
- type CutAppTunnelIn
- type DMSGServerInfo
- type DeniedSubscriber
- type DeregisterServiceIn
- type DiagDmsg
- type DiagDmsgOverSkynet
- type DiagDmsgSession
- type DiagPanics
- type DiagQueue
- type DiagReachCards
- type DiagRelayClient
- type DiagRelayTimer
- type DiagRuntime
- type DiagSnapshot
- type DiagTransport
- type DiagVStreamMux
- type Diagnostics
- type DialDmsgPingViaServerIn
- type Dmsg
- type DmsgClientSessionInfo
- type DmsgClientSessions
- type DmsgConnectAllResult
- type DmsgConvergeResult
- type DmsgHTTPRequest
- type DmsgHTTPResponse
- type DmsgPorterStatus
- type DmsgProbeReasonResponse
- type DmsgProbeRequest
- type DmsgProbeViaServerRequest
- type DmsgPtyExecArgs
- type DmsgRelayAttachment
- type DmsgRelayClient
- type DmsgRelayRole
- type DmsgServerClient
- type DmsgServerRole
- type DmsgServerSession
- type EffectiveRoutingConfig
- type EmbeddedProxiesStatus
- type EmbeddedProxyInfo
- type EmbeddedProxyStats
- type EmbeddedServiceControlArgs
- type EmbeddedServiceState
- type EmbeddedSkymailInfo
- type ExecWasmInfo
- type FeedStatus
- type FetchCXOArgs
- type FetchCXOResult
- type FetchServiceDataIn
- type FilterServersIn
- type ForwardedPort
- type Forwarding
- type GroupAddMemberRequest
- type GroupCatalogEntry
- type GroupCatalogResponse
- type GroupCreateArgs
- type GroupCreateResponse
- type GroupDescriptor
- type GroupFileKeyArgs
- type GroupFileKeyResult
- type GroupHistoryPageArgs
- type GroupHistoryRequest
- type GroupInfo
- type GroupJoinArgs
- type GroupJoinPoWRequest
- type GroupJoinRequest
- type GroupMessage
- type GroupPeerBackfillRequest
- type GroupPeerRequest
- type GroupPollRequest
- type GroupPromoteAdminRequest
- type GroupReadOnlyRequest
- type GroupResolveArgs
- type GroupResolveResult
- type GroupSendArgs
- type GroupSetListedRequest
- type GroupSetMetaArgs
- type GroupUnsendArgs
- type HVAddTransportArgs
- type HVAppArgs
- type HVAutoconnectArgs
- type HVAutostartArgs
- type HVCalcRoutesArgs
- type HVDmsgSessionsArgs
- type HVForwardedPortArgs
- type HVLogsArgs
- type HVMinHopsArgs
- type HVProxyArgs
- type HVRewardArgs
- type HVRoutingRuleArgs
- type HVTCPPortArgs
- type HVTransportArgs
- type HVVisorEntry
- type HVVisorTree
- type HVVisorTreeNode
- type HealthInfo
- type HostBridgeForward
- type HostBridgeForwardArgs
- type HostBridgeStatus
- type HostStatsInfo
- type HypervisorPasswordChangeIn
- type Hypervisors
- type LANDmsgServerInfo
- type LoadStats
- type LocalTransportStatsResponse
- type LocalUptimeArgs
- type LocalUptimeResponse
- type Mail
- type MailAttachmentRequest
- type MailMessageRequest
- type MailSettingsUpdate
- type MailSettingsWire
- type MailStatus
- type ModulePresence
- type MuxDirectionInput
- type MuxHopInfo
- type MuxLegInfo
- type MuxRehomeInput
- type MuxRouteGroupInfo
- type MuxRouteInput
- type MuxWeightsInput
- type NetworkViewResponse
- type Node
- type NodeHealth
- type Overview
- type PairAddRequest
- type PairCode
- type PairDeleteRequest
- type PairInfo
- type PairMessage
- type PairPollRequest
- type PairSendRequest
- type PendingHypervisor
- type PingConfig
- type PoolTunnelInfo
- type PortDetail
- type ProcessStatsInfo
- type Profile
- type ProfileSetArgs
- type Proxies
- type ProxyTestConfig
- type ProxyTestResult
- type RecentAppLogRequest
- type RegisterCXOFeedRequest
- type RolesSnapshot
- type RouteGroupInfo
- type RouteHopInfo
- type RouterDialSettings
- type RouterKnob
- type RouterSettings
- type Routing
- type RoutingPoliciesSummary
- type RoutingPolicyInfo
- type RoutingRuleResp
- type RuntimeLogsDelta
- type RuntimeStatsInfo
- type ServiceHealthEntry
- type SetAppAddIn
- type SetAppArgsIn
- type SetAppBoolIn
- type SetAppEnvBatchIn
- type SetAppEnvFullIn
- type SetAppEnvIn
- type SetAppErrorIn
- type SetAppLauncherModeIn
- type SetAppMapIn
- type SetAppNetworkInterfaceIn
- type SetAppPKIn
- type SetAppRoutingPolicyIn
- type SetAppSettingsIn
- type SetAppStatusIn
- type SetAppStringIn
- type SetAppWhitelistIn
- type SetAutoStartIn
- type SetEmbeddedProxyBindRequest
- type SetEmbeddedProxyEnabledRequest
- type SetEmbeddedProxyUpstreamRequest
- type SetHypervisorAuthIn
- type SetSTCPAddrIn
- type SkychatHTTPIn
- type SkychatHTTPOut
- type SkychatPasswordChangeIn
- type SkyenvEdits
- type SkyenvState
- type SkynetHTTPRequest
- type SkynetHTTPResponse
- type StartAppIn
- type StartVPNClientIn
- type StateFieldSet
- type StateSnapshot
- type StateSnapshotReq
- type StopAllPingsOut
- type Summary
- type TPDAnnounceState
- type TPDLeafPublisherState
- type TPSAddTransportIn
- type TPSExternalAddTransportIn
- type TPSExternalGetTransportsIn
- type TPSRemoveTransportIn
- type TPSStatus
- type TPSTransportResponse
- type TestResult
- type TransportLogEntry
- type TransportRPCCallRequest
- type TransportSummary
- type Transports
- type TransportsIn
- type UDPForwardIn
- type UIServerStatus
- type UptimeHistoryArgs
- type UptimeHistoryResponse
- type Vhost
- type VisorCatRequest
- type VisorCatResponse
- type VisorSCPRequest
- type VoiceAudioSnapshot
- type VoiceDialingInfo
- type VoiceMuteReq
- type VoiceRingback
Constants ¶
const ( // VisorSCPUpload pushes a local file to the remote host's rootDir. VisorSCPUpload = "upload" // VisorSCPDownload pulls a file from the remote host's rootDir // into a local path. VisorSCPDownload = "download" )
VisorSCPDirection enumerates the two scp transfer directions.
const ( // VisorSCPTransportDmsg dials peer:port over dmsg. VisorSCPTransportDmsg = "dmsg" // VisorSCPTransportSkynet dials peer:port over the skywire router // (appnet TypeSkynet). Routing through skynet keeps the bytes off // the dmsg overlay and lets the transfer ride whatever transports // the router picks for the route group. VisorSCPTransportSkynet = "skynet" )
VisorSCPTransport enumerates the transports the visor will dial the peer's dmsgscp host over. Both peers expose the host on dmsg AND skynet at the same port; the caller picks per-call.
const ( // VisorCatModeDial opens an outbound stream to (RemotePK, Port) // over the chosen transport. The visor exposes the stream to the // CLI as a 127.0.0.1 loopback TCP listener — the CLI dials that // listener and the visor splices the two halves. VisorCatModeDial = "dial" // VisorCatModeListen opens a one-shot listener on Port over the // chosen transport (dmsg + skynet mirror), authorizes the first // inbound stream against the dmsgscp whitelist, and splices it // to a 127.0.0.1 loopback the CLI dials. VisorCatModeListen = "listen" )
VisorCatMode enumerates the two cat operation modes.
const ( // VisorCatTransportDmsg dials/listens over dmsg. VisorCatTransportDmsg = "dmsg" // VisorCatTransportSkynet dials/listens over the skywire router // (appnet.TypeSkynet). VisorCatTransportSkynet = "skynet" )
VisorCatTransport enumerates the transports the visor will use for a VisorCat call — identical to VisorSCP's set so a caller's `--transport=skynet` keeps the same meaning across both commands.
const ( SelectSummary = "summary" // summary SelectHealth = "health" // health + service_health SelectRouting = "routing" // routing_stats + route_groups + routing_policy + router_config SelectMux = "mux" // mux_route_groups + mux_counters (+ route_groups count) SelectPool = "pool" // pool: the standby-tunnel pool table SelectApps = "apps" // apps SelectTransports = "transports" // transports + persistent_transports SelectModules = "modules" // modules SelectCXO = "cxo" // cxo feed publish-health SelectServices = "services" // deployment services the visor embeds: stores, CXO aggregators and publishers SelectProxy = "proxy" // visor-side proxystatus snapshot (skysocks); opt-in only SelectDiag = "diag" // router intake, transport queues/handlers, vstream, dmsg ping/relay, runtime SelectRoles = "roles" // in-process dmsg server, dmsg relay (both directions), transit refusal )
State*-select keys name the projectable subtrees of a StateSnapshot. Passing a subset to StateSnapshotProjected makes the SERVER build and marshal ONLY those sections, so a cheap `--select mux` skips the expensive transports build (the full snapshot is ~900 KB, dominated by transports at ~307 KB; mux is ~75 KB). The keys match the snapshot's JSON field names (or a short alias) so a --jq expression written against the full snapshot transfers to a projection unchanged.
const (
// RPCPrefix is the prefix used with all RPC calls.
RPCPrefix = "app-visor"
)
const SkyenvRedacted = "(set)"
SkyenvRedacted is what Skyenv reports in place of a secret's value, and what SetSkyenv ignores when a form sends it back unchanged.
const (
// SupportedProtocolVersion is the app protocol version a visor reports.
SupportedProtocolVersion = "0.1.0"
)
Variables ¶
var ( // ErrNotImplemented occurs when a method is not implemented. ErrNotImplemented = errors.New("not implemented") )
var StateSelectKeys = []string{ SelectSummary, SelectHealth, SelectRouting, SelectMux, SelectPool, SelectApps, SelectTransports, SelectModules, SelectCXO, SelectServices, SelectProxy, SelectDiag, SelectRoles, }
StateSelectKeys is the documented set of --select keys, in help order.
Functions ¶
func HypervisorFingerprint ¶
HypervisorFingerprint is the short, stable name a pending key is approved by: the first 40 bits of sha256(pk) as two hex groups ("a1b2c-3d4e5").
func RegisterLocalAPI ¶
func RegisterLocalAPI(api API)
RegisterLocalAPI publishes api as the visor running in this process, replacing any previous registration (a visor restart in the same process re-registers, the way the handler registry re-registers on an app restart).
func SkyenvSecret ¶
SkyenvSecret reports variables whose value never leaves the visor: Skyenv reports only that they are set.
func UnregisterLocalAPI ¶
func UnregisterLocalAPI(api API)
UnregisterLocalAPI clears the registration only if it still holds api.
Compare-and-clear, not a plain clear: a visor shutting down can finish unwinding after a replacement has already registered (tests build visors back to back in one process), and an unconditional clear there would take the live visor out and leave in-process apps dialing a port nobody serves.
Types ¶
type API ¶
type API interface {
Node
Hypervisors
Chat
CXO
Proxies
Apps
Forwarding
Diagnostics
Dmsg
Routing
Transports
Mail
}
API is everything a visor answers over RPC. Callers that need one part of it can take the narrower interface it embeds.
func LocalAPI ¶
func LocalAPI() API
LocalAPI returns the visor running in this process, or nil when there is none and the caller must dial the RPC.
Close on the returned value is a no-op. Callers treat what they get as an RPC *client* and close it when they redial — doing that to the visor itself would shut the process down.
func NewMockRPCClient ¶
NewMockRPCClient creates a new mock API.
func NewProxyRPCClient ¶
func NewProxyRPCClient(log logrus.FieldLogger, conn io.ReadWriteCloser, prefix string, timeout time.Duration, remotePK cipher.PubKey) API
NewProxyRPCClient wraps a local rpc.Client connection so that every Call against the returned API is transparently routed to a remote visor via the local visor's TransportRPCCall method.
Use case: `skywire cli visor info --rpc skynet://<pk>` — the CLI dials the LOCAL visor as usual, but every typed method (Summary, Health, Overview, ...) gets dispatched on the remote visor identified by remotePK. Auth: the local visor's PK must be in the remote's hypervisor or dmsgpty whitelist (TransportRPCServer enforces this on the receiving side).
Limitation: methods with structured Go args (AddTransport, SetMinHops, etc.) don't currently survive the TransportRPCCall JSON-bytes wire format. No-arg query methods (the bulk of what the CLI does) work directly.
func NewRPCClient ¶
func NewRPCClient(log logrus.FieldLogger, conn io.ReadWriteCloser, prefix string, timeout time.Duration) API
NewRPCClient creates a new API.
type ARSelfEntry ¶
type ARSelfEntry struct {
Type string `json:"type"` // "stcpr", "sudph" or "wt"
RemoteAddr string `json:"remote_addr,omitempty"` // public IPv4 as AR sees the visor
RemoteAddrV6 string `json:"remote_addr_v6,omitempty"` // public IPv6 as AR sees the visor (#1525 Phase 4a)
Port string `json:"port,omitempty"` // listen port
Addresses []string `json:"addresses,omitempty"` // local interface addresses the visor advertised
// CertHash is the SHA-256 of the self-signed certificate a WebTransport
// dialler must pin, lowercase hex. WT only — the other carriers have no
// certificate. Empty from a visor too old to report it, which is why the
// CLI omits the field rather than rendering "(none)": absent here means
// "not said", and only a visor that knows about WT can distinguish that
// from "not registered".
CertHash string `json:"cert_hash,omitempty"`
// CertHashNext is the hash of the certificate served after the next
// rotation, pinned alongside CertHash. WT only; empty when not advertised.
CertHashNext string `json:"cert_hash_next,omitempty"`
}
ARSelfEntry is one transport-type-row of this visor's own AR registration: the IP:port it is reachable on according to the address-resolver.
RemoteAddrV6 is the optional IPv6 counterpart of RemoteAddr, populated when this visor has bound the AR over an IPv6 HTTP client (#2719's secondary bind). Empty for v4-only deployments and on older AR servers that don't capture family — same backward-compat shape as the underlying addrresolver.VisorData (#2715).
type ARSelfRegistration ¶
type ARSelfRegistration struct {
Entries []ARSelfEntry `json:"entries,omitempty"`
// Queried lists the transport types this visor actually checked, whether or
// not it is registered for them. It exists so a caller can tell "asked, not
// registered" from "never asked".
//
// Without it the two are the same silence, and the CLI cannot say which it
// is looking at: a type missing from Entries might be unregistered, or the
// answering visor might predate that type entirely. That is not
// hypothetical here — `--via dmsg://<pk>` and `--rpc` point these commands
// at other people's visors across the mesh, running whatever version they
// are running. Locally it cannot happen, because the CLI and the visor are
// the same binary.
//
// Empty from a visor too old to report it, which is itself the signal:
// nothing can be concluded from a type's absence.
Queried []string `json:"queried,omitempty"`
}
ARSelfRegistration is the visor's own AR record across transport types. One ARSelfEntry per transport the visor is currently registered for. Empty when the visor has not (yet) bound any transport with AR.
type AddPtyWhitelistIn ¶
AddPtyWhitelistIn carries the PKs to merge into the visor's shared peer whitelist (a hypervisor pushing its own hypervisors).
type AddTransportIn ¶
type AddTransportIn struct {
RemotePK cipher.PubKey
TpType string
Timeout time.Duration
Label string // "user" or "skycoin" (default: "skycoin")
NoRegister bool // skip transport discovery registration (only valid for "user" label)
SkipLatencyProbe bool // deprecated: latency is now measured at the transport level
}
type AppLogsRequest ¶
type AppNameIn ¶
type AppNameIn struct {
AppName string
}
AppNameIn carries a single app name for RPCs whose only argument is the target's name (DeleteApp, etc.).
type AppRouteStatus ¶
type AppRouteStatus struct {
AppName string `json:"app_name"`
Route router.RouteStatus `json:"route"`
}
AppRouteStatus combines route status with the app that owns it.
type AppSettings ¶
type AppSettings struct {
AppName string `json:"app_name"`
Values map[string]int64 `json:"values,omitempty"`
// Text carries the LIST knobs (pool.exclude_pks, pool.require_tp_types),
// whose payload is a comma-separated set of tokens rather than an int64.
Text map[string]string `json:"text,omitempty"`
Version uint64 `json:"version"`
Applied uint64 `json:"applied"`
}
AppSettings is the CLI's read of an app's live tuning knobs: the values the visor intends, the version they carry, and the version the app last reported having installed. Version != Applied is a change still in flight — the app installs it on its next pull (one tunnel.probe_interval, 5 s by default).
type Apps ¶
type Apps interface {
App(appName string) (*appserver.AppState, error)
Apps() ([]*appserver.AppState, error)
StartApp(appName string) error
StartAppWithMode(appName, launcherMode string) error
// SetAppRoutingPolicy installs (or clears, when path is "" /
// "none") a per-app routing policy. Backend is dispatched by
// file extension: "@/path.star" uses Starlark, "@/path.wasm"
// uses WASM. The swap is live — the running app picks up the
// new policy on its next dial without a restart.
SetAppRoutingPolicy(appName, path string) error
AddApp(appName, binaryName string) error
DeleteApp(appName string) error
RegisterApp(procConf appcommon.ProcConfig) (appcommon.ProcKey, error)
DeregisterApp(procKey appcommon.ProcKey) error
StopApp(appName string) error
KillApp(appName string) error
SetAppDetailedStatus(appName, state string) error
SetAppError(appName, stateErr string) error
RestartApp(appName string) error
SetAutoStart(appName string, autostart bool) error
SetAppWhitelist(appName, whitelist string) error
// AddPtyWhitelist merges PKs into the visor's shared peer
// whitelist (a connected hypervisor pushing its own hypervisors
// for transitive pty + RPC trust).
AddPtyWhitelist(pks []cipher.PubKey) error
SetAppPK(appName string, pk cipher.PubKey) error
SetAppSecure(appName string, isSecure bool) error
SetAppAddress(appName string, address string) error
SetAppKillswitch(appName string, killswitch bool) error
SetAppNetworkInterface(appName string, netifc string) error
SetAppDNS(appName string, dnsaddr string) error
DoCustomSetting(appName string, customSetting map[string]any) error
SetAppArgs(appName string, args []string) error
// GetAppSettings / SetAppSettings carry the live tuning knobs held for an
// app (pulled by the app, persisted by the visor; see api_app_settings.go).
GetAppSettings(appName string) (AppSettings, error)
SetAppSettings(appName string, vals map[string]int64, text map[string]string) (AppSettings, error)
// CutAppTunnel closes exactly one of an app's tunnels — the route group
// whose port is rgPort — and lets the app's own pool replace it.
CutAppTunnel(appName string, rgPort uint16) (uint64, error)
SetAppEnv(appName, key, value string) error
SetAppEnvBatch(appName string, env map[string]string) error
SetAppEnvFull(appName string, env []string) error
SetAppLauncherMode(appName, mode string) error
AppHelp(appName string) (string, error)
LogsSince(timestamp time.Time, appName string) ([]string, error)
RecentAppLog(appName, level string) ([]string, error)
GetAppStats(appName string) (appserver.AppStats, error)
GetAppError(appName string) (string, error)
GetAppConnectionsSummary(appName string) ([]appserver.ConnectionSummary, error)
StartVPNClient(pk cipher.PubKey) error
StartVPNClientWithMode(pk cipher.PubKey, launcherMode string) error
StopVPNClient(appName string) error
VPNServers(version, country string) ([]servicedisc.Service, error)
StartSkysocksClient(pk string) error
StopSkysocksClients() error
ProxyServers(version, country string) ([]servicedisc.Service, error)
TestProxy(config ProxyTestConfig) ([]ProxyTestResult, error)
// AppDirectStreams reports the live DIRECT (0-hop) streams the named
// app holds — the AppDirectMux shortcut's counterpart to
// RouteGroupMuxInfo. A dial eligible for that shortcut builds no route
// group, so an app using it has a well-defined path that the
// route-group queries above cannot see. Empty appName reports all.
AppDirectStreams(appName string) ([]transport.VStreamInfo, error)
}
Apps is starting, stopping and configuring apps, the VPN and skysocks clients among them.
type BandwidthResult ¶
type BandwidthResult struct {
BytesSent uint64 `json:"bytes_sent"`
BytesReceived uint64 `json:"bytes_received"`
Duration time.Duration `json:"duration"`
UploadSpeed float64 `json:"upload_speed_kbps"` // KB/s
DownloadSpeed float64 `json:"download_speed_kbps"` // KB/s
}
BandwidthResult contains the results of a bandwidth test
type BandwidthTestConfig ¶
type BandwidthTestConfig struct {
PK cipher.PubKey
Duration time.Duration // How long to run the test
PacketSize int // Size of each packet in KB
LocalRoute bool // Use local route calculation
}
BandwidthTestConfig contains parameters for bandwidth testing
type CXO ¶
type CXO interface {
FetchCXO(args FetchCXOArgs) (*FetchCXOResult, error)
CXOStatus() ([]FeedStatus, error)
CXORefreshFeed(args CXORefreshArgs) (*FeedStatus, error)
// CXO user feeds — visor-published TreeStore feeds beyond the
// always-on telemetry one. See pkg/visor/cxo_user_feeds.go.
RegisterCXOFeed(name string, dmsgPort uint16, description string) error
UnregisterCXOFeed(name string) error
ListCXOFeeds() []logserver.CXOFeedEntry
}
CXO is the visor's CXO feeds.
type CXOFeedState ¶
type CXOFeedState struct {
Name string `json:"name"`
Port uint16 `json:"port,omitempty"`
treestore.PublishState
// CurrentLeaves is populated only for the "stats" telemetry feed: it
// reports the count of per-transport telemetry rows the feed carries
// across its ≤16 compact sharded leaves (transports/telemetry/<sh>).
// With the sharded shape every packed row is a LIVE transport (the
// sampler re-encodes each shard from the live set every tick), so Live
// == Total and Dead is structurally 0 — the stale-leaf bloat the old
// per-transport `current` format accumulated no longer exists.
CurrentLeaves *CurrentLeafStats `json:"current_leaves,omitempty"`
// Allowlist is the set of PKs currently permitted to subscribe to this
// feed (nil = OPEN to all). For a service-consumed feed (stats,
// tp-list, registration) this MUST contain the consuming service's PK
// or that service can't fill — its subscribe is rejected and it shows
// up under Denied below.
Allowlist []string `json:"allowlist,omitempty"`
// Denied lists would-be subscribers the allowlist turned away
// (most-recent first). A denied PK that isn't a known peer is the
// direct signature of a gating misconfiguration — e.g. TPD dialing in
// under a CXO node key that differs from the transport_discovery_dmsg
// PK the visor allowlisted.
Denied []DeniedSubscriber `json:"denied,omitempty"`
}
CXOFeedState pairs a feed's identity (name + dmsg port) with its live publish-health snapshot. Surfaced by StateSnapshot under .cxo.
type CXORefreshArgs ¶
type CXORefreshArgs struct {
Feed string `json:"feed"`
Timeout time.Duration `json:"timeout,omitempty"`
}
CXORefreshArgs identifies which feed CXORefreshFeed should force a synchronous subscribe → first-Root → walk cycle on. Timeout caps how long the visor will wait for the first Root before giving up; zero means "use the manager's firstSyncTimeout default" (10s).
type Chat ¶
type Chat interface {
SkychatPasswordIsSet() (bool, error)
SetSkychatPassword(oldPassword, newPassword string) error
ClearSkychatPassword(oldPassword string) error
SkychatLocalAddr() (string, error)
// SkychatHTTP sends one HTTP request to the local skychat app, including a
// portless in-process one. The response is buffered, so not for its streams.
SkychatHTTP(in SkychatHTTPIn) (SkychatHTTPOut, error)
// Chat-pair feeds — per-partner CXO feeds with read-side
// allowlists. See pkg/visor/pairing.go.
PairAdd(peerPK cipher.PubKey) error
PairList() ([]PairInfo, error)
PairRemove(peerPK cipher.PubKey) error
PairMarkActive(peerPK cipher.PubKey) error
PairSend(peerPK cipher.PubKey, text string) (string, error)
PairDelete(peerPK cipher.PubKey, id string) error
PairPoll(since time.Time) ([]PairMessage, error)
// Skychat profile — this visor's published display name and avatar,
// and a peer's. See pkg/visor/profile.go.
ProfileGet() (Profile, error)
ProfileSet(args ProfileSetArgs) (Profile, error)
ProfileFetch(pk cipher.PubKey) (Profile, error)
// Chat-group feeds — D1 owner-centric CXO feeds with multi-PK
// allowlists. See pkg/visor/group.go.
GroupCreate(args GroupCreateArgs) (GroupInfo, string, error)
GroupJoin(args GroupJoinArgs) (GroupInfo, error)
GroupResolve(args GroupResolveArgs) (GroupResolveResult, error)
GroupAskAgain(id string) (GroupInfo, error)
GroupList() ([]GroupInfo, error)
GroupGet(id string) (GroupInfo, error)
GroupInvite(id string) (string, error)
GroupAddMember(id string, pk cipher.PubKey) (GroupInfo, error)
GroupJoinRequests(id string) ([]GroupJoinRequest, error)
GroupApproveJoin(id string, pk cipher.PubKey) (GroupInfo, error)
GroupDenyJoin(id string, pk cipher.PubKey) error
GroupRemoveMember(id string, pk cipher.PubKey) (GroupInfo, error)
GroupBanMember(id string, pk cipher.PubKey) (GroupInfo, error)
GroupUnbanMember(id string, pk cipher.PubKey) (GroupInfo, error)
GroupMuteMember(id string, pk cipher.PubKey) (GroupInfo, error)
GroupUnmuteMember(id string, pk cipher.PubKey) (GroupInfo, error)
GroupSetReadOnly(id string, readOnly bool) (GroupInfo, error)
GroupSetListed(id string, listed bool) (GroupInfo, error)
GroupSetMeta(args GroupSetMetaArgs) (GroupInfo, error)
GroupRefreshMeta(id string) (GroupInfo, error)
GroupCatalog(host cipher.PubKey) ([]GroupCatalogEntry, bool, error)
GroupPromoteAdmin(id string, pk cipher.PubKey) (GroupInfo, error)
GroupDemoteAdmin(id string, pk cipher.PubKey) (GroupInfo, error)
GroupRotateKey(id string) (GroupInfo, error)
GroupSetPeerBackfill(id string, enabled bool) (GroupInfo, error)
GroupSetJoinPoW(id string, bits uint8) (GroupInfo, error)
GroupSend(args GroupSendArgs) error
GroupFileKey(args GroupFileKeyArgs) (GroupFileKeyResult, error)
GroupUnsend(args GroupUnsendArgs) error
GroupPoll(since time.Time) ([]GroupMessage, error)
GroupDelete(id string) error
GroupLeave(id string) error
GroupHistory(groupID string, limit int) ([]GroupMessage, error)
GroupHistoryPage(args GroupHistoryPageArgs) ([]GroupMessage, error)
GroupHistoryGroups() ([]string, error)
// Skychat 1:1 voice calls (pkg/skychat/call).
VoiceCall(peer cipher.PubKey) (string, error)
// VoiceDial places a call and returns its id without waiting for an
// answer — what a UI needs, and what an HTTP handler can actually
// deliver. See Visor.VoiceDial.
VoiceDial(peer cipher.PubKey) (string, error)
VoiceHangup(callID string) error
VoiceActive() ([]string, error)
VoiceAnswer(callID string) error
VoiceDecline(callID string) error
VoiceIncoming() ([]string, error)
// VoiceDialing lists the calls this visor is PLACING and that have not
// been answered yet. It is what lets a UI show "calling…" and, more to
// the point, call it off: hanging up takes a call id, and until the
// invite is answered this is the only place one exists.
VoiceDialing() ([]VoiceDialingInfo, error)
// VoiceSetRingback sets the tone callers hear while this visor rings;
// empty Data clears it. It is kept across restarts.
VoiceSetRingback(tone VoiceRingback) error
// VoiceRingback returns this visor's own ringback tone.
VoiceRingback() (VoiceRingback, error)
// VoiceDialRingback returns the ringback tone the peer of an outbound
// call plays, once it has arrived (VoiceDialingInfo.Ringback).
VoiceDialRingback(callID string) (VoiceRingback, error)
VoiceCallAudio(callID string) (sent, recv []int16, err error)
VoiceMute(callID string, mic, speaker bool) error
}
Chat is skychat's pairing, profiles, groups and voice calls.
type ConfigFieldChange ¶
type ConfigFieldChange struct {
// Path is the dotted config path as the caller supplied it.
Path string `json:"path"`
// Old and New are the field's JSON values before and after.
// Old is null when the path addressed an absent map key.
Old json.RawMessage `json:"old"`
New json.RawMessage `json:"new"`
// Live is true when a running subsystem took the value; false
// means it is on disk and applies at the next visor start.
Live bool `json:"live"`
}
ConfigFieldChange reports one field's before/after from SetConfigFields.
func (ConfigFieldChange) String ¶
func (c ConfigFieldChange) String() string
String renders one change the way `config set` prints it.
type CurrentLeafStats ¶
type CurrentLeafStats struct {
Total int `json:"total"`
Live int `json:"live"`
Dead int `json:"dead"`
}
CurrentLeafStats is the live/dead breakdown of the telemetry feed's per-transport telemetry rows, decoded from the compact sharded leaves (transports/telemetry/<sh>). Each row is classified by whether its transport is in the visor's live set; with the sharded shape the sampler only ever packs live transports, so Dead is normally 0.
type CutAppTunnelIn ¶
CutAppTunnelIn names one tunnel of one app: the route group port `proxy mux info` prints as dst_port.
type DMSGServerInfo ¶
type DMSGServerInfo struct {
PK cipher.PubKey `json:"pk"`
Latency time.Duration `json:"latency"` // Round-trip latency via self-ping, 0 if not measured
// Carrier is the transport the client↔server session runs on (tcp | ws | wt |
// quic); Protocol is its human-readable label (e.g. "tcp", "wss",
// "webtransport", "quic"). Empty when the session can't be matched. Lets the
// UI show HOW each server was reached, not just that it was.
Carrier string `json:"carrier,omitempty"`
Protocol string `json:"protocol,omitempty"`
// Streams is the number of open mux streams on this session: 0 = idle (a
// candidate for the idle-session reaper once it is over min_sessions), >0 =
// carrying traffic, -1 = unmeasurable (quic, or no session matched this
// server PK) which the reaper treats as busy. This is the same count
// reapExcessIdleSessions decides on, so an operator seeing more sessions
// than sessions_count can tell whether they are legitimately in use or the
// reaper is not doing its job.
Streams int `json:"streams"`
}
DMSGServerInfo contains information about a connected DMSG server including latency.
type DeniedSubscriber ¶
type DeniedSubscriber struct {
PK string `json:"pk"`
Count int `json:"count"`
LastAt time.Time `json:"last_at"`
}
DeniedSubscriber is one rejected-subscriber record for CXOFeedState.
type DeregisterServiceIn ¶
type DiagDmsg ¶
type DiagDmsg struct {
// Unpublished: this client publishes no discovery entry (a browser visor).
Unpublished bool `json:"unpublished"`
Sessions []DiagDmsgSession `json:"sessions,omitempty"`
RelayNominees []cipher.PubKey `json:"relay_nominees,omitempty"`
RelayingFor []DiagRelayClient `json:"relaying_for,omitempty"`
RelayBackoff []DiagRelayTimer `json:"relay_backoff,omitempty"`
RelayDialSkip []DiagRelayTimer `json:"relay_dial_skip,omitempty"`
// OverSkynet counts the dials to .dmsg peers (DmsgHTTP and the resolving
// proxy) the visor carried over its skynet transports, and those that
// fell back to dmsg, with the last reason one fell back.
OverSkynet *DiagDmsgOverSkynet `json:"over_skynet,omitempty"`
}
DiagDmsg is the dmsg client's session and relay state.
type DiagDmsgOverSkynet ¶ added in v1.3.99
type DiagDmsgOverSkynet struct {
Skynet uint64 `json:"skynet"`
Fallback uint64 `json:"fallback"`
LastError string `json:"last_error,omitempty"`
LastPK string `json:"last_pk,omitempty"`
}
DiagDmsgOverSkynet is how the visor's dials to .dmsg peers went.
type DiagDmsgSession ¶
type DiagDmsgSession struct {
PK cipher.PubKey `json:"pk"`
Carrier string `json:"carrier"`
Protocol string `json:"protocol"`
Streams int `json:"streams"`
LatencyMS float64 `json:"latency_ms"`
// PingFails is the consecutive liveness-ping failures; 2 closes the session.
PingFails int `json:"ping_fails"`
}
DiagDmsgSession is one dmsg session's liveness.
type DiagPanics ¶
type DiagPanics struct {
Count uint64 `json:"count"`
Last []logging.PanicEntry `json:"last,omitempty"`
}
DiagPanics is the recovered-panic accounting. Count keeps rising after Last has wrapped, so the two together say whether what Last shows is the whole story.
type DiagReachCards ¶ added in v1.3.100
type DiagReachCards struct {
// Advertised is whether this visor serves its card (ar_transport_limit >= 0).
Advertised bool `json:"advertised"`
// Held is how many peers' cards are cached.
Held int `json:"held"`
// Fetches, Hits and Misses count card fetches, and lookups a card answered
// or left to the address resolver.
Fetches uint64 `json:"fetches"`
Hits uint64 `json:"hits"`
Misses uint64 `json:"misses"`
}
DiagReachCards is how dials were answered from peers' own reach cards.
type DiagRelayClient ¶
DiagRelayClient is a peer attached to this visor as its dmsg relay.
type DiagRelayTimer ¶
DiagRelayTimer is a relay-side backoff or skip with its remaining time.
type DiagRuntime ¶
type DiagRuntime struct {
Goroutines int `json:"goroutines"`
HeapAllocMB float64 `json:"heap_alloc_mb"`
// HeapLiveMB is the heap still in use after the last GC, where the runtime
// reports it. HeapAllocMB also counts garbage not yet collected.
HeapLiveMB float64 `json:"heap_live_mb,omitempty"`
SysMB float64 `json:"sys_mb"`
NumGC uint32 `json:"num_gc"`
GoVersion string `json:"go_version"`
}
DiagRuntime is the Go runtime at a glance.
type DiagSnapshot ¶
type DiagSnapshot struct {
Runtime DiagRuntime `json:"runtime"`
// Panics is the recovered-panic accounting: how many have happened since
// start and the most recent few with their stacks. An UNrecovered panic
// goes to local/log/skywire-crash.log (debug.SetCrashOutput, see
// storeLog); this is the other half, which nothing else records. Omitted
// when none have happened, so its presence is the signal.
Panics *DiagPanics `json:"panics,omitempty"`
// TransportReadQueue is the shared queue every transport read loop feeds
// and the router drains; at capacity, every transport stalls behind the
// router (pings and pongs included).
TransportReadQueue *DiagQueue `json:"transport_read_queue,omitempty"`
// Intake is the router's inbound-path view: unknown/control packets by
// type, stale-route drops, and each route group's app queue depth.
Intake *router.IntakeStats `json:"intake,omitempty"`
// RouteSource is where multi-hop routes came from: the local graph (a
// hypervisor's attached visors), the route finder, or the local fallback.
RouteSource *router.RouteSourceStats `json:"route_source,omitempty"`
// RouteSetup is how this visor's route setups were ISSUED: batched vs
// single vs fell back because the setup node is un-upgraded, plus whether
// the RSN-oracle queried once per fill and whether the concurrent dials of a
// fill landed on distinct intermediates.
RouteSetup *router.SetupPathStats `json:"route_setup,omitempty"`
// VStream is one entry per virtual-stream mux (skynet forwarding,
// app-direct dials, visor RPC): open streams, relay legs, and frames that
// arrived for streams this side does not have.
VStream []DiagVStreamMux `json:"vstream,omitempty"`
// Dmsg is per-session ping health plus the relay nominee/backoff state.
Dmsg *DiagDmsg `json:"dmsg,omitempty"`
// Reach counts the reach cards this visor serves and fetches (reach_card.go).
Reach *DiagReachCards `json:"reach,omitempty"`
// Transports is per-transport liveness: missed pongs, last packet age,
// and which route-ID-0 handlers are wired (a missing one means that
// packet type is dropped by the router — #4725).
Transports []DiagTransport `json:"transports,omitempty"`
// TransportEvents is the last transport.TransportEventRingSize opens and
// closes, oldest first, each close with the reason the code gave. This is
// where to look when a transport that was in `tp ls` is gone: the visor log
// ring holds minutes; this holds the events.
TransportEvents []transport.TransportEvent `json:"transport_events,omitempty"`
// TransportLastClose is the last close event of each of the last
// transport.TransportLastCloseMax transports that closed, keyed by
// transport id. TransportEvents is a ring and on a public visor it is
// flooded by autoconnect opens — 256 entries spanned three minutes on one
// exit visor — so the one close being chased was already gone. This
// survives any amount of open churn: look up the transport id here to get
// the reason it died and how old it was.
TransportLastClose map[uuid.UUID]transport.TransportEvent `json:"transport_last_close,omitempty"`
// MuxEvents is the last router.MuxEventRingSize route-group and mux-leg
// changes, oldest first, each with the reason the code gave and who
// initiated it (local/remote/operator/adaptive/policy). This is where to
// look when a leg that was in `proxy mux info` is gone and
// transport_events shows its transport still open — the removal came from
// the router, not the transport layer.
MuxEvents []router.MuxEvent `json:"mux_events,omitempty"`
}
DiagSnapshot is the `diag` section of a StateSnapshot.
type DiagTransport ¶
type DiagTransport struct {
ID uuid.UUID `json:"id"`
Remote cipher.PubKey `json:"remote"`
Type string `json:"type"`
MissedPongs int64 `json:"missed_pongs"`
PongSeen bool `json:"pong_seen"`
// LastRecvAgoS is seconds since the read loop last received any packet
// (-1 = never). A transport with pongs flowing but climbing app-level
// timeouts is the router-intake case, not a link problem.
LastRecvAgoS float64 `json:"last_recv_ago_s"`
// MalformedFrames counts frames whose type byte was outside the known
// range — the peer wrote a packet whose size field did not match it.
MalformedFrames int64 `json:"malformed_frames"`
Handlers []string `json:"handlers,omitempty"`
}
DiagTransport is one transport's liveness and wiring.
type DiagVStreamMux ¶
type DiagVStreamMux struct {
Name string `json:"name"`
transport.VStreamMuxStats
StreamList []transport.VStreamInfo `json:"stream_list,omitempty"`
}
DiagVStreamMux names one VStream mux and carries its counters, plus one row per live stream. The rows are what turn "streams: 27" into an answer: which app (or none) opened each one, over which transport, how long ago, and how deep its inbound queue is right now.
type Diagnostics ¶
type Diagnostics interface {
DialPing(config PingConfig) error
Ping(config PingConfig) ([]time.Duration, error)
PingOnce(config PingConfig) (time.Duration, error)
StopPing(pk cipher.PubKey) error
StopAllPings() (int, []string, error)
DialDmsgPing(pk cipher.PubKey) error
DialDmsgPingViaServer(pk cipher.PubKey, serverPK cipher.PubKey) error
DmsgPing(conf PingConfig) ([]time.Duration, error)
DmsgPingOnce(conf PingConfig) (time.Duration, error)
StopDmsgPing(pk cipher.PubKey) error
GetDmsgPingServerPK(pk cipher.PubKey) (cipher.PubKey, error)
GetRemoteDmsgServers(pk cipher.PubKey) ([]cipher.PubKey, error)
GetPreferredDmsgServer(remotePK cipher.PubKey) (cipher.PubKey, error)
BandwidthTest(conf BandwidthTestConfig) (BandwidthResult, error)
DmsgBandwidthTest(conf BandwidthTestConfig) (BandwidthResult, error)
TestVisor(config PingConfig) ([]TestResult, error)
DmsgProbe(pk cipher.PubKey, port uint16) (bool, error)
DmsgProbeReason(pk cipher.PubKey, port uint16) (bool, string, error)
DmsgProbeViaServer(pk cipher.PubKey, port uint16, serverPK cipher.PubKey) (bool, error)
SkynetProbe(pk cipher.PubKey, port uint16) (bool, error)
}
Diagnostics is pings, bandwidth tests and probes.
type DialDmsgPingViaServerIn ¶
type Dmsg ¶
type Dmsg interface {
DmsgPortHits() []dmsg.PortHit
DmsgPtyExec(args DmsgPtyExecArgs) (*pty.CommandExecResult, error)
IsDMSGClientReady() (bool, error)
DMSGServers() ([]DMSGServerInfo, error)
// LAN DMSG server
SetLANDmsgServer(LANDmsgServerInfo) error
DialDmsgRPC(pk cipher.PubKey) (net.Conn, error)
DmsgHTTP(req DmsgHTTPRequest) (*DmsgHTTPResponse, error)
SkynetHTTP(req SkynetHTTPRequest) (*SkynetHTTPResponse, error)
VisorSCP(req VisorSCPRequest) error
VisorCat(req VisorCatRequest) (*VisorCatResponse, error)
DmsgConnectAll() (*DmsgConnectAllResult, error)
SetDmsgSessionsCount(count int) (*DmsgConnectAllResult, error)
DmsgSessions() (*DmsgClientSessions, error)
DmsgConverge(carriers []string) (*DmsgConvergeResult, error)
// DMSG diagnostics
DmsgPorterStats() (*DmsgPorterStatus, error)
DmsgPorterReset() (*DmsgPorterStatus, error)
DmsgPorterDiag() (*netutil.EphemeralDiagResult, error)
DmsgReconnect() (int, error)
DmsgSetMinSessions(n int) error
}
Dmsg is the visor's dmsg client and the requests it makes over dmsg and skynet.
type DmsgClientSessionInfo ¶
type DmsgClientSessionInfo struct {
PK cipher.PubKey `json:"pk"`
Role string `json:"role"` // "main" | "route_setup" | "transport_setup"
Count int `json:"count"`
Servers []cipher.PubKey `json:"servers"`
// Sessions carries the same servers plus the protocol each one was reached
// over (tcp / ws / wss / webtransport / quic). Parallel to Servers, sorted
// the same way, so existing Servers consumers keep working.
Sessions []DmsgServerSession `json:"sessions,omitempty"`
// RelayPeers are the visor's current relay nominees (peers it wants a
// skynet-carried session through); RelayClients the peers currently
// attached to THIS visor's relay acceptor.
RelayPeers []cipher.PubKey `json:"relay_peers,omitempty"`
RelayClients []cipher.PubKey `json:"relay_clients,omitempty"`
}
DmsgClientSessionInfo is one dmsg client's current session state.
type DmsgClientSessions ¶
type DmsgClientSessions struct {
Main *DmsgClientSessionInfo `json:"main,omitempty"`
RouteSetup *DmsgClientSessionInfo `json:"route_setup,omitempty"`
TransportSetup *DmsgClientSessionInfo `json:"transport_setup,omitempty"`
}
DmsgClientSessions enumerates every dmsg client running inside the visor (main + embedded route setup node + embedded transport setup node) along with the dmsg server PKs each one currently has an active session to. Used by the `skywire cli dmsg sessions` command for operators investigating connectivity issues — the embedded RSN / TPS use SEPARATE dmsg keys and therefore SEPARATE sets of sessions from the main visor, so checking one doesn't tell you about the others.
type DmsgConnectAllResult ¶
type DmsgConnectAllResult struct {
Total int `json:"total"` // total servers in discovery
AlreadyConnected int `json:"already_connected"` // sessions in place before the call
NewlyConnected int `json:"newly_connected"` // sessions opened by the call
Failed map[string]string `json:"failed,omitempty"` // server PK → error text for any that could not be connected
}
DmsgConnectAllResult summarizes the result of DmsgConnectAll.
type DmsgConvergeResult ¶
type DmsgConvergeResult struct {
Carriers []string `json:"carriers"` // the effective ordered preference used
Converged int `json:"converged"` // sessions re-dialed to a more-preferred carrier
Sessions []dmsg.SessionCarrier `json:"sessions"` // per-session carrier after the pass
}
DmsgConvergeResult reports the outcome of a carrier-convergence pass.
type DmsgHTTPRequest ¶
type DmsgHTTPRequest struct {
URL string `json:"url"`
Method string `json:"method"`
Header map[string]string `json:"header,omitempty"`
Body []byte `json:"body,omitempty"`
}
DmsgHTTPRequest represents an HTTP request to be made over dmsg
type DmsgHTTPResponse ¶
type DmsgHTTPResponse struct {
StatusCode int `json:"status_code"`
Status string `json:"status"`
Header map[string]string `json:"header,omitempty"`
Body []byte `json:"body,omitempty"`
}
DmsgHTTPResponse represents an HTTP response received over dmsg
type DmsgPorterStatus ¶
type DmsgPorterStatus struct {
MainPorts int `json:"main_ports"`
RSNPorts int `json:"rsn_ports,omitempty"`
MainFreed int `json:"main_freed,omitempty"`
RSNFreed int `json:"rsn_freed,omitempty"`
// StreamCensus groups the dmsg streams still in memory by port and state.
StreamCensus []dmsg.StreamCensusRow `json:"stream_census,omitempty"`
}
DmsgPorterStatus contains DMSG porter diagnostics.
type DmsgProbeReasonResponse ¶
DmsgProbeReasonResponse carries a probe result together with why it failed.
type DmsgProbeRequest ¶
type DmsgProbeViaServerRequest ¶
DmsgProbeViaServerRequest is the argument for the DmsgProbeViaServer RPC.
type DmsgPtyExecArgs ¶
type DmsgPtyExecArgs struct {
RemotePK cipher.PubKey
RemotePort uint16
Req pty.CommandExecReq
// Scheme: "" (default — MultiDialer chain), "dmsg" (force dmsg
// only), "skynet" (force skynet only), or "tcp" (the remote's
// direct-TCP pty listener at Addr, dialed as this visor). Unknown
// values return a clear error rather than silently falling back.
Scheme string
// Addr is the host:port of the direct-TCP listener for Scheme "tcp".
Addr string
}
DmsgPtyExecArgs is the request shape for API.DmsgPtyExec. RemotePK identifies the target visor's dmsgpty host; RemotePort defaults to pty.DefaultPort (22) when zero. Req carries the command, arguments, optional environment overrides, optional stdin, and per-call timeout — see pty.CommandExecReq.
Scheme overrides the dialer choice. The visor's dmsgpty Host is wired with a MultiDialer that tries skynet first (transport-aware, rides existing transports for low latency) and falls back to dmsg on miss. That ordering breaks down when skynet's dial blocks past the caller's ctx without honoring it — dmsg never gets tried and the whole exec hangs. Operators who know the peer has a working dmsg session can pass Scheme="dmsg" to skip skynet entirely. Empty keeps the default MultiDialer behavior.
type DmsgRelayAttachment ¶
type DmsgRelayAttachment struct {
PK cipher.PubKey `json:"pk"`
Carrier string `json:"carrier"`
Streams int `json:"streams"`
LatencyMS float64 `json:"latency_ms"`
}
DmsgRelayAttachment is one nominated relay this visor holds a session with.
type DmsgRelayClient ¶
DmsgRelayClient is a peer attached to this visor as its dmsg relay.
type DmsgRelayRole ¶
type DmsgRelayRole struct {
// Port is the dmsg port the relay acceptor listens on over skynet.
Port uint16 `json:"relay_port"`
// RelayPeers are the peers this visor NOMINATED as its relays
// (relayNominees → dmsg.Client.SetRelayPeers). Same field name and
// meaning as `dmsg sessions`.
RelayPeers []cipher.PubKey `json:"relay_peers,omitempty"`
// Attached is the subset of RelayPeers this visor currently holds a
// session with, and the carrier that session rides. Carrier "skynet" is
// an actual relay attachment; anything else means the nominee was reached
// as a plain dmsg server instead.
Attached []DmsgRelayAttachment `json:"attached,omitempty"`
// RelayClients are the peers attached TO this visor's relay acceptor,
// each with the streams open on its relay session. Same field name and
// meaning as `dmsg sessions`, which reports the keys alone.
RelayClients []DmsgRelayClient `json:"relay_clients,omitempty"`
// RelayedStreams is the relay slots in use across all attached peers, and
// MaxRelayedStreams the cap they are charged against (dmsg.relay_max_streams).
// A cap of 0 or less means this visor relays for nobody.
RelayedStreams int `json:"relayed_streams"`
MaxRelayedStreams int `json:"max_relayed_streams"`
// RelayRefused counts stream requests turned away at capacity (dmsg error
// 308) since start. Nonzero means this hub refused traffic it was asked to
// carry — at the dialer that refusal is indistinguishable from the
// destination being down, so without this it is only ever diagnosed from
// the wrong end.
RelayRefused int `json:"relay_refused"`
}
DmsgRelayRole is both directions of the dmsg relay: the relays this visor attaches to, and the peers it relays for.
type DmsgServerClient ¶
type DmsgServerClient struct {
PK cipher.PubKey `json:"pk"`
Streams int `json:"streams"`
Peer bool `json:"peer,omitempty"`
}
DmsgServerClient is one session held by this visor's in-process dmsg server: the connected key, how many streams it has open, and whether the session is another dmsg server (a peer link) rather than a client.
type DmsgServerRole ¶
type DmsgServerRole struct {
// Enabled is what the config asks for; Running is what actually started.
// Enabled && !Running is the interesting case — e.g. no dmsg discovery PK
// to register with, so the server no-opped at init.
Enabled bool `json:"enabled"`
Running bool `json:"running"`
// Mode distinguishes the two servers a visor can host: "own_key" is the
// bare server sharing the visor's PK/SK and dmsg client, "config_path" is
// the whole standalone dmsg-server service run in-process from its own
// config file, on its OWN key. Empty when no server is configured.
Mode string `json:"mode,omitempty"`
// PK is the key the server registers under: the visor's own key in
// "own_key" mode, the config file's key in "config_path" mode.
PK cipher.PubKey `json:"pk,omitempty"`
// OwnKey is true when the server shares the visor's identity, i.e. one
// discovery entry carries both the Client and the Server section.
OwnKey bool `json:"own_key"`
// SharedTransportPort: the server took the dmsg branch of the transport
// port's TCP multiplexer instead of opening a listener of its own, so no
// second port is bound or forwarded.
LocalAddress string `json:"local_address,omitempty"`
PublicAddress string `json:"public_address,omitempty"`
ConfigPath string `json:"config_path,omitempty"`
// StartedAt is when the server was started (zero when it is not running).
StartedAt time.Time `json:"started_at,omitempty"`
// SessionCount is how many dmsg sessions this server currently holds, and
// Clients names them. Answering "who is actually on this dmsg server" used
// to require asking the discovery — which reports what CLIENTS claim about
// their delegated servers, not what the server itself is holding, and says
// nothing about how much traffic each one is running. A co-resident visor
// knows the real answer; this reports it.
//
// Peers are separated from ordinary clients because a server-to-server link
// is not a client at all: counting the two together makes a server look
// busier than it is, and the peer mesh is the part an operator tunes
// separately.
//
// Only populated in own_key mode — config_path mode runs the server inside
// an unexported service type that exposes no session handle.
SessionCount int `json:"session_count"`
PeerCount int `json:"peer_count"`
Clients []DmsgServerClient `json:"clients,omitempty"`
}
DmsgServerRole is the in-process dmsg server (dmsg.server.* in the config).
type DmsgServerSession ¶
type DmsgServerSession struct {
PK cipher.PubKey `json:"pk"`
// Carrier is the raw dmsg carrier: tcp | ws | wt | quic.
Carrier string `json:"carrier"`
// Protocol is a human-readable label distinguishing ws from wss:
// tcp | ws | wss | webtransport | quic.
Protocol string `json:"protocol"`
// Address is the endpoint the carrier dialed (host:port or ws(s)://…).
Address string `json:"address,omitempty"`
// Streams is the number of open mux streams on this session (0 = idle,
// -1 = unmeasurable/quic). Same count the idle-session reaper uses.
Streams int `json:"streams"`
}
DmsgServerSession is one active dmsg-server session and the protocol the local client used to reach it.
type EffectiveRoutingConfig ¶
type EffectiveRoutingConfig struct {
MinHops uint16 `json:"min_hops"`
ForceLocalRoutes bool `json:"force_local_routes"`
ExistingTPOnly bool `json:"existing_tp_only"`
TransportPreference []string `json:"transport_preference,omitempty"`
EnableCascadeRouteSetup bool `json:"enable_cascade_route_setup"`
PolicyPerDial string `json:"policy_per_dial,omitempty"`
}
EffectiveRoutingConfig is the routing configuration in force at runtime. MinHops/MuxRoutes/ForceLocalRoutes/ExistingTPOnly/ TransportPreference are read from the live router (GetRouterSettings), so they reflect any runtime set that diverged from the config file; EnableCascadeRouteSetup and PolicyPerDial are the configured source (PolicyPerDial is a path/inline-source string, never a secret).
type EmbeddedProxiesStatus ¶
type EmbeddedProxiesStatus struct {
DmsgWeb *EmbeddedProxyInfo `json:"dmsg_web,omitempty"`
SkynetWeb *EmbeddedProxyInfo `json:"skynet_web,omitempty"`
SkymailBridge *EmbeddedSkymailInfo `json:"skymail_bridge,omitempty"`
}
EmbeddedProxiesStatus bundles the state of every in-process resolving proxy. Separate fields (not a map) so the UI can treat each proxy's presence/absence as a hard-coded toggle.
type EmbeddedProxyInfo ¶
type EmbeddedProxyInfo struct {
// Enabled is the config flag value, reflecting the intended
// state. Running is the observed state; mismatches happen
// briefly during Start/Stop or when a dependency is still
// bootstrapping.
Enabled bool `json:"enabled"`
// Running is true once the resolver goroutine has been spawned.
Running bool `json:"running"`
// DomainSuffix is the TLD matched by the resolver (e.g. ".dmsg").
DomainSuffix string `json:"domain_suffix,omitempty"`
// SocksAddr is the localhost SOCKS5 listener (e.g. "127.0.0.1:4445").
// Empty when disabled or when Config.ProxyPort is 0.
SocksAddr string `json:"socks_addr,omitempty"`
// UpstreamSOCKS is the configured fallthrough, empty for direct.
UpstreamSOCKS string `json:"upstream_socks,omitempty"`
// UpstreamRules are the per-domain upstreams, longest suffix first.
UpstreamRules []proxyroute.Rule `json:"upstream_rules,omitempty"`
// Stats is the cumulative request counter snapshot. Zero-valued
// when the resolver has never been constructed.
Stats *EmbeddedProxyStats `json:"stats,omitempty"`
}
EmbeddedProxyInfo describes the state of one in-process resolving proxy (dmsgweb or skynetweb). The hypervisor UI renders this so users can copy the SOCKS5 address into their browser without poking at the visor config directly.
type EmbeddedProxyStats ¶
type EmbeddedProxyStats struct {
StartedAt time.Time `json:"started_at,omitempty"`
UptimeSec int64 `json:"uptime_sec,omitempty"`
TotalRequests uint64 `json:"total_requests"`
Successful uint64 `json:"successful"`
Failed uint64 `json:"failed"`
Active int64 `json:"active"`
LastRequestAt *time.Time `json:"last_request_at,omitempty"`
LastSuccessAt *time.Time `json:"last_success_at,omitempty"`
LastFailureAt *time.Time `json:"last_failure_at,omitempty"`
LastError string `json:"last_error,omitempty"`
}
EmbeddedProxyStats is a JSON-friendly stats snapshot common to dmsgweb and skynetweb. Mirrors pkg/dmsgweb.StatsSnapshot / pkg/skynetweb.StatsSnapshot shapes — duplicated here so the RPC surface stays decoupled from the internal stats types.
type EmbeddedServiceControlArgs ¶ added in v1.3.100
EmbeddedServiceControlArgs names an embedded service and what to do with it: stop, start or restart.
type EmbeddedServiceState ¶ added in v1.3.98
type EmbeddedServiceState struct {
Type string `json:"type"`
Name string `json:"name"`
// URL is where the service answers over dmsg: the visor's key, its
// dmsg HTTP port and the service's path prefix.
URL string `json:"url"`
// PlainHTTP is the block's plain-HTTP address, if it serves one.
PlainHTTP string `json:"plain_http,omitempty"`
Running bool `json:"running"`
// OwnKey is set when the service runs under its own key rather than the
// visor's, with its own dmsg client; Restarts counts its restarts.
OwnKey bool `json:"own_key,omitempty"`
Restarts int `json:"restarts,omitempty"`
// Stopped is set while an operator has stopped it.
Stopped bool `json:"stopped,omitempty"`
Error string `json:"error,omitempty"`
services.State
}
EmbeddedServiceState is one deployment service running inside the visor (config.embedded_services), as `skywire cli visor state` reports it.
type EmbeddedSkymailInfo ¶
type EmbeddedSkymailInfo struct {
Enabled bool `json:"enabled"`
Running bool `json:"running"`
Addr string `json:"addr,omitempty"`
Mode string `json:"mode,omitempty"`
Suffix string `json:"suffix,omitempty"`
}
EmbeddedSkymailInfo is the runtime snapshot for the in-process SMTP bridge. Distinct from EmbeddedProxyInfo (which is SOCKS5- shaped) because the bridge has no upstream-SOCKS concept and its listener is an SMTP server, not a SOCKS5 proxy.
type ExecWasmInfo ¶
type ExecWasmInfo struct {
// Path is the module on disk.
Path string `json:"path"`
// Version and Revision are from the manifest beside it, when there is one.
Version string `json:"version,omitempty"`
Revision string `json:"revision,omitempty"`
// Stamp is the served content fingerprint, which the page polls.
Stamp string `json:"stamp,omitempty"`
// Source is the visor the module is refreshed from when the desk is
// opened. Empty when it is not refreshed.
Source string `json:"source,omitempty"`
}
ExecWasmInfo describes the js/wasm module a visor serves for the desk.
type FeedStatus ¶
type FeedStatus = cxosub.FeedStatus
FeedStatus is one row of CXOSubscriptionManager.Status.
type FetchCXOArgs ¶
type FetchCXOArgs struct {
// Feed is one of: "tpd-metrics", "tpd-uptime".
Feed string `json:"feed"`
// Path is the TreeStore path inside the feed, e.g.
// "metrics/days/7" or "uptimes/days/30".
Path string `json:"path"`
}
FetchCXOArgs identifies which CXO feed + path the caller wants the visor to read from its lazy-on-demand subscriber cache. Feed names are stable strings the CLI's URL→feed mapping table emits; adding a new feed means adding a case to the visor's FetchCXO switch and a row to the mapping table — nothing in between needs to know.
type FetchCXOResult ¶
type FetchCXOResult struct {
Hit bool `json:"hit"`
Body []byte `json:"body,omitempty"`
LastRootAt time.Time `json:"last_root_at,omitempty"`
Reason string `json:"reason,omitempty"`
}
FetchCXOResult is the visor's reply for a FetchCXO probe. Hit is true when the subscriber returned a cached payload; a miss carries a Reason string ("not ready", "cooling down", "unknown feed", …) so the CLI's debug log has something concrete to print.
type FetchServiceDataIn ¶
type FilterServersIn ¶
type ForwardedPort ¶
type ForwardedPort struct {
// Port is the DMSG/skynet port exposed to the network.
Port int `json:"port"`
// LocalPort is the TCP port on localhost to forward to. If zero,
// defaults to Port (same port number locally and remotely).
LocalPort int `json:"local_port,omitempty"`
Label string `json:"label,omitempty"`
Description string `json:"description,omitempty"`
ShowOnLanding bool `json:"show_on_landing"`
Whitelist []cipher.PubKey `json:"whitelist,omitempty"` // empty = accessible to all authenticated peers
Skynet bool `json:"skynet"` // forward over skynet (sky-forwarding server)
DMSG bool `json:"dmsg"` // forward over DMSG (service registry)
// UDP, when true, enables UDP-datagram semantics on this
// forward rather than the default TCP-stream semantics.
// Implementation rides DatagramRouteGroup (see
// pkg/router/datagram_route_group.go and the faithful-UDP
// design in #2607): faithful loss, no head-of-line blocking on
// reorder, per-datagram AEAD. For DNS / NTP / VoIP / gaming —
// anything where a late packet is worse than a lost one.
//
// Stage 4 of #2607: this field is recognized by the visor's
// forwarded-port listener loop, which binds a local UDP socket
// at EffectiveLocalPort() and pumps datagrams to/from the
// peer-side DatagramRouteGroup. The route-setup machinery that
// constructs the DatagramRouteGroup itself lives in stage 5's
// app API.
UDP bool `json:"udp,omitempty"`
// ProxyAddr is an optional local address (e.g., "127.0.0.1:3000")
// to reverse-proxy to. For port 80, this replaces the visor's
// default landing page with content from the local service.
ProxyAddr string `json:"proxy_addr,omitempty"`
// PreserveHost controls the Host header on the request the
// reverse-proxy emits to the backend. Currently effective on the
// port-80 HTTP reverse-proxy (the only forward type that touches
// HTTP headers; raw-TCP forwards don't see HTTP at all).
//
// false (default): visor rewrites Host to the backend's address
// (target.Host). Useful when the backend
// validates Host against its listening address
// — the historical behavior.
// true: visor preserves whatever Host the incoming
// request already carried (e.g. magnetosphere
// .net after the skynetweb resolver's
// subdomain rewrite). Required when the
// backend (Caddy, nginx, traefik) dispatches
// its virtual hosts by Host header.
PreserveHost bool `json:"preserve_host,omitempty"`
// InjectPK, when true, makes this forward HTTP-aware: instead of a
// raw TCP splice, the visor terminates HTTP and reverse-proxies to
// the backend, stamping the noise-authenticated caller into request
// headers the backend can trust:
//
// X-Skywire-Remote-PK the caller's 66-hex public key (omitted if
// the peer can't be identified)
// X-Skywire-Transport "dmsg" or "skynet"
//
// Any client-supplied copies of those headers are stripped first, so
// they cannot be spoofed over this path. This lets a forwarded website
// do per-PK behavior (auth, personalization) that a raw splice can't,
// because the backend otherwise never learns who is connecting.
//
// HTTP only — enabling it on a non-HTTP service breaks the stream. The
// header is only trustworthy if the backend is reachable ONLY through
// the visor (bind it to loopback); see docs/guides/skynet-website-auth.md.
InjectPK bool `json:"inject_pk,omitempty"`
// Vhosts are sites on port 80 chosen by the request's Host, each a local
// service reverse-proxied without Caddy. Set on the port 80 entry.
Vhosts []Vhost `json:"vhosts,omitempty"`
}
ForwardedPort describes a single forwarded port with its metadata.
func (*ForwardedPort) DialTarget ¶
func (fp *ForwardedPort) DialTarget() string
DialTarget returns the address that incoming forwarded connections should be proxied to. ProxyAddr wins when set ("host:port" or "ip:port"); otherwise it falls back to localhost:EffectiveLocalPort.
func (*ForwardedPort) EffectiveLocalPort ¶
func (fp *ForwardedPort) EffectiveLocalPort() int
EffectiveLocalPort returns the local TCP port to forward to. Returns LocalPort if set, otherwise Port.
type Forwarding ¶
type Forwarding interface {
RegisterTCPPort(localPort int) error
DeregisterTCPPort(localPort int) error
ListTCPPorts() ([]int, error)
RegisterForwardedPort(p ForwardedPort) error
UpdateForwardedPort(p ForwardedPort) error
ListForwardedPorts() ([]ForwardedPort, error)
// DialUDPForward / StopUDPForward / ListUDPForwards drive client-side
// faithful-UDP port forwarding (#2607): bridge a local UDP socket to
// a remote forwarded_ports.udp service via DialPacket.
DialUDPForward(remotePK cipher.PubKey, remotePort, localPort int) error
StopUDPForward(localPort int) error
ListUDPForwards() ([]int, error)
ConnectRawTCP(network string, remotePK cipher.PubKey, remotePort, localPort int) (uuid.UUID, error)
DisconnectRawTCP(id uuid.UUID) error
ListRawTCP() (map[uuid.UUID]*appnet.RawTCPForwardConn, error)
}
Forwarding is exposing local ports over skynet and dmsg, and forwarding remote ones.
type GroupAddMemberRequest ¶
GroupAddMemberRequest is the input to RPC.GroupAddMember.
type GroupCatalogEntry ¶
type GroupCatalogEntry struct {
ID string `json:"id"`
HostPK cipher.PubKey `json:"host_pk"`
Name string `json:"name"`
Kind skychatgroup.Kind `json:"kind"`
Mode skychatgroup.Mode `json:"mode"`
Policy skychatgroup.JoinPolicy `json:"policy"`
PriceHint string `json:"price_hint,omitempty"`
Address string `json:"address"`
}
GroupCatalogEntry is the RPC-facing shape of one discovered group.
Port and PoWBits are deliberately absent: they are join mechanics the visor uses internally, and a caller acts on Address, which carries everything needed to join and nothing a UI has to understand.
type GroupCatalogResponse ¶
type GroupCatalogResponse struct {
Entries []GroupCatalogEntry `json:"entries"`
Truncated bool `json:"truncated,omitempty"`
}
GroupCatalogResponse pairs the discovered entries with whether the host had more than it sent.
type GroupCreateArgs ¶
type GroupCreateArgs struct {
Name string `json:"name"`
// Kind is the group type: "public" (open admission, plaintext),
// "private" (admin-approved admission, encrypted) or "channel"
// (open admission, plaintext, only admins may post). Preferred
// over Mode.
Kind skychatgroup.Kind `json:"kind,omitempty"`
// Mode is the legacy field, kept so an older RPC client keeps
// working: it carried the same two values and mapped onto the same
// two group types. Used only when Kind is empty, and it cannot name
// a channel — public and channel share ModePublic.
Mode skychatgroup.Mode `json:"mode,omitempty"`
InitialMembers []cipher.PubKey `json:"initial_members,omitempty"`
// DisablePeerBackfill is the creator's choice on whether any online
// member may serve this group's history to a joiner, or only admins.
// The zero value keeps backfill ENABLED, which is the default an
// operator gets by not saying anything and matches the group record's
// own inverted field. An admin can change it later with
// GroupSetPeerBackfill.
DisablePeerBackfill bool `json:"disable_peer_backfill,omitempty"`
// Listed opts the new group into this visor's discovery catalog. The
// zero value keeps it unlisted, which is the private direction — see
// skychatgroup.Record.Listed for why that default matters.
Listed bool `json:"listed,omitempty"`
}
GroupCreateArgs is the RPC input for GroupCreate.
func (GroupCreateArgs) ResolvedKind ¶
func (a GroupCreateArgs) ResolvedKind() skychatgroup.Kind
ResolvedKind resolves the group type from either field, defaulting to public.
type GroupCreateResponse ¶
GroupCreateResponse pairs the persisted GroupInfo with the freshly-encoded invite link the operator should distribute.
type GroupDescriptor ¶
type GroupDescriptor struct {
ID string `json:"id"`
HostPK cipher.PubKey `json:"host_pk"`
Name string `json:"name"`
Kind skychatgroup.Kind `json:"kind"`
Mode skychatgroup.Mode `json:"mode"`
Policy skychatgroup.JoinPolicy `json:"policy"`
Port uint16 `json:"port"`
PoWBits uint8 `json:"pow_bits,omitempty"`
ReadOnly bool `json:"read_only,omitempty"`
PriceHint string `json:"price_hint,omitempty"`
Banned bool `json:"banned,omitempty"`
}
GroupDescriptor is the RPC-facing shape of group.GroupDescriptor. Re-declared rather than aliased so the RPC surface can carry display-oriented additions (a rendered kind label, later a price) that the protocol type has no business knowing about.
type GroupFileKeyArgs ¶
GroupFileKeyArgs is the RPC input for GroupFileKey: which group, and which attachment within it.
type GroupFileKeyResult ¶
type GroupFileKeyResult struct {
// Seal is the key to encrypt a new attachment with. Nil for a
// plaintext (public) group, where sealing would protect nothing: the
// caller sends such files as-is.
Seal []byte `json:"seal,omitempty"`
// Open is every key that may open an existing attachment, current
// epoch first then the ring — the order that makes the common case a
// single trial decryption.
Open [][]byte `json:"open,omitempty"`
// Epoch is the group's current key generation, for diagnostics.
Epoch uint64 `json:"epoch,omitempty"`
// Encrypted reports whether this group seals attachments at all,
// distinguishing "public group, nothing to do" from "encrypted group
// whose key we somehow lack" — which is an error, not a no-op.
Encrypted bool `json:"encrypted"`
}
GroupFileKeyResult carries the keys for one group attachment.
Two fields rather than one because the two uses differ: sealing needs exactly the current key, while opening has to try the retired ones too (an attachment shared before a rotation must keep opening afterwards, the same way message history does).
Both are keys DERIVED for this one file id — the group key itself never crosses the RPC boundary. See the group package's filekey.go.
type GroupHistoryPageArgs ¶
type GroupHistoryPageArgs struct {
GroupID string `json:"group_id"`
// Before is the exclusive upper bound — the oldest message the caller
// already has. Zero means "the newest page".
Before time.Time `json:"before,omitempty"`
Limit int `json:"limit,omitempty"`
}
GroupHistoryPageArgs is the RPC input for GroupHistoryPage.
type GroupHistoryRequest ¶
GroupHistoryRequest is the input shape for GroupHistory. GroupID is required; Limit caps the result set (0 = all).
type GroupInfo ¶
type GroupInfo struct {
ID string `json:"id"`
Name string `json:"name"`
// Avatar is the group's picture as a data URI, empty when unset.
// The URI form rather than bytes for the same reason Profile carries
// one over RPC: JSON-friendly and directly usable as an <img> src,
// with the MIME inside it always the validated one.
Avatar string `json:"avatar,omitempty"`
OwnerPK cipher.PubKey `json:"owner_pk"`
Port uint16 `json:"port"`
Mode skychatgroup.Mode `json:"mode"`
// Kind is the user-facing group type — "public" (open admission,
// plaintext) or "private" (admin-approved admission, encrypted).
// Mode is retained above for older clients; new code should read
// Kind, JoinPolicy and PostPolicy.
Kind skychatgroup.Kind `json:"kind,omitempty"`
// JoinPolicy and PostPolicy are derived, not stored: they answer
// "can someone walk in" and "who may speak right now" so a UI
// doesn't have to re-derive the rules from Kind + ReadOnly.
JoinPolicy skychatgroup.JoinPolicy `json:"join_policy,omitempty"`
PostPolicy skychatgroup.PostPolicy `json:"post_policy,omitempty"`
// Banned and Muted are the moderation lists. Banned PKs are out of
// the group and refused at the join gate; muted PKs read but
// cannot post.
Banned []cipher.PubKey `json:"banned,omitempty"`
Muted []cipher.PubKey `json:"muted,omitempty"`
// ReadOnly suspends posting for every non-admin.
ReadOnly bool `json:"read_only,omitempty"`
// JoinPoWBits is how much proof of work this group asks of a join
// request, in leading zero bits — the price of one identity. Zero
// means none. Surfaced so an operator under a flood can see the
// current setting and raise it.
JoinPoWBits uint8 `json:"join_pow_bits"`
// PeerBackfill reports whether any online member may serve this
// group's history and messages to a joiner (true) or only admins
// (false). Positive sense here even though the record stores the
// negative — an API consumer should not have to reason about a double
// negative to render a checkbox.
PeerBackfill bool `json:"peer_backfill"`
// Listed reports whether THIS visor publishes the group in its
// discovery catalog. Local, not gossiped — another admin's copy of the
// same group carries its own answer. See skychatgroup.Record.Listed.
Listed bool `json:"listed,omitempty"`
// KeyEpoch is the generation of the key this group currently encrypts
// with — 0 for a plaintext group or one still on its create-time key,
// incremented by every rotation. Surfaced so an operator can see that
// an eviction actually re-keyed the group, and that every member
// converged onto the same epoch.
KeyEpoch uint64 `json:"key_epoch,omitempty"`
// KeyAge is how long the current key has been in force, in seconds.
// The epoch number alone doesn't say whether it is a week old or a
// year; this is what makes "bounded in time" visible.
KeyAgeSeconds int64 `json:"key_age_seconds,omitempty"`
// KeyRotatesInSeconds is how long until this group's key is due for
// replacement on age. Negative means it is already due and the next
// background tick will re-key it. Zero for a plaintext group.
KeyRotatesInSeconds int64 `json:"key_rotates_in_seconds,omitempty"`
// GovernanceSealed reports whether this group's membership and
// moderation history is encrypted on the feed as well as its
// messages — who was added, promoted, banned or muted, and when.
//
// True exactly when the group is encrypted; surfaced as its own
// field rather than left for a client to infer from Kind, because
// "the bans are private too" is a distinct promise from "the
// messages are private" and it was NOT true before this build. A
// client that shows it can tell the operator which one they have.
GovernanceSealed bool `json:"governance_sealed,omitempty"`
// CanPost / CannotPostReason answer "may THIS visor post into this
// group right now", pre-computed so the UI can disable the composer
// and explain why without duplicating the precedence rules
// (banned > muted > read-only).
CanPost bool `json:"can_post"`
CannotPostReason string `json:"cannot_post_reason,omitempty"`
// PendingJoins is the number of join requests awaiting an admin
// decision. Zero for non-admins and for open groups, which admit
// without queuing. Populated by GroupList and GroupGet.
PendingJoins int `json:"pending_joins,omitempty"`
// Admins is the per-record roster-authority set. Mirrors
// Record.Admins exactly — founder is implicitly admin and is
// surfaced explicitly here after EnsureFounderInAdmins runs on
// the store read path, so RPC clients can render the admin list
// without having to OR in OwnerPK themselves.
Admins []cipher.PubKey `json:"admins,omitempty"`
Members []cipher.PubKey `json:"members"`
Role skychatgroup.Role `json:"role"`
Status skychatgroup.Status `json:"status"`
CreatedAt time.Time `json:"created_at"`
JoinedAt time.Time `json:"joined_at"`
LastMessageAt time.Time `json:"last_message_at,omitempty"`
// SubscriberAlive is the live health of this visor's subscriber
// side. Populated by GroupList; left zero by other accessors that
// don't need it. See group.Manager.IsSubscriberAlive for semantics.
SubscriberAlive bool `json:"subscriber_alive"`
// PeerLastInbound is the per-peer last-inbound time, keyed by
// peer-PK hex. Populated by GroupList and GroupGet alongside
// SubscriberAlive. A zero time means the peerSub for that peer
// is connecting, silent since startup, or (legacy s.sub path)
// not individually tracked. Empty map for owner-role sessions
// that don't follow peer feeds. Operator-facing: lets `cli
// skychat group info` show which specific peer is stale in a
// group whose session-level SubscriberAlive is otherwise true.
PeerLastInbound map[string]time.Time `json:"peer_last_inbound,omitempty"`
// SubDropCount is the running total of inbox-to-stream drops
// across every live + torn-down gRPC StreamGroupMessages
// subscriber on THIS VISOR. Bumped in groupInbox.deliver's
// select+default branch when a subscriber's bounded channel is
// full (per-subscriber 256-message buffer set by the gRPC
// handler); persisted across unsubscribe so a single rolling
// total survives stream restarts.
//
// Inbox-wide, not group-scoped — the inbox fans every message
// to every live subscriber regardless of group, so a drop is
// "this subscriber couldn't keep up" rather than "this group is
// noisy". Repeated across every GroupInfo here for operator
// convenience; cross-checking the value between two groups in
// the same /status response always returns the same number.
//
// Distinct from the inbox ring's overflow drop semantics — the
// ring keeps the most-recent groupInboxCap (1024) messages
// regardless of subscriber draining. SubDropCount only counts
// messages that reached deliver's fan-out but failed to enqueue
// onto a particular subscriber's channel; the ring still has
// them and the next StreamGroupMessages reconnect's backlog
// replay picks them up via SinceTimestampNs (#2630/#2659).
//
// Surfaced live so the chat-app's /status can flag a busy group
// whose subscriber side is silently dropping under burst — pre-
// fix the count was only readable at unsubscribe time, leaving a
// gap where an operator watching /status saw subscriber_alive=true
// and last_message_at advancing but the CLI listener pipe
// missing messages.
SubDropCount uint64 `json:"sub_drop_count"`
// DeliverCount is the running total of groupInbox.deliver()
// invocations since visor startup — every message that landed
// at the inbox layer, regardless of downstream consumption.
//
// Combined with PeerUpdateCount (per-peer) and SubDropCount,
// localizes drops along the receive path:
// PeerUpdateCount[peer] = CXO peerSub → Session callback fired
// DeliverCount = Session → inbox.deliver() enqueued
// SubDropCount = inbox → gRPC subscriber channel dropped
//
// Deltas tell where messages are lost:
// peerUpdate_sum < deliverCount → impossible (deliver is downstream)
// peerUpdate_sum > deliverCount → drops in Session.makePeerOnUpdate's
// deliver call site (per-peer callback fired
// but message never reached inbox)
// deliverCount > rcvd_at_client → drops between inbox and the CLI listener
// (subDropCount accounts for some; the rest
// are gRPC adapter or stream.Send)
//
// Visor-wide, not group-scoped (matches SubDropCount semantics).
// Repeated across every GroupInfo for operator convenience.
DeliverCount uint64 `json:"deliver_count"`
// StreamSendCount is the running total of successful stream.Send
// calls on rpcgrpc.StreamGroupMessages across both PingServer
// instances (local CLI + dmsg-RPC). Counts data events only;
// the Subscribed sentinel that the handler emits before entering
// the dispatch loop is NOT included.
//
// Pairs with DeliverCount to localize drops between the inbox
// layer and the CLI listener:
// DeliverCount > StreamSendCount → drops between inbox and
// stream (SubDropCount accounts
// for some; rest are adapter
// backpressure or stream
// flow-control on the gRPC
// send buffer).
// DeliverCount == StreamSendCount → everything that landed
// in the inbox was sent to
// the wire; any operator-
// observed loss is downstream
// of stream.Send (gRPC client
// recv, CLI buffering, or
// Monitor task wrapper).
//
// Visor-wide, not group-scoped. Reset only on visor restart.
StreamSendCount uint64 `json:"stream_send_count"`
// PeerUpdateCount is the per-peer count of treestore subscriber
// OnUpdate callbacks observed by Session.makePeerOnUpdate, keyed
// by peer-PK hex. Populated alongside PeerLastInbound. Bumped on
// every events>0 callback (the same seam that bumps the
// peerLastInboundNs liveness signal).
//
// Empty map for owner-role sessions that don't follow peer feeds.
// Operator-facing: an idle peer with PeerLastInbound zero AND
// PeerUpdateCount zero has never been heard from; an idle peer
// with PeerLastInbound stale but PeerUpdateCount > 0 went silent
// after a known interaction. Comparing PeerUpdateCount sums to
// DeliverCount localizes drops upstream vs downstream of the
// inbox enqueue.
PeerUpdateCount map[string]uint64 `json:"peer_update_count,omitempty"`
}
GroupInfo is the public summary of a chat group, returned by GroupList and GroupGet.
type GroupJoinArgs ¶
type GroupJoinArgs struct {
// Invite is a skychat:invite:<base64url> link. Self-contained: it
// works even while the group's host is offline, because it carries
// the port and mode inline.
Invite string `json:"invite"`
// Address is the short form — skychat://<host-pk>/<group-id>. Not
// self-contained: the host is asked what the group is (see
// group.Manager.JoinByAddress) before the ordinary join runs, so
// this needs the host reachable and an invite does not.
//
// Both are accepted because they trade against each other rather
// than one superseding the other: an address is short enough to scan
// or read aloud and stays correct as the group changes, a link keeps
// working when nobody is home.
Address string `json:"address,omitempty"`
}
GroupJoinArgs is the RPC input for GroupJoin. Exactly one of the two fields is used, Invite first.
type GroupJoinPoWRequest ¶
GroupJoinPoWRequest sets the join proof-of-work difficulty.
type GroupJoinRequest ¶
type GroupJoinRequest struct {
GroupID string `json:"group_id"`
PK cipher.PubKey `json:"pk"`
Note string `json:"note,omitempty"`
AskedAt time.Time `json:"asked_at"`
Status skychatgroup.JoinStatus `json:"status"`
DecidedAt time.Time `json:"decided_at,omitempty"`
DecidedBy cipher.PubKey `json:"decided_by,omitempty"`
}
GroupJoinRequest is one entry in a group's admission queue.
type GroupMessage ¶
type GroupMessage struct {
GroupID string `json:"group_id"`
SenderPK cipher.PubKey `json:"sender_pk"`
Text string `json:"text"`
TS time.Time `json:"ts"`
}
GroupMessage is one inbound message delivered through the visor's group inbox. Outbound (owner-only Sends) are NOT echoed here; the caller already knows what it sent.
type GroupPeerBackfillRequest ¶
GroupPeerBackfillRequest toggles whether any online member may serve the group's history to a joiner.
type GroupPeerRequest ¶
GroupPeerRequest is the (group, peer) input shared by every admission + moderation command: approve, deny, remove, ban, unban, mute, unmute. One request type rather than seven identical ones — the method name already carries the verb.
type GroupPollRequest ¶
GroupPollRequest is the input to RPC.GroupPoll.
type GroupPromoteAdminRequest ¶
GroupPromoteAdminRequest is the input to RPC.GroupPromoteAdmin / GroupDemoteAdmin. Shape mirrors GroupAddMemberRequest.
type GroupReadOnlyRequest ¶
GroupReadOnlyRequest toggles group-wide read-only.
type GroupResolveArgs ¶
type GroupResolveArgs struct {
// Address is any spelling the address parser accepts — a bare public
// key, skychat://<pk>, skychat://<pk>/<group-id> — or a
// skychat:invite: link, which is answered from the link itself
// without a round trip.
Address string `json:"address"`
}
GroupResolveArgs is the RPC input for GroupResolve.
type GroupResolveResult ¶
type GroupResolveResult struct {
// Target is "dm" or "group".
Target string `json:"target"`
// PK is the peer for a DM, the host for a group address.
PK cipher.PubKey `json:"pk"`
// Address is the canonical skychat:// form of what was resolved,
// suitable for display, copying, and QR encoding.
Address string `json:"address"`
// Group is populated for a group address: what the group is and what
// joining it will involve. Nil for a DM.
Group *GroupDescriptor `json:"group,omitempty"`
// Joined reports that this visor is already an active member, so the
// caller should open the group rather than offer to join it.
Joined bool `json:"joined,omitempty"`
// Status is this visor's own record status for the group when one
// exists — "awaiting_approval" and "denied" in particular, which are
// the difference between offering "Send request" and explaining that
// one was already refused.
Status skychatgroup.Status `json:"status,omitempty"`
// Invite carries the link back when the input WAS a link, so a
// caller that resolved one can hand it straight to GroupJoin without
// re-parsing.
Invite string `json:"invite,omitempty"`
}
GroupResolveResult describes what an address points at, so a UI can offer the one right action instead of making the user pick.
The zero-ish DM case is deliberately cheap: a bare public key needs no network at all to classify, because a key that names a person and a key that hosts a channel are the same 66 characters — only the presence of a group ID distinguishes them, and that is in the address.
type GroupSendArgs ¶
GroupSendArgs is the RPC input for GroupSend.
type GroupSetListedRequest ¶
GroupSetListedRequest is the input to RPC.GroupSetListed.
type GroupSetMetaArgs ¶
type GroupSetMetaArgs struct {
ID string `json:"id"`
// Name is the new display name; empty keeps the current one.
Name string `json:"name,omitempty"`
// Avatar is the new picture as a data URI (or bare base64), consulted
// only when SetAvatar is true. SetAvatar with an empty Avatar clears
// the picture — the flag is what tells "clear it" apart from "leave
// it alone".
Avatar string `json:"avatar,omitempty"`
SetAvatar bool `json:"set_avatar,omitempty"`
}
GroupSetMetaArgs is the input for GroupSetMeta. Zero-valued halves stay untouched, so one call can rename, re-picture, or both.
type GroupUnsendArgs ¶
GroupUnsendArgs is the RPC input for GroupUnsend. TS is the message's UnixNano timestamp (the value carried in the delivered message).
type HVAddTransportArgs ¶
type HVAutoconnectArgs ¶
type HVAutostartArgs ¶
type HVCalcRoutesArgs ¶
type HVDmsgSessionsArgs ¶
type HVForwardedPortArgs ¶
type HVForwardedPortArgs struct {
PK cipher.PubKey
Port ForwardedPort
}
type HVMinHopsArgs ¶
type HVProxyArgs ¶
type HVRewardArgs ¶
type HVTCPPortArgs ¶
type HVVisorEntry ¶
type HVVisorEntry struct {
PK cipher.PubKey `json:"pk"`
Online bool `json:"online"`
IsLocal bool `json:"is_local,omitempty"`
Version string `json:"version,omitempty"`
BuildTag string `json:"build_tag,omitempty"`
Uptime float64 `json:"uptime_seconds,omitempty"`
LocalIP string `json:"local_ip,omitempty"`
PublicIP string `json:"public_ip,omitempty"`
CountryCode string `json:"country_code,omitempty"`
IsSymmetricNAT bool `json:"symmetric_nat,omitempty"`
Transports int `json:"transports"`
// TransportSummaries is the full per-transport detail (type,
// remote PK, sent/recv counters, etc.) the hvui's node-list
// table needs to render its Transports column. Populated by
// populateEntryFromSummary from summary.Overview.Transports.
// omitempty so older sub-hypervisor binaries that don't fill
// this field don't blow the JSON shape.
TransportSummaries []*TransportSummary `json:"transport_summaries,omitempty"`
Apps int `json:"apps"`
RewardAddress string `json:"reward_address,omitempty"`
ConfigVersion string `json:"config_version,omitempty"`
// ServicesHealth is the remote visor's most recent
// HealthInfo.ServicesHealth ("healthy", "unhealthy",
// "connecting", ""). Carried so the hvui's tree-summary
// sub-section can render the same green / yellow / gray status
// dot that the local section's main table does — without this,
// every sub-section row falls through to nodeStatusClass's
// "online but health unknown" branch and renders as a gray
// outline circle even when the visor is fully healthy.
ServicesHealth string `json:"services_health,omitempty"`
// Hostname is the visor's os.Hostname(). The hvui's main node
// list uses this as the default Label when no explicit label is
// set; without it, sub-section rows render with an empty Label
// column even though the visor itself reports a valid hostname.
// Carried separately from PK because Overview.Hostname doesn't
// survive the HVVisorEntry round-trip otherwise.
Hostname string `json:"hostname,omitempty"`
Error string `json:"error,omitempty"`
// ProxiedVia is set when this entry was discovered through a connected
// sub-hypervisor rather than a direct connection. The value is the PK
// of the sub-hypervisor that proxies operations on this visor.
ProxiedVia *cipher.PubKey `json:"proxied_via,omitempty"`
// Load is the visor's resource snapshot (load average, mem %, disk %),
// from summary.Load. Rendered by `hv ls --load`. omitempty so older
// sub-hypervisor binaries that don't carry it don't break the JSON shape.
Load *LoadStats `json:"load,omitempty"`
// Hypervisors is the set of hypervisors THIS visor is configured to be
// managed by (its conf.Hypervisors), reported by the visor itself. An
// attached visor commonly answers to more than one hypervisor, and until
// now the only way to learn the others was to ask that visor directly:
// the tree sections describe hypervisors THIS one can reach, not the ones
// its peers have set. omitempty so an older visor that does not report
// them is absent rather than empty.
Hypervisors []cipher.PubKey `json:"hypervisors,omitempty"`
}
HVVisorEntry is a summary of a remote visor connected to this hypervisor.
type HVVisorTree ¶
type HVVisorTree struct {
Sections []HVVisorTreeNode `json:"sections"`
}
HVVisorTree is the structured response of HVListVisorsTree — a flat list of hypervisor sections. The first entry is the local hypervisor; subsequent entries are sub-hypervisors reachable from it. Each section's `via_chain` documents the path from the local hypervisor down to that sub-hypervisor, so the UI can render a breadcrumb without recomputing.
Visor entries replicate across sections: a visor V that's connected to both the local hypervisor and a sub-hypervisor will appear in BOTH sections — the semantics are "every table shows every visor directly connected to that hypervisor," intentionally. Tables themselves dedup: two paths to the same sub-hypervisor render once.
type HVVisorTreeNode ¶
type HVVisorTreeNode struct {
HypervisorPK cipher.PubKey `json:"hypervisor_pk"`
ViaChain []cipher.PubKey `json:"via_chain,omitempty"`
Visors []HVVisorEntry `json:"visors"`
SubError string `json:"sub_error,omitempty"`
}
HVVisorTreeNode is one hypervisor's section in the tree response: the hypervisor's PK, the chain of hypervisors from the local one down to this one (empty for the local hypervisor itself), and the visors directly connected to this hypervisor (NOT transitively merged from any sub-hypervisors below it).
Sub-hypervisors that fail to respond surface their error via the SubError field instead of being silently dropped — the UI can render a placeholder row with the error text, and operators can tell "no sub-visors" from "query failed."
type HealthInfo ¶
type HealthInfo struct {
ServicesHealth string `json:"services_health"`
UptimeTrackerHealth string `json:"uptime_tracker_health,omitempty"`
AutoconnectHealth string `json:"autoconnect_health,omitempty"`
TransportabilityHealth string `json:"transportability_health,omitempty"`
}
HealthInfo carries information about visor's services health. ServicesHealth is the aggregate status — "connecting" if any subsystem is unhealthy, "healthy" only when all are healthy. The per-subsystem fields let the UI show which specific subsystem is the blocker rather than a generic label.
type HostBridgeForward ¶ added in v1.3.101
type HostBridgeForward struct {
// Host is the address asked for on the host, Bound the one it got.
Host string `json:"host"`
Bound string `json:"bound,omitempty"`
Local string `json:"local"`
Error string `json:"error,omitempty"`
}
HostBridgeForward is a TCP listener on the bridge's host whose connections are passed to a local address of the visor.
type HostBridgeForwardArgs ¶ added in v1.3.101
HostBridgeForwardArgs asks for a forward from Host to Local.
type HostBridgeStatus ¶ added in v1.3.101
type HostBridgeStatus struct {
URL string `json:"url,omitempty"`
Connected bool `json:"connected"`
Error string `json:"error,omitempty"`
Forwards []HostBridgeForward `json:"forwards"`
}
HostBridgeStatus is the visor's session to a host bridge, which lends a browser visor the sockets of its host. See pkg/hostbridge.
type HostStatsInfo ¶
type HostStatsInfo struct {
// Host identity (mostly static; useful as a header above the
// graphs so the user knows which box they're looking at).
Hostname string `json:"hostname,omitempty"`
OS string `json:"os,omitempty"`
Platform string `json:"platform,omitempty"`
Arch string `json:"arch,omitempty"`
UptimeSeconds uint64 `json:"uptime_seconds,omitempty"`
// CPU
CPUPercent float64 `json:"cpu_percent"`
CPUCount int `json:"cpu_count"`
CPULogicalCount int `json:"cpu_logical_count"`
// Memory (bytes)
MemTotal uint64 `json:"mem_total"`
MemUsed uint64 `json:"mem_used"`
MemAvailable uint64 `json:"mem_available"`
MemPercent float64 `json:"mem_percent"`
SwapTotal uint64 `json:"swap_total,omitempty"`
SwapUsed uint64 `json:"swap_used,omitempty"`
SwapPercent float64 `json:"swap_percent,omitempty"`
// Disk — root filesystem only. Per-mount breakdown can be a
// follow-up; "/" is the signal users care about for "is the
// visor about to run out of room for its log buffer / cxo
// tree-store?"
DiskTotal uint64 `json:"disk_total,omitempty"`
DiskUsed uint64 `json:"disk_used,omitempty"`
DiskFree uint64 `json:"disk_free,omitempty"`
DiskPercent float64 `json:"disk_percent,omitempty"`
// Network — cumulative across all interfaces since boot. Client
// diffs to derive Bps. Per-interface breakdown is omitted to
// keep the payload small; can be added later as a `Per []…`
// field if a user wants it.
NetBytesSent uint64 `json:"net_bytes_sent"`
NetBytesRecv uint64 `json:"net_bytes_recv"`
NetPacketsSent uint64 `json:"net_packets_sent,omitempty"`
NetPacketsRecv uint64 `json:"net_packets_recv,omitempty"`
// Visor process specifics. Process is nil when we can't read
// our own /proc entry (rare; surface as null in JSON).
Process *ProcessStatsInfo `json:"process,omitempty"`
}
HostStatsInfo carries a snapshot of host system + visor process resource utilization. Returned by Visor.HostStats and surfaced to the hypervisor UI via /visors/<pk>/host-stats.
All byte counts are bytes (not KB/MB); the UI is responsible for scaling for display.
type HypervisorPasswordChangeIn ¶
HypervisorPasswordChangeIn carries the old + new password for the hypervisor UI "admin" account. Mirrors the shape of usermanager.ChangePassword and SkychatPasswordChangeIn.
type Hypervisors ¶
type Hypervisors interface {
RemoteVisors() ([]string, error)
AddHypervisor(pk cipher.PubKey) error
// PendingHypervisors lists peers waiting to be approved as hypervisors
// (a same-origin transport or a refused RPC), by fingerprint.
PendingHypervisors() ([]PendingHypervisor, error)
// ApproveHypervisor approves a pending key by public key or fingerprint
// (or unique prefix); it is AddHypervisor with a lookup in front.
ApproveHypervisor(sel string) (cipher.PubKey, error)
// NewPairCode mints a one-time pairing code valid for ttl (0 = default).
NewPairCode(ttl time.Duration) (PairCode, error)
RemoveHypervisor(pk cipher.PubKey) error
RemoveAllHypervisors() (int, error)
SetHypervisorPassword(oldPassword, newPassword string) error
SetHypervisorPasswordForce(newPassword string) error
TransportRPCCall(remotePK cipher.PubKey, method string, args json.RawMessage) (json.RawMessage, error)
HVListVisors() ([]HVVisorEntry, error)
HVListDirectVisors() ([]HVVisorEntry, error)
HVListVisorsTree() (*HVVisorTree, error)
HVVisorSummary(pk cipher.PubKey) (*Summary, error)
HVStartApp(pk cipher.PubKey, appName string) error
HVStopApp(pk cipher.PubKey, appName string) error
HVSetMinHops(pk cipher.PubKey, hops uint16) error
HVSetRewardAddress(pk cipher.PubKey, addr string) (string, error)
HVRemoveTransport(pk cipher.PubKey, tid uuid.UUID) error
HVRemoveRoutingRule(pk cipher.PubKey, key routing.RouteID) error
HVAddTransport(pk, remote cipher.PubKey, tpType, label string, timeout time.Duration) (*TransportSummary, error)
HVSetPublicAutoconnect(pk cipher.PubKey, enable bool) error
HVSetCalculateRoutes(pk cipher.PubKey, enable bool) error
HVReload(pk cipher.PubKey) error
HVShutdown(pk cipher.PubKey) error
HVServiceHealth(pk cipher.PubKey) ([]ServiceHealthEntry, error)
HVDmsgSessions(pk cipher.PubKey) (*DmsgClientSessions, error)
HVDmsgConnectAll(pk cipher.PubKey) (*DmsgConnectAllResult, error)
HVSetDmsgSessionsCount(pk cipher.PubKey, count int) (*DmsgConnectAllResult, error)
HVLogsSince(pk cipher.PubKey, since time.Time, appName string) ([]string, error)
HVSetAutoStart(pk cipher.PubKey, appName string, autostart bool) error
HVEmbeddedProxies(pk cipher.PubKey) (*EmbeddedProxiesStatus, error)
HVSetEmbeddedProxyEnabled(pk cipher.PubKey, kind string, enable bool) error
HVSetEmbeddedProxyUpstream(pk cipher.PubKey, kind, addr string) error
HVListTCPPorts(pk cipher.PubKey) ([]int, error)
HVRegisterTCPPort(pk cipher.PubKey, port int) error
HVDeregisterTCPPort(pk cipher.PubKey, port int) error
HVListForwardedPorts(pk cipher.PubKey) ([]ForwardedPort, error)
HVRegisterForwardedPort(pk cipher.PubKey, p ForwardedPort) error
HVUpdateForwardedPort(pk cipher.PubKey, p ForwardedPort) error
}
Hypervisors is pairing this visor with hypervisors, and a hypervisor's control of the visors paired with it.
type LANDmsgServerInfo ¶
type LANDmsgServerInfo struct {
Enabled bool `json:"enabled"`
PK cipher.PubKey `json:"pk,omitempty"`
Address string `json:"address,omitempty"` // LAN-routable "host:port" advertised by the hypervisor.
PublicAddress string `json:"public_address,omitempty"` // Operator-set WAN-routable "host:port"; empty when not configured.
// DiscoveryURL is the hypervisor-hosted dmsg-discovery proxy URL that
// receiving visors should use as their primary discovery (with their
// existing public dmsg-discovery as fall-through behind it). Empty
// when the hypervisor's HTTP address isn't remotely reachable AND the
// operator hasn't set lan_dmsg_server.public_discovery_url. Visors
// that receive a non-empty value save it to config; the change takes
// effect on the next visor restart.
DiscoveryURL string `json:"discovery_url,omitempty"`
}
type LoadStats ¶
type LoadStats struct {
Load1 float64 `json:"load1"`
Load5 float64 `json:"load5"`
Load15 float64 `json:"load15"`
CPUCores int `json:"cpu_cores"`
MemUsedPercent float64 `json:"mem_used_percent"`
DiskUsedPercent float64 `json:"disk_used_percent"`
}
LoadStats is a lightweight, always-meaningful resource snapshot used by `cli visor hv ls --load`: load averages (which, unlike a single CPUPercent sample, need no prior baseline to be meaningful) plus instantaneous memory and root-disk usage percentages. Cheap to gather (a few /proc reads + one statfs), so it's populated on every Summary without a sampling interval.
type LocalTransportStatsResponse ¶
type LocalTransportStatsResponse struct {
// Transports is the per-transport rollup, sorted by total
// bytes (sent+recv) descending so the busiest transports
// come first.
Transports []*stats.TransportRecord `json:"transports"`
// FetchedAt is when the snapshot was assembled. Lets the
// hvui surface a "last sample" timestamp.
FetchedAt time.Time `json:"fetched_at"`
}
LocalTransportStatsResponse is the wire shape returned by LocalTransportStats. Keep this stable independent of the bbolt schema — additive fields only on changes.
type LocalUptimeArgs ¶
type LocalUptimeArgs struct {
Since time.Time `json:"since,omitempty"`
Until time.Time `json:"until,omitempty"`
}
LocalUptimeArgs is the request shape. Empty Since/Until mean "default 7-day window ending now" — caller-side defaults match the logserver's own /stats/uptime behavior so a hypervisor and a direct curl agree on the rendered timeline.
type LocalUptimeResponse ¶
type LocalUptimeResponse struct {
Tiers map[string]map[string]string `json:"tiers"`
Since time.Time `json:"since"`
Until time.Time `json:"until"`
FetchedAt time.Time `json:"fetched_at"`
}
LocalUptimeResponse is the wire shape for LocalUptimeStats.
The tier name is whatever the tracker recorded (the visor uses "process", "dmsg", "skynet"; future probes may add more — keep the renderer name-agnostic). Dates are UTC YYYY-MM-DD; bitmaps are 288 chars where '.' = online slot and ' ' = offline slot.
type Mail ¶
type Mail interface {
// MailStatus reports whether the mailbox runs, its addresses, and
// who may deliver to it.
MailStatus() (*MailStatus, error)
// MailList lists a folder ("INBOX" or "Sent"), newest first.
MailList(folder string) ([]skymail.Summary, error)
// MailRead renders one message and marks it read.
MailRead(folder, id string) (*skymail.Rendered, error)
// MailRaw returns one message exactly as stored.
MailRaw(folder, id string) ([]byte, error)
// MailAttachment decodes attachment n of a message, numbered as
// MailRead lists them.
MailAttachment(folder, id string, n int) (*skymail.AttachmentData, error)
// MailSend delivers a message now; a recipient whose visor cannot
// be reached gets an error in the result, not a queue entry.
MailSend(msg skymail.Outgoing) (*skymail.SendResult, error)
// MailDelete removes one message.
MailDelete(folder, id string) error
// MailSetWhitelist replaces the PKs allowed to deliver; empty
// accepts everyone. Persisted with the mail.
MailSetWhitelist(pks []cipher.PubKey) error
// MailSetSettings changes whether the mailbox runs and its limits,
// at once, and keeps them beside the mail (settings.json).
MailSetSettings(u MailSettingsUpdate) error
}
Mail is the visor's own mailbox (pkg/skymail): mail to its PK over skynet and dmsg, kept verbatim in a Maildir.
type MailAttachmentRequest ¶
MailAttachmentRequest names one attachment of one message.
type MailMessageRequest ¶
MailMessageRequest names one message.
type MailSettingsUpdate ¶
type MailSettingsUpdate struct {
Enable *bool `json:"enable,omitempty"`
MaxMessageSize *int64 `json:"max_message_size,omitempty"`
MaxTotalSize *int64 `json:"max_total_size,omitempty"`
MaxAge *time.Duration `json:"max_age,omitempty"`
}
MailSettingsUpdate changes the fields that are set; nil leaves one as it is. A zero limit restores its default, a negative one removes it.
func (MailSettingsUpdate) Wire ¶
func (u MailSettingsUpdate) Wire() MailSettingsWire
Wire encodes u for the RPC.
type MailSettingsWire ¶
type MailSettingsWire struct {
EnableSet, MaxMessageSizeSet, MaxTotalSizeSet, MaxAgeSet bool
Enable bool
MaxMessageSize int64
MaxTotalSize int64
MaxAge time.Duration
}
MailSettingsWire is MailSettingsUpdate as it crosses the RPC. gob flattens pointers and drops zero values, so a pointer to false or to 0 would arrive as nil: "leave it" instead of "turn it off" or "back to the default". The Set flags carry the difference.
func (MailSettingsWire) Update ¶
func (w MailSettingsWire) Update() MailSettingsUpdate
Update decodes w.
type MailStatus ¶
type MailStatus struct {
Enabled bool `json:"enabled"`
Running bool `json:"running"`
Reason string `json:"reason,omitempty"` // why it is not running
// Limits are the effective ones; Usage is the bytes held now.
Limits skymail.Limits `json:"limits"`
Usage int64 `json:"usage"`
// Address and AddressDmsg are the default addresses; any local part
// at the same domain reaches the same mailbox.
Address string `json:"address,omitempty"`
AddressDmsg string `json:"address_dmsg,omitempty"`
Dir string `json:"dir,omitempty"`
Whitelist []cipher.PubKey `json:"whitelist"`
Unread int `json:"unread"`
Total int `json:"total"`
}
MailStatus is the state of the visor's mailbox.
type ModulePresence ¶
type ModulePresence struct {
StatsTracker bool `json:"stats_tracker"`
UptimeRecorder bool `json:"uptime_recorder"`
EmbeddedTPS bool `json:"embedded_transport_setup"`
EmbeddedRouteSetup bool `json:"embedded_route_setup"`
// ExecWasm describes the js/wasm module this visor serves for the desk.
ExecWasm *ExecWasmInfo `json:"exec_wasm,omitempty"`
}
ModulePresence reports which optional subsystems are wired on this visor. A false here means the module was not configured/started (nil), which is often exactly the thing being debugged ("why is there no stats feed?").
type MuxDirectionInput ¶
MuxDirectionInput carries the app-scoped manual direction pin for SetMuxDirection: Mode is "auto" (release), "default" or "flipped".
type MuxHopInfo ¶
type MuxHopInfo struct {
TpID string `json:"tp_id"`
From string `json:"from"`
To string `json:"to"`
TpType string `json:"tp_type"`
LatencyMS float64 `json:"latency_ms,omitempty"`
}
MuxHopInfo is one hop of a mux leg's forward route. From/To are FULL public keys (never truncated). LatencyMS is the hop's transport RTT where known (first hop owned; single-intermediate far hop derived).
type MuxLegInfo ¶
type MuxLegInfo struct {
Index int `json:"index"`
TransportID string `json:"transport_id"`
TpType string `json:"tp_type"`
RemotePK string `json:"remote_pk"`
// Source names where a leg that is not this group's own dial came from —
// a leg the standby-pool arbiter took ("standby :4, re-homed in place").
Source string `json:"source,omitempty"`
// LatencyMS is the FIRST-HOP transport RTT; RouteLatencyMS is the leg's
// TRUE end-to-end route latency (all hops, from the leg-liveness pong) �
// on a multihop leg the two differ sharply. Direct is true for a 1-hop
// route straight to the destination, false for a relayed (multihop) leg.
LatencyMS float64 `json:"latency_ms,omitempty"`
RouteLatencyMS float64 `json:"route_latency_ms,omitempty"`
// AckDelayMS is the leg's own EWMA send�ack delay; InflightBytes and
// WindowBytes are its real unacknowledged bytes and the send window they
// are bounded by (see router.MuxLeg).
AckDelayMS float64 `json:"ack_delay_ms"`
InflightBytes float64 `json:"inflight_bytes"`
WindowBytes float64 `json:"window_bytes"`
Direct bool `json:"direct"`
SentBytes uint64 `json:"sent_bytes"`
SentPackets uint64 `json:"sent_packets"`
RecvBytes uint64 `json:"recv_bytes"`
RecvPackets uint64 `json:"recv_packets"`
// PayloadBytes is the UNIQUE in-order payload this leg delivered (each seq
// counted once, retransmits/duplicates excluded) � so per-leg values sum to
// the transfer size and cleanly attribute which legs carried a direction's
// data, unlike RecvBytes which includes retransmit inflation.
PayloadBytes uint64 `json:"payload_bytes"`
// DupBytes is inbound DUPLICATE data (seqs already delivered/buffered on
// arrival) � the peer's spurious-retransmit waste, which rides the fastest
// leg. RepairBytes is inbound FEC repair frames (deliberate overhead).
// With PayloadBytes they decompose RecvBytes, so a standby leg showing
// traffic is attributable from telemetry.
DupBytes uint64 `json:"dup_bytes"`
RepairBytes uint64 `json:"repair_bytes"`
// Retransmits is SACK retransmit packets carried by this leg (loss
// signal). Alive/Standby are the leg's gate_state: Alive=false once the
// transport is closed; Standby=true for a warm standby (rules kept,
// not sending). Surfaced for the per-leg telemetry harness.
Retransmits uint64 `json:"retransmits"`
// GoodputBps is this leg's recent goodput � the EWMA of (sent+recv) bytes
// per second over the telemetry refresh window (~1s for the status page).
// The RATE the leg is currently moving, as opposed to the cumulative
// SentBytes/RecvBytes totals. 0 until a second sample lands.
// GoodputUpBps/GoodputDownBps split it by direction (send-rate / recv-rate);
// GoodputBps is their sum.
GoodputBps float64 `json:"goodput_bps,omitempty"`
GoodputUpBps float64 `json:"goodput_up_bps,omitempty"`
GoodputDownBps float64 `json:"goodput_down_bps,omitempty"`
Alive bool `json:"alive"`
Standby bool `json:"standby"`
// Hops is the leg's full forward route (every hop to the destination),
// with full PKs and per-hop transport type + latency where known.
Hops []MuxHopInfo `json:"hops,omitempty"`
// CapacityPriorBps is the pool arbiter's PRIOR throughput estimate for
// this leg (router.throughputPrior) — what a standby tunnel is ranked by
// before it has carried anything to measure.
CapacityPriorBps float64 `json:"capacity_prior_bps,omitempty"`
}
MuxLegInfo is one route in a mux'd group.
type MuxRehomeInput ¶
MuxRehomeInput is the argument of the RehomeTunnelLeg RPC: the app, the ACTIVE tunnel that is to gain a leg, and the STANDBY tunnel whose chain it takes. Both ports are the dst_port `proxy mux info` prints.
type MuxRouteGroupInfo ¶
type MuxRouteGroupInfo struct {
Desc routing.RouteDescriptorFields `json:"desc"`
// FarEndPK is the peer at the other end of this route group — the exit for
// a dialing client. The setup node gives each edge the descriptor that
// points AT that edge, so Desc.DstPK is the LOCAL visor on both sides and
// consumers reading it as the destination printed this visor as its own
// exit. Filled by the router; render this, never an end of Desc.
FarEndPK cipher.PubKey `json:"far_end_pk"`
// AppName is the app that dialed this route group. Empty on the accept
// side, where this visor is the far end of someone else's dial.
AppName string `json:"app_name,omitempty"`
MuxEnabled bool `json:"mux_enabled"`
SACKEnabled bool `json:"sack_enabled"`
PerFrameNoise bool `json:"per_frame_noise"`
// Directional: unidirectional send selection (CapUniDir) is active � each
// direction rides a disjoint leg class. Flipped: the direction->leg-class
// mapping is swapped (heavy direction took the mux). With per-leg `direct`,
// this tells which class carries which direction without log-grepping.
Directional bool `json:"directional,omitempty"`
Flipped bool `json:"flipped,omitempty"`
// FlipPinned is the operator's MANUAL direction pin on a directional group:
// "auto" (flip controller in charge), "default" or "flipped" (mapping pinned,
// controller dormant until released). Empty on a non-directional mux.
FlipPinned string `json:"flip_pinned,omitempty"`
// Distribution names how the mux spreads outbound packets across its legs
// (weight mode: "auto", "round-robin", "weighted", "capacity",
// "latency-adaptive", "sticky:5tuple", "size-threshold", "dscp-priority").
// Empty for a single-leg / non-mux group.
Distribution string `json:"distribution,omitempty"`
// ReorderPending is the number of received packets buffered out-of-order
// (head-of-line-blocking depth); ReorderGapAgeMS is how long the current
// reorder frontier gap has stayed open in ms (0 when contiguous). A rising
// pending count with a growing gap age marks a stalled/black-holing leg.
ReorderPending int `json:"reorder_pending,omitempty"`
ReorderGapAgeMS float64 `json:"reorder_gap_age_ms,omitempty"`
// WriteSeq is the total DATA frames this mux has emitted outbound � a cheap
// aggregate send-progress counter across all legs.
WriteSeq uint32 `json:"write_seq,omitempty"`
// AggSentBytes / AggRecvBytes are the rg-scoped totals summed across every
// leg (what this route group moved, distinct from per-transport totals that
// also count other groups sharing the transport).
AggSentBytes uint64 `json:"agg_sent_bytes,omitempty"`
AggRecvBytes uint64 `json:"agg_recv_bytes,omitempty"`
// AggGoodputBps is the route-group's recent goodput � the sum of the
// per-leg goodput RATES (bytes/sec), i.e. what the whole group is moving
// right now, distinct from the cumulative AggSentBytes/AggRecvBytes totals.
// AggGoodputUpBps/AggGoodputDownBps split it by direction (sum of the
// per-leg send-rates / recv-rates); AggGoodputBps is their sum.
AggGoodputBps float64 `json:"agg_goodput_bps,omitempty"`
AggGoodputUpBps float64 `json:"agg_goodput_up_bps,omitempty"`
AggGoodputDownBps float64 `json:"agg_goodput_down_bps,omitempty"`
// FEC (forward error correction) telemetry. FECEnabled reports whether both
// peers negotiated CapFEC on this group. FECRepairBytesSent/Recv are cumulative
// repair-frame bytes scheduled onto / received from legs � the TRUE FEC
// overhead, separable from data (AggRecvBytes) and retransmit (per-leg
// Retransmits). FECReconstructs counts frontier frames recovered from repair
// (each a slow-leg head-of-line stall this group avoided).
FECEnabled bool `json:"fec_enabled,omitempty"`
FECRepairBytesSent uint64 `json:"fec_repair_bytes_sent,omitempty"`
FECRepairBytesRecv uint64 `json:"fec_repair_bytes_recv,omitempty"`
FECReconstructs uint64 `json:"fec_reconstructs,omitempty"`
Legs []MuxLegInfo `json:"legs"`
// Events is this route group's most recent leg/group changes with their
// reasons, oldest first � the churn next to the legs, so a reading that
// shows a leg missing also shows who took it and why. The whole-visor ring
// is diag.mux_events in `visor state`.
Events []router.MuxEvent `json:"events,omitempty"`
// Recovery is the group's loss-recovery state: the sender-side retransmit
// machinery (retx buffer occupancy and held seq range, retransmits sent /
// skipped-because-no-longer-held / failed, tail-loss probes, inbound SACK
// feedback) next to the receiver-side reorder frontier (the seq waited on,
// the packets dammed behind it, outbound SACK feedback, wedge counters). A
// reorder wedge is a two-ended failure, and before this only the RECEIVER
// logged anything � the sender had nothing to show. Nil when the group has
// no mux.
Recovery *router.MuxRecovery `json:"recovery,omitempty"`
// TunnelRole is the DIALING end's label for this route group � "active"
// (it carries streams) or "standby" (held open, kept alive and measured,
// carrying nothing, ready to take over). Absent for every route group that
// is not one of a multi-tunnel app's tunnels.
//
// Read it on the LOCAL end. An exit sees how many tunnels a client holds
// but not which of them are in standby, so this field is always empty in
// an accepting visor's `visor state`.
TunnelRole string `json:"tunnel_role,omitempty"`
// DisjointRoutes: routes to the far end sharing no intermediate and no first
// hop; what an auto-sized standby pool holds (0 = not yet counted).
DisjointRoutes int `json:"disjoint_routes,omitempty"`
// LegReserve: a standby group a leg split built — composable as a leg,
// never promotable to a tunnel (it has no app session).
LegReserve bool `json:"leg_reserve,omitempty"`
// AgeMS is how long this route group has existed � for a pooled STANDBY
// tunnel, its AUDITION age: how long it has been held open and measured
// without carrying a stream.
AgeMS float64 `json:"age_ms,omitempty"`
// Shape is the SESSION's measured multiplexing shape: every ACTIVE tunnel
// this app holds to this exit with its live leg count — "2x2" is two
// tunnels of two legs, "4x1" pure stream level, "1x4" pure packet level.
// ShapeTarget is the shape it is being held at, ShapeSource whether that
// came from the auto rule (tunnel.count x pool.active_width) or from the
// mux.shape knob. Advisory: reported, not yet converged toward. Empty on
// a standby tunnel and on every accept-side group.
Shape string `json:"shape,omitempty"`
ShapeTarget string `json:"shape_target,omitempty"`
ShapeSource string `json:"shape_source,omitempty"`
// ShapeTunnels is the k the target asks for (0 under auto); LastMove and
// MoveCounts are the session's shape-move history, keyed by the four move
// names pool_leg_taken / pool_leg_released / tunnel_promoted /
// tunnel_parked.
ShapeTunnels int `json:"shape_tunnels,omitempty"`
LastMove *router.MuxShapeMove `json:"last_move,omitempty"`
MoveCounts map[string]uint64 `json:"move_counts,omitempty"`
}
MuxRouteGroupInfo is one route-group's mux state plus per-leg counters. Returned by RouteGroupMuxInfo for 'cli proxy mux-info'.
type MuxRouteInput ¶
type MuxRouteInput struct {
AppName string
// Forward and Reverse are the caller-supplied hop lists for
// AddMuxRoute. Same shape 'cli route calc' emits. Empty for
// RemoveMuxRoute.
Forward []routing.Hop
Reverse []routing.Hop
// TransportID identifies the leg to remove; unused by AddMuxRoute.
TransportID uuid.UUID
// Target is the desired total leg count for GrowMuxRoute and MinHops
// is the hop-count floor for the legs it adds. Both unused by
// Add/RemoveMuxRoute.
Target int
MinHops int
// Legs is the RELATIVE leg count for GrowMuxFromPool � "grow this group
// by k legs" � as opposed to Target's absolute "grow it to N legs".
// Unused by every other op.
Legs int
// SrcPort disambiguates between concurrent rg's owned by the same
// app (one per concurrent SOCKS5 connection on skysocks-client,
// etc.). Zero means "auto-pick if exactly one rg is active for
// the app, error otherwise."
SrcPort uint16
}
type MuxWeightsInput ¶
MuxWeightsInput is the argument of the SetMuxWeights / ClearMuxWeights / MuxWeights RPCs. Weights are keyed by the leg's first-hop transport id as a string, so the wire form matches what `mux info` prints and what an operator types.
type NetworkViewResponse ¶
type Node ¶
type Node interface {
Overview() (*Overview, error)
Summary() (*Summary, error)
StateSnapshot() (*StateSnapshot, error)
StateSnapshotProjected(fields []string) (*StateSnapshot, error)
Health() (*HealthInfo, error)
IsStartupComplete() bool
EnableHypervisor() error
DisableHypervisor() error
EnableHypervisorPersist(persist bool) error
DisableHypervisorPersist(persist bool) error
IsHypervisorEnabled() bool
EnableHypervisorUIPersist(persist bool) error
DisableHypervisorUIPersist(persist bool) error
IsHypervisorUIServing() bool
SetHypervisorAuthPersist(enable, persist bool) error
IsHypervisorAuthEnabled() bool
Uptime() (float64, error)
UptimeHistory(args UptimeHistoryArgs) (*UptimeHistoryResponse, error)
RuntimeStats() (*RuntimeStatsInfo, error)
GoroutineDump() (string, error)
Reload() error
Suspend() error
Resume() error
IsSuspended() (bool, error)
Shutdown() error
RuntimeLogs() (string, error)
RuntimeLogsSince(since int64) (RuntimeLogsDelta, error)
HostStats() (*HostStatsInfo, error)
NetworkView() (*NetworkViewResponse, error)
Ports() (map[string]PortDetail, error)
SetRewardAddress(string) (string, error)
GetRewardAddress() (string, error)
DeleteRewardAddress() error
GetRuntimeConfig() ([]byte, error)
SetRuntimeConfig(rawJSON []byte) error
SetConfigFields(fields map[string]json.RawMessage) ([]ConfigFieldChange, error)
// Skyenv reads /etc/skywire.conf: the durable settings every config
// regen is built from. SetSkyenv edits it the way `skywire autoconfig
// --<flag>` does; it takes effect at the next regen.
Skyenv() (SkyenvState, error)
SetSkyenv(edits SkyenvEdits) (SkyenvState, error)
GetConfigPath() (string, error)
ReinitiateModule(module string) error
DeregisterService(pks []cipher.PubKey, serviceType string) error
StartUIServer(addr string) error
StopUIServer() error
UIServerStatus() (*UIServerStatus, error)
CheckAREntry(pk string) ([]string, error)
ARSelfInfo() (*ARSelfRegistration, error)
// EmbeddedServiceControl stops, starts or restarts an embedded service that
// runs under its own key.
EmbeddedServiceControl(name, action string) error
// HostBridgeConnect connects the visor to the host bridge at url and
// keeps it connected. HostBridgeDisconnect ends it.
HostBridgeConnect(url string) error
HostBridgeDisconnect() error
HostBridgeStatus() (HostBridgeStatus, error)
// HostBridgeForward listens on host, an address on the bridge's host,
// and passes each connection to local. HostBridgeUnforward stops it.
HostBridgeForward(host, local string) (HostBridgeForward, error)
HostBridgeUnforward(host string) error
// Close closes the API connection (for RPC clients)
Close() error
}
Node is the visor itself: status, lifecycle, configuration, rewards and the UI server.
type NodeHealth ¶
type NodeHealth struct {
PK cipher.PubKey `json:"pk"`
Healthy bool `json:"healthy"`
LastChecked time.Time `json:"last_checked"`
LastError string `json:"last_error,omitempty"`
Latency time.Duration `json:"latency_ms"`
}
NodeHealth represents the health status of a setup node.
type Overview ¶
type Overview struct {
PubKey cipher.PubKey `json:"local_pk"`
BuildInfo *buildinfo.Info `json:"build_info"`
AppProtoVersion string `json:"app_protocol_version"`
Apps []*appserver.AppState `json:"apps"`
Transports []*TransportSummary `json:"transports"`
RoutesCount int `json:"routes_count"`
LocalIP string `json:"local_ip"`
PublicIP string `json:"public_ip"`
IsSymmetricNAT bool `json:"is_symmetic_nat"`
// NATType is the visor's STUN-classified NAT type (e.g. "Full cone NAT",
// "Symmetric NAT"), determined once at startup. Surfaced so `cli visor ip`
// reports the visor's already-known result instead of re-running STUN.
NATType string `json:"nat_type,omitempty"`
CountryCode string `json:"country_code,omitempty"`
RegionName string `json:"region_name,omitempty"`
CityName string `json:"city_name,omitempty"`
Latitude float64 `json:"latitude,omitempty"`
Longitude float64 `json:"longitude,omitempty"`
Hypervisors []cipher.PubKey `json:"hypervisors"`
ConnectedHypervisor []cipher.PubKey `json:"connected_hypervisor"`
// Hostname is the operating-system hostname the visor process
// sees at the time of the Overview call. Best-effort:
// os.Hostname() failures (sandbox / containerized environments
// missing the syscall) yield an empty string rather than
// erroring out the whole Overview. Surfaced to operators in the
// hypervisor UI as the default label fallback when no explicit
// label is set, and shown in `cli visor info`.
Hostname string `json:"hostname,omitempty"`
}
Overview provides a range of basic information about a Visor.
type PairAddRequest ¶
PairAddRequest is the input to RPC.PairAdd.
type PairDeleteRequest ¶
type PairDeleteRequest struct {
PeerPK cipher.PubKey `json:"peer_pk"`
// ID is the message id returned by PairSend.
ID string `json:"id"`
}
PairDeleteRequest is the input to RPC.PairDelete.
type PairInfo ¶
type PairInfo struct {
PeerPK cipher.PubKey `json:"peer_pk"`
Status pairing.Status `json:"status"`
Port uint16 `json:"port"`
EstablishedAt time.Time `json:"established_at"`
LastMessageAt time.Time `json:"last_message_at,omitempty"`
// Epoch is the short-lived key this conversation currently seals
// under, as hex. Empty means the pair has not derived one yet and is
// still on the legacy static key — which is worth showing, because
// the two have materially different guarantees and nothing else in
// the UI would distinguish them.
Epoch string `json:"epoch,omitempty"`
// ForwardSecret is true once an epoch exists, i.e. once messages
// stop being openable with the two visors' identity keys alone.
ForwardSecret bool `json:"forward_secret"`
// KeyGeneration is how many ratchet keys this side has minted for
// the pair. Each one retires the previous secret, so it doubles as
// "how many times has the window closed behind us".
KeyGeneration uint64 `json:"key_generation,omitempty"`
}
PairInfo is the public summary of a chat pair, returned by PairList and used as the poll cursor for PairPoll.
type PairMessage ¶
type PairMessage struct {
PeerPK cipher.PubKey `json:"peer_pk"`
Text string `json:"text"`
TS time.Time `json:"ts"`
// ID names this message on both sides of the pair. On a chat message
// it is the message's own id (derived from the sender's timestamp);
// on a delete record it is the id of the message being retracted.
// Clients need it to correlate a delete with the bubble it removes.
ID string `json:"id,omitempty"`
// Type is empty for a chat message and pairing.MessageTypeDelete for
// a retraction. A client that only knows about chat messages should
// skip any record with a non-empty Type rather than render it.
Type string `json:"type,omitempty"`
}
PairMessage is one inbound message delivered through the visor's pair inbox. Outbound messages (sent via PairSend) are not echoed here; the caller already knows what it sent.
type PairPollRequest ¶
type PairPollRequest struct {
// Since is the lower bound (exclusive). Pass time.Time{} (zero)
// to retrieve the entire current inbox window.
Since time.Time `json:"since"`
}
PairPollRequest is the input to RPC.PairPoll.
type PairSendRequest ¶
PairSendRequest is the input to RPC.PairSend.
type PendingHypervisor ¶
type PendingHypervisor struct {
PK cipher.PubKey `json:"pk"`
Fingerprint string `json:"fingerprint"`
FirstSeen time.Time `json:"first_seen"`
LastSeen time.Time `json:"last_seen"`
// Via is how the peer was noticed: "transport" (it holds a same-origin
// transport to us) or "rpc" (it tried the transport RPC and was refused).
Via string `json:"via"`
}
PendingHypervisor is a peer that asked to drive this visor but is not yet in its hypervisor list.
type PingConfig ¶
type PingConfig struct {
PK cipher.PubKey
Tries int
PcktSize int
PubVisCount int
LocalRoute bool // Skip route finder and use local route calculation
TransportID string // Optional: use specific transport (skips route calculation)
ForwardHops []RouteHopInfo // Optional: explicit forward route (skips route calculation)
ReverseHops []RouteHopInfo // Optional: explicit reverse route (skips route calculation)
// RouteIndex identifies which of multiple parallel routes to the
// same peer this PingConfig refers to. Zero (the default) means
// "primary / single route" and preserves all legacy single-route
// behavior. Non-zero values are used by mux-aware callers
// (`cli visor ping mux-bw`) to dial multiple routes to the same
// target without their conns trampling each other in the visor's
// per-route conn map. See PingRouteRef in pkg/visor/ping.go.
RouteIndex int
// MinHops, when > 0, forces the route-finder to skip paths with
// fewer than this many hops on THIS dial — overrides the visor-
// global routing.min_hops config for the duration of the call.
// Plumbed straight into router.DialOptions.MinHops. Used by
// `cli visor ping mux-bw --min-hops N` to verify the operator's
// "mux via intermediates > direct" hypothesis: without it, the
// router's direct-transport fast path would short-circuit every
// dial to use the direct stcpr whenever one existed. 0 = inherit
// visor-global setting.
MinHops int
// SetupTimeout, when > 0, overrides DialPing's hardcoded 30s
// dial timeout. Multi-hop route setup through 4+ intermediates
// can take 30-120s (route-finder + setup-node round trips +
// saveRouteGroupRules retries), exceeding the legacy 30s
// ceiling. mux-bw passes its cfg.SetupTimeout here. 0 falls
// back to the existing 30s default.
SetupTimeout time.Duration
// Timeout bounds a single PingOnce round-trip (ack + echo reads).
// 0 = 10s default. mux-bw's probe loop sets this to the remaining
// pump/idle window so a stuck probe can't outlive the measurement
// and hang the run.
Timeout time.Duration
}
PingConfig use as configuration for ping command
type PoolTunnelInfo ¶
type PoolTunnelInfo struct {
// LocalPort is the standby route group's local port (Desc.SrcPort on
// this end) — the same port the pool arbiter and `mux_route_groups`
// already key on.
LocalPort routing.Port `json:"local_port"`
// FirstHopPK/TpType are the leading leg's remote pk and transport type.
FirstHopPK string `json:"first_hop_pk,omitempty"`
TpType string `json:"tp_type,omitempty"`
// Hops is the leading leg's forward hop count (1 for a direct route).
Hops int `json:"hops"`
// CapacityPriorBps is the leading leg's PRIOR throughput estimate — the
// value the pool ranks candidates by before it has measured one.
CapacityPriorBps float64 `json:"capacity_prior_bps,omitempty"`
// AuditionAgeMS is how long this standby tunnel has been held open,
// pinged and measured without carrying a stream (MuxRouteGroupInfo.AgeMS).
AuditionAgeMS float64 `json:"audition_age_ms,omitempty"`
// LegSource names where the leading leg came from when it is not this
// group's own dial (e.g. "standby :4, re-homed in place").
LegSource string `json:"leg_source,omitempty"`
// Legs is this standby tunnel's total leg count.
Legs int `json:"legs"`
}
PoolTunnelInfo is one row of the standby-tunnel pool table (`visor state --select pool`). Every field is projected from the leading leg of a MuxRouteGroupInfo entry whose TunnelRole is "standby" — see poolTableFrom.
type PortDetail ¶
PortDetail type of port details
type ProcessStatsInfo ¶
type ProcessStatsInfo struct {
PID int32 `json:"pid"`
CPUPercent float64 `json:"cpu_percent"`
MemRSS uint64 `json:"mem_rss"`
MemVMS uint64 `json:"mem_vms,omitempty"`
NumThreads int32 `json:"num_threads,omitempty"`
NumFDs int32 `json:"num_fds,omitempty"`
StartTimeMS int64 `json:"start_time_ms,omitempty"`
OpenConns int `json:"open_conns,omitempty"`
}
ProcessStatsInfo is the visor process's slice of HostStats — what process.NewProcess(os.Getpid()) returns from gopsutil.
type Profile ¶
type Profile struct {
// PK is whose profile this is. Filled in by the visor from the key it
// was asked about (or its own), never from the answer's body — a host
// that could name the key in its own response could name someone
// else's.
PK cipher.PubKey `json:"pk"`
Name string `json:"name,omitempty"`
// Avatar is the encoded image, bounded by profile.MaxAvatarDim and
// profile.MaxAvatarBytes on the way in. Carried as a
// data URI rather than raw bytes because the only consumer is a
// browser <img>, and building it here keeps the declared MIME type
// the one the visor actually decoded.
Avatar string `json:"avatar,omitempty"`
Updated time.Time `json:"updated,omitzero"`
// Address is the canonical skychat:// form of this key, so a caller
// holding a profile can render, copy or QR-encode the address without
// knowing the grammar.
Address string `json:"address,omitempty"`
}
Profile is the RPC-facing shape of a skychat profile.
Re-declared rather than aliased for the same reason GroupDescriptor is: the RPC surface carries display-oriented additions the protocol type has no business knowing about — here, the public key it belongs to and a ready-to-render data URI, both of which are derived by the receiver.
type ProfileSetArgs ¶
type ProfileSetArgs struct {
Name string `json:"name"`
// Avatar is the new image as a data URI (what a browser's canvas
// produces) or raw base64. Empty clears the avatar; see Clear for
// removing the profile entirely.
//
// A string rather than []byte so the one caller that matters can pass
// exactly what `canvas.toDataURL()` gave it, with no re-encoding step
// to get wrong on the way.
Avatar string `json:"avatar,omitempty"`
// Clear removes the published profile entirely rather than saving an
// empty one. Distinct from sending blank fields because "I have no
// profile" and "my name is empty" want the same disk state and the
// caller should not have to know that.
Clear bool `json:"clear,omitempty"`
}
ProfileSetArgs is the RPC input for ProfileSet.
type Proxies ¶
type Proxies interface {
// EmbeddedProxies reports the runtime state of the in-process
// .dmsg / .skynet resolving proxies. Hypervisor UI consumes this
// to render the "browser proxy" widget — listener addresses,
// domain suffix, running state.
EmbeddedProxies() (*EmbeddedProxiesStatus, error)
// SetEmbeddedProxyEnabled flips a resolver on or off at runtime.
// `kind` is "dmsg" or "skynet"; `enable` true starts the
// resolver, false stops it. Idempotent. Only affects the live
// runtime — the on-disk config is unchanged, so a visor restart
// reverts to the config's Enable flag.
SetEmbeddedProxyEnabled(kind string, enable bool) error
SetEmbeddedProxyUpstream(kind, addr string) error
SetEmbeddedProxyBind(kind, addr string) error
}
Proxies is the visor's embedded proxies.
type ProxyTestConfig ¶
type ProxyTestConfig struct {
Servers []cipher.PubKey `json:"servers"` // Proxy servers to test
TestURL string `json:"test_url"` // URL to fetch through proxy (default from deployment.Prod.GeoIP)
Timeout time.Duration `json:"timeout"` // Timeout per test (default: 30s)
}
ProxyTestConfig configures proxy testing
type ProxyTestResult ¶
type ProxyTestResult struct {
PK string `json:"pk"` // Proxy server public key
Status string `json:"status"` // "OK", "FAIL", "TIMEOUT"
Duration int64 `json:"duration"` // Duration in milliseconds
IP string `json:"ip"` // IP returned by test
Location string `json:"location"` // Geo location (City, Country)
Error string `json:"error"` // Error message if failed
}
ProxyTestResult contains the result of a single proxy test
type RecentAppLogRequest ¶
type RecentAppLogRequest struct {
// AppName should match the app name in visor config.
AppName string `json:"app_name"`
// Level is the minimum severity ("trace"|"debug"|"info"|"warn"|"error").
// Empty defaults to "debug".
Level string `json:"level"`
}
RecentAppLogRequest asks for the recent app-scoped route/transport events + log lines captured in the log broadcaster's per-app ring.
type RegisterCXOFeedRequest ¶
type RegisterCXOFeedRequest struct {
Name string `json:"name"`
DmsgPort uint16 `json:"dmsg_port"`
Description string `json:"description,omitempty"`
}
RegisterCXOFeedRequest is the input to RPC.RegisterCXOFeed.
type RolesSnapshot ¶
type RolesSnapshot struct {
// PK is the visor's own public key — the key the own-key dmsg server and
// the relay acceptor both answer under.
PK cipher.PubKey `json:"pk"`
// NoTransit reports routing.no_transit: this visor refuses to be an
// INTERMEDIATE hop on someone else's route (its own edges still work).
NoTransit bool `json:"no_transit"`
DmsgServer DmsgServerRole `json:"dmsg_server"`
DmsgRelay DmsgRelayRole `json:"dmsg_relay"`
}
RolesSnapshot is the `roles` section of a StateSnapshot.
type RouteGroupInfo ¶
type RouteGroupInfo struct {
ConsumeRuleID routing.RouteID `json:"consume_rule_id"`
FwdRuleID routing.RouteID `json:"fwd_rule_id"`
Desc routing.RouteDescriptorFields `json:"desc"`
FwdNextTpID string `json:"fwd_next_tp_id,omitempty"`
// Initiator is true when this visor dialed the remote end of the
// route, false when the route was accepted from a remote setup-node
// request. Distinguishes outbound proxy/VPN client connections from
// inbound listener connections.
Initiator bool `json:"initiator"`
// Hops is the stored forward route path (transport IDs, edges, types)
// for this route group, populated when the route group is active.
Hops []RouteHopInfo `json:"hops,omitempty"`
}
type RouteHopInfo ¶
RouteHopInfo contains detailed information about a single hop in a route.
type RouterDialSettings ¶
type RouterDialSettings struct {
UnknownLatencyCostMs float64 `json:"unknown_latency_cost_ms"`
UnknownHopPenaltyMs float64 `json:"unknown_hop_penalty_ms"`
TypePriorScale float64 `json:"type_prior_scale"`
ThroughputPriorScale float64 `json:"throughput_prior_scale"`
RouteCandidates int `json:"route_candidates"`
MuxRouteHeadroom int `json:"mux_route_headroom"`
ForegroundMux int `json:"foreground_mux"`
TunnelLegs int `json:"tunnel_legs"`
DeadRouteYoungAgeMs int64 `json:"dead_route_young_age_ms"`
WarmPlanTTLMs int64 `json:"warm_plan_ttl_ms"`
WarmPlanBucketCap int `json:"warm_plan_bucket_cap"`
PreferPKs []string `json:"prefer_pks,omitempty"`
ClearPreferPKs bool `json:"clear_prefer_pks,omitempty"`
// TypePriorScaleSet / ThroughputPriorScaleSet mark the two multipliers as
// given, since 0 is meaningful for them (it drops the term from the score)
// and so cannot double as "unset".
TypePriorScaleSet bool `json:"type_prior_scale_set,omitempty"`
ThroughputPriorScaleSet bool `json:"throughput_prior_scale_set,omitempty"`
// TunnelLegsSet distinguishes "set tunnel legs to 0" (turn the dial-time
// widening off) from "leave it alone", since 0 is both the default and a
// meaningful instruction.
TunnelLegsSet bool `json:"tunnel_legs_set,omitempty"`
}
RouterDialSettings bundles the visor-wide DIAL-TIME router knobs — the route-ranking priors, the candidate counts, the warm-plan cache shape, the dead-route young-death window, the dial-time tunnel width and the operator's prefer-these-peers list.
It is a separate struct from RouterSettings (which carries the live-group knobs) so the two commands stay independently readable and a caller parsing `route settings dial --json` gets one document, not a merged one.
On a SET, a zero field means "leave unchanged" — the same tri-state RouterSettings uses — except PreferPKs, where an explicitly empty (non-nil, length-0) slice clears the list. ClearPreferPKs makes that unambiguous over the wire, where nil and empty do not survive the round trip distinctly.
type RouterKnob ¶
type RouterKnob struct {
Name string `json:"name"`
Kind string `json:"kind"`
// Value is the live value, formatted the way `route settings` takes it back.
Value string `json:"value"`
// Default is what the binary compiled with.
Default string `json:"default"`
// Set reports an explicit set, as opposed to a value that merely equals the
// default.
Set bool `json:"set"`
// Persisted is what the visor config holds for this knob, empty when nothing
// is written. A Persisted that differs from Value is a change that will be
// lost — or gained — at the next restart.
Persisted string `json:"persisted,omitempty"`
Doc string `json:"doc,omitempty"`
}
RouterKnob is one row of RouterSettings.KnobState.
type RouterSettings ¶
type RouterSettings struct {
ForceLocalRoutes bool `json:"force_local_routes"`
ExistingTPOnly bool `json:"existing_tp_only"`
MinHops uint16 `json:"min_hops"`
// TransportPreference is the transport-type priority order: which type
// is tried first when a transport has to be created, and which existing
// one a route rides when several reach the same peer. GET always answers
// the full order in effect. On PUT:
// omitted / null — leave the order unchanged;
// [] — revert to the built-in default;
// non-empty — that order, most-preferred first (unlisted types
// sort after it).
// Written to routing.transport_preference, so it survives a restart —
// but not a config regen (no skywire.conf field).
TransportPreference []string `json:"transport_preference,omitempty"`
// The mux send-window shape and the adaptive park hold, live from
// pkg/router/settings.go. Each zero value means "leave unchanged" on PUT,
// so an older client that does not know a field cannot reset it. GET always
// answers the values in force.
//
// windowRefreshInterval is deliberately absent: it becomes a per-route-group
// ticker when the group is built, so moving it live is a locking change
// rather than a knob.
EcfMaxWindowBytes int64 `json:"ecf_max_window_bytes,omitempty"`
EcfMinWindowBytes int64 `json:"ecf_min_window_bytes,omitempty"`
EcfWindowMargin float64 `json:"ecf_window_margin,omitempty"`
SendWindowWaitMax time.Duration `json:"send_window_wait_max,omitempty"`
LegParkMinHold time.Duration `json:"leg_park_min_hold,omitempty"`
// The dead-route exclusion window and its ceiling, live from
// pkg/router/settings.go with the same zero-means-unchanged rule.
DeadRouteHold time.Duration `json:"dead_route_hold,omitempty"`
DeadRouteHoldMax time.Duration `json:"dead_route_hold_max,omitempty"`
// Shared-bottleneck detection: how many per-leg delay samples a verdict
// needs, and the minimum spacing between two per-SACK samples for one leg.
// Same zero-means-unchanged rule.
SBDMinSamples int `json:"sbd_min_samples,omitempty"`
SBDSampleInterval time.Duration `json:"sbd_sample_interval,omitempty"`
// The terms of the park TRIAL that qualifies a shared-bottleneck ruling: how
// long the park is held before the aggregate goodput is re-read, the fraction
// of goodput it may cost before it is undone, and the first exemption window
// the vindicated pair earns. Same zero-means-unchanged rule.
SBDTrialWindow time.Duration `json:"sbd_trial_window,omitempty"`
SBDTrialLoss float64 `json:"sbd_trial_loss,omitempty"`
SBDBackoff time.Duration `json:"sbd_backoff,omitempty"`
// SBDMinEvidenceRate is the aggregate delivered-bytes rate (B/s) a group must
// be carrying before a shared-bottleneck ruling may park one of its legs: no
// traffic, no ruling. Same zero-means-unchanged rule.
SBDMinEvidenceRate int64 `json:"sbd_min_evidence_rate,omitempty"`
// ForwardSpill lets a FORWARD frame leave the confined leg when that leg is at
// its send window (the pre-fix behavior). Off by default: the writer waits for
// the window instead, because every live row that spilled an upload across two
// skewed legs collapsed. Tri-state on PUT like SBDDemote — nil leaves it alone.
ForwardSpill *bool `json:"forward_spill,omitempty"`
// ForwardSwitchMargin is how much LOWER a challenger leg must measure before the
// forward direction moves off the leg it holds (0.2 = 20 %), for two consecutive
// samples. Same zero-means-unchanged rule.
ForwardSwitchMargin float64 `json:"forward_switch_margin,omitempty"`
// LegStarveRatio is how many times the best ready leg's delay basis a leg's
// own must exceed before the scheduler cuts it to a probe per window, and
// LegProbeBytes is that probe. Same zero-means-unchanged rule; a very large
// ratio disables the gate.
LegStarveRatio float64 `json:"leg_starve_ratio,omitempty"`
LegProbeBytes int64 `json:"leg_probe_bytes,omitempty"`
// SBDDemote gates the DEMOTION half of shared-bottleneck detection: false (the
// default) records every ruling as an sbd_ruling mux event and parks nothing.
// Like MuxFEC it is a tri-state on PUT — nil leaves it alone — because a bool
// has no "zero means unchanged" spelling.
SBDDemote *bool `json:"sbd_demote,omitempty"`
// MuxFEC advertises FEC on mux route groups created from now on; unlike
// the rest it is a tri-state on PUT, see SetRouterSettings.
MuxFEC *bool `json:"mux_fec,omitempty"`
// Knobs is the whole catalog as one map of catalog-name to formatted value.
// On PUT it is applied as a PARTIAL set — a knob the map does not name is
// left alone — which is what lets a sweep move one value without restating
// the other eighty. On GET it carries every knob's live value, so a bench
// runner can save it and restore it verbatim.
Knobs map[string]string `json:"knobs,omitempty"`
// KnobApp scopes a PUT's Knobs to the route groups owned by one app rather
// than the whole visor. Empty is the visor-wide set.
KnobApp string `json:"knob_app,omitempty"`
// KnobReset restores every knob to its compiled default and drops every
// per-app override, before Knobs (if any) is applied. With KnobApp set it
// drops only that app's overrides.
KnobReset bool `json:"knob_reset,omitempty"`
// KnobState is the GET-side detail: every knob with its live value, its
// compiled default, whether it was explicitly set, and what is written in
// the config — the persisted-vs-live comparison an operator needs before a
// restart.
KnobState []RouterKnob `json:"knob_state,omitempty"`
// AppKnobs is every app's override map on GET, app name to knob map.
AppKnobs map[string]map[string]string `json:"app_knobs,omitempty"`
}
RouterSettings bundles the visor-wide router knobs the universal "Router Settings" UI panel surfaces. Mirrors the per-flag CLI surface ('cli proxy start --local-route' etc.) so the UI can achieve parity in one round-trip rather than four separate calls.
type Routing ¶
type Routing interface {
SetExistingTPOnly(enabled bool) error
SetForceLocalRoutes(enabled bool) error
GetRouterSettings() (RouterSettings, error)
SetRouterSettings(s RouterSettings) error
SetMuxMode(mode string) error
SetMuxCap(n int) error
SetMuxWidth(n int) error
SetMuxStandby(n int) error
RoutingRules() ([]routing.Rule, error)
RoutingRule(key routing.RouteID) (routing.Rule, error)
SaveRoutingRule(rule routing.Rule) error
RemoveRoutingRule(key routing.RouteID) error
RouteGroups() ([]RouteGroupInfo, error)
RoutingStats() (routing.RoutingTableStats, error)
// RoutingPolicies returns a snapshot of the currently-installed
// routing-policy state: the visor-wide default plus any per-app
// overrides. Empty struct when no policies are configured.
// Hypervisor UI consumes this to display the policy panel in
// the routing tab.
RoutingPolicies() (*RoutingPoliciesSummary, error)
// RouteGroupMuxInfo returns per-mux-leg byte/packet/latency
// counters for every active route group tagged with the named
// app (skysocks-client, vpn-client, etc.). Empty slice when
// nothing is currently dialed via that app.
RouteGroupMuxInfo(appName string) ([]MuxRouteGroupInfo, error)
ActiveRoutes() ([]AppRouteStatus, error)
AddMuxRoute(appName string, fwd, rev []routing.Hop, srcPort uint16) error
GrowMuxRoute(appName string, target, minHops int, srcPort uint16) (int, error)
// GrowMuxFromPool grows the app's tunnel by `legs` additional mux legs,
// built on the plans of the app's STANDBY tunnels to the same exit
// (already ranked, first-hop transport already up) and falling back to
// GrowMuxRoute's route-finder path for whatever the pool cannot cover.
GrowMuxFromPool(appName string, legs, minHops int, srcPort uint16) (int, error)
RemoveMuxRoute(appName string, tpID uuid.UUID, srcPort uint16) error
// SetMuxDirection pins (mode "default"/"flipped") or releases (mode
// "auto") the unidirectional direction→leg-class mapping on ALL of the
// app's active directional route groups. The pin is coordinated with the
// peer over the wire; RouteGroupMuxInfo reports the live state.
SetMuxDirection(appName, mode string) error
// AddMuxRouteForward is AddMuxRoute with the reverse direction dropped:
// the leg adds UPSTREAM send capacity only (`proxy mux add --forward-only`).
AddMuxRouteForward(appName string, fwd, rev []routing.Hop, srcPort uint16) error
// SetMuxWeights / ClearMuxWeights / MuxWeights are the operator's per-leg
// send-weight override on one route group — the reachable form of the
// router's WeightModeExplicit. Clearing returns the group to ECF.
SetMuxWeights(appName string, weights map[string]float64, srcPort uint16) (router.MuxWeightsView, error)
ClearMuxWeights(appName string, srcPort uint16) (router.MuxWeightsView, error)
MuxWeights(appName string, srcPort uint16) (router.MuxWeightsView, error)
// RouteGroupMuxNegotiated reports, per route group, the capabilities the
// two ends negotiated and the send-window shape this end is applying.
RouteGroupMuxNegotiated(appName string) ([]router.MuxNegotiated, error)
// RehomeTunnelLeg moves a STANDBY tunnel's whole built chain into an ACTIVE
// tunnel as one more mux leg, in place, with no setup-node dial
// (`proxy mux adopt`). Both ports are the dst_port `proxy mux info` prints.
RehomeTunnelLeg(appName string, targetPort, standbyPort uint16) error
// GetRouterDialSettings / SetRouterDialSettings are the DIAL-TIME router
// knobs: ranking priors, candidate counts, warm-plan cache shape, the
// dead-route young-death window and the prefer-these-peers list.
GetRouterDialSettings() (RouterDialSettings, error)
SetRouterDialSettings(RouterDialSettings) error
ServiceHealth() ([]ServiceHealthEntry, error)
FetchServiceData(service, path string) ([]byte, error)
SetMinHops(uint16) error
GetMinHops() (uint16, error)
SetCalculateRoutes(enabled bool) error
GetCalculateRoutes() (bool, error)
GetRouteSetupNodesSorted() ([]cipher.PubKey, error)
GetRSNHealth() ([]NodeHealth, error)
// Embedded Route Setup Node (RSN) stats
RouteSetupStats() (*setupmetrics.StatsSnapshot, error)
ResetRouteSetupStats() error
}
Routing is routes, route groups, their multiplexing and the router's settings.
type RoutingPoliciesSummary ¶
type RoutingPoliciesSummary struct {
Default *RoutingPolicyInfo `json:"default,omitempty"`
PerApp map[string]*RoutingPolicyInfo `json:"per_app"`
}
RoutingPoliciesSummary is the JSON shape returned by /visors/{pk}/routing-policies. Default may be nil when no visor-wide policy is configured; PerApp is empty (not nil) so the JSON encodes as {} rather than null for missing data.
type RoutingPolicyInfo ¶
type RoutingPolicyInfo struct {
// Source is the path or inline marker the engine was
// constructed from — file path, "<inline>", or "<noop>".
Source string `json:"source"`
// Active reports whether an evaluator is currently loaded
// (false on a noop / failed-to-load engine).
Active bool `json:"active"`
// Backend is "skylark" or "wasm", derived from the source
// file extension. Inline policies are always skylark.
// Empty string when Source is "<noop>" / "<inline>" — UI
// can fall back to Source for display.
Backend string `json:"backend,omitempty"`
}
RoutingPolicyInfo describes one installed engine for the UI.
type RoutingRuleResp ¶
type RoutingRuleResp struct {
Key routing.RouteID `json:"key"`
Rule string `json:"rule"`
Summary *routing.RuleSummary `json:"rule_summary,omitempty"`
}
RoutingRuleResp is one routing rule as the summary and the hypervisor API report it: its route ID and a hex or summarized form of the rule.
type RuntimeLogsDelta ¶
type RuntimeLogsDelta struct {
// Entries is the JSON-encoded log lines (each is one full JSON
// object, same shape returned by RuntimeLogs's array elements).
Entries []string `json:"entries"`
// Latest is the highest log_line currently buffered. Pass it as
// `since` on the next call to receive only newly-arrived entries.
Latest int64 `json:"latest"`
// Dropped tells the caller how many entries they missed since
// their last cursor (because the buffer wrapped past them).
// Zero when the caller is keeping up with the poll cadence.
Dropped int64 `json:"dropped"`
}
RuntimeLogsDelta is the diff-streaming response shape: only the entries newer than the caller's cursor, plus the new cursor and a count of entries the caller missed because they aged out of the ring buffer between calls (0 when keeping up).
type RuntimeStatsInfo ¶
type RuntimeStatsInfo struct {
NumGoroutine int `json:"num_goroutine"`
NumCPU int `json:"num_cpu"`
GOMAXPROCS int `json:"gomaxprocs"`
GoVersion string `json:"go_version"`
// Memory stats in bytes
MemAlloc uint64 `json:"mem_alloc"`
MemTotalAlloc uint64 `json:"mem_total_alloc"`
MemSys uint64 `json:"mem_sys"`
MemHeapAlloc uint64 `json:"mem_heap_alloc"`
MemHeapSys uint64 `json:"mem_heap_sys"`
NumGC uint32 `json:"num_gc"`
}
RuntimeStatsInfo carries Go runtime statistics for the visor process.
type ServiceHealthEntry ¶
type ServiceHealthEntry struct {
Name string `json:"name"`
URL string `json:"url"`
Status string `json:"status"`
Version string `json:"version,omitempty"`
Error string `json:"error,omitempty"`
LatencyMs int64 `json:"latency_ms"`
Transport string `json:"transport,omitempty"` // "dmsg" or "http"
// IP is the public ip:port of a DMSG server, sourced from the
// dmsg-discovery all_servers endpoint (queried over dmsg). Only DMSG
// servers carry an address; other services leave it empty and the UI
// renders a hyphen.
IP string `json:"ip,omitempty"`
}
ServiceHealthEntry represents the health status of a deployment service.
type SetAppAddIn ¶
type SetAppArgsIn ¶
SetAppArgsIn replaces the entire Args slice on an app.
type SetAppBoolIn ¶
type SetAppEnvBatchIn ¶
SetAppEnvBatchIn carries a multi-key environment mutation. Map values are strings (env vars are KEY=string by definition); empty values delete.
type SetAppEnvFullIn ¶
SetAppEnvFullIn replaces the entire Env slice on an app.
type SetAppEnvIn ¶
SetAppEnvIn carries a single KEY=value mutation for an app's environment. Empty Value deletes the entry.
type SetAppErrorIn ¶
type SetAppLauncherModeIn ¶
SetAppLauncherModeIn persists the launcher-mode preference. Mode is "" / "internal" / "external".
type SetAppMapIn ¶
type SetAppPKIn ¶
type SetAppRoutingPolicyIn ¶
SetAppRoutingPolicyIn carries (app name, policy-path) for the runtime per-app routing-policy swap RPC. Path forms match the config field: "@/path.star", "@/path.wasm", inline-Starlark, or "" / "none" to clear.
type SetAppSettingsIn ¶
type SetAppSettingsIn struct {
AppName string
Values map[string]int64
// Text carries the LIST knobs, whose payload is a token set rather than an
// int64. Empty Values AND empty Text is the full reset.
Text map[string]string
}
SetAppSettingsIn replaces the whole live tuning knob set for an app. An empty Values is a full reset to the compiled defaults.
type SetAppStatusIn ¶
type SetAppStringIn ¶
type SetAppWhitelistIn ¶
SetAppWhitelistIn carries a comma-separated list of public keys allowed to connect to skysocks / vpn-server. Empty = open to all authenticated peers. Replaces the prior SetAppPasswordIn � those apps no longer accept a passcode flag.
type SetAutoStartIn ¶
type SetHypervisorAuthIn ¶
SetHypervisorAuthIn is the argument of SetHypervisorAuth.
type SetSTCPAddrIn ¶
type SkychatHTTPIn ¶ added in v1.3.100
type SkychatHTTPIn struct {
Method string
Path string
Query string
Headers map[string][]string
Body []byte
}
SkychatHTTPIn is one request to the local skychat app. Path is the part after the app's root, such as "history".
type SkychatHTTPOut ¶ added in v1.3.100
SkychatHTTPOut is skychat's buffered response.
type SkychatPasswordChangeIn ¶
SkychatPasswordChangeIn carries the old + new password for the hypervisor's "Skychat password" set/change flow. Mirrors the shape of usermanager.ChangePassword.
type SkyenvEdits ¶
type SkyenvEdits struct {
// Set maps a flag name (e.g. "ishv", "hvpks") to its value as the flag
// would take it: "true"/"false", a number, or a comma-separated list.
Set map[string]string `json:"set,omitempty"`
// Unset lists flag names whose variable returns to its default.
Unset []string `json:"unset,omitempty"`
}
SkyenvEdits is one SetSkyenv request, addressed by autoconfig flag name.
type SkyenvState ¶
type SkyenvState struct {
// Path is the file the visor resolved (SKYENV, else the OS default).
Path string `json:"path"`
// Exists is false before the first `skywire autoconfig` run creates it.
Exists bool `json:"exists"`
// Writable is whether this visor can edit the file. A visor running as
// an ordinary user cannot edit a root-owned /etc/skywire.conf; a form
// should then show the `sudo skywire autoconfig --<flag>` to run instead.
Writable bool `json:"writable"`
// Values holds the ACTIVE assignments only; a commented line means the
// variable is at its default and is absent here.
Values map[string]string `json:"values"`
// Flags describes every autoconfig flag and the variable it writes.
Flags []autoconfigcmd.Flag `json:"flags"`
}
SkyenvState is the visor's /etc/skywire.conf as a settings form needs it.
type SkynetHTTPRequest ¶
type SkynetHTTPRequest struct {
PK cipher.PubKey `json:"pk"`
Port uint16 `json:"port"`
Path string `json:"path"`
Method string `json:"method"`
Header map[string]string `json:"header,omitempty"`
Body []byte `json:"body,omitempty"`
}
SkynetHTTPRequest represents an HTTP request to make over skynet.
type SkynetHTTPResponse ¶
type SkynetHTTPResponse struct {
StatusCode int `json:"status_code"`
Status string `json:"status"`
Header map[string]string `json:"header,omitempty"`
Body []byte `json:"body,omitempty"`
}
SkynetHTTPResponse represents an HTTP response received over skynet.
type StartAppIn ¶
type StartVPNClientIn ¶
type StateFieldSet ¶
StateFieldSet is the parsed --select set. A nil set means "everything in the default full snapshot" (proxy stays opt-in even then). An entry present but unknown is ignored here and surfaced as a Note by the builder.
func NewStateFieldSet ¶
func NewStateFieldSet(fields []string) StateFieldSet
NewStateFieldSet parses the requested field keys. An empty/nil fields slice returns a nil set, i.e. build the full default snapshot.
func (StateFieldSet) Has ¶
func (s StateFieldSet) Has(k string) bool
Has reports whether section k should be built. A nil set (no --select) builds every default section; proxy is never a default section (see wantProxy).
type StateSnapshot ¶
type StateSnapshot struct {
At time.Time `json:"at"`
Suspended bool `json:"suspended"`
Summary *Summary `json:"summary,omitempty"`
Health *HealthInfo `json:"health,omitempty"`
ServiceHealth []ServiceHealthEntry `json:"service_health,omitempty"`
RoutingStats *routing.RoutingTableStats `json:"routing_stats,omitempty"`
RouteGroups int `json:"route_groups"`
RoutingPolicy *RoutingPoliciesSummary `json:"routing_policy,omitempty"`
Apps []*appserver.AppState `json:"apps,omitempty"`
Transports []*TransportSummary `json:"transports,omitempty"`
Persistent []transport.PersistentTransports `json:"persistent_transports,omitempty"`
Modules *ModulePresence `json:"modules,omitempty"`
// RouterConfig is the routing configuration actually IN FORCE at
// runtime (min_hops / mux_routes / force_local / existing_tp_only
// / transport_preference are the live router values, which can
// differ from the config file after a runtime set; cascade +
// policy_per_dial are the configured source). This is the
// policy-vs-globals view — what the router will do independent of
// any per-app routing policy.
RouterConfig *EffectiveRoutingConfig `json:"router_config,omitempty"`
// MuxRouteGroups is the per-leg mux shape of EVERY active route
// group (the same RouteGroupMuxInfo 'mux plot' reads), so the live
// multipath layout — each leg's transport, type, remote, rtt,
// bandwidth, and alive/standby gate state — is visible in one
// snapshot rather than one-app-at-a-time.
MuxRouteGroups []MuxRouteGroupInfo `json:"mux_route_groups,omitempty"`
// MuxCounters are the whole-router cumulative tallies (tunnel
// promotions/flips, leg re-homes sent/received/acked/failed, forward
// fan-out engage/release) that the bounded mux event ring does not keep
// once it wraps. Built alongside MuxRouteGroups (--select mux).
MuxCounters *router.MuxCounters `json:"mux_counters,omitempty"`
// Pool is the standby-tunnel pool table: one row per route group this
// visor's local end labeled "standby" (pool_arbiter.go), projected from
// the SAME MuxRouteGroupInfo entries MuxRouteGroups holds — local port,
// first-hop pk+transport type, hop count, capacity prior bps, audition
// age, leg source, and leg count, at a glance across the whole pool.
Pool []PoolTunnelInfo `json:"pool,omitempty"`
// CXOFeeds is the live publish-health of each CXO feed (system
// telemetry/tp-list feed first, then user feeds): dirty state, secs
// since last OK publish, in-memory leaf/node counts, and any standing
// publish error with its concrete type + isMissingObject verdict.
// This is the diagnostic surface for TPD-agreement issues — a frozen
// stats feed (Frozen=true, a climbing SecsSinceOKPublish, a LastErr)
// is exactly why TPD under-reports a visor's transports, and it's now
// a query against the live visor (local or --via dmsg://<pk>).
CXOFeeds []CXOFeedState `json:"cxo,omitempty"`
Services []EmbeddedServiceState `json:"services,omitempty"`
// TPDLeafPub says whether the transport manager holds the CXO
// transport-list snapshot publisher, and — when it does not — why.
// Without it transport registration silently falls back to the HTTP
// re-register path, which an empty .cxo alone does not distinguish
// from "stats module still starting".
TPDLeafPub *TPDLeafPublisherState `json:"tpd_leaf_publisher,omitempty"`
// Proxy is the visor-side live proxystatus snapshot for the skysocks
// surface — the same per-leg mux telemetry, running flag, and (when the
// client pushes it) range-split summary the status.skysocks page renders.
// It is OPT-IN: built only for `--select proxy`, never in the full/default
// snapshot, so the default payload is unchanged.
Proxy *proxystatus.Snapshot `json:"proxy,omitempty"`
// Diag is the in-process plumbing view (router intake, transport read
// queue and handlers, VStream muxes, dmsg ping/relay state, Go runtime) —
// see DiagSnapshot. Cheap; part of the default snapshot.
Diag *DiagSnapshot `json:"diag,omitempty"`
// Roles is what this visor is FOR the network: the in-process dmsg
// server (if any, and on which key/address), both directions of the dmsg
// relay, and whether it refuses transit. See RolesSnapshot. Cheap; part
// of the default snapshot.
Roles *RolesSnapshot `json:"roles,omitempty"`
// Notes collects per-section errors ("routing: <err>") so the snapshot is
// self-describing about what it could and could not read.
Notes []string `json:"notes,omitempty"`
}
StateSnapshot is a curated, secrets-free view of the visor's live runtime state, aggregated from the same RPC-safe DTOs the individual CLI subcommands return. It exists so an operator (or an agent) can introspect the whole runtime in ONE call — `skywire cli visor state` — and project exactly the field they want with the shared --jq / --shape flags, instead of stitching together a dozen subcommands.
SAFETY: every embedded field is an existing API response type, i.e. already designed to cross the RPC boundary — so this carries no mutexes, channels, contexts, live connections, or secret keys. The visor's secret key is NEVER included; identity is public-key only (via Summary.Overview.PubKey). Each section is populated best-effort: a section that errors (e.g. a subsystem not yet initialized, or the visor suspended) is left nil and the reason recorded in Notes, so a partially-up or suspended visor still returns a useful snapshot rather than failing the whole call.
type StateSnapshotReq ¶
type StateSnapshotReq struct {
Fields []string
}
StateSnapshotReq is the argument to StateSnapshotProjected: the subtree keys (see the StateSelect* constants) to build. Empty builds the full snapshot.
type StopAllPingsOut ¶
type Summary ¶
type Summary struct {
Overview *Overview `json:"overview"`
Health *HealthInfo `json:"health"`
Uptime float64 `json:"uptime"`
Routes []RoutingRuleResp `json:"routes"`
RouteGroups []RouteGroupInfo `json:"route_groups,omitempty"`
IsHypervisor bool `json:"is_hypervisor,omitempty"`
// HypervisorAddr is the host:port the hypervisor UI is bound to
// when IsHypervisor=true. Empty when this visor isn't hosting a
// hypervisor (or when v.conf.Hypervisor is nil). Sourced from
// v.conf.Hypervisor.HTTPAddr.
HypervisorAddr string `json:"hypervisor_addr,omitempty"`
DmsgStats *dmsgtracker.DmsgClientSummary `json:"dmsg_stats"`
ConnectedDmsgServers []string `json:"connected_dmsg_servers"` // Deprecated: use DMSGServers instead
DMSGServers []DMSGServerInfo `json:"dmsg_servers"` // Connected DMSG servers with latencies
Online bool `json:"online"`
// OfflineSince is set on cached summaries served when the live
// RPC fails. Lets the UI render a "offline since X" indicator
// alongside the otherwise-stale fields. nil when Online=true.
OfflineSince *time.Time `json:"offline_since,omitempty"`
// LastSeenAt is the timestamp of the last successful live
// summary fetch. Set on both fresh and cached responses so the
// UI can show "as of HH:MM:SS" even on stale rows. nil only on
// the never-seen path.
LastSeenAt *time.Time `json:"last_seen_at,omitempty"`
MinHops uint16 `json:"min_hops"`
PersistentTransports []transport.PersistentTransports `json:"persistent_transports"`
RewardAddress string `json:"reward_address"`
// RewardEligible reflects the reward system's verdict on this visor's most
// recent survey PUSH: non-nil false = REJECTED (e.g. version below the reward
// floor) — the hypervisor UI shows a red mark, distinct from the hyphen for no
// reward address. nil = no verdict yet (never pushed / no reward address).
RewardEligible *bool `json:"reward_eligible,omitempty"`
RewardIneligibleReason string `json:"reward_ineligible_reason,omitempty"`
BuildTag string `json:"build_tag"`
ConfigVersion string `json:"config_version"`
PublicAutoconnect bool `json:"public_autoconnect"`
IsPublic bool `json:"is_public"`
// Load is a lightweight resource snapshot (load average, mem %, disk %)
// for the `hv ls --load` view. omitempty so the field is absent on
// summaries from older visors that don't populate it.
Load *LoadStats `json:"load,omitempty"`
}
Summary provides detailed info including overview and health of the visor.
type TPDAnnounceState ¶
type TPDAnnounceState struct {
To string `json:"to"`
OK int64 `json:"ok"`
Failed int64 `json:"failed"`
SecsSinceOK float64 `json:"secs_since_ok"`
LastError string `json:"last_error,omitempty"`
SecsSinceLastFail float64 `json:"secs_since_last_fail"`
}
TPDAnnounceState counts the announces of the transport-list feed to TPD. A Secs* field is -1 when the event has not happened.
type TPDLeafPublisherState ¶
type TPDLeafPublisherState struct {
Wired bool `json:"wired"`
Reason string `json:"reason,omitempty"`
// Announce is how the dials that let TPD fetch this feed are going.
// A wired publisher whose announces fail is invisible to TPD, and the
// route finder with it; before this the failures were Trace-only.
Announce *TPDAnnounceState `json:"announce,omitempty"`
}
TPDLeafPublisherState reports whether the transport manager holds the CXO transport-list snapshot publisher (transport.Manager. SetTPDLeafPublisher). Wired=false means transport registration runs over the HTTP/dmsg-HTTP re-register path instead, and Reason carries why the publisher was never installed — the treestore construction error, "dmsg client absent", "stats disabled by config", or a generic "not completed init" note during the startup window.
type TPSAddTransportIn ¶
type TPSRemoveTransportIn ¶
type TPSStatus ¶
type TPSStatus struct {
Enabled bool `json:"enabled"`
PubKey cipher.PubKey `json:"pub_key,omitempty"`
}
TPSStatus contains the status of the embedded Transport Setup Node.
type TPSTransportResponse ¶
type TPSTransportResponse struct {
ID uuid.UUID `json:"id"`
Local cipher.PubKey `json:"local"`
Remote cipher.PubKey `json:"remote"`
Type string `json:"type"`
}
TPSTransportResponse contains information about a transport managed by TPS.
type TestResult ¶
TestResult type of test result
type TransportLogEntry ¶
type TransportRPCCallRequest ¶
type TransportRPCCallRequest struct {
RemotePK cipher.PubKey `json:"remote_pk"`
Method string `json:"method"`
Args json.RawMessage `json:"args,omitempty"` // JSON-encoded RPC arguments
}
type TransportSummary ¶
type TransportSummary struct {
ID uuid.UUID `json:"id"`
Local cipher.PubKey `json:"local_pk"`
Remote cipher.PubKey `json:"remote_pk"`
Type types.Type `json:"type"`
Log *transport.LogEntry `json:"log,omitempty"`
IsSetup bool `json:"is_setup"`
Label transport.Label `json:"label"`
// LatencyMS is the smoothed average inter-visor RTT for this
// transport in milliseconds, measured by transport-level
// ping/pong (or RSN-fallback for old peers). Zero means no
// measurement yet. Populated from tp.GetLatency().
LatencyMS float64 `json:"latency_ms,omitempty"`
// ThroughputBps is the passively-observed peak goodput (bytes/sec)
// this transport has carried � a measured CAPACITY lower-bound,
// distinct from RTT (a low-latency link can still be low-throughput,
// e.g. webrtc). Zero until real traffic has flowed. Populated from
// tp.GetThroughputBps().
ThroughputBps float64 `json:"throughput_bps,omitempty"`
// Initiator is true when this visor dialed out to establish the
// transport (outgoing); false when it accepted an inbound dial
// (incoming). The transport is bidirectional � this records only
// who originated it, for in/out reporting.
Initiator bool `json:"initiator"`
// RemoteIP is the host portion of the underlying transport's raw
// remote address (e.g. "1.2.3.4"). Empty for dmsg � which relays
// through a server rather than dialing the peer directly, so an
// empty RemoteIP is itself the "relayed, not direct" signal.
// Populated from tp.RemoteIP().
RemoteIP string `json:"remote_ip,omitempty"`
// RemoteCountry is the ISO country code the embedded geoip db maps
// RemoteIP to (the same db the routing-policy provider uses). Empty
// when there is no direct IP (dmsg) or no geoip hit.
RemoteCountry string `json:"remote_country,omitempty"`
// Endpoint carries the per-transport-type low-level connection
// metadata � the direct IP:port for stcp/stcpr/sudph/squicr, the
// relaying dmsg server PK for dmsg, the QUIC TLS fingerprint/ALPN
// for squicr, the selected ICE candidate for webrtc. Secrets-free
// (dmsg = server PK only, never a secret key). nil when the
// transport isn't serving or its type exposes no details.
// Populated from tp.ConnDetails().
Endpoint *network.ConnDetails `json:"endpoint,omitempty"`
}
func (TransportSummary) MarshalJSON ¶
func (ts TransportSummary) MarshalJSON() ([]byte, error)
MarshalJSON emits id / local_pk / remote_pk only when they are set.
encoding/json's `omitempty` cannot express this: uuid.UUID and cipher.PubKey are fixed-size arrays, and omitempty never treats an array as empty � so an otherwise-blank entry still costs ~170 bytes of "000�0" on the wire. That is what makes the node-list projection worth doing at all (see compactTransportSummaries, which emits type and direction only). A real transport has all three set and serializes exactly as it did before.
type Transports ¶
type Transports interface {
TransportTypes() ([]string, error)
Transports(types []string, pks []cipher.PubKey, logs bool) ([]*TransportSummary, error)
Transport(tid uuid.UUID) (*TransportSummary, error)
AddTransport(remote cipher.PubKey, tpType string, timeout time.Duration, label string, noRegister bool, skipLatencyProbe bool) (*TransportSummary, error)
SetSTCPAddr(pk cipher.PubKey, addr string) error
RemoveTransport(tid uuid.UUID) error
RemoveAllTransports() error
SetPublicAutoconnect(pAc bool) error
SetIsPublic(isPublic bool) error
GetIsPublic() bool
LocalTransportStats() (*LocalTransportStatsResponse, error)
LocalUptimeStats(args LocalUptimeArgs) (*LocalUptimeResponse, error)
StartPublicAutoconnect() error
StopPublicAutoconnect() error
PublicAutoconnectStatus() (bool, error)
GetPersistentTransports() ([]transport.PersistentTransports, error)
SetPersistentTransports([]transport.PersistentTransports) error
GetTransportLogs(days int) ([]TransportLogEntry, error)
DiscoverTransportsByPK(pk cipher.PubKey) ([]*transport.Entry, error)
DiscoverTransportByID(id uuid.UUID) (*transport.Entry, error)
// Embedded Transport Setup Node (TPS) controls
TPSStatus() (*TPSStatus, error)
TPSAddTransport(targetPK, remotePK cipher.PubKey, tpType string) (*TPSTransportResponse, error)
TPSRemoveTransport(targetPK cipher.PubKey, tpID uuid.UUID) error
TPSGetTransports(targetPK cipher.PubKey) ([]TPSTransportResponse, error)
// External TPS operations (dial external TPS over dmsg)
GetTransportSetupNodes() ([]cipher.PubKey, error)
GetTransportSetupNodesSorted() ([]cipher.PubKey, error)
GetTPSHealth() ([]NodeHealth, error)
TPSExternalHealthCheck(tpsPK cipher.PubKey) error
TPSExternalAddTransport(tpsPK, targetPK, remotePK cipher.PubKey, tpType string) (*TPSTransportResponse, error)
TPSExternalGetTransports(tpsPK, targetPK cipher.PubKey) ([]TPSTransportResponse, error)
}
Transports is the visor's transports, transport discovery and transport setup.
type TransportsIn ¶
type UDPForwardIn ¶
UDPForwardIn is the argument for DialUDPForward (#2607): dial a remote forwarded_ports.udp service and bridge it to a local UDP socket.
type UIServerStatus ¶
type UIServerStatus struct {
Running bool `json:"running"`
LocalAddr string `json:"local_addr,omitempty"`
DmsgPort uint16 `json:"dmsg_port,omitempty"`
}
UIServerStatus contains the status of the UI server.
type UptimeHistoryArgs ¶
type UptimeHistoryArgs struct {
Since time.Time
Limit int
IncludeTimeline bool
// TimelineDate, when set with IncludeTimeline, returns the bitmap
// for that UTC date instead of today.
TimelineDate time.Time
}
UptimeHistoryArgs is the request shape for API.UptimeHistory. All fields are optional: empty Since reads everything in retention, zero Limit returns all rows, IncludeTimeline=false skips the timeline byte slice.
type UptimeHistoryResponse ¶
type UptimeHistoryResponse struct {
Current serviceuptime.SessionRecord `json:"current"`
Sessions []serviceuptime.SessionRecord `json:"sessions"`
Timeline []byte `json:"timeline,omitempty"`
TimelineDate string `json:"timeline_date,omitempty"`
}
UptimeHistoryResponse carries the visor's own session history. Current is the in-flight session row; Sessions is everything the recorder has retained, oldest first. Timeline (when requested) is the 36-byte 288-slot bitmap for TimelineDate, suitable for rendering with serviceuptime.FormatBitmap.
type Vhost ¶ added in v1.3.101
type Vhost struct {
Name string `json:"name"`
Aliases []string `json:"aliases,omitempty"`
ProxyAddr string `json:"proxy_addr"`
Whitelist []cipher.PubKey `json:"whitelist,omitempty"` // empty = everyone
// PreserveHost passes the request's Host to the backend, as for a port 80
// forward; by default the backend sees its own address.
PreserveHost bool `json:"preserve_host,omitempty"`
}
Vhost is a site the visor serves on port 80 for one or more Host names, as the resolving proxy rewrites them: "status" for status.<pk>.skynet, or "status.skywire.dev" for status.skywire.dev.<pk>.skynet.
type VisorCatRequest ¶
type VisorCatRequest struct {
// Mode is VisorCatModeDial or VisorCatModeListen.
Mode string `json:"mode"`
// RemotePK is the peer's visor PK. Required in dial mode;
// ignored in listen mode (the listener accepts whatever PK the
// dmsgscp whitelist authorizes).
RemotePK cipher.PubKey `json:"remote_pk,omitempty"`
// Port is the remote port to dial in dial mode, or the local
// port to listen on in listen mode.
Port uint16 `json:"port"`
// Transport is VisorCatTransportDmsg or VisorCatTransportSkynet.
// Empty defaults to dmsg.
Transport string `json:"transport,omitempty"`
// Timeout bounds the dial (dial mode) or the accept-wait (listen
// mode) plus the splice. Zero defaults: 60s for dial, 5m for
// listen.
Timeout time.Duration `json:"timeout,omitempty"`
// Routes requests N parallel mux routes for the skynet transport
// in dial mode. The router opens N route-groups in parallel and
// stripes writes across them with sequence numbers + resequencing
// on reads — bytes remain ordered at the app layer. Ignored for
// dmsg transport and for listen mode (listener accepts whatever
// the peer dials). 0 or 1 = single route (default).
Routes int `json:"routes,omitempty"`
}
VisorCatRequest describes a stream-splice the visor should perform on the caller's behalf. The visor process opens the remote stream (dial or listen) over the chosen transport and exposes one end as a 127.0.0.1 loopback TCP listener — bytes never traverse the local RPC channel beyond the initial request + response.
type VisorCatResponse ¶
type VisorCatResponse struct {
// LocalAddr is "127.0.0.1:PORT" the CLI dials to bridge stdio.
LocalAddr string `json:"local_addr"`
}
VisorCatResponse carries the 127.0.0.1 loopback address the CLI should dial. The visor's accept-and-splice goroutine waits on this listener; the CLI's dial completes the splice loop.
type VisorSCPRequest ¶
type VisorSCPRequest struct {
// RemotePK is the peer's visor PK. The peer must have a dmsgscp
// host bound and the caller's PK on the host's whitelist.
RemotePK cipher.PubKey `json:"remote_pk"`
// Port is the peer's dmsgscp port (same for both transports —
// dmsgscp.DefaultPort is 23).
Port uint16 `json:"port"`
// Direction is VisorSCPUpload or VisorSCPDownload.
Direction string `json:"direction"`
// LocalPath is the path on the visor host's filesystem. For an
// upload it's the source; for a download it's the destination.
LocalPath string `json:"local_path"`
// RemotePath is the path relative to the peer's rootDir. For an
// upload it's the destination; for a download it's the source.
// Absolute paths and `..` components are rejected by the peer.
RemotePath string `json:"remote_path"`
// Transport is VisorSCPTransportDmsg or VisorSCPTransportSkynet.
// Empty defaults to dmsg.
Transport string `json:"transport,omitempty"`
// Timeout bounds the whole transfer (dial + scp protocol +
// payload). Zero falls back to a 5-minute default.
Timeout time.Duration `json:"timeout,omitempty"`
}
VisorSCPRequest describes a peer-to-peer file transfer the visor should perform on the caller's behalf. The visor process opens the stream over the chosen transport (it has both dmsgC + appnet resolvers wired in, where a standalone CLI does not) and drives the dmsgscp wire protocol entirely inside the visor.
Local files are read/written on the visor host's filesystem. Operators running the CLI as the same user as the visor process see the obvious "this is my $HOME" behavior.
type VoiceAudioSnapshot ¶
VoiceAudioSnapshot is the recent sent/received PCM of an active call.
type VoiceDialingInfo ¶
type VoiceDialingInfo struct {
CallID string `json:"call_id"`
Peer string `json:"peer"`
// State is how far the call has got: "connecting", "calling" (the peer
// has the invite but predates ringing reports) or "ringing" — or, for a
// few seconds after it ended unanswered, why: "offline", "declined",
// "busy", "no_answer" or "failed". Empty from a visor that predates it.
State string `json:"state,omitempty"`
// Reason is the detail behind an outcome.
Reason string `json:"reason,omitempty"`
// Ringback is true once the peer's own ringback tone has arrived and can
// be played (VoiceDialRingback); false means play an ordinary ring.
Ringback bool `json:"ringback,omitempty"`
}
VoiceDialingInfo is one call this visor is placing, before it is answered.
type VoiceMuteReq ¶
VoiceMuteReq toggles the mic/speaker mute of a call.
type VoiceRingback ¶ added in v1.3.98
type VoiceRingback struct {
Data []byte `json:"data,omitempty"`
Mime string `json:"mime,omitempty"`
}
VoiceRingback is a ringback tone: what a caller hears while a visor rings. Empty Data means none.