honeybee

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Feb 4, 2026 License: MIT Imports: 10 Imported by: 0

README

go-honeybee - WebSocket Connection Management for Go

Source: https://git.wisehodl.dev/jay/go-honeybee

Mirror: https://github.com/wisehodl/go-honeybee

What this library does

go-honeybee provides reliable WebSocket connection primitives with automatic reconnection. It manages connection lifecycle, exponential backoff retry, and thread-safe message handling.

What this library does not do

go-honeybee does not implement protocol-specific message parsing, subscription management, or connection pooling (yet). It provides the foundation for building protocol implementations (like Nostr clients) on top of stable WebSocket connections.

Installation

Add go-honeybee to your project:

go get git.wisehodl.dev/jay/go-honeybee

If the primary repository is unavailable, use the replace directive in your go.mod:

replace git.wisehodl.dev/jay/go-honeybee => github.com/wisehodl/go-honeybee latest

Usage

Basic Connection
import "git.wisehodl.dev/jay/go-honeybee"

// Create connection
conn, err := honeybee.NewConnection("wss://relay.example.com", nil)
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

// Connect with default retry disabled
if err := conn.Connect(); err != nil {
    log.Fatal(err)
}

// Handle messages
go func() {
    for msg := range conn.Incoming() {
        // Process incoming message
    }
}()

// Handle errors
go func() {
    for err := range conn.Errors() {
        log.Printf("Connection error: %v", err)
    }
}()

// Send message
conn.Send([]byte(`{"type":"subscribe"}`))
Retry When Connecting
config := &honeybee.Config{
    Retry: &honeybee.RetryConfig{
        MaxRetries:   0,                  // 0 = infinite
        InitialDelay: 1 * time.Second,
        MaxDelay:     30 * time.Second,
        JitterFactor: 0.5,
    },
}

conn, err := honeybee.NewConnection("wss://relay.example.com", config)
Configuration Options
config, err := honeybee.NewConfig(
    honeybee.WithRetry(),
    honeybee.WithReadTimeout(30 * time.Second),
    honeybee.WithWriteTimeout(10 * time.Second),
)

conn, err := honeybee.NewConnection("wss://relay.example.com", config)

Connection States

Connections transition through these states:

  • StateDisconnected - Initial state, no socket
  • StateConnecting - Connection attempt in progress
  • StateConnected - Active connection, messages flowing
  • StateClosed - Connection terminated

Check current state with conn.State().

Testing

Run tests with:

go test ./...

Run with race detector:

go test -race ./...

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ParseURL

func ParseURL(urlStr string) (*url.URL, error)

func SetConfig

func SetConfig(config *Config, options ...ConfigOption) error

func ValidateConfig

func ValidateConfig(config *Config) error

Types

type CloseHandler

type CloseHandler func(code int, text string) error

type Config

type Config struct {
	CloseHandler CloseHandler
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
	Retry        *RetryConfig
}

func GetDefaultConfig

func GetDefaultConfig() *Config

func NewConfig

func NewConfig(options ...ConfigOption) (*Config, error)

type ConfigOption

type ConfigOption func(*Config) error

func WithCloseHandler

func WithCloseHandler(handler CloseHandler) ConfigOption

func WithReadTimeout

func WithReadTimeout(value time.Duration) ConfigOption

When ReadTimeout is set to zero, read timeouts are disabled.

func WithRetry

func WithRetry() ConfigOption

WithRetry enables retry with default parameters (infinite retries, 1s initial delay, 5s max delay, 0.5 jitter factor).

If passed after granular retry options (WithRetryMaxRetries, etc.), it will overwrite them. Use either WithRetry alone or the granular options; not both.

func WithRetryInitialDelay

func WithRetryInitialDelay(value time.Duration) ConfigOption

func WithRetryJitterFactor

func WithRetryJitterFactor(value float64) ConfigOption

func WithRetryMaxDelay

func WithRetryMaxDelay(value time.Duration) ConfigOption

func WithRetryMaxRetries

func WithRetryMaxRetries(value int) ConfigOption

func WithWriteTimeout

func WithWriteTimeout(value time.Duration) ConfigOption

When WriteTimeout is set to zero, read timeouts are disabled.

type Connection

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

func NewConnection

func NewConnection(urlStr string, config *Config, logger *slog.Logger) (*Connection, error)

func NewConnectionFromSocket

func NewConnectionFromSocket(socket Socket, config *Config, logger *slog.Logger) (*Connection, error)

func (*Connection) Close

func (c *Connection) Close() error

Close shuts down the connection and waits for goroutines to exit. If the underlying socket blocks indefinitely on read or write operations, Close will also block. This is expected behavior - hung sockets require external intervention (timeouts, process termination, etc).

func (*Connection) Connect

func (c *Connection) Connect() error

func (*Connection) Errors

func (c *Connection) Errors() <-chan error

func (*Connection) Incoming

func (c *Connection) Incoming() <-chan []byte

func (*Connection) Send

func (c *Connection) Send(data []byte) error

func (*Connection) State

func (c *Connection) State() ConnectionState

type ConnectionState

type ConnectionState int
const (
	StateDisconnected ConnectionState = iota
	StateConnecting
	StateConnected
	StateClosed
)

func (ConnectionState) String

func (s ConnectionState) String() string

type Dialer

type Dialer interface {
	Dial(urlStr string, requestHeader http.Header) (Socket, *http.Response, error)
}

func NewDialer

func NewDialer() Dialer

type GorillaDialer

type GorillaDialer struct {
	*websocket.Dialer
}

func NewGorillaDialer

func NewGorillaDialer() *GorillaDialer

func (*GorillaDialer) Dial

func (d *GorillaDialer) Dial(
	urlStr string, requestHeader http.Header,
) (
	Socket, *http.Response, error,
)

Returns the Socket interface

type RetryConfig

type RetryConfig struct {
	MaxRetries   int
	InitialDelay time.Duration
	MaxDelay     time.Duration
	JitterFactor float64
}

func GetDefaultRetryConfig

func GetDefaultRetryConfig() *RetryConfig

type RetryManager

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

func NewRetryManager

func NewRetryManager(config *RetryConfig) *RetryManager

func (*RetryManager) CalculateDelay

func (r *RetryManager) CalculateDelay() time.Duration

func (*RetryManager) RecordRetry

func (m *RetryManager) RecordRetry()

func (*RetryManager) RetryCount

func (m *RetryManager) RetryCount() int

func (*RetryManager) ShouldRetry

func (r *RetryManager) ShouldRetry() bool

type Socket

type Socket interface {
	WriteMessage(messageType int, data []byte) error
	ReadMessage() (messageType int, p []byte, err error)
	Close() error

	SetReadDeadline(t time.Time) error
	SetWriteDeadline(t time.Time) error
	SetCloseHandler(h func(code int, text string) error)
}

func AcquireSocket

func AcquireSocket(
	retryMgr *RetryManager,
	dialer Dialer,
	urlStr string,
	logger *slog.Logger,
) (Socket, *http.Response, error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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