Client Initialization
Connection management, configuration options, and reconnection strategies for the Go SDK
Client Initialization
The LX Go client supports multiple transport protocols with automatic failover and comprehensive configuration options.
Creating a Client
Basic Initialization
package main
import (
"context"
"log"
"github.com/luxfi/dex/sdk/go/client"
)
func main() {
// Minimal configuration - JSON-RPC only
c, err := client.NewClient(
client.WithJSONRPCURL("http://localhost:8080"),
)
if err != nil {
log.Fatal("Failed to create client:", err)
}
defer c.Disconnect()
// Client is ready for JSON-RPC operations
ctx := context.Background()
if err := c.Ping(ctx); err != nil {
log.Fatal("Server not responding:", err)
}
}Full Configuration
package main
import (
"context"
"log"
"time"
"github.com/luxfi/dex/sdk/go/client"
)
func main() {
c, err := client.NewClient(
// Protocol endpoints
client.WithJSONRPCURL("http://localhost:8080"),
client.WithWebSocketURL("ws://localhost:8081"),
client.WithGRPCURL("localhost:50051"),
// Authentication
client.WithAPIKey("your-api-key"),
)
if err != nil {
log.Fatal("Failed to create client:", err)
}
defer c.Disconnect()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// Connect to gRPC (primary protocol for orders)
if err := c.ConnectGRPC(ctx); err != nil {
log.Printf("gRPC unavailable, falling back to JSON-RPC: %v", err)
}
// Connect to WebSocket (for real-time data)
if err := c.ConnectWebSocket(ctx); err != nil {
log.Printf("WebSocket unavailable: %v", err)
}
log.Println("Client fully connected")
}Configuration Options
WithJSONRPCURL
Sets the JSON-RPC endpoint URL. This is the fallback protocol when gRPC is unavailable.
client.WithJSONRPCURL("http://localhost:8080")
// With custom path
client.WithJSONRPCURL("http://api.lux.network/rpc")
// HTTPS for production
client.WithJSONRPCURL("https://api.lux.network/rpc")WithWebSocketURL
Sets the WebSocket endpoint for real-time streaming data.
client.WithWebSocketURL("ws://localhost:8081")
// Secure WebSocket for production
client.WithWebSocketURL("wss://api.lux.network/ws")WithGRPCURL
Sets the gRPC endpoint for high-performance operations.
client.WithGRPCURL("localhost:50051")
// Remote endpoint
client.WithGRPCURL("api.lux.network:50051")WithAPIKey
Sets the API key for authenticated requests.
client.WithAPIKey("your-api-key")Connection Management
Connecting to gRPC
gRPC provides the lowest latency for order operations.
package main
import (
"context"
"log"
"time"
"github.com/luxfi/dex/sdk/go/client"
)
func main() {
c, err := client.NewClient(
client.WithGRPCURL("localhost:50051"),
)
if err != nil {
log.Fatal(err)
}
defer c.Disconnect()
// Connect with timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := c.ConnectGRPC(ctx); err != nil {
log.Fatal("Failed to connect to gRPC:", err)
}
log.Println("gRPC connected successfully")
}Connecting to WebSocket
WebSocket provides real-time streaming for market data.
package main
import (
"context"
"log"
"time"
"github.com/luxfi/dex/sdk/go/client"
)
func main() {
c, err := client.NewClient(
client.WithWebSocketURL("ws://localhost:8081"),
)
if err != nil {
log.Fatal(err)
}
defer c.Disconnect()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := c.ConnectWebSocket(ctx); err != nil {
log.Fatal("Failed to connect to WebSocket:", err)
}
log.Println("WebSocket connected successfully")
}Connection Status
package main
import (
"context"
"log"
"time"
"github.com/luxfi/dex/sdk/go/client"
)
func main() {
c, err := client.NewClient(
client.WithJSONRPCURL("http://localhost:8080"),
client.WithGRPCURL("localhost:50051"),
)
if err != nil {
log.Fatal(err)
}
defer c.Disconnect()
ctx := context.Background()
// Check server health via JSON-RPC
if err := c.Ping(ctx); err != nil {
log.Printf("JSON-RPC unavailable: %v", err)
} else {
log.Println("JSON-RPC: OK")
}
// Get node info
info, err := c.GetInfo(ctx)
if err != nil {
log.Printf("Failed to get node info: %v", err)
} else {
log.Printf("Node: %s, Network: %s, Syncing: %v",
info.Version, info.Network, info.Syncing)
}
}Reconnection Strategies
Automatic Reconnection
Implement automatic reconnection with exponential backoff:
package main
import (
"context"
"log"
"math"
"time"
"github.com/luxfi/dex/sdk/go/client"
)
type ReconnectingClient struct {
client *client.Client
grpcURL string
wsURL string
maxRetries int
baseDelay time.Duration
}
func NewReconnectingClient(grpcURL, wsURL string) (*ReconnectingClient, error) {
c, err := client.NewClient(
client.WithGRPCURL(grpcURL),
client.WithWebSocketURL(wsURL),
)
if err != nil {
return nil, err
}
return &ReconnectingClient{
client: c,
grpcURL: grpcURL,
wsURL: wsURL,
maxRetries: 10,
baseDelay: 100 * time.Millisecond,
}, nil
}
func (rc *ReconnectingClient) ConnectWithRetry(ctx context.Context) error {
for attempt := 0; attempt < rc.maxRetries; attempt++ {
// Calculate exponential backoff with jitter
delay := rc.baseDelay * time.Duration(math.Pow(2, float64(attempt)))
if delay > 30*time.Second {
delay = 30 * time.Second
}
// Add jitter (0-25% of delay)
jitter := time.Duration(float64(delay) * 0.25 * (float64(time.Now().UnixNano()%100) / 100))
delay += jitter
if attempt > 0 {
log.Printf("Reconnection attempt %d/%d in %v", attempt+1, rc.maxRetries, delay)
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(delay):
}
}
// Try gRPC first
if err := rc.client.ConnectGRPC(ctx); err != nil {
log.Printf("gRPC connection failed: %v", err)
continue
}
// Then WebSocket
if err := rc.client.ConnectWebSocket(ctx); err != nil {
log.Printf("WebSocket connection failed: %v", err)
// Continue even if WebSocket fails - gRPC is primary
}
log.Println("Connected successfully")
return nil
}
return fmt.Errorf("failed to connect after %d attempts", rc.maxRetries)
}
func (rc *ReconnectingClient) Close() error {
return rc.client.Disconnect()
}
func main() {
rc, err := NewReconnectingClient("localhost:50051", "ws://localhost:8081")
if err != nil {
log.Fatal(err)
}
defer rc.Close()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
if err := rc.ConnectWithRetry(ctx); err != nil {
log.Fatal("Failed to establish connection:", err)
}
}Health Check Loop
Maintain connection health with periodic checks:
package main
import (
"context"
"log"
"sync"
"time"
"github.com/luxfi/dex/sdk/go/client"
)
type HealthMonitor struct {
client *client.Client
interval time.Duration
mu sync.RWMutex
healthy bool
stopCh chan struct{}
}
func NewHealthMonitor(c *client.Client, interval time.Duration) *HealthMonitor {
return &HealthMonitor{
client: c,
interval: interval,
healthy: true,
stopCh: make(chan struct{}),
}
}
func (hm *HealthMonitor) Start(ctx context.Context) {
ticker := time.NewTicker(hm.interval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-hm.stopCh:
return
case <-ticker.C:
hm.checkHealth(ctx)
}
}
}
func (hm *HealthMonitor) checkHealth(ctx context.Context) {
checkCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
err := hm.client.Ping(checkCtx)
hm.mu.Lock()
wasHealthy := hm.healthy
hm.healthy = err == nil
hm.mu.Unlock()
if wasHealthy && !hm.healthy {
log.Println("Connection became unhealthy")
} else if !wasHealthy && hm.healthy {
log.Println("Connection recovered")
}
}
func (hm *HealthMonitor) IsHealthy() bool {
hm.mu.RLock()
defer hm.mu.RUnlock()
return hm.healthy
}
func (hm *HealthMonitor) Stop() {
close(hm.stopCh)
}
func main() {
c, err := client.NewClient(
client.WithJSONRPCURL("http://localhost:8080"),
)
if err != nil {
log.Fatal(err)
}
defer c.Disconnect()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
monitor := NewHealthMonitor(c, 10*time.Second)
go monitor.Start(ctx)
defer monitor.Stop()
// Check health before operations
if !monitor.IsHealthy() {
log.Println("Skipping operation - connection unhealthy")
return
}
// Perform operations...
}Connection Pooling
For high-throughput applications, use a connection pool:
package main
import (
"context"
"log"
"sync"
"sync/atomic"
"github.com/luxfi/dex/sdk/go/client"
)
type ClientPool struct {
clients []*client.Client
size int
counter uint64
mu sync.RWMutex
}
func NewClientPool(size int, grpcURL string) (*ClientPool, error) {
pool := &ClientPool{
clients: make([]*client.Client, size),
size: size,
}
ctx := context.Background()
for i := 0; i < size; i++ {
c, err := client.NewClient(
client.WithGRPCURL(grpcURL),
)
if err != nil {
pool.Close()
return nil, err
}
if err := c.ConnectGRPC(ctx); err != nil {
pool.Close()
return nil, err
}
pool.clients[i] = c
}
return pool, nil
}
// Get returns a client using round-robin selection
func (p *ClientPool) Get() *client.Client {
idx := atomic.AddUint64(&p.counter, 1) % uint64(p.size)
return p.clients[idx]
}
// Execute runs a function with a pooled client
func (p *ClientPool) Execute(fn func(*client.Client) error) error {
c := p.Get()
return fn(c)
}
func (p *ClientPool) Close() error {
p.mu.Lock()
defer p.mu.Unlock()
var lastErr error
for _, c := range p.clients {
if c != nil {
if err := c.Disconnect(); err != nil {
lastErr = err
}
}
}
return lastErr
}
func main() {
pool, err := NewClientPool(10, "localhost:50051")
if err != nil {
log.Fatal(err)
}
defer pool.Close()
ctx := context.Background()
// Execute operation using pooled client
err = pool.Execute(func(c *client.Client) error {
order := &client.Order{
Symbol: "BTC-USD",
Type: client.OrderTypeLimit,
Side: client.OrderSideBuy,
Price: 50000.00,
Size: 0.1,
}
_, err := c.PlaceOrder(ctx, order)
return err
})
if err != nil {
log.Printf("Order failed: %v", err)
}
}Graceful Shutdown
Handle application shutdown gracefully:
package main
import (
"context"
"log"
"os"
"os/signal"
"sync"
"syscall"
"time"
"github.com/luxfi/dex/sdk/go/client"
)
func main() {
c, err := client.NewClient(
client.WithJSONRPCURL("http://localhost:8080"),
client.WithWebSocketURL("ws://localhost:8081"),
client.WithGRPCURL("localhost:50051"),
)
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Connect to all protocols
if err := c.ConnectGRPC(ctx); err != nil {
log.Printf("gRPC unavailable: %v", err)
}
if err := c.ConnectWebSocket(ctx); err != nil {
log.Printf("WebSocket unavailable: %v", err)
}
// Handle shutdown signals
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
// WaitGroup for tracking in-flight operations
var wg sync.WaitGroup
// Start background workers
wg.Add(1)
go func() {
defer wg.Done()
// Worker logic here
<-ctx.Done()
log.Println("Worker shutting down...")
}()
// Wait for shutdown signal
<-sigCh
log.Println("Shutdown signal received")
// Cancel context to stop workers
cancel()
// Wait for operations to complete with timeout
done := make(chan struct{})
go func() {
wg.Wait()
close(done)
}()
select {
case <-done:
log.Println("All operations completed")
case <-time.After(30 * time.Second):
log.Println("Shutdown timeout, forcing exit")
}
// Disconnect client
if err := c.Disconnect(); err != nil {
log.Printf("Error during disconnect: %v", err)
}
log.Println("Shutdown complete")
}Next Steps
- Orders - Learn how to place and manage orders
- Order Book - Subscribe to market data
- WebSocket - Real-time streaming