Documentation
¶
Index ¶
- func GenerateOrLoadSecret(store *RelayStore, envSecret string) ([]byte, error)
- func IssueWingJWT(secret []byte, userID, publicKey, wingID string) (string, time.Time, error)
- func NewLoginProxy(loginAddr string) *httputil.ReverseProxy
- func SeedDefaultSkills(store *RelayStore) error
- func WaitForWing(ctx context.Context, local *WingRegistry, peers *PeerDirectory, wingID string, ...) (machineID string, found bool)
- type BandwidthMeter
- func (b *BandwidthMeter) AddUsage(userID string, bytes int64)
- func (b *BandwidthMeter) DrainCounters() map[string]int64
- func (b *BandwidthMeter) ExceededMonthly(userID string) bool
- func (b *BandwidthMeter) ExceededUsers() []string
- func (b *BandwidthMeter) InvalidateUser(userID string)
- func (b *BandwidthMeter) IsExceeded(userID string) bool
- func (b *BandwidthMeter) MonthlyUsage(userID string) int64
- func (b *BandwidthMeter) SeedFromDB()
- func (b *BandwidthMeter) SetExceeded(userIDs []string)
- func (b *BandwidthMeter) SetTierLookup(fn TierLookup)
- func (b *BandwidthMeter) StartSync(ctx context.Context, interval time.Duration)
- func (b *BandwidthMeter) Wait(ctx context.Context, userID string, n int) error
- type ChatRegistry
- type ChatSession
- type ClusterState
- type ConnectedWing
- type DeviceCodeRow
- type Entitlement
- type EntitlementCache
- type EntitlementEntry
- type Org
- type OrgInvite
- type OrgMember
- type PTYRegistry
- func (r *PTYRegistry) Add(s *PTYSession) bool
- func (r *PTYRegistry) All() []*PTYSession
- func (r *PTYRegistry) CountForUser(userID string) int
- func (r *PTYRegistry) Get(id string) *PTYSession
- func (r *PTYRegistry) IsTombstoned(id string) bool
- func (r *PTYRegistry) ListForUser(userID string) []*PTYSession
- func (r *PTYRegistry) Remove(id string)
- func (r *PTYRegistry) SyncFromWing(wingID, userID string, sessions []ws.SessionInfo, removeStale bool)
- type PTYSession
- type PeerDirectory
- func (p *PeerDirectory) AllWings() []*PeerWing
- func (p *PeerDirectory) CountForUser(userID string) int
- func (p *PeerDirectory) FindByWingID(wingID string) *PeerWing
- func (p *PeerDirectory) FindWing(wingID string) *PeerWing
- func (p *PeerDirectory) RemoveWing(wingID string)
- func (p *PeerDirectory) Replace(wings []*PeerWing) (added, removed []*PeerWing)
- func (p *PeerDirectory) UpdateCh() <-chan struct{}
- type PeerWing
- type RateLimiter
- type RelayStore
- func (s *RelayStore) AddOrgMember(orgID, userID, role string) error
- func (s *RelayStore) AppendAudit(userID, event string, detail *string) error
- func (s *RelayStore) BackfillProUsers() error
- func (s *RelayStore) ClaimDeviceCode(code, userID string) error
- func (s *RelayStore) Close() error
- func (s *RelayStore) ConsumeMagicLink(token string) (string, error)
- func (s *RelayStore) ConsumeOrgInvite(token string) (string, string, string, error)
- func (s *RelayStore) CountEntitlementsBySub(subID string) (int, error)
- func (s *RelayStore) CountOrgMembers(orgID string) (int, error)
- func (s *RelayStore) CountOrgsOwnedByUser(userID string) (int, error)
- func (s *RelayStore) CreateDeviceCode(code, userCode, deviceID string, expiresAt time.Time) error
- func (s *RelayStore) CreateDeviceCodeWithKey(code, userCode, deviceID, publicKey string, expiresAt time.Time) error
- func (s *RelayStore) CreateDeviceToken(token, userID, deviceID string, expiresAt *time.Time) error
- func (s *RelayStore) CreateEntitlement(ent *Entitlement) error
- func (s *RelayStore) CreateLocalUser() (*User, string, error)
- func (s *RelayStore) CreateMagicLink(id, email, token string, expiresAt time.Time) error
- func (s *RelayStore) CreateOrg(id, name, slug, ownerUserID string) error
- func (s *RelayStore) CreateOrgInvite(id, orgID, email, token, invitedBy, role string) error
- func (s *RelayStore) CreateSession(token, userID string, expiresAt time.Time) error
- func (s *RelayStore) CreateSkill(...) error
- func (s *RelayStore) CreateSubscription(sub *Subscription) error
- func (s *RelayStore) CreateUser(id string) error
- func (s *RelayStore) CreateUserDev() (*User, error)
- func (s *RelayStore) DB() *sql.DB
- func (s *RelayStore) DeleteEntitlementByUserAndSub(userID, subID string) error
- func (s *RelayStore) DeleteEntitlementsBySub(subID string) ([]string, error)
- func (s *RelayStore) DeleteLabel(targetID, scopeType, scopeID string) error
- func (s *RelayStore) DeleteSession(token string) error
- func (s *RelayStore) DeleteSkill(name string) error
- func (s *RelayStore) DeleteToken(token string) error
- func (s *RelayStore) GetActiveOrgSubscription(orgID string) (*Subscription, error)
- func (s *RelayStore) GetActivePersonalSubscription(userID string) (*Subscription, error)
- func (s *RelayStore) GetDeviceCode(code string) (*DeviceCodeRow, error)
- func (s *RelayStore) GetDeviceCodeByUserCode(userCode string) (*DeviceCodeRow, error)
- func (s *RelayStore) GetInviteByToken(token string) (*OrgInvite, error)
- func (s *RelayStore) GetOrCreateUserByEmail(email string) (*User, error)
- func (s *RelayStore) GetOrgByID(id string) (*Org, error)
- func (s *RelayStore) GetOrgBySlug(slug string) (*Org, error)
- func (s *RelayStore) GetOrgMemberRole(orgID, userID string) string
- func (s *RelayStore) GetRelayConfig(key string) (string, error)
- func (s *RelayStore) GetSession(token string) (*User, error)
- func (s *RelayStore) GetSkill(name string) (*SkillRow, error)
- func (s *RelayStore) GetUserByEmail(email string) (*User, error)
- func (s *RelayStore) GetUserByID(id string) (*User, error)
- func (s *RelayStore) GetUserByProvider(provider, providerID string) (*User, error)
- func (s *RelayStore) IsOrgMember(orgID, userID string) bool
- func (s *RelayStore) IsUserPro(userID string) bool
- func (s *RelayStore) ListOrgMembers(orgID string) ([]*OrgMember, error)
- func (s *RelayStore) ListOrgsForUser(userID string) ([]*Org, error)
- func (s *RelayStore) ListPendingInvites(orgID string) ([]*OrgInvite, error)
- func (s *RelayStore) ListSkills(category string) ([]*SkillRow, error)
- func (s *RelayStore) RemoveOrgMember(orgID, userID string) error
- func (s *RelayStore) ResolveLabel(targetID, userID, orgID string) string
- func (s *RelayStore) ResolveLabels(targetIDs []string, userID, orgID string) map[string]string
- func (s *RelayStore) RevokeOrgInvite(token string) error
- func (s *RelayStore) SearchSkills(query string) ([]*SkillRow, error)
- func (s *RelayStore) SetLabel(targetID, scopeType, scopeID, label string) error
- func (s *RelayStore) SetOrgMaxSeats(orgID string, seats int) error
- func (s *RelayStore) SetRelayConfig(key, value string) error
- func (s *RelayStore) UpdateSubscriptionSeats(subID string, seats int) error
- func (s *RelayStore) UpdateSubscriptionStatus(subID, status string) error
- func (s *RelayStore) UpdateUserEmail(userID, email string) error
- func (s *RelayStore) UpdateUserTier(userID, tier string) error
- func (s *RelayStore) UpsertUser(u *User) error
- func (s *RelayStore) ValidateToken(token string) (userID string, deviceID string, err error)
- type Server
- func (s *Server) GracefulShutdown(httpSrv *http.Server, timeout time.Duration) error
- func (s *Server) IsEdge() bool
- func (s *Server) IsLogin() bool
- func (s *Server) MachineID() string
- func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (s *Server) SetLocalUser(u *User)
- func (s *Server) SetLoginProxy(p http.Handler)
- func (s *Server) SetSessionCache(sc *SessionCache)
- func (s *Server) StartClusterExpiry(ctx context.Context)
- func (s *Server) StartEdgeSync(ctx context.Context, loginAddr string, interval time.Duration)
- type ServerConfig
- type SessionCache
- type SessionValidation
- type SkillRow
- type Subscription
- type SyncRequest
- type SyncResponse
- type SyncWing
- type TierLookup
- type User
- type WingClaims
- type WingEvent
- type WingInfo
- type WingRegistry
- func (r *WingRegistry) Add(w *ConnectedWing)
- func (r *WingRegistry) All() []*ConnectedWing
- func (r *WingRegistry) BroadcastAll(ctx context.Context, data []byte)
- func (r *WingRegistry) CloseAll()
- func (r *WingRegistry) CountForUser(userID string) int
- func (r *WingRegistry) FindByID(wingID string) *ConnectedWing
- func (r *WingRegistry) ListForUser(userID string) []*ConnectedWing
- func (r *WingRegistry) RegisterAuditRequest(reqID string, ch chan any)
- func (r *WingRegistry) RegisterDirRequest(reqID string, ch chan *ws.DirResults)
- func (r *WingRegistry) RegisterHistoryRequest(reqID string, ch chan *ws.SessionsHistoryResults)
- func (r *WingRegistry) RegisterSessionRequest(reqID string, ch chan *ws.SessionsSync)
- func (r *WingRegistry) Remove(id string)
- func (r *WingRegistry) ResolveAuditMessage(reqID string, msg any)
- func (r *WingRegistry) ResolveDirRequest(reqID string, results *ws.DirResults)
- func (r *WingRegistry) ResolveHistoryRequest(reqID string, results *ws.SessionsHistoryResults)
- func (r *WingRegistry) ResolveSessionRequest(reqID string, results *ws.SessionsSync)
- func (r *WingRegistry) Subscribe(userID string, ch chan WingEvent)
- func (r *WingRegistry) Touch(wingID string)
- func (r *WingRegistry) UnregisterAuditRequest(reqID string)
- func (r *WingRegistry) UnregisterDirRequest(reqID string)
- func (r *WingRegistry) UnregisterHistoryRequest(reqID string)
- func (r *WingRegistry) UnregisterSessionRequest(reqID string)
- func (r *WingRegistry) Unsubscribe(userID string, ch chan WingEvent)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GenerateOrLoadSecret ¶
func GenerateOrLoadSecret(store *RelayStore, envSecret string) ([]byte, error)
GenerateOrLoadSecret returns the JWT signing secret. Priority: envSecret (from WT_JWT_SECRET) > relay_config DB > auto-generate.
func IssueWingJWT ¶
IssueWingJWT creates a signed JWT for a wing connection.
func NewLoginProxy ¶ added in v0.23.0
func NewLoginProxy(loginAddr string) *httputil.ReverseProxy
NewLoginProxy creates a reverse proxy to the login node for edge nodes. Edge nodes proxy API, auth, and page requests to the login node while serving WebSocket connections directly.
func SeedDefaultSkills ¶
func SeedDefaultSkills(store *RelayStore) error
func WaitForWing ¶ added in v0.23.0
func WaitForWing(ctx context.Context, local *WingRegistry, peers *PeerDirectory, wingID string, timeout time.Duration) (machineID string, found bool)
WaitForWing waits for a wing to appear locally or via sync.
Types ¶
type BandwidthMeter ¶
type BandwidthMeter struct {
// contains filtered or unexported fields
}
BandwidthMeter applies per-user rate limiting on relay traffic and periodically syncs usage to the DB.
func NewBandwidthMeter ¶
func NewBandwidthMeter(bytesPerSec int, burst int, db *sql.DB) *BandwidthMeter
NewBandwidthMeter creates a meter with the given sustained rate (bytes/sec) and burst (bytes).
func (*BandwidthMeter) AddUsage ¶ added in v0.23.0
func (b *BandwidthMeter) AddUsage(userID string, bytes int64)
AddUsage adds external usage bytes (reported by edge nodes) to the local counters.
func (*BandwidthMeter) DrainCounters ¶ added in v0.23.0
func (b *BandwidthMeter) DrainCounters() map[string]int64
DrainCounters returns per-user byte counts accumulated since the last drain, then resets them. Used by edge nodes to report usage to login via the sync protocol.
func (*BandwidthMeter) ExceededMonthly ¶ added in v0.23.0
func (b *BandwidthMeter) ExceededMonthly(userID string) bool
ExceededMonthly returns true if a free-tier user has exceeded their monthly cap. Always returns false for pro/team users.
func (*BandwidthMeter) ExceededUsers ¶ added in v0.23.0
func (b *BandwidthMeter) ExceededUsers() []string
ExceededUsers returns user IDs that have exceeded their monthly bandwidth cap. Only meaningful on the login node where counters reflect cluster-wide totals.
func (*BandwidthMeter) InvalidateUser ¶ added in v0.23.0
func (b *BandwidthMeter) InvalidateUser(userID string)
func (*BandwidthMeter) IsExceeded ¶ added in v0.23.0
func (b *BandwidthMeter) IsExceeded(userID string) bool
IsExceeded returns true if a user has been flagged as over their monthly cap.
func (*BandwidthMeter) MonthlyUsage ¶ added in v0.23.0
func (b *BandwidthMeter) MonthlyUsage(userID string) int64
MonthlyUsage returns the user's current month bandwidth usage in bytes.
func (*BandwidthMeter) SeedFromDB ¶ added in v0.23.0
func (b *BandwidthMeter) SeedFromDB()
SeedFromDB loads current month's bandwidth totals from the DB into memory. Called on login startup to avoid resetting counters to zero.
func (*BandwidthMeter) SetExceeded ¶ added in v0.23.0
func (b *BandwidthMeter) SetExceeded(userIDs []string)
SetExceeded replaces the set of users who exceeded their monthly cap (pushed from login via sync).
func (*BandwidthMeter) SetTierLookup ¶ added in v0.23.0
func (b *BandwidthMeter) SetTierLookup(fn TierLookup)
SetTierLookup sets the function used to look up user tiers for rate differentiation.
type ChatRegistry ¶
type ChatRegistry struct {
// contains filtered or unexported fields
}
ChatRegistry tracks active chat sessions.
func NewChatRegistry ¶
func NewChatRegistry() *ChatRegistry
func (*ChatRegistry) Add ¶
func (r *ChatRegistry) Add(s *ChatSession)
func (*ChatRegistry) All ¶ added in v0.23.0
func (r *ChatRegistry) All() []*ChatSession
All returns all chat sessions.
func (*ChatRegistry) CountForUser ¶
func (r *ChatRegistry) CountForUser(userID string) int
CountForUser returns the number of chat sessions for a given user.
func (*ChatRegistry) Get ¶
func (r *ChatRegistry) Get(id string) *ChatSession
func (*ChatRegistry) ListForUser ¶
func (r *ChatRegistry) ListForUser(userID string) []*ChatSession
ListForUser returns all chat sessions for a given user.
func (*ChatRegistry) Remove ¶
func (r *ChatRegistry) Remove(id string)
type ChatSession ¶
type ChatSession struct {
ID string
WingID string
UserID string
Agent string
Status string // "active", "exited"
BrowserConn *websocket.Conn
// contains filtered or unexported fields
}
ChatSession tracks a browser <-> wing chat connection through the relay.
type ClusterState ¶ added in v0.23.0
type ClusterState struct {
// contains filtered or unexported fields
}
ClusterState tracks wings across all nodes (login node only). Edges send their full wing list every second; login merges and responds with the full cluster state. Dead nodes expire after 10s of silence.
func NewClusterState ¶ added in v0.23.0
func NewClusterState() *ClusterState
func (*ClusterState) All ¶ added in v0.23.0
func (c *ClusterState) All() []SyncWing
All returns all edge wings, expiring dead nodes first.
func (*ClusterState) Sync ¶ added in v0.23.0
func (c *ClusterState) Sync(nodeID string, wings []SyncWing) (others, all []SyncWing)
Sync replaces an edge's wing list, expires dead nodes, and returns:
- others: all wings except the requesting edge's (for edge response)
- all: all edge wings across all nodes (for login's PeerDirectory)
type ConnectedWing ¶
type ConnectedWing struct {
ID string
UserID string
WingID string
Hostname string // display name from os.Hostname()
Platform string // runtime.GOOS from wing
Version string // build version from wing
PublicKey string
Agents []string
Skills []string
Labels []string
Identities []string
Projects []ws.WingProject
EggConfig string // serialized YAML of wing's egg config
OrgID string // org slug this wing serves (from --org flag)
AllowEmails []string // explicit email allow list (from --allow flag)
RootDir string // root directory constraint (from --root flag)
Conn *websocket.Conn
LastSeen time.Time
}
ConnectedWing represents a wing connected via WebSocket.
type DeviceCodeRow ¶
type Entitlement ¶ added in v0.23.0
type EntitlementCache ¶ added in v0.23.0
type EntitlementCache struct {
// contains filtered or unexported fields
}
EntitlementCache caches user tier info on edge nodes, polling the login node periodically.
func NewEntitlementCache ¶ added in v0.23.0
func NewEntitlementCache(loginAddr string) *EntitlementCache
func (*EntitlementCache) GetTier ¶ added in v0.23.0
func (c *EntitlementCache) GetTier(userID string) string
GetTier returns the cached tier for a user, defaulting to "free".
type EntitlementEntry ¶ added in v0.23.0
EntitlementEntry is a user's entitlement info for edge node caching.
type Org ¶ added in v0.23.0
type Org struct {
ID string
Name string
Slug string
OwnerUserID string
MaxSeats int
CreatedAt time.Time
}
Org represents an organization that can share wings among members.
type OrgInvite ¶ added in v0.23.0
type OrgInvite struct {
ID string
OrgID string
Email string
Token string
InvitedBy string
Role string
CreatedAt time.Time
ClaimedAt *time.Time
}
OrgInvite represents a pending invite to an org.
type OrgMember ¶ added in v0.23.0
type OrgMember struct {
OrgID string
UserID string
Role string // "owner", "admin", "member"
CreatedAt time.Time
}
OrgMember represents a user's membership in an org.
type PTYRegistry ¶
type PTYRegistry struct {
// contains filtered or unexported fields
}
PTYRegistry tracks active PTY sessions.
func NewPTYRegistry ¶
func NewPTYRegistry() *PTYRegistry
func (*PTYRegistry) Add ¶
func (r *PTYRegistry) Add(s *PTYSession) bool
func (*PTYRegistry) All ¶ added in v0.23.0
func (r *PTYRegistry) All() []*PTYSession
All returns all PTY sessions.
func (*PTYRegistry) CountForUser ¶
func (r *PTYRegistry) CountForUser(userID string) int
CountForUser returns the number of PTY sessions for a given user.
func (*PTYRegistry) Get ¶
func (r *PTYRegistry) Get(id string) *PTYSession
func (*PTYRegistry) IsTombstoned ¶ added in v0.7.34
func (r *PTYRegistry) IsTombstoned(id string) bool
IsTombstoned returns true if the session was recently deleted.
func (*PTYRegistry) ListForUser ¶
func (r *PTYRegistry) ListForUser(userID string) []*PTYSession
ListForUser returns all PTY sessions for a given user.
func (*PTYRegistry) Remove ¶
func (r *PTYRegistry) Remove(id string)
func (*PTYRegistry) SyncFromWing ¶ added in v0.7.32
func (r *PTYRegistry) SyncFromWing(wingID, userID string, sessions []ws.SessionInfo, removeStale bool)
SyncFromWing reconciles the registry with the wing's authoritative session list. When removeStale is true (on-demand requests), removes sessions the wing no longer reports. When false (heartbeat), only adds missing sessions.
type PTYSession ¶
type PTYSession struct {
ID string
WingID string
UserID string
Agent string
CWD string // working directory for this session
EggConfig string // serialized YAML of egg config at spawn time
NeedsAttention bool // terminal bell detected — session wants user attention
Status string // "active", "detached", "exited"
BrowserConn *websocket.Conn
// contains filtered or unexported fields
}
PTYSession tracks a browser <-> wing PTY connection through the relay.
type PeerDirectory ¶ added in v0.23.0
type PeerDirectory struct {
// contains filtered or unexported fields
}
PeerDirectory tracks wings on other nodes, updated via full-state sync.
func NewPeerDirectory ¶ added in v0.23.0
func NewPeerDirectory() *PeerDirectory
func (*PeerDirectory) AllWings ¶ added in v0.23.0
func (p *PeerDirectory) AllWings() []*PeerWing
AllWings returns all known remote wings.
func (*PeerDirectory) CountForUser ¶ added in v0.23.0
func (p *PeerDirectory) CountForUser(userID string) int
CountForUser returns the number of peer wings for a given user.
func (*PeerDirectory) FindByWingID ¶ added in v0.27.0
func (p *PeerDirectory) FindByWingID(wingID string) *PeerWing
FindByWingID looks up a peer wing by its persistent wing ID.
func (*PeerDirectory) FindWing ¶ added in v0.23.0
func (p *PeerDirectory) FindWing(wingID string) *PeerWing
FindWing looks up a wing by ID.
func (*PeerDirectory) RemoveWing ¶ added in v0.23.0
func (p *PeerDirectory) RemoveWing(wingID string)
RemoveWing removes a single wing.
func (*PeerDirectory) Replace ¶ added in v0.23.0
func (p *PeerDirectory) Replace(wings []*PeerWing) (added, removed []*PeerWing)
Replace swaps the entire wing set and returns the diff.
func (*PeerDirectory) UpdateCh ¶ added in v0.23.0
func (p *PeerDirectory) UpdateCh() <-chan struct{}
UpdateCh returns a channel signaled on updates.
type PeerWing ¶ added in v0.23.0
type PeerWing struct {
WingID string
MachineID string // Fly machine hosting this wing (for fly-replay)
NodeID string
WingInfo *WingInfo
}
PeerWing represents a wing connected to a remote node.
type RateLimiter ¶ added in v0.12.0
type RateLimiter struct {
// contains filtered or unexported fields
}
RateLimiter applies per-IP request rate limiting. "Friends and family" limits — just enough to prevent abuse.
func NewRateLimiter ¶ added in v0.12.0
func NewRateLimiter(reqPerSec float64, burst int) *RateLimiter
NewRateLimiter creates a per-IP rate limiter. reqPerSec is the sustained rate, burst is the max burst size.
func (*RateLimiter) Allow ¶ added in v0.12.0
func (rl *RateLimiter) Allow(ip string) bool
Allow returns true if the request is within rate limits for the given IP.
func (*RateLimiter) Middleware ¶ added in v0.12.0
func (rl *RateLimiter) Middleware(next http.Handler) http.Handler
Middleware wraps an http.Handler with rate limiting.
type RelayStore ¶
type RelayStore struct {
// contains filtered or unexported fields
}
func OpenRelay ¶
func OpenRelay(dsn string) (*RelayStore, error)
func (*RelayStore) AddOrgMember ¶ added in v0.23.0
func (s *RelayStore) AddOrgMember(orgID, userID, role string) error
AddOrgMember adds a user to an org, enforcing max_seats.
func (*RelayStore) AppendAudit ¶
func (s *RelayStore) AppendAudit(userID, event string, detail *string) error
func (*RelayStore) BackfillProUsers ¶ added in v0.23.0
func (s *RelayStore) BackfillProUsers() error
func (*RelayStore) ClaimDeviceCode ¶
func (s *RelayStore) ClaimDeviceCode(code, userID string) error
func (*RelayStore) Close ¶
func (s *RelayStore) Close() error
func (*RelayStore) ConsumeMagicLink ¶
func (s *RelayStore) ConsumeMagicLink(token string) (string, error)
func (*RelayStore) ConsumeOrgInvite ¶ added in v0.23.0
ConsumeOrgInvite validates a token, marks it claimed, returns email, orgID, and role.
func (*RelayStore) CountEntitlementsBySub ¶ added in v0.23.0
func (s *RelayStore) CountEntitlementsBySub(subID string) (int, error)
func (*RelayStore) CountOrgMembers ¶ added in v0.23.0
func (s *RelayStore) CountOrgMembers(orgID string) (int, error)
CountOrgMembers returns the number of members in an org.
func (*RelayStore) CountOrgsOwnedByUser ¶ added in v0.32.1
func (s *RelayStore) CountOrgsOwnedByUser(userID string) (int, error)
CountOrgsOwnedByUser returns the number of orgs a user has created.
func (*RelayStore) CreateDeviceCode ¶
func (s *RelayStore) CreateDeviceCode(code, userCode, deviceID string, expiresAt time.Time) error
func (*RelayStore) CreateDeviceCodeWithKey ¶
func (s *RelayStore) CreateDeviceCodeWithKey(code, userCode, deviceID, publicKey string, expiresAt time.Time) error
func (*RelayStore) CreateDeviceToken ¶
func (s *RelayStore) CreateDeviceToken(token, userID, deviceID string, expiresAt *time.Time) error
func (*RelayStore) CreateEntitlement ¶ added in v0.23.0
func (s *RelayStore) CreateEntitlement(ent *Entitlement) error
func (*RelayStore) CreateLocalUser ¶ added in v0.7.4
func (s *RelayStore) CreateLocalUser() (*User, string, error)
CreateLocalUser creates the local-mode user and a non-expiring device token. Returns the social user, device token string, and whether the user already existed.
func (*RelayStore) CreateMagicLink ¶
func (s *RelayStore) CreateMagicLink(id, email, token string, expiresAt time.Time) error
func (*RelayStore) CreateOrg ¶ added in v0.23.0
func (s *RelayStore) CreateOrg(id, name, slug, ownerUserID string) error
CreateOrg creates a new org and adds the owner as an owner member.
func (*RelayStore) CreateOrgInvite ¶ added in v0.23.0
func (s *RelayStore) CreateOrgInvite(id, orgID, email, token, invitedBy, role string) error
CreateOrgInvite creates a pending invite.
func (*RelayStore) CreateSession ¶
func (s *RelayStore) CreateSession(token, userID string, expiresAt time.Time) error
func (*RelayStore) CreateSkill ¶
func (s *RelayStore) CreateSkill(name, description, category, agent, tags, content, sha256, publisher, sourceURL string, weight int) error
func (*RelayStore) CreateSubscription ¶ added in v0.23.0
func (s *RelayStore) CreateSubscription(sub *Subscription) error
func (*RelayStore) CreateUser ¶
func (s *RelayStore) CreateUser(id string) error
func (*RelayStore) CreateUserDev ¶ added in v0.23.0
func (s *RelayStore) CreateUserDev() (*User, error)
CreateUserDev creates a dev-mode social user if one doesn't exist.
func (*RelayStore) DB ¶
func (s *RelayStore) DB() *sql.DB
DB returns the underlying database connection.
func (*RelayStore) DeleteEntitlementByUserAndSub ¶ added in v0.23.0
func (s *RelayStore) DeleteEntitlementByUserAndSub(userID, subID string) error
func (*RelayStore) DeleteEntitlementsBySub ¶ added in v0.23.0
func (s *RelayStore) DeleteEntitlementsBySub(subID string) ([]string, error)
func (*RelayStore) DeleteLabel ¶ added in v0.23.0
func (s *RelayStore) DeleteLabel(targetID, scopeType, scopeID string) error
DeleteLabel removes a label for a target at a given scope.
func (*RelayStore) DeleteSession ¶
func (s *RelayStore) DeleteSession(token string) error
func (*RelayStore) DeleteSkill ¶
func (s *RelayStore) DeleteSkill(name string) error
func (*RelayStore) DeleteToken ¶
func (s *RelayStore) DeleteToken(token string) error
func (*RelayStore) GetActiveOrgSubscription ¶ added in v0.23.0
func (s *RelayStore) GetActiveOrgSubscription(orgID string) (*Subscription, error)
func (*RelayStore) GetActivePersonalSubscription ¶ added in v0.23.0
func (s *RelayStore) GetActivePersonalSubscription(userID string) (*Subscription, error)
func (*RelayStore) GetDeviceCode ¶
func (s *RelayStore) GetDeviceCode(code string) (*DeviceCodeRow, error)
func (*RelayStore) GetDeviceCodeByUserCode ¶
func (s *RelayStore) GetDeviceCodeByUserCode(userCode string) (*DeviceCodeRow, error)
GetDeviceCodeByUserCode finds a device code by user_code.
func (*RelayStore) GetInviteByToken ¶ added in v0.32.4
func (s *RelayStore) GetInviteByToken(token string) (*OrgInvite, error)
GetInviteByToken returns an invite by its token (claimed or not).
func (*RelayStore) GetOrCreateUserByEmail ¶ added in v0.23.0
func (s *RelayStore) GetOrCreateUserByEmail(email string) (*User, error)
func (*RelayStore) GetOrgByID ¶ added in v0.23.0
func (s *RelayStore) GetOrgByID(id string) (*Org, error)
GetOrgByID returns an org by ID.
func (*RelayStore) GetOrgBySlug ¶ added in v0.23.0
func (s *RelayStore) GetOrgBySlug(slug string) (*Org, error)
GetOrgBySlug returns an org by slug.
func (*RelayStore) GetOrgMemberRole ¶ added in v0.23.0
func (s *RelayStore) GetOrgMemberRole(orgID, userID string) string
GetOrgMemberRole returns the role of a user in an org, or "" if not a member.
func (*RelayStore) GetRelayConfig ¶
func (s *RelayStore) GetRelayConfig(key string) (string, error)
GetRelayConfig reads a value from the relay_config table.
func (*RelayStore) GetSession ¶
func (s *RelayStore) GetSession(token string) (*User, error)
func (*RelayStore) GetUserByEmail ¶ added in v0.23.0
func (s *RelayStore) GetUserByEmail(email string) (*User, error)
GetUserByEmail returns a user by email.
func (*RelayStore) GetUserByID ¶ added in v0.23.0
func (s *RelayStore) GetUserByID(id string) (*User, error)
GetUserByID returns a user by their ID.
func (*RelayStore) GetUserByProvider ¶ added in v0.23.0
func (s *RelayStore) GetUserByProvider(provider, providerID string) (*User, error)
func (*RelayStore) IsOrgMember ¶ added in v0.23.0
func (s *RelayStore) IsOrgMember(orgID, userID string) bool
IsOrgMember returns true if the user is a member of the org.
func (*RelayStore) IsUserPro ¶ added in v0.23.0
func (s *RelayStore) IsUserPro(userID string) bool
func (*RelayStore) ListOrgMembers ¶ added in v0.23.0
func (s *RelayStore) ListOrgMembers(orgID string) ([]*OrgMember, error)
ListOrgMembers returns all members of an org with their user info.
func (*RelayStore) ListOrgsForUser ¶ added in v0.23.0
func (s *RelayStore) ListOrgsForUser(userID string) ([]*Org, error)
ListOrgsForUser returns all orgs a user belongs to.
func (*RelayStore) ListPendingInvites ¶ added in v0.23.0
func (s *RelayStore) ListPendingInvites(orgID string) ([]*OrgInvite, error)
ListPendingInvites returns unclaimed invites for an org.
func (*RelayStore) ListSkills ¶
func (s *RelayStore) ListSkills(category string) ([]*SkillRow, error)
func (*RelayStore) RemoveOrgMember ¶ added in v0.23.0
func (s *RelayStore) RemoveOrgMember(orgID, userID string) error
RemoveOrgMember removes a user from an org.
func (*RelayStore) ResolveLabel ¶ added in v0.23.0
func (s *RelayStore) ResolveLabel(targetID, userID, orgID string) string
ResolveLabel returns the best label for a target: org-scoped first, then personal.
func (*RelayStore) ResolveLabels ¶ added in v0.23.0
func (s *RelayStore) ResolveLabels(targetIDs []string, userID, orgID string) map[string]string
ResolveLabels batch-resolves labels for multiple targets.
func (*RelayStore) RevokeOrgInvite ¶ added in v0.32.4
func (s *RelayStore) RevokeOrgInvite(token string) error
RevokeOrgInvite deletes a pending invite by token.
func (*RelayStore) SearchSkills ¶
func (s *RelayStore) SearchSkills(query string) ([]*SkillRow, error)
func (*RelayStore) SetLabel ¶ added in v0.23.0
func (s *RelayStore) SetLabel(targetID, scopeType, scopeID, label string) error
SetLabel upserts a label for a target (wing or session).
func (*RelayStore) SetOrgMaxSeats ¶ added in v0.23.0
func (s *RelayStore) SetOrgMaxSeats(orgID string, seats int) error
SetOrgMaxSeats updates the max seat count for an org.
func (*RelayStore) SetRelayConfig ¶
func (s *RelayStore) SetRelayConfig(key, value string) error
SetRelayConfig writes a value to the relay_config table.
func (*RelayStore) UpdateSubscriptionSeats ¶ added in v0.23.0
func (s *RelayStore) UpdateSubscriptionSeats(subID string, seats int) error
UpdateSubscriptionSeats updates the seat count on a subscription.
func (*RelayStore) UpdateSubscriptionStatus ¶ added in v0.23.0
func (s *RelayStore) UpdateSubscriptionStatus(subID, status string) error
func (*RelayStore) UpdateUserEmail ¶ added in v0.23.0
func (s *RelayStore) UpdateUserEmail(userID, email string) error
UpdateUserEmail sets the email for a user.
func (*RelayStore) UpdateUserTier ¶ added in v0.23.0
func (s *RelayStore) UpdateUserTier(userID, tier string) error
UpdateUserTier sets the tier for a user.
func (*RelayStore) UpsertUser ¶ added in v0.23.0
func (s *RelayStore) UpsertUser(u *User) error
func (*RelayStore) ValidateToken ¶
func (s *RelayStore) ValidateToken(token string) (userID string, deviceID string, err error)
type Server ¶
type Server struct {
Store *RelayStore
Config ServerConfig
DevTemplateDir string // if set, re-read templates from disk on each request
DevMode bool // if set, auto-claim device codes with test-user
LocalMode bool // if set, bypass auth — single-user, zero-config
Wings *WingRegistry
PTY *PTYRegistry
Chat *ChatRegistry
Bandwidth *BandwidthMeter
RateLimit *RateLimiter
// Cluster sync (multi-node)
Peers *PeerDirectory
Cluster *ClusterState
EntitlementCache *EntitlementCache
// contains filtered or unexported fields
}
func NewServer ¶
func NewServer(store *RelayStore, cfg ServerConfig) *Server
func (*Server) GracefulShutdown ¶ added in v0.23.0
GracefulShutdown sends relay.restart to all connected WebSockets, then shuts down the HTTP server.
func (*Server) IsEdge ¶ added in v0.23.0
IsEdge returns true if this node is an edge relay (no SQLite).
func (*Server) MachineID ¶ added in v0.23.0
MachineID returns this node's unique machine identifier.
func (*Server) SetLocalUser ¶ added in v0.7.4
func (*Server) SetLoginProxy ¶ added in v0.23.0
SetLoginProxy sets the reverse proxy used by edge nodes to forward requests to the login node.
func (*Server) SetSessionCache ¶ added in v0.23.0
func (s *Server) SetSessionCache(sc *SessionCache)
SetSessionCache sets the session cache for edge nodes.
func (*Server) StartClusterExpiry ¶ added in v0.23.0
StartClusterExpiry periodically expires dead edge nodes on the login node.
type ServerConfig ¶
type ServerConfig struct {
BaseURL string
AppHost string // e.g. "app.wingthing.ai" — serve SPA at root
WSHost string // e.g. "ws.wingthing.ai" — WebSocket only
JWTSecret string // base64-encoded; overrides DB-stored secret
GitHubClientID string
GitHubClientSecret string
GoogleClientID string
GoogleClientSecret string
SMTPHost string
SMTPPort string
SMTPUser string
SMTPPass string
SMTPFrom string
NodeRole string // "login", "edge", or "" (single node)
LoginNodeAddr string // internal address of login node (for edge nodes)
FlyMachineID string // from FLY_MACHINE_ID env var
FlyRegion string // from FLY_REGION env var
}
type SessionCache ¶ added in v0.23.0
type SessionCache struct {
// contains filtered or unexported fields
}
SessionCache caches session token → user info on edge nodes. Each validated session is cached for 5 minutes to avoid hitting the login node on every request.
func NewSessionCache ¶ added in v0.23.0
func NewSessionCache() *SessionCache
func (*SessionCache) Validate ¶ added in v0.23.0
func (sc *SessionCache) Validate(token, loginAddr string) *User
Validate checks the cache or calls the login node to validate a session token.
type SessionValidation ¶ added in v0.23.0
type SessionValidation struct {
UserID string `json:"user_id"`
DisplayName string `json:"display_name"`
Tier string `json:"tier"`
}
SessionValidation is the response from the session validation endpoint.
type Subscription ¶ added in v0.23.0
type SyncRequest ¶ added in v0.23.0
type SyncRequest struct {
NodeID string `json:"node_id"`
Wings []SyncWing `json:"wings"`
Bandwidth map[string]int64 `json:"bandwidth,omitempty"` // userID → bytes since last sync
}
SyncRequest is sent from edge to login every sync interval.
type SyncResponse ¶ added in v0.23.0
type SyncResponse struct {
Wings []SyncWing `json:"wings"`
BannedUsers []string `json:"banned_users,omitempty"`
}
SyncResponse is the full cluster state returned from login.
type SyncWing ¶ added in v0.23.0
type SyncWing struct {
WingID string `json:"wing_id"`
NodeID string `json:"node_id"`
Info WingInfo `json:"info"`
}
SyncWing is a wing entry in the cluster sync protocol.
type TierLookup ¶ added in v0.23.0
TierLookup returns a user's tier string ("free", "pro", "team").
type User ¶ added in v0.23.0
type User struct {
ID string
Provider string
ProviderID string
DisplayName string
AvatarURL *string
Email *string
Tier string // "free", "pro", "team"
IsPro bool
CreatedAt time.Time
}
User represents an authenticated user (via OAuth, magic link, or local mode).
type WingClaims ¶
type WingClaims struct {
jwt.RegisteredClaims
PublicKey string `json:"pub,omitempty"`
WingID string `json:"wing,omitempty"`
}
WingClaims are the JWT claims for a wing connection.
func ValidateWingJWT ¶
func ValidateWingJWT(secret []byte, tokenString string) (*WingClaims, error)
ValidateWingJWT verifies a JWT and returns the claims.
type WingEvent ¶ added in v0.7.5
type WingEvent struct {
Type string `json:"type"` // "wing.online" or "wing.offline"
ConnID string `json:"conn_id"`
WingID string `json:"wing_id"`
Hostname string `json:"hostname,omitempty"`
Platform string `json:"platform,omitempty"`
Version string `json:"version,omitempty"`
Agents []string `json:"agents,omitempty"`
Labels []string `json:"labels,omitempty"`
PublicKey string `json:"public_key,omitempty"`
Projects []ws.WingProject `json:"projects,omitempty"`
}
WingEvent is sent to dashboard subscribers when a wing connects or disconnects.
type WingInfo ¶ added in v0.23.0
type WingInfo struct {
UserID string `json:"user_id"`
WingID string `json:"wing_id,omitempty"`
Hostname string `json:"hostname,omitempty"`
Platform string `json:"platform,omitempty"`
Version string `json:"version,omitempty"`
Agents []string `json:"agents,omitempty"`
Labels []string `json:"labels,omitempty"`
Projects []ws.WingProject `json:"projects,omitempty"`
PublicKey string `json:"public_key,omitempty"`
OrgID string `json:"org_id,omitempty"`
}
WingInfo contains summary info about a wing for cluster sync.
type WingRegistry ¶
type WingRegistry struct {
// OnWingEvent is called after Add/Remove with the wing and event.
// The Server uses this to notify org members (the registry itself
// only knows about the wing owner).
OnWingEvent func(wing *ConnectedWing, ev WingEvent)
// contains filtered or unexported fields
}
WingRegistry tracks all connected wings.
func NewWingRegistry ¶
func NewWingRegistry() *WingRegistry
func (*WingRegistry) Add ¶
func (r *WingRegistry) Add(w *ConnectedWing)
func (*WingRegistry) All ¶ added in v0.23.0
func (r *WingRegistry) All() []*ConnectedWing
All returns all connected wings.
func (*WingRegistry) BroadcastAll ¶ added in v0.23.0
func (r *WingRegistry) BroadcastAll(ctx context.Context, data []byte)
BroadcastAll sends a message to every connected wing.
func (*WingRegistry) CloseAll ¶ added in v0.23.0
func (r *WingRegistry) CloseAll()
CloseAll closes all connected wing WebSockets.
func (*WingRegistry) CountForUser ¶
func (r *WingRegistry) CountForUser(userID string) int
CountForUser returns the number of wings connected for a given user.
func (*WingRegistry) FindByID ¶
func (r *WingRegistry) FindByID(wingID string) *ConnectedWing
func (*WingRegistry) ListForUser ¶
func (r *WingRegistry) ListForUser(userID string) []*ConnectedWing
ListForUser returns all wings connected for a given user.
func (*WingRegistry) RegisterAuditRequest ¶ added in v0.23.0
func (r *WingRegistry) RegisterAuditRequest(reqID string, ch chan any)
func (*WingRegistry) RegisterDirRequest ¶ added in v0.6.3
func (r *WingRegistry) RegisterDirRequest(reqID string, ch chan *ws.DirResults)
func (*WingRegistry) RegisterHistoryRequest ¶ added in v0.23.0
func (r *WingRegistry) RegisterHistoryRequest(reqID string, ch chan *ws.SessionsHistoryResults)
func (*WingRegistry) RegisterSessionRequest ¶ added in v0.7.32
func (r *WingRegistry) RegisterSessionRequest(reqID string, ch chan *ws.SessionsSync)
func (*WingRegistry) Remove ¶
func (r *WingRegistry) Remove(id string)
func (*WingRegistry) ResolveAuditMessage ¶ added in v0.23.0
func (r *WingRegistry) ResolveAuditMessage(reqID string, msg any)
func (*WingRegistry) ResolveDirRequest ¶ added in v0.6.3
func (r *WingRegistry) ResolveDirRequest(reqID string, results *ws.DirResults)
func (*WingRegistry) ResolveHistoryRequest ¶ added in v0.23.0
func (r *WingRegistry) ResolveHistoryRequest(reqID string, results *ws.SessionsHistoryResults)
func (*WingRegistry) ResolveSessionRequest ¶ added in v0.7.32
func (r *WingRegistry) ResolveSessionRequest(reqID string, results *ws.SessionsSync)
func (*WingRegistry) Subscribe ¶ added in v0.7.5
func (r *WingRegistry) Subscribe(userID string, ch chan WingEvent)
func (*WingRegistry) Touch ¶
func (r *WingRegistry) Touch(wingID string)
func (*WingRegistry) UnregisterAuditRequest ¶ added in v0.23.0
func (r *WingRegistry) UnregisterAuditRequest(reqID string)
func (*WingRegistry) UnregisterDirRequest ¶ added in v0.6.3
func (r *WingRegistry) UnregisterDirRequest(reqID string)
func (*WingRegistry) UnregisterHistoryRequest ¶ added in v0.23.0
func (r *WingRegistry) UnregisterHistoryRequest(reqID string)
func (*WingRegistry) UnregisterSessionRequest ¶ added in v0.7.32
func (r *WingRegistry) UnregisterSessionRequest(reqID string)
func (*WingRegistry) Unsubscribe ¶ added in v0.7.5
func (r *WingRegistry) Unsubscribe(userID string, ch chan WingEvent)