Documentation
¶
Index ¶
- Constants
- Variables
- func HashToken(token string) string
- func NormalizeAPIURL(raw string) (string, *url.URL, error)
- type Config
- type CreatePeerInput
- type FederatedRelay
- type HealthDTO
- type Peer
- type PeerStatus
- type PublicRelayDTO
- type RelaySource
- type Service
- func (s *Service) Authorized(r *http.Request) bool
- func (s *Service) CreatePeer(ctx context.Context, in CreatePeerInput) (Peer, error)
- func (s *Service) PublicHealth(ctx context.Context) HealthDTO
- func (s *Service) PublicRelays(ctx context.Context) ([]PublicRelayDTO, error)
- func (s *Service) RegisterPublic(r chi.Router, limiter auth.Limiter)
- func (s *Service) Run(ctx context.Context)
- func (s *Service) Store() *Store
- func (s *Service) SyncAll(ctx context.Context)
- func (s *Service) SyncPeer(ctx context.Context, id int64) error
- type Store
- func (s *Store) Create(ctx context.Context, in CreatePeerInput) (Peer, error)
- func (s *Store) Delete(ctx context.Context, id int64) error
- func (s *Store) Get(ctx context.Context, id int64) (Peer, error)
- func (s *Store) List(ctx context.Context) ([]Peer, error)
- func (s *Store) ListFederatedRelays(ctx context.Context) ([]FederatedRelay, error)
- func (s *Store) ReplaceFederatedRelays(ctx context.Context, peerID int64, relays []FederatedRelay) error
- func (s *Store) Token(ctx context.Context, id int64) (string, error)
- func (s *Store) UpdateStatus(ctx context.Context, id int64, status PeerStatus, errMsg *string) error
Constants ¶
const MinTokenLen = 16
MinTokenLen is the shortest accepted peer token (the peer's RDPANEL_FEDERATION_TOKEN has the same minimum).
Variables ¶
var ErrNoToken = errors.New("federation: no stored token for this peer")
ErrNoToken means a peer has no stored token (it was registered by a version that kept tokens in memory only): delete and re-add it.
Functions ¶
Types ¶
type Config ¶
type Config struct {
Store *Store
Relays RelaySource
Version string
SyncInterval time.Duration
Log *slog.Logger
// InboundToken is the bearer token peers must present to this panel's
// federation endpoints (RDPANEL_FEDERATION_TOKEN). Empty refuses all.
InboundToken string
// AllowPrivate reports whether peers may live on private, loopback or
// link-local addresses (the relays "allow private hosts" option).
// nil: never.
AllowPrivate func(context.Context) bool
// HTTPClient overrides the outgoing client (tests). The default refuses
// private addresses at dial time (unless AllowPrivate), ignores proxy
// variables and does not follow redirects.
HTTPClient *http.Client
// Lookup resolves peer host names for the registration check
// (default net.DefaultResolver.LookupNetIP).
Lookup func(ctx context.Context, network, host string) ([]netip.Addr, error)
}
Config configures the federation service.
type CreatePeerInput ¶
CreatePeerInput is input for registering a new peer panel.
type FederatedRelay ¶
type FederatedRelay struct {
ID int64 `json:"id"`
PeerID int64 `json:"peer_id"`
PeerName string `json:"peer_name,omitempty"`
RemoteName string `json:"remote_name"`
PublicHost string `json:"public_host"`
Region string `json:"region,omitempty"`
Health string `json:"health"`
LastSyncAt time.Time `json:"last_sync_at"`
}
FederatedRelay represents a relay announced by a peered RD Panel.
type HealthDTO ¶
type HealthDTO struct {
Status string `json:"status"`
Version string `json:"version"`
ActiveRelays int `json:"active_relays"`
TimestampNano int64 `json:"timestamp_nano"`
}
HealthDTO is the response to /api/v1/federation/health.
type Peer ¶
type Peer struct {
ID int64 `json:"id"`
Name string `json:"name"`
APIURL string `json:"api_url"`
TokenHash string `json:"-"`
SyncRelays bool `json:"sync_relays"`
Status PeerStatus `json:"status"`
LastSyncAt *time.Time `json:"last_sync_at,omitempty"`
LastError *string `json:"last_error,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Peer represents an external peered RD Panel instance.
type PeerStatus ¶
type PeerStatus string
PeerStatus is the connection status of a peered RD Panel.
const ( StatusUnknown PeerStatus = "unknown" StatusActive PeerStatus = "active" // StatusUnreachable marks a peer whose last sync failed: unreachable, // token rejected, or an invalid answer. Peer.LastError says which. StatusUnreachable PeerStatus = "unreachable" )
type PublicRelayDTO ¶
type PublicRelayDTO struct {
Name string `json:"name"`
PublicHost string `json:"public_host"`
Region string `json:"region,omitempty"`
Health string `json:"health"`
}
PublicRelayDTO is what a panel announces to peers.
type RelaySource ¶
RelaySource provides active local relays to announce.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service manages federation peering, relay synchronization and public federation endpoints.
func (*Service) Authorized ¶ added in v0.11.0
Authorized reports whether r carries this panel's federation token. The comparison is constant-time over SHA-256 digests.
func (*Service) CreatePeer ¶ added in v0.11.0
CreatePeer validates and registers a peer. Unless private peers are allowed, an api_url pointing at a private, loopback or link-local address (literally or via DNS) is refused.
func (*Service) PublicHealth ¶
PublicHealth returns local health for peering verification.
func (*Service) PublicRelays ¶
func (s *Service) PublicRelays(ctx context.Context) ([]PublicRelayDTO, error)
PublicRelays returns local active relays for peering peers.
func (*Service) RegisterPublic ¶ added in v0.11.0
RegisterPublic mounts GET /health and GET /relays (under /api/v1/federation). Both require the federation bearer token; failed attempts back off per client IP through limiter (nil: no limit).
func (*Service) Run ¶ added in v0.11.0
Run is the background sync loop (an app worker); it returns when ctx ends.
type Store ¶
type Store struct {
DB *db.DB
// AEAD seals peer tokens (required by Create and Token).
AEAD *crypto.AEAD
Now func() time.Time
}
Store persists federation peers and announced relays.
The token this panel presents to a peer is needed in plaintext for every sync, so it is kept AEAD-sealed in the panel settings under "federation.peer.<id>.token" (crypto.FederationPeerTokenAD); the federation_peers.token_hash column only holds its SHA-256.
func (*Store) Delete ¶
Delete removes a peer, its stored token and its announced relays (via CASCADE).
func (*Store) ListFederatedRelays ¶
func (s *Store) ListFederatedRelays(ctx context.Context) ([]FederatedRelay, error)
ListFederatedRelays returns all federated relays from all active peers. They are shown for visibility only: nothing adds them to hbbs' rotation.
func (*Store) ReplaceFederatedRelays ¶
func (s *Store) ReplaceFederatedRelays(ctx context.Context, peerID int64, relays []FederatedRelay) error
ReplaceFederatedRelays atomically replaces the relays associated with a peer.
func (*Store) Token ¶ added in v0.11.0
Token returns the token this panel presents to peer id (ErrNoToken when none is stored).
func (*Store) UpdateStatus ¶
func (s *Store) UpdateStatus(ctx context.Context, id int64, status PeerStatus, errMsg *string) error
UpdateStatus records a peer's sync attempt and current connectivity status.