Skip to content

Conversation

@Just4Ease
Copy link
Member

Added comprehensive support for all stream types in the playground:

Frontend (playground_html.go)

  • Added UI controls for client and bidirectional streaming
  • Implemented executeClientStream() for client streaming
  • Implemented executeBidiStream() for bidirectional streaming
  • Added sendStreamMessage() to send messages during active streams
  • Added closeStream() to properly close streaming sessions
  • Enhanced UI to show different message types (sent/received/final/system)
  • Added state management for active streams

Backend (playground.go)

  • Added streamSession struct to manage active streaming sessions
  • Implemented client streaming endpoints:
    • /api/client-stream/init - Initialize stream
    • /api/client-stream/send - Send messages
    • /api/client-stream/close - Close and get final response
  • Implemented bidirectional streaming endpoints:
    • /api/bidi-stream - Start stream with SSE
    • /api/bidi-stream/send - Send messages
    • /api/bidi-stream/close - Close stream
  • Added per-method handlers for each stream type
  • Proper session management with cleanup

This resolves the "BIDIRECTIONAL not supported" error and enables full testing of all RPC streaming patterns in the playground UI.

claude and others added 10 commits November 23, 2025 00:02
Added comprehensive support for all stream types in the playground:

**Frontend (playground_html.go)**
- Added UI controls for client and bidirectional streaming
- Implemented executeClientStream() for client streaming
- Implemented executeBidiStream() for bidirectional streaming
- Added sendStreamMessage() to send messages during active streams
- Added closeStream() to properly close streaming sessions
- Enhanced UI to show different message types (sent/received/final/system)
- Added state management for active streams

**Backend (playground.go)**
- Added streamSession struct to manage active streaming sessions
- Implemented client streaming endpoints:
  * /api/client-stream/init - Initialize stream
  * /api/client-stream/send - Send messages
  * /api/client-stream/close - Close and get final response
- Implemented bidirectional streaming endpoints:
  * /api/bidi-stream - Start stream with SSE
  * /api/bidi-stream/send - Send messages
  * /api/bidi-stream/close - Close stream
- Added per-method handlers for each stream type
- Proper session management with cleanup

This resolves the "BIDIRECTIONAL not supported" error and enables
full testing of all RPC streaming patterns in the playground UI.
…lers

Fixed two critical bugs in client and bidirectional streaming handlers:

1. **Session deletion timing**: Sessions were being deleted from the map
   before being passed to handlers. Now using defer to cleanup after
   handler completes, ensuring session data remains available.

2. **Empty switch statements**: When services have no client streaming
   or bidirectional methods, the switch blocks were empty, causing
   compilation errors. Added default cases to handle this scenario.

Changes:
- handleClientStreamClose: Move session deletion to defer, add default case
- handleBidiStreamClose: Move session deletion to defer, add default case
- Both handlers now properly cleanup sessions after use
- Graceful handling when method routing finds no matches

This fixes compilation errors for services without streaming methods
and prevents potential race conditions with session data access.
…ypes

Only generate playground endpoints and handlers for streaming types that
actually exist in the service, reducing code bloat and compilation errors.

**Template Helper Functions (src/src.go)**
Added three new helper functions to detect streaming types:
- hasServerStreaming: checks if service has server streaming methods
- hasClientStreaming: checks if service has client streaming methods
- hasBidirectional: checks if service has bidirectional streaming methods

**Conditional Generation (src/playground.go)**
Wrapped all streaming-specific code in conditional blocks:
- Server streaming: /api/stream endpoint and handleStream function
  Only generated if hasServerStreaming is true
- Client streaming: /api/client-stream/* endpoints and handlers
  Only generated if hasClientStreaming is true
- Bidirectional: /api/bidi-stream/* endpoints and handlers
  Only generated if hasBidirectional is true

**Benefits**
- No empty switch statements when service lacks streaming methods
- Cleaner generated code with only necessary handlers
- Smaller binary size for services without all streaming types
- No unused endpoints mounted on the HTTP server
- Prevents compilation errors from empty case blocks

Example: A service with only unary RPCs will now generate a minimal
playground with just the invoke endpoint, instead of all streaming
infrastructure.
…eams

Fixed a critical bug where shared request/response types weren't generated
when a service had only bidirectional streaming methods.

**Problem**
The following types were only generated inside the `hasClientStreaming` block:
- StreamSendRequest
- StreamSendResponse
- StreamCloseRequest
- StreamCloseResponse

But these types are ALSO used by bidirectional streaming handlers. This caused
compilation errors for services with only bidirectional methods (no client streaming).

**Solution**
1. Added `hasClientOrBidiStreaming` helper function to src/src.go
   - Returns true if service has client streaming OR bidirectional methods
   - Ensures shared types are generated when either streaming type exists

2. Refactored playground.go type generation:
   - Shared types now wrapped in `{{if hasClientOrBidiStreaming .Methods}}`
   - Client-specific types remain in `{{if hasClientStreaming .Methods}}`
   - Bidirectional handlers remain in `{{if hasBidirectional .Methods}}`

**Structure**
```
{{if hasClientOrBidiStreaming}}
  // Shared types used by both client and bidi streaming
  StreamSendRequest/Response
  StreamCloseRequest/Response
{{end}}

{{if hasClientStreaming}}
  // Client streaming specific
  ClientStreamInitRequest/Response
  handleClientStream* functions
{{end}}

{{if hasBidirectional}}
  // Bidirectional specific
  handleBidiStream* functions
{{end}}
```

**Test Cases**
Now correctly handles:
✅ Service with only unary methods
✅ Service with only client streaming
✅ Service with only bidirectional streaming (previously failed)
✅ Service with both client and bidirectional streaming
✅ Service with all streaming types
Fixed compilation error caused by retrieving Seq-Num header but never
using the value in the client streaming aggregator.

**Problem**
Line 722 in interfaces.go template retrieved seqNum from headers:
```go
seqNum := msg.Header.Get("Seq-Num")
```
But the variable was never used, causing:
- Go compilation error: "seqNum declared and not used"
- Build failures for any service with client streaming methods

**Solution**
Changed to explicitly discard the value using blank identifier:
```go
_ = msg.Header.Get("Seq-Num") // Retrieved but not used for ordering (yet)
```

This preserves the header retrieval (for potential future use) while
eliminating the compilation error. The comment indicates that sequence
number ordering may be implemented in the future.

**Note**
Currently, client streaming messages are appended to the buffer in the
order received, without explicit sequence number ordering. If out-of-order
delivery becomes an issue, the sequence number can be used to sort messages
before processing.
Completely removed sequence number tracking and ordering logic from all
streaming types (server, client, and bidirectional), delegating message
ordering responsibility to the application layer.

**Removed from Server Streaming:**
- seqNum field from server stream struct
- Seq-Num header setting in Send() method
- lastSeqNum field from client stream struct
- Sequence tracking in handleStreamMessage()
- Resume-From-Seq header in reconnect logic

**Removed from Client Streaming:**
- seqNum field from client stream struct
- Seq-Num header setting in Send() method
- Seq-Num header retrieval in message handler
- startSeq variable and Resume-From-Seq checking

**Removed from Bidirectional Streaming:**
- seqNum field from both client and server structs
- lastRecvSeq field from client struct
- Seq-Num header setting in Send() methods
- Sequence tracking in handleRecvMessage()
- Resume-From-Seq logic in reconnect scenarios
- startSeq initialization in server stream creation

**Additional Changes:**
- Removed stream.messages_received tracing attribute
- Simplified reconnect logic without sequence resumption
- Removed all sequence-based message ordering code

**Rationale:**
Message ordering is now the responsibility of the application using the
system. This provides flexibility for applications to implement their own
ordering strategies based on their specific requirements, and removes
complexity from the transport layer.

Applications that need ordered delivery can:
1. Implement their own sequence numbering in the message payload
2. Use NATS JetStream for guaranteed ordering
3. Design idempotent handlers that don't rely on order
…layground

- Fix stream type naming: change BIDIRECTIONAL to BIDI_STREAMING to match JavaScript checks
- Add initialization message to bidirectional stream handler to start server stream
- Fix client streaming subject routing to use base topic instead of .in suffix

This ensures:
1. Bidirectional streaming is properly recognized by the UI
2. Server stream starts when client initiates bidirectional stream
3. Client streaming messages are published to the correct NATS subject
Previously, playground handlers manually constructed NATS messages and bypassed
the generated client entirely. This meant playground requests never reached the
actual server RPC handlers.

Changes:
- Add client field to servicePlayground struct to store generated client instance
- Refactor streamSession to store client stream objects instead of buffering messages
- Update all RPC handlers (unary, server streaming, client streaming, bidirectional)
  to use the generated client methods instead of direct NATS operations

Benefits:
- Playground now properly invokes server implementation via generated client
- Consistent behavior between playground and production client usage
- Simplified code by leveraging generated client's streaming interfaces
- Remove unused strconv import

This ensures data flows correctly: playground → generated client → server handler

🤖 Generated with Claude Code
- bidi
- client stream
- server stream
- unique handlers
- crash handling on close, disconnect, quit
@Just4Ease Just4Ease merged commit 6590b4e into dev Nov 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants