gravity

package
v1.0.195 Latest Latest
Warning

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

Go to latest
Published: Apr 2, 2026 License: MIT Imports: 40 Imported by: 0

README

Gravity Client

Generic gRPC client for connecting to Gravity servers. This package was extracted from the hadron project to enable reuse across multiple tools and projects.

Package Structure

  • gravity/ - Main gravity client implementation
  • gravity/proto/ - Protocol buffer definitions and generated code
  • gravity/provider/ - Provider interface definitions
  • gravity/network/ - Network interface definitions

Module Path Conventions

All packages use the base module path: github.com/agentuity/go-common

  • Proto package: github.com/agentuity/go-common/gravity/proto
  • Provider interfaces: github.com/agentuity/go-common/gravity/provider
  • Network interfaces: github.com/agentuity/go-common/gravity/network

Usage

import (
    "github.com/agentuity/go-common/gravity"
)

// Create gravity client with your provider and network implementations
config := gravity.GravityConfig{
    Provider:     myProvider,
    NetworkInterface: myNetworkInterface,
    // ... other config
}

client, err := gravity.New(config)
if err != nil {
    return err
}

if err := client.Start(); err != nil {
    return err
}

Documentation

Index

Constants

View Source
const (
	// DefaultMaxGravityPeers is the maximum number of Gravity servers
	// a single Hadron will connect to simultaneously.
	DefaultMaxGravityPeers = 3

	// DefaultPeerDiscoveryInterval controls how often DNS is re-resolved
	// to discover additional Gravity peers.
	DefaultPeerDiscoveryInterval = 30 * time.Minute

	// DefaultPeerCycleInterval controls how often one connection is rotated
	// when more Gravity peers are available than active connections.
	DefaultPeerCycleInterval = 2 * time.Hour

	// DefaultStreamsPerGravity is the number of tunnel streams established
	// per Gravity server connection.
	DefaultStreamsPerGravity = 2

	// DefaultBindingTTL is how long a flow stays pinned to the same Gravity.
	DefaultBindingTTL = 5 * time.Second
)
View Source
const (
	StateClosed   = resilience.StateClosed
	StateHalfOpen = resilience.StateHalfOpen
	StateOpen     = resilience.StateOpen
)

Variables

View Source
var (
	ErrCircuitBreakerOpen    = resilience.ErrCircuitBreakerOpen
	ErrCircuitBreakerTimeout = resilience.ErrCircuitBreakerTimeout
	ErrTooManyFailures       = resilience.ErrTooManyFailures
)
View Source
var (
	DefaultRetryConfig          = resilience.DefaultRetryConfig
	DefaultRetryableErrors      = resilience.DefaultRetryableErrors
	Retry                       = resilience.Retry
	RetryWithCircuitBreaker     = resilience.RetryWithCircuitBreaker
	ExponentialBackoff          = resilience.ExponentialBackoff
	LinearBackoff               = resilience.LinearBackoff
	RetryWithStats              = resilience.RetryWithStats
	NewCircuitBreaker           = resilience.NewCircuitBreaker
	DefaultCircuitBreakerConfig = resilience.DefaultCircuitBreakerConfig
)

Re-export functions for backward compatibility

View Source
var ErrConnectionClosed = errors.New("gravity connection closed")

Error variables for consistency with old implementation

View Source
var ErrNoGravityFound = errors.New("no available gravity URL resolved")

Functions

func Identify added in v1.0.139

func Identify(ctx context.Context, config IdentifyConfig) (*pb.IdentifyResponse, error)

Identify performs a one-shot authentication to retrieve the org ID. It connects using a self-signed certificate generated from the provided ECDSA private key.

Types

type CircuitBreaker

type CircuitBreaker = resilience.CircuitBreaker

Re-export types and functions from resilience package for backward compatibility

type CircuitBreakerConfig

type CircuitBreakerConfig = resilience.CircuitBreakerConfig

Re-export types and functions from resilience package for backward compatibility

type CircuitBreakerState

type CircuitBreakerState = resilience.CircuitBreakerState

Re-export types and functions from resilience package for backward compatibility

type CircuitBreakerStats

type CircuitBreakerStats = resilience.CircuitBreakerStats

Re-export types and functions from resilience package for backward compatibility

type ConnectionPoolConfig

type ConnectionPoolConfig struct {
	// Connection pool size (4-8 connections as per PLAN.md)
	PoolSize int

	// Streams per connection for packet multiplexing
	StreamsPerConnection int

	// Stream allocation strategy
	AllocationStrategy StreamAllocationStrategy

	// Health check and failover settings
	HealthCheckInterval time.Duration
	FailoverTimeout     time.Duration

	// MaxGravityPeers caps how many Gravity servers Hadron connects to.
	// Default: DefaultMaxGravityPeers (3).
	MaxGravityPeers int

	// StreamsPerGravity is tunnel streams per Gravity host.
	// Default: DefaultStreamsPerGravity (2).
	StreamsPerGravity int
}

ConnectionPoolConfig holds configuration for gRPC connection pool optimization

type EndpointSelector added in v1.0.182

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

EndpointSelector manages sticky flow-to-endpoint bindings.

func NewEndpointSelector added in v1.0.182

func NewEndpointSelector(ttl time.Duration) *EndpointSelector

NewEndpointSelector creates a selector with the given binding TTL.

func (*EndpointSelector) ExpireBindings added in v1.0.182

func (s *EndpointSelector) ExpireBindings()

ExpireBindings removes bindings older than the TTL. Called periodically from a background goroutine.

func (*EndpointSelector) Len added in v1.0.182

func (s *EndpointSelector) Len() int

Len returns the current number of active bindings.

func (*EndpointSelector) RecordInboundFlow added in v1.0.188

func (s *EndpointSelector) RecordInboundFlow(packet []byte, endpoint *GravityEndpoint)

RecordInboundFlow records a reverse-flow binding for an inbound packet so that the response (e.g., SYNACK for a SYN) routes back through the same endpoint. Without this, the outbound SYNACK's flow key (src/dst swapped) wouldn't match the original SYN's binding and would be round-robined to a random endpoint, breaking the TCP handshake.

func (*EndpointSelector) Select added in v1.0.182

func (s *EndpointSelector) Select(packet []byte, endpoints []*GravityEndpoint) *GravityEndpoint

Select picks an endpoint for the given packet. It extracts the flow key from the IPv6 packet header and checks for an existing binding. If the binding exists and is within TTL, the same endpoint is returned. Otherwise, a new endpoint is selected via round-robin.

type FlowKey added in v1.0.182

type FlowKey struct {
	SrcIP   [16]byte
	DstIP   [16]byte
	SrcPort uint16
	DstPort uint16
	Proto   uint8
}

FlowKey identifies a network flow by its 5-tuple. Uses fixed-size arrays for efficient map key comparison.

func ExtractFlowKey added in v1.0.182

func ExtractFlowKey(packet []byte) FlowKey

ExtractFlowKey reads the 5-tuple directly from an IPv6 packet. Reads fixed offsets — no gopacket parsing overhead on hot path.

type GravityClient

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

GravityClient implements the provider.Server interface using gRPC transport

func New

func New(config GravityConfig) (*GravityClient, error)

New creates a new gRPC-based Gravity server client

func (*GravityClient) Close

func (g *GravityClient) Close() error

Close will shutdown the client

func (*GravityClient) Disconnected added in v1.0.102

func (g *GravityClient) Disconnected(ctx context.Context)

Disconnected will wait for the client to be disconnected or the ctx to be cancelled

func (*GravityClient) GetAPIURL

func (g *GravityClient) GetAPIURL() string

GetAPIURL returns the API URL received from gravity server

func (*GravityClient) GetConnectionPoolStats

func (g *GravityClient) GetConnectionPoolStats() map[string]any

GetConnectionPoolStats returns current connection pool statistics for monitoring

func (*GravityClient) GetDeploymentMetadata

func (g *GravityClient) GetDeploymentMetadata(ctx context.Context, deploymentID, orgID string) (*pb.DeploymentMetadataResponse, error)

GetDeploymentMetadata makes a gRPC call to get deployment metadata

func (*GravityClient) GetIPv6Address

func (g *GravityClient) GetIPv6Address() string

GetIPv6Address returns the IPv6 address for external use

func (*GravityClient) GetInboundPackets

func (g *GravityClient) GetInboundPackets() <-chan *PooledBuffer

func (*GravityClient) GetSandboxMetadata added in v1.0.138

func (g *GravityClient) GetSandboxMetadata(ctx context.Context, sandboxID, orgID string, generateCertificate bool) (*pb.SandboxMetadataResponse, error)

GetSandboxMetadata makes a gRPC call to get sandbox metadata

func (*GravityClient) GetSecret

func (g *GravityClient) GetSecret() string

GetSecret returns the authentication secret for external use

func (*GravityClient) GetTextMessages

func (g *GravityClient) GetTextMessages() <-chan *PooledBuffer

func (*GravityClient) IsConnected

func (g *GravityClient) IsConnected() bool

func (*GravityClient) Pause

func (g *GravityClient) Pause(reason string) error

Pause sends a pause event to the gravity server

func (*GravityClient) Resume

func (g *GravityClient) Resume(reason string) error

Resume sends a resume event to the gravity server

func (*GravityClient) SendCheckpointURLRequest added in v1.0.152

func (g *GravityClient) SendCheckpointURLRequest(sandboxID string, operation pb.CheckpointURLOperation, checkpointKey string, orgID string, timeout time.Duration) (*pb.CheckpointURLResponse, error)

SendCheckpointURLRequest sends a checkpoint URL request and waits for response (sync). Used by suspend/resume operations to get presigned S3 URLs from Gravity.

func (*GravityClient) SendEvacuateRequest added in v1.0.151

func (g *GravityClient) SendEvacuateRequest(machineID, reason string, sandboxes []*pb.SandboxEvacInfo) error

SendEvacuateRequest sends a request to evacuate sandboxes on this machine.

func (*GravityClient) SendMonitorReport added in v1.0.163

func (g *GravityClient) SendMonitorReport(report *pb.NodeMonitorReport) error

SendMonitorReport sends a NodeMonitorReport to the gravity server via the control stream. This is fire-and-forget — no response is expected. If the stream is unavailable, the report is silently dropped (stale data is worse than missing data). The send is bounded by a short timeout so it cannot block the monitor loop.

func (*GravityClient) SendPacket

func (g *GravityClient) SendPacket(data []byte) error

func (*GravityClient) SendRouteDeploymentRequest

func (g *GravityClient) SendRouteDeploymentRequest(deploymentID, virtualIP string, timeout time.Duration) (*pb.RouteDeploymentResponse, error)

SendRouteDeploymentRequest sends a route deployment request and waits for response (sync)

func (*GravityClient) SendRouteSandboxRequest added in v1.0.136

func (g *GravityClient) SendRouteSandboxRequest(sandboxID, virtualIP string, timeout time.Duration) (*pb.RouteSandboxResponse, error)

SendRouteSandboxRequest sends a route sandbox request and waits for response (sync)

func (*GravityClient) SetEvacuationCallback added in v1.0.151

func (g *GravityClient) SetEvacuationCallback(cb func())

SetEvacuationCallback sets the callback called when evacuation plan processing completes.

func (*GravityClient) SetMonitorCommandHandler added in v1.0.163

func (g *GravityClient) SetMonitorCommandHandler(handler func(cmd *pb.MonitorCommand))

SetMonitorCommandHandler registers a callback for incoming MonitorCommand messages from the gravity server (e.g., interval adjustments, snapshot requests).

func (*GravityClient) Start

func (g *GravityClient) Start() error

Start establishes gRPC connections and starts the client. When GravityURLs is configured with multiple URLs, the multi-endpoint path is used (multiple Gravity servers, sticky tunnel selection, peer cycling). Otherwise, the original single-URL path is used — identical to pre-multi-tunnel behavior.

func (*GravityClient) TunnelStats added in v1.0.168

func (g *GravityClient) TunnelStats() TunnelStatsSnapshot

TunnelStats returns a point-in-time snapshot of all tunnel health counters. This is safe to call from any goroutine (all reads are atomic or under lock). NOTE: InboundHighWater is reset to 0 on each call (atomic Swap).

func (*GravityClient) Unprovision

func (g *GravityClient) Unprovision(deploymentID string) error

Unprovision sends an unprovision request to the gravity server

func (*GravityClient) WaitForSession added in v1.0.150

func (g *GravityClient) WaitForSession(timeout time.Duration) error

WaitForSession blocks until the session is fully authenticated and configured, or the timeout/context expires.

func (*GravityClient) WritePacket

func (g *GravityClient) WritePacket(payload []byte) error

WritePacket sends a tunnel packet via gRPC tunnel stream using load balancing

type GravityConfig

type GravityConfig struct {
	Context  context.Context
	Logger   logger.Logger
	Provider provider.Provider
	URL      string
	// GravityURLs is a list of Gravity server URLs to connect to.
	// If set, this takes precedence over URL.
	// Hadron connects to up to MaxGravityPeers servers from this list.
	GravityURLs          []string
	CACert               string
	IP4Address           string
	IP6Address           string
	ECDSAPrivateKey      *ecdsa.PrivateKey
	InstanceID           string
	Region               string // Region where the instance is located, for display only
	AvailabilityZone     string // Availability zone where the instance is located, for display only
	CloudProvider        string // Type of cloud provider (e.g., aws, gcp, azure), for display only
	ClientVersion        string
	ClientName           string
	Capabilities         *pb.ClientCapabilities
	PingInterval         time.Duration
	WorkingDir           string
	TraceLogPackets      bool
	NetworkInterface     network.NetworkInterface
	ConnectionPoolConfig *ConnectionPoolConfig
	SkipAutoReconnect    bool
	InstanceTags         []string // Tags for display only
	InstanceType         string   // Type of instance (e.g., t2.micro)
	DefaultServerName    string   // Fallback TLS ServerName when connecting via IP address (default: "gravity.agentuity.com")
	UseMultiConnect      bool     // Use multiple connections to gravity

	// DiscoveryResolveFunc is called periodically to re-resolve the set of
	// available Gravity server URLs. If nil, no re-resolution or cycling occurs.
	// The function should return ALL available URLs (not capped by MaxGravityPeers).
	// The GravityClient handles selection and capping internally.
	DiscoveryResolveFunc func() []string

	// PeerDiscoveryInterval is how often to re-resolve DNS for new Gravity peers.
	// Default: 30 minutes.
	PeerDiscoveryInterval time.Duration

	// PeerCycleInterval is how often to rotate one connection when there are more
	// available Gravities than active connections. Only cycles if DNS returns more
	// IPs than MaxGravityPeers. Default: 2 hours.
	PeerCycleInterval time.Duration

	// MaxReconnectAttempts is the maximum number of reconnection attempts before
	// invoking ReconnectionFailedCallback. Default: 10
	MaxReconnectAttempts int

	// ReconnectAttemptTimeout is the timeout for each individual reconnection
	// attempt. If a single attempt takes longer than this, it is cancelled and
	// the next attempt begins. Default: 2 minutes
	ReconnectAttemptTimeout time.Duration

	// ReconnectionFailedCallback is invoked when all reconnection attempts are
	// exhausted. This is typically used to crash the process so a supervisor
	// (e.g. systemd) can perform a clean restart. If nil, the client simply
	// stops reconnecting.
	ReconnectionFailedCallback func(attempts int, lastErr error)
}

GravityConfig contains configuration for the Gravity client

type GravityEndpoint added in v1.0.182

type GravityEndpoint struct {
	// URL is the address of this Gravity server.
	URL string

	// TLSServerName is the hostname to use for TLS SNI when the URL contains
	// an IP address (e.g., after DNS resolution). If empty, the hostname is
	// extracted from URL as usual.
	TLSServerName string
	// contains filtered or unexported fields
}

GravityEndpoint represents a connection to a single Gravity server.

func (*GravityEndpoint) IsHealthy added in v1.0.182

func (e *GravityEndpoint) IsHealthy() bool

IsHealthy returns true if the endpoint is currently reachable.

type IdentifyConfig added in v1.0.149

type IdentifyConfig struct {
	GravityURL        string
	InstanceID        string
	ECDSAPrivateKey   *ecdsa.PrivateKey
	CACert            string // Optional: additional CA certificate PEM to trust
	DefaultServerName string // Optional: fallback TLS ServerName when connecting via IP address
}

IdentifyConfig contains configuration for the Identify one-shot call.

type PooledBuffer

type PooledBuffer struct {
	Buffer []byte
	Length int
}

PooledBuffer represents a buffer from the pool

type RetryConfig

type RetryConfig = resilience.RetryConfig

Re-export types and functions from resilience package for backward compatibility

type RetryStats

type RetryStats = resilience.RetryStats

Re-export types and functions from resilience package for backward compatibility

type RetryableFunc

type RetryableFunc = resilience.RetryableFunc

Re-export types and functions from resilience package for backward compatibility

type StreamAllocationStrategy

type StreamAllocationStrategy int

StreamAllocationStrategy defines how streams are selected for load distribution

const (
	RoundRobin StreamAllocationStrategy = iota
	HashBased
	LeastConnections
	WeightedRoundRobin
)

func (StreamAllocationStrategy) String

func (s StreamAllocationStrategy) String() string

String method for StreamAllocationStrategy enum

type StreamInfo

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

StreamInfo tracks individual stream health and load

type StreamManager

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

StreamManager manages multiple gRPC streams for multiplexing with advanced load balancing

type StreamMetrics

type StreamMetrics struct {
	PacketsSent     int64
	PacketsReceived int64
	BytesSent       int64
	BytesReceived   int64
	LastLatency     time.Duration
	ErrorCount      int64
	LastError       time.Time
	LastSendUs      int64 // unix microseconds of last successful send
	LastRecvUs      int64 // unix microseconds of last successful receive
}

StreamMetrics tracks performance metrics for individual streams

type StreamMetricsSnapshot added in v1.0.168

type StreamMetricsSnapshot struct {
	StreamID        string
	ConnectionIndex int
	Healthy         bool
	PacketsSent     int64
	PacketsReceived int64
	BytesSent       int64
	BytesReceived   int64
	ErrorCount      int64
	LastSendUs      int64
	LastRecvUs      int64
}

StreamMetricsSnapshot is a point-in-time copy of per-stream metrics.

type TunnelBinding added in v1.0.182

type TunnelBinding struct {
	Endpoint *GravityEndpoint
	LastUsed time.Time
	IsReturn bool // true = reverse-flow binding from RecordInboundFlow
}

TunnelBinding tracks which endpoint a flow is pinned to.

type TunnelStatsSnapshot added in v1.0.168

type TunnelStatsSnapshot struct {
	// Inbound (gravity → hadron → container)
	InboundReceived  uint64
	InboundDelivered uint64
	InboundDropped   uint64
	InboundBytes     uint64

	// Outbound (container → hadron → gravity)
	OutboundReceived uint64
	OutboundSent     uint64
	OutboundErrors   uint64
	OutboundBytes    uint64

	// Control plane
	PingsSent      uint64
	PongsReceived  uint64
	PingTimeouts   uint64
	LastPingSentUs int64
	LastPongRecvUs int64

	// Channel
	InboundChannelLen int
	InboundChannelCap int
	InboundHighWater  int32

	// Connection pool (point-in-time)
	TotalConnections      int
	HealthyConnections    int
	TotalTunnelStreams    int
	HealthyTunnelStreams  int
	TotalControlStreams   int
	HealthyControlStreams int

	// Per-stream metrics
	StreamMetrics map[string]StreamMetricsSnapshot
}

TunnelStatsSnapshot is a point-in-time snapshot of tunnel counters. All values are cumulative totals (deltas are computed by the caller).

Directories

Path Synopsis
Package vip provides deterministic virtual IP generation for Gravity.
Package vip provides deterministic virtual IP generation for Gravity.

Jump to

Keyboard shortcuts

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