# WebSocket REQ Handling Comparison: Khatru vs Next.orly.dev

## Overview

This document compares how two Nostr relay implementations handle WebSocket connections and REQ (subscription) messages:

1. **Khatru** - A popular Go-based Nostr relay library by fiatjaf
2. **Next.orly.dev** - A custom relay implementation with advanced features

## Architecture Comparison

### Khatru Architecture

- **Monolithic approach**: Single large `HandleWebsocket` method (~380 lines) processes all message types
- **Inline processing**: REQ handling is embedded within the main websocket handler
- **Hook-based extensibility**: Uses function slices for customizable behavior
- **Simple structure**: WebSocket struct with basic fields and mutex for thread safety

### Next.orly.dev Architecture

- **Modular approach**: Separate methods for each message type (`HandleReq`, `HandleEvent`, etc.)
- **Layered processing**: Message identification → envelope parsing → type-specific handling
- **Publisher-subscriber system**: Dedicated infrastructure for subscription management
- **Rich context**: Listener struct with detailed state tracking and metrics

## Connection Establishment

### Khatru

```go
// Simple websocket upgrade
conn, err := rl.upgrader.Upgrade(w, r, nil)
ws := &WebSocket{
    conn:               conn,
    Request:            r,
    Challenge:          hex.EncodeToString(challenge),
    negentropySessions: xsync.NewMapOf[string, *NegentropySession](),
}
```

### Next.orly.dev

```go
// More sophisticated setup with IP whitelisting
conn, err = websocket.Accept(w, r, &websocket.AcceptOptions{OriginPatterns: []string{"*"}})
listener := &Listener{
    ctx:    ctx,
    Server: s,
    conn:   conn,
    remote: remote,
    req:    r,
}
// Immediate AUTH challenge if ACLs are configured
```

**Key Differences:**

- Next.orly.dev includes IP whitelisting and immediate authentication challenges
- Khatru uses fasthttp/websocket library vs next.orly.dev using coder/websocket
- Next.orly.dev has more detailed connection state tracking

## Message Processing

### Khatru

- Uses `nostr.MessageParser` for sequential parsing
- Switch statement on envelope type within goroutine
- Direct processing without intermediate validation layers

### Next.orly.dev

- Custom envelope identification system (`envelopes.Identify`)
- Separate validation and processing phases
- Extensive logging and error handling at each step

## REQ Message Handling

### Khatru REQ Processing

```go
case *nostr.ReqEnvelope:
    eose := sync.WaitGroup{}
    eose.Add(len(env.Filters))

    // Handle each filter separately
    for _, filter := range env.Filters {
        err := srl.handleRequest(reqCtx, env.SubscriptionID, &eose, ws, filter)
        if err != nil {
            // Fail everything if any filter is rejected
            ws.WriteJSON(nostr.ClosedEnvelope{SubscriptionID: env.SubscriptionID, Reason: reason})
            return
        } else {
            rl.addListener(ws, env.SubscriptionID, srl, filter, cancelReqCtx)
        }
    }

    go func() {
        eose.Wait()
        ws.WriteJSON(nostr.EOSEEnvelope(env.SubscriptionID))
    }()
```

### Next.orly.dev REQ Processing

```go
// Comprehensive ACL and authentication checks first
accessLevel := acl.Registry.GetAccessLevel(l.authedPubkey.Load(), l.remote)
switch accessLevel {
case "none":
    return // Send auth-required response
}

// Process all filters and collect events
for _, f := range *env.Filters {
    filterEvents, err = l.QueryEvents(queryCtx, f)
    allEvents = append(allEvents, filterEvents...)
}

// Apply privacy and privilege checks
// Send all historical events
// Set up ongoing subscription only if needed
```

## Key Architectural Differences

### 1. **Filter Processing Strategy**

**Khatru:**

- Processes each filter independently and concurrently
- Uses WaitGroup to coordinate EOSE across all filters
- Immediately sets up listeners for ongoing subscriptions
- Fails entire subscription if any filter is rejected

**Next.orly.dev:**

- Processes all filters sequentially in a single context
- Collects all events before applying access control
- Only sets up subscriptions for filters that need ongoing updates
- Gracefully handles individual filter failures

### 2. **Access Control Integration**

**Khatru:**

- Basic NIP-42 authentication support
- Hook-based authorization via `RejectFilter` functions
- Limited built-in access control features

**Next.orly.dev:**

- Comprehensive ACL system with multiple access levels
- Built-in support for private events with npub authorization
- Privileged event filtering based on pubkey and p-tags
- Granular permission checking at multiple stages

### 3. **Subscription Management**

**Khatru:**

```go
// Simple listener registration
type listenerSpec struct {
    filter     nostr.Filter
    cancel     context.CancelCauseFunc
    subRelay   *Relay
}
rl.addListener(ws, subscriptionID, relay, filter, cancel)
```

**Next.orly.dev:**

```go
// Publisher-subscriber system with rich metadata
type W struct {
    Conn         *websocket.Conn
    remote       string
    Id           string
    Receiver     event.C
    Filters      *filter.S
    AuthedPubkey []byte
}
l.publishers.Receive(&W{...})
```

### 4. **Performance Optimizations**

**Khatru:**

- Concurrent filter processing
- Immediate streaming of events as they're found
- Memory-efficient with direct event streaming

**Next.orly.dev:**

- Batch processing with deduplication
- Memory management with explicit `ev.Free()` calls
- Smart subscription cancellation for ID-only queries
- Event result caching and seen-tracking

### 5. **Error Handling & Observability**

**Khatru:**

- Basic error logging
- Simple connection state management
- Limited metrics and observability

**Next.orly.dev:**

- Comprehensive error handling with context preservation
- Detailed logging at each processing stage
- Built-in metrics (message count, REQ count, event count)
- Graceful degradation on individual component failures

## Memory Management

### Khatru

- Relies on Go's garbage collector
- Simple WebSocket struct with minimal state
- Uses sync.Map for thread-safe operations

### Next.orly.dev

- Explicit memory management with `ev.Free()` calls
- Resource pooling and reuse patterns
- Detailed tracking of connection resources

## Concurrency Models

### Khatru

- Per-connection goroutine for message reading
- Additional goroutines for each message processing
- WaitGroup coordination for multi-filter EOSE

### Next.orly.dev

- Per-connection goroutine with single-threaded message processing
- Publisher-subscriber system handles concurrent event distribution
- Context-based cancellation throughout

## Trade-offs Analysis

### Khatru Advantages

- **Simplicity**: Easier to understand and modify
- **Performance**: Lower latency due to concurrent processing
- **Flexibility**: Hook-based architecture allows extensive customization
- **Streaming**: Events sent as soon as they're found

### Khatru Disadvantages

- **Monolithic**: Large methods harder to maintain
- **Limited ACL**: Basic authentication and authorization
- **Error handling**: Less graceful failure recovery
- **Resource usage**: No explicit memory management

### Next.orly.dev Advantages

- **Security**: Comprehensive ACL and privacy features
- **Observability**: Extensive logging and metrics
- **Resource management**: Explicit memory and connection lifecycle management
- **Modularity**: Easier to test and extend individual components
- **Robustness**: Graceful handling of edge cases and failures

### Next.orly.dev Disadvantages

- **Complexity**: Higher cognitive overhead and learning curve
- **Latency**: Sequential processing may be slower for some use cases
- **Resource overhead**: More memory usage due to batching and state tracking
- **Coupling**: Tighter integration between components

## Conclusion

Both implementations represent different philosophies:

- **Khatru** prioritizes simplicity, performance, and extensibility through a hook-based architecture
- **Next.orly.dev** prioritizes security, observability, and robustness through comprehensive built-in features

The choice between them depends on specific requirements:

- Choose **Khatru** for high-performance relays with custom business logic
- Choose **Next.orly.dev** for production relays requiring comprehensive access control and monitoring

Both approaches demonstrate mature understanding of Nostr protocol requirements while making different trade-offs in complexity vs. features.
