Skip to content

feat: Add Feishu WebSocket long connection support#297

Open
eathard wants to merge 5 commits intoRightNow-AI:mainfrom
eathard:feature/feishu-websocket
Open

feat: Add Feishu WebSocket long connection support#297
eathard wants to merge 5 commits intoRightNow-AI:mainfrom
eathard:feature/feishu-websocket

Conversation

@eathard
Copy link

@eathard eathard commented Mar 4, 2026

Pull Request: Feishu WebSocket Long Connection Support

Summary

Implements WebSocket long connection mode for Feishu/Lark integration, enabling OpenFang to receive messages from local environments without requiring public IP or port forwarding.

Changes

  • Core Implementation: Complete WebSocket protocol support with protobuf encoding/decoding
  • Connection Mode: Added FeishuConnectionMode enum (websocket/webhook)
  • Protocol: Manual protobuf implementation without external .proto files
  • Features:
    • Dynamic ticket-based authentication
    • Ping/pong keepalive mechanism (configurable interval)
    • Message fragmentation handling for large payloads
    • Gzip compression support
  • Bug Fixes: Fixed receive_id error by using chat_id instead of sender_id
  • Logging: Enhanced visibility with info-level logs for WebSocket operations

Files Modified

  • crates/openfang-channels/src/feishu.rs (+998 lines)
  • crates/openfang-types/src/config.rs (+22 lines)
  • crates/openfang-channels/Cargo.toml (+4 dependencies)
  • Cargo.lock (dependency updates)
  • crates/openfang-api/src/channel_bridge.rs (minor update)

Dependencies Added

  • tokio-tungstenite - WebSocket client
  • prost & prost-types - Protobuf encoding
  • flate2 - Gzip decompression

Testing

✅ WebSocket connection established successfully
✅ Message reception verified with test messages
✅ Protobuf frame decoding functional
✅ Ping/pong keepalive working (90s interval)
✅ Event payload parsing correct

Configuration Example

[channels.feishu]
app_id = "cli_a922bea3c6785cc8"
app_secret_env = "FEISHU_APP_SECRET"
connection_mode = "websocket"  # New: "websocket" or "webhook"
default_agent = "assistant"

Documentation

  • Added FEISHU_WEBSOCKET_README.md with setup instructions
  • Updated CHANGELOG.md for v0.3.13
  • Created RELEASE_NOTES_v0.3.13.md with detailed release notes

Breaking Changes

⚠️ Constructor change: FeishuAdapter::new() now requires connection_mode instead of webhook_port

Before:

FeishuAdapter::new(app_id, app_secret, webhook_port)

After:

use openfang_types::config::FeishuConnectionMode;
FeishuAdapter::new(app_id, app_secret, FeishuConnectionMode::WebSocket)

Checklist

  • Code compiles without errors
  • Tested locally with WebSocket connection
  • Documentation updated
  • CHANGELOG updated
  • CI/CD tests passing (to be verified)
  • No merge conflicts (to be verified)

Related Issues

Resolves: #S143 (Feishu WebSocket Long Connection Implementation)

Additional Notes

  • Debug version tested and working (release build pending due to memory constraints)
  • Protocol implementation based on official Feishu documentation
  • Ready for code review and testing

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

OpenFang Developers and others added 3 commits March 4, 2026 21:56
This commit implements WebSocket long connection mode for Feishu/Lark
integration, allowing OpenFang to receive messages from local environments
without requiring public IP or port forwarding.

## Key Changes

### Core Implementation
- **feishu.rs**: Add WebSocket connection support with protobuf message handling
  - Implement Feishu WebSocket protocol (wss://msg-frontier.feishu.cn/ws/v2)
  - Add manual protobuf encoding/decoding (no external proto files)
  - Implement ping/pong keepalive mechanism
  - Add message fragmentation handling for large payloads
  - Support both webhook and WebSocket connection modes

### Configuration
- **config.rs**: Add `FeishuConnectionMode` enum (websocket/webhook)
- **Cargo.toml**: Add required dependencies (tokio-tungstenite, prost, flate2)
- **channel_bridge.rs**: Update to support new connection mode parameter

### Bug Fixes
- Fix `receive_id` error by using `chat_id` instead of `sender_id`
- Change log levels from `trace!` to `info!` for better visibility

### Documentation
- Add FEISHU_WEBSOCKET_README.md with setup and usage instructions

## Technical Details

- Protocol: Custom protobuf over WebSocket
- Authentication: Dynamic ticket-based handshake
- Compression: Gzip for message payloads
- Frame: SeqID, LogID, service, method, headers, payload

Resolves: #S143
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix panic when logging shell commands containing multi-byte UTF-8 characters
(e.g., Chinese characters). The previous code used byte indexing to truncate
strings, which could panic when truncating at a byte that fell in the middle of
a multi-byte character.

Error: byte index 100 is not a char boundary; it is inside '统' (bytes 98..101)

Solution: Use char_indices() for safe character-boundary string truncation.

Fixes: #issue
@eathard
Copy link
Author

eathard commented Mar 5, 2026

Additional Bug Fix Included

This PR now also includes a critical bug fix for UTF-8 character handling:

Fix: UTF-8 character boundary panic in subprocess_sandbox.rs

  • Problem: When shell commands contained multi-byte UTF-8 characters (e.g., Chinese), the logging code would panic with: byte index 100 is not a char boundary; it is inside '统' (bytes 98..101)
  • Root Cause: Used byte indexing (&command[..100]) to truncate strings for logging, which is unsafe for multi-byte UTF-8 characters
  • Solution: Use char_indices() for safe character-boundary string truncation
  • File: crates/openfang-runtime/src/subprocess_sandbox.rs

This fix ensures that OpenFang can safely handle shell commands with international characters, making it more robust for global users.

Resolve Cargo.lock conflicts by updating dependencies to latest compatible versions.
Updated openfang workspace packages from v0.3.12 to v0.3.17.
egargale pushed a commit to egargale/openfang that referenced this pull request Mar 5, 2026
* test: deepen coverage for health doctor provider and tunnels

* test: add broad trait and module re-export coverage
Sync with latest main (v0.3.20) and resolve Cargo.lock conflicts.
Updated workspace dependencies from v0.3.17 to v0.3.20.
All conflicts resolved, PR ready for merge.
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.

1 participant