client

package
v0.0.0-...-6d0ab7c Latest Latest
Warning

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

Go to latest
Published: Aug 27, 2025 License: Apache-2.0 Imports: 9 Imported by: 1

Documentation

Overview

Package client provides a robust WebSocket client for connecting to webhook sprinkler servers. It handles automatic reconnection, ping/pong keep-alive, and comprehensive logging.

Package client provides a robust WebSocket client for webhook sprinkler servers.

The client handles:

  • Automatic reconnection with exponential backoff
  • Ping/pong keep-alive messages
  • Structured logging with customizable output
  • Event callbacks for custom processing
  • Graceful shutdown

Basic usage:

config := client.Config{
    ServerURL:    "wss://example.com/ws",
    Organization: "myorg",
    Token:        "ghp_...",
    OnEvent: func(event client.Event) {
        fmt.Printf("Got event: %s\n", event.Type)
    },
}

c, err := client.New(config)
if err != nil {
    log.Fatal(err)
}

ctx := context.Background()
if err := c.Start(ctx); err != nil {
    log.Fatal(err)
}

To disable logging or customize output:

import "log/slog"
import "io"

// Silence all logs
config.Logger = slog.New(slog.NewTextHandler(io.Discard, nil))

// Or use JSON logging
config.Logger = slog.New(slog.NewJSONHandler(os.Stdout, nil))

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AuthenticationError

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

AuthenticationError represents an authentication or authorization failure that should not trigger reconnection attempts.

func (*AuthenticationError) Error

func (e *AuthenticationError) Error() string

type Client

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

Client represents a WebSocket client with automatic reconnection.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/codeGROOVE-dev/sprinkler/pkg/client"
)

func main() {
	// Create client configuration
	config := client.Config{
		ServerURL:      "wss://hook.example.com/ws",
		Organization:   "myorg",
		Token:          "ghp_yourtoken",
		EventTypes:     []string{"pull_request", "issue_comment"},
		UserEventsOnly: true,
		Verbose:        false,
		MaxRetries:     5,
		OnEvent: func(event client.Event) {
			// Process each event
			fmt.Printf("Event: %s at %s\n", event.Type, event.URL)
		},
		OnConnect: func() {
			log.Println("Connected successfully!")
		},
		OnDisconnect: func(err error) {
			log.Printf("Disconnected: %v", err)
		},
	}

	// Create the client
	c, err := client.New(config)
	if err != nil {
		log.Fatal(err)
	}

	// Create a context with timeout
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
	defer cancel()

	// Start the client (blocks until error or context cancellation)
	if err := c.Start(ctx); err != nil {
		log.Printf("Client stopped: %v", err)
	}
}
Example (CustomLogger)
package main

import (
	"io"
	"log"
	"log/slog"
	"os"

	"github.com/codeGROOVE-dev/sprinkler/pkg/client"
)

func main() {
	// Example 1: Silence all logs
	silentLogger := slog.New(slog.NewTextHandler(io.Discard, nil))

	// Example 2: JSON logging to a file
	logFile, err := os.Create("client.log")
	if err == nil {
		defer func() {
			if err := logFile.Close(); err != nil {
				log.Printf("Failed to close log file: %v", err)
			}
		}()
	}
	var jsonLogger *slog.Logger
	if logFile != nil {
		jsonLogger = slog.New(slog.NewJSONHandler(logFile, &slog.HandlerOptions{
			Level: slog.LevelDebug,
		}))
	}

	// Example 3: Structured logging with custom format
	structuredLogger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
		Level: slog.LevelInfo,
	}))

	// Use the silent logger for a client that produces no output
	config := client.Config{
		ServerURL:    "wss://hook.example.com/ws",
		Organization: "myorg",
		Token:        "ghp_yourtoken",
		Logger:       silentLogger, // No log output
	}

	c, err := client.New(config)
	if err != nil {
		log.Fatal(err)
	}

	// Alternative: use the JSON logger
	if jsonLogger != nil {
		config.Logger = jsonLogger
		c2, err := client.New(config)
		if err != nil {
			log.Fatal(err)
		}
		_ = c2
	}

	// Alternative: use structured text logger
	config.Logger = structuredLogger
	c3, err := client.New(config)
	if err != nil {
		log.Fatal(err)
	}

	_ = c
	_ = c3
}
Example (GracefulShutdown)
package main

import (
	"context"
	"log"
	"time"

	"github.com/codeGROOVE-dev/sprinkler/pkg/client"
)

func main() {
	config := client.Config{
		ServerURL:    "wss://hook.example.com/ws",
		Organization: "myorg",
		Token:        "ghp_yourtoken",
	}

	c, err := client.New(config)
	if err != nil {
		log.Fatal(err)
	}

	// Start client in goroutine
	ctx := context.Background()
	go func() {
		if err := c.Start(ctx); err != nil {
			log.Printf("Client error: %v", err)
		}
	}()

	// Do some work...
	time.Sleep(10 * time.Second)

	// Gracefully stop the client
	c.Stop()
}

func New

func New(config Config) (*Client, error)

New creates a new robust WebSocket client.

func (*Client) Start

func (c *Client) Start(ctx context.Context) error

Start begins the connection process with automatic reconnection.

func (*Client) Stop

func (c *Client) Stop()

Stop gracefully stops the client.

type Config

type Config struct {
	OnConnect      func()
	OnDisconnect   func(error)
	OnEvent        func(Event)
	ServerURL      string
	Token          string
	Organization   string
	EventTypes     []string
	PullRequests   []string // List of PR URLs to subscribe to
	MaxBackoff     time.Duration
	PingInterval   time.Duration
	MaxRetries     int
	UserEventsOnly bool
	Verbose        bool
	NoReconnect    bool
	Logger         *slog.Logger // Optional logger, defaults to text handler on stderr
}

Config holds the configuration for the client.

type Event

type Event struct {
	Timestamp time.Time `json:"timestamp"`
	Raw       map[string]any
	Type      string `json:"type"`
	URL       string `json:"url"`
}

Event represents a webhook event received from the server.

Jump to

Keyboard shortcuts

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