mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
aa4faddade
Result: {"status":"keep","total_issues":8,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_usestdlibvars":0,"golint_wastedassign":0,"golint_total":8,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_usetesting":0,"golint_test_total":0,"golint_vetx_total":0,"eslint_problems":0,"eslint_errors":0,"eslint_warnings":0,"tsc_errors":0,"vitest_failed":0,"vitest_total":116,"measure_s":81}
160 lines
4.7 KiB
Go
160 lines
4.7 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Package wsclient provides WebSocket client abstractions for edge node communication.
|
|
package wsclient
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
pkgprotocol "github.com/Rain-kl/Wavelet/pkg/protocol"
|
|
shared "github.com/Rain-kl/Wavelet/pkg/wsclient"
|
|
)
|
|
|
|
// WSMessage is an alias for the shared WebSocket message type.
|
|
type WSMessage = shared.WSMessage
|
|
|
|
// MessageHandler is an alias for the shared WebSocket message handler type.
|
|
type MessageHandler = shared.MessageHandler
|
|
|
|
// Preset represents a predefined connection configuration for a specific edge role.
|
|
type Preset int
|
|
|
|
const (
|
|
// PresetAgent is the configuration preset for agent connections.
|
|
PresetAgent Preset = iota
|
|
// PresetRelay is the configuration preset for relay connections.
|
|
PresetRelay
|
|
// PresetFlared is the configuration preset for flared (tunnel) connections.
|
|
PresetFlared
|
|
)
|
|
|
|
type presetConfig struct {
|
|
HeaderKey string
|
|
WSPath string
|
|
}
|
|
|
|
var presets = map[Preset]presetConfig{
|
|
PresetAgent: {HeaderKey: "X-Agent-Token", WSPath: "/api/v1/agent/ws"},
|
|
PresetRelay: {HeaderKey: "X-Agent-Token", WSPath: "/api/v1/relay/ws"},
|
|
PresetFlared: {HeaderKey: "X-Tunnel-Token", WSPath: "/api/v1/tunnel/ws"},
|
|
}
|
|
|
|
// PresetHeaderKey returns the HTTP header key used for authentication with the given preset.
|
|
func PresetHeaderKey(preset Preset) string {
|
|
return presets[preset].HeaderKey
|
|
}
|
|
|
|
// PresetWSPath returns the WebSocket path used for the given preset.
|
|
func PresetWSPath(preset Preset) string {
|
|
return presets[preset].WSPath
|
|
}
|
|
|
|
// Client is a WebSocket client configured for a specific edge preset.
|
|
type Client struct {
|
|
sharedClient *shared.Client
|
|
}
|
|
|
|
// New creates a new Client for the given preset, base URL, token, and timeout.
|
|
func New(preset Preset, baseURL, token string, timeout time.Duration) *Client {
|
|
cfg := presets[preset]
|
|
return &Client{
|
|
sharedClient: shared.New(shared.Config{
|
|
BaseURL: baseURL,
|
|
Token: token,
|
|
Timeout: timeout,
|
|
HeaderKey: cfg.HeaderKey,
|
|
WSPath: cfg.WSPath,
|
|
}),
|
|
}
|
|
}
|
|
|
|
// SetToken updates the authentication token used by the client.
|
|
func (c *Client) SetToken(token string) {
|
|
c.sharedClient.SetToken(token)
|
|
}
|
|
|
|
// URL returns the fully resolved WebSocket URL for this client.
|
|
func (c *Client) URL() string {
|
|
return c.sharedClient.URL()
|
|
}
|
|
|
|
// Connection represents an established WebSocket connection to an edge node.
|
|
type Connection struct {
|
|
sharedConn *shared.Connection
|
|
}
|
|
|
|
// Connect establishes a WebSocket connection using the client configuration.
|
|
func (c *Client) Connect(ctx context.Context) (*Connection, error) {
|
|
conn, err := c.sharedClient.Connect(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Connection{sharedConn: conn}, nil
|
|
}
|
|
|
|
// AgentConnection is a Connection specialized for agent node communication.
|
|
type AgentConnection struct {
|
|
Connection
|
|
}
|
|
|
|
// ConnectAgent establishes a WebSocket connection and returns it as an AgentConnection.
|
|
func (c *Client) ConnectAgent(ctx context.Context) (*AgentConnection, error) {
|
|
conn, err := c.Connect(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &AgentConnection{Connection: *conn}, nil
|
|
}
|
|
|
|
// URL returns the resolved WebSocket URL of this connection.
|
|
func (conn *Connection) URL() string {
|
|
if conn == nil || conn.sharedConn == nil {
|
|
return ""
|
|
}
|
|
return conn.sharedConn.URL
|
|
}
|
|
|
|
// SendPing sends a ping message over the connection.
|
|
func (conn *Connection) SendPing() error {
|
|
return conn.sharedConn.SendMessage(pkgprotocol.WSMessageTypePing, nil)
|
|
}
|
|
|
|
// SendPong sends a pong message over the connection.
|
|
func (conn *Connection) SendPong() error {
|
|
return conn.sharedConn.SendMessage(pkgprotocol.WSMessageTypePong, nil)
|
|
}
|
|
|
|
// SendMessage sends a typed message with an optional payload over the connection.
|
|
func (conn *Connection) SendMessage(msgType string, payload any) error {
|
|
return conn.sharedConn.SendMessage(msgType, payload)
|
|
}
|
|
|
|
// Receive reads the next message from the connection.
|
|
func (conn *Connection) Receive() (pkgprotocol.WSMessage, error) {
|
|
var message pkgprotocol.WSMessage
|
|
if err := conn.sharedConn.Receive(&message); err != nil {
|
|
return message, err
|
|
}
|
|
return message, nil
|
|
}
|
|
|
|
// RunReceiveLoop blocks and dispatches incoming messages to the handler until the context is canceled.
|
|
func (conn *Connection) RunReceiveLoop(ctx context.Context, handler MessageHandler) error {
|
|
return conn.sharedConn.RunReceiveLoop(ctx, handler)
|
|
}
|
|
|
|
// Close gracefully closes the WebSocket connection.
|
|
func (conn *Connection) Close() error {
|
|
if conn == nil || conn.sharedConn == nil {
|
|
return nil
|
|
}
|
|
return conn.sharedConn.Close()
|
|
}
|
|
|
|
// SendStatus sends a node status payload over the agent connection.
|
|
func (conn *AgentConnection) SendStatus(payload pkgprotocol.NodePayload) error {
|
|
return conn.sharedConn.SendMessage(pkgprotocol.WSMessageTypeStatus, payload)
|
|
}
|