Documentation
¶
Index ¶
- func GenerateOrLoadSecret(store *RelayStore, envSecret string) ([]byte, error)
- func IssueWingJWT(secret []byte, userID, publicKey, machineID string) (string, time.Time, error)
- func SeedDefaultSkills(store *RelayStore) error
- type BandwidthMeter
- type ChatRegistry
- type ChatSession
- type ConnectedWing
- type DeviceCodeRow
- type PTYRegistry
- func (r *PTYRegistry) Add(s *PTYSession) bool
- 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 RateLimiter
- type RelayStore
- func (s *RelayStore) AppendAudit(userID, event string, detail *string) 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) 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) CreateLocalUser() (*SocialUser, string, error)
- func (s *RelayStore) CreateMagicLink(id, email, token string, expiresAt time.Time) error
- func (s *RelayStore) CreateSession(token, socialUserID string, expiresAt time.Time) error
- func (s *RelayStore) CreateSkill(...) error
- func (s *RelayStore) CreateSocialUserDev() (*SocialUser, error)
- func (s *RelayStore) CreateUser(id string) error
- func (s *RelayStore) DB() *sql.DB
- func (s *RelayStore) DeleteSession(token string) error
- func (s *RelayStore) DeleteSkill(name string) error
- func (s *RelayStore) DeleteToken(token string) error
- func (s *RelayStore) DequeueTask(taskID string) error
- func (s *RelayStore) EnqueueTask(t *ws.QueuedTask) error
- func (s *RelayStore) GetDeviceCode(code string) (*DeviceCodeRow, error)
- func (s *RelayStore) GetDeviceCodeByUserCode(userCode string) (*DeviceCodeRow, error)
- func (s *RelayStore) GetOrCreateSocialUserByEmail(email string) (*SocialUser, error)
- func (s *RelayStore) GetRelayConfig(key string) (string, error)
- func (s *RelayStore) GetSession(token string) (*SocialUser, error)
- func (s *RelayStore) GetSkill(name string) (*SkillRow, error)
- func (s *RelayStore) GetSocialUserByProvider(provider, providerID string) (*SocialUser, error)
- func (s *RelayStore) ListPendingTasks(userID string) ([]*ws.QueuedTask, error)
- func (s *RelayStore) ListSkills(category string) ([]*SkillRow, error)
- func (s *RelayStore) SearchSkills(query string) ([]*SkillRow, error)
- func (s *RelayStore) SetRelayConfig(key, value string) error
- func (s *RelayStore) UpsertSocialUser(u *SocialUser) error
- func (s *RelayStore) ValidateToken(token string) (userID string, deviceID string, err error)
- type Server
- type ServerConfig
- type SkillRow
- type SocialUser
- type WingClaims
- type WingEvent
- type WingRegistry
- func (r *WingRegistry) Add(w *ConnectedWing)
- func (r *WingRegistry) CountForUser(userID string) int
- func (r *WingRegistry) FindByID(wingID string) *ConnectedWing
- func (r *WingRegistry) FindByIdentity(identity string) *ConnectedWing
- func (r *WingRegistry) FindForUser(userID string) *ConnectedWing
- func (r *WingRegistry) ListForUser(userID string) []*ConnectedWing
- func (r *WingRegistry) RegisterDirRequest(reqID string, ch chan *ws.DirResults)
- func (r *WingRegistry) RegisterSessionRequest(reqID string, ch chan *ws.SessionsSync)
- func (r *WingRegistry) Remove(id string)
- func (r *WingRegistry) ResolveDirRequest(reqID string, results *ws.DirResults)
- 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) UnregisterDirRequest(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 SeedDefaultSkills ¶
func SeedDefaultSkills(store *RelayStore) error
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).
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) 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 ConnectedWing ¶
type ConnectedWing struct {
ID string
UserID string
MachineID string
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
Conn *websocket.Conn
LastSeen time.Time
}
ConnectedWing represents a wing connected via WebSocket.
type DeviceCodeRow ¶
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) 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 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) AppendAudit ¶
func (s *RelayStore) AppendAudit(userID, event string, detail *string) 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) 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) CreateLocalUser ¶ added in v0.7.4
func (s *RelayStore) CreateLocalUser() (*SocialUser, 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) CreateSession ¶
func (s *RelayStore) CreateSession(token, socialUserID 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) CreateSocialUserDev ¶
func (s *RelayStore) CreateSocialUserDev() (*SocialUser, error)
CreateSocialUserDev creates a dev-mode social user if one doesn't exist.
func (*RelayStore) CreateUser ¶
func (s *RelayStore) CreateUser(id string) error
func (*RelayStore) DB ¶
func (s *RelayStore) DB() *sql.DB
DB returns the underlying database connection.
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) DequeueTask ¶
func (s *RelayStore) DequeueTask(taskID string) error
DequeueTask deletes a task from the queue after dispatch.
func (*RelayStore) EnqueueTask ¶
func (s *RelayStore) EnqueueTask(t *ws.QueuedTask) error
EnqueueTask stores a task in the offline queue. The payload is opaque JSON forwarded to the wing as-is — the relay never inspects it.
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) GetOrCreateSocialUserByEmail ¶
func (s *RelayStore) GetOrCreateSocialUserByEmail(email string) (*SocialUser, error)
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) (*SocialUser, error)
func (*RelayStore) GetSocialUserByProvider ¶
func (s *RelayStore) GetSocialUserByProvider(provider, providerID string) (*SocialUser, error)
func (*RelayStore) ListPendingTasks ¶
func (s *RelayStore) ListPendingTasks(userID string) ([]*ws.QueuedTask, error)
ListPendingTasks returns queued tasks for a user that haven't been dispatched.
func (*RelayStore) ListSkills ¶
func (s *RelayStore) ListSkills(category string) ([]*SkillRow, error)
func (*RelayStore) SearchSkills ¶
func (s *RelayStore) SearchSkills(query string) ([]*SkillRow, error)
func (*RelayStore) SetRelayConfig ¶
func (s *RelayStore) SetRelayConfig(key, value string) error
SetRelayConfig writes a value to the relay_config table.
func (*RelayStore) UpsertSocialUser ¶
func (s *RelayStore) UpsertSocialUser(u *SocialUser) 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
// contains filtered or unexported fields
}
func NewServer ¶
func NewServer(store *RelayStore, cfg ServerConfig) *Server
func (*Server) SetLocalUser ¶ added in v0.7.4
func (s *Server) SetLocalUser(u *SocialUser)
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
SMTPHost string
SMTPPort string
SMTPUser string
SMTPPass string
SMTPFrom string
}
type SocialUser ¶
type SocialUser struct {
ID string
Provider string
ProviderID string
DisplayName string
AvatarURL *string
IsPro bool
CreatedAt time.Time
}
SocialUser represents an authenticated user (via OAuth, magic link, or local mode).
type WingClaims ¶
type WingClaims struct {
jwt.RegisteredClaims
PublicKey string `json:"pub,omitempty"`
MachineID string `json:"machine,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"
WingID string `json:"wing_id"`
MachineID string `json:"machine_id"`
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 WingRegistry ¶
type WingRegistry struct {
// 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) 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) FindByIdentity ¶
func (r *WingRegistry) FindByIdentity(identity string) *ConnectedWing
func (*WingRegistry) FindForUser ¶
func (r *WingRegistry) FindForUser(userID string) *ConnectedWing
func (*WingRegistry) ListForUser ¶
func (r *WingRegistry) ListForUser(userID string) []*ConnectedWing
ListForUser returns all wings connected for a given user.
func (*WingRegistry) RegisterDirRequest ¶ added in v0.6.3
func (r *WingRegistry) RegisterDirRequest(reqID string, ch chan *ws.DirResults)
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) ResolveDirRequest ¶ added in v0.6.3
func (r *WingRegistry) ResolveDirRequest(reqID string, results *ws.DirResults)
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) UnregisterDirRequest ¶ added in v0.6.3
func (r *WingRegistry) UnregisterDirRequest(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)