diff --git a/Cargo.toml b/Cargo.toml index 652ee02..c54de1b 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "solana-streamer-sdk" -version = "0.5.0" +version = "1.0.0" edition = "2021" authors = ["William ", "sgxiang ", "wei <1415121722@qq.com>"] repository = "https://github.com/0xfnzero/solana-streamer" diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 0000000..8d910af --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,398 @@ +# Migration Guide: v0.5.x to v1.0.0 + +## Overview + +Version 1.0.0 introduces a significant architectural improvement by transitioning from a trait-based event system to an enum-based event system. This change brings: + +- **Better Type Safety**: Compile-time guarantees for event types +- **Improved Performance**: Eliminates dynamic dispatch overhead (no `Box`) +- **Simpler Code**: Standard Rust patterns instead of custom macros +- **Better IDE Support**: Full autocomplete and type inference + +## Breaking Changes Summary + +| Component | v0.5.x | v1.0.0 | +| ------------------ | --------------------------- | --------------------------- | +| Event Type | `Box` | `DexEvent` (enum) | +| Callback Signature | `Fn(Box)` | `Fn(DexEvent)` | +| Event Matching | `match_event!` macro | Standard `match` expression | +| Metadata Access | `.event_type()` | `.metadata().event_type` | +| Event Properties | `.signature()` | `.metadata().signature` | + +## Migration Steps + +### Step 1: Update Callback Signatures + +**Before (v0.5.x):** + +```rust +use solana_streamer_sdk::streaming::event_parser::UnifiedEvent; + +let callback = |event: Box| { + println!("Received event: {:?}", event); +}; +``` + +**After (v1.0.0):** + +```rust +use solana_streamer_sdk::streaming::event_parser::DexEvent; + +let callback = |event: DexEvent| { + println!("Received event: {:?}", event); +}; +``` + +### Step 2: Update Event Matching + +**Before (v0.5.x):** + +```rust +use solana_streamer_sdk::match_event; + +match_event!(event, { + PumpFunTradeEvent => |e: PumpFunTradeEvent| { + println!("PumpFun trade: {:?}", e); + }, + RaydiumCpmmSwapEvent => |e: RaydiumCpmmSwapEvent| { + println!("Raydium swap: {:?}", e); + }, +}); +``` + +**After (v1.0.0):** + +```rust +match event { + DexEvent::PumpFunTradeEvent(e) => { + println!("PumpFun trade: {:?}", e); + } + DexEvent::RaydiumCpmmSwapEvent(e) => { + println!("Raydium swap: {:?}", e); + } + _ => {} +} +``` + +### Step 3: Update Metadata Access + +**Before (v0.5.x):** + +```rust +let event_type = event.event_type(); +let signature = event.signature(); +let slot = event.slot(); +let protocol = event.protocol(); +``` + +**After (v1.0.0):** + +```rust +let event_type = event.metadata().event_type; +let signature = event.metadata().signature; +let slot = event.metadata().slot; +let protocol = event.metadata().protocol; +``` + +### Step 4: Update Import Statements + +**Before (v0.5.x):** + +```rust +use solana_streamer_sdk::{ + match_event, + streaming::event_parser::{ + UnifiedEvent, + protocols::{ + pumpfun::{PumpFunTradeEvent, PumpFunCreateTokenEvent}, + raydium_cpmm::{RaydiumCpmmSwapEvent}, + }, + }, +}; +``` + +**After (v1.0.0):** + +```rust +use solana_streamer_sdk::streaming::event_parser::{ + DexEvent, + protocols::{ + pumpfun::{PumpFunTradeEvent, PumpFunCreateTokenEvent}, + raydium_cpmm::{RaydiumCpmmSwapEvent}, + }, +}; +``` + +Note: The `match_event!` macro is no longer needed or available. + +## Complete Example Migration + +### Before (v0.5.x) + +```rust +use solana_streamer_sdk::{ + match_event, + streaming::{ + event_parser::{ + UnifiedEvent, + protocols::{ + pumpfun::{PumpFunTradeEvent, PumpFunCreateTokenEvent}, + raydium_cpmm::RaydiumCpmmSwapEvent, + }, + }, + YellowstoneGrpc, + }, +}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let grpc = YellowstoneGrpc::new( + "grpc-endpoint".to_string(), + Some("api-key".to_string()), + )?; + + let callback = |event: Box| { + println!( + "Event type: {:?}, Signature: {}", + event.event_type(), + event.signature() + ); + + match_event!(event, { + PumpFunTradeEvent => |e: PumpFunTradeEvent| { + println!("PumpFun trade: {} SOL", e.sol_amount); + }, + PumpFunCreateTokenEvent => |e: PumpFunCreateTokenEvent| { + println!("New token: {}", e.name); + }, + RaydiumCpmmSwapEvent => |e: RaydiumCpmmSwapEvent| { + println!("Raydium swap"); + }, + }); + }; + + grpc.subscribe_events( + protocols, + event_filter, + tx_filter, + account_filter, + callback, + ).await?; + + Ok(()) +} +``` + +### After (v1.0.0) + +```rust +use solana_streamer_sdk::streaming::{ + event_parser::{ + DexEvent, + protocols::{ + pumpfun::{PumpFunTradeEvent, PumpFunCreateTokenEvent}, + raydium_cpmm::RaydiumCpmmSwapEvent, + }, + }, + YellowstoneGrpc, +}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let grpc = YellowstoneGrpc::new( + "grpc-endpoint".to_string(), + Some("api-key".to_string()), + )?; + + let callback = |event: DexEvent| { + println!( + "Event type: {:?}, Signature: {}", + event.metadata().event_type, + event.metadata().signature + ); + + match event { + DexEvent::PumpFunTradeEvent(e) => { + println!("PumpFun trade: {} SOL", e.sol_amount); + } + DexEvent::PumpFunCreateTokenEvent(e) => { + println!("New token: {}", e.name); + } + DexEvent::RaydiumCpmmSwapEvent(e) => { + println!("Raydium swap"); + } + _ => {} + } + }; + + grpc.subscribe_events( + protocols, + event_filter, + tx_filter, + account_filter, + callback, + ).await?; + + Ok(()) +} +``` + +## Advanced Patterns + +### Pattern 1: Event Filtering with Match + +**v1.0.0:** + +```rust +let callback = |event: DexEvent| { + // Only process specific event types + match event { + DexEvent::PumpFunTradeEvent(e) if e.is_buy => { + println!("Buy: {} tokens", e.token_amount); + } + DexEvent::PumpFunTradeEvent(e) if !e.is_buy => { + println!("Sell: {} tokens", e.token_amount); + } + _ => {} // Ignore other events + } +}; +``` + +### Pattern 2: Generic Event Processing + +**v1.0.0:** + +```rust +fn process_event(event: DexEvent) { + let metadata = event.metadata(); + + println!("Protocol: {:?}", metadata.protocol); + println!("Event Type: {:?}", metadata.event_type); + println!("Signature: {}", metadata.signature); + println!("Slot: {}", metadata.slot); + + // Process specific event types + match event { + DexEvent::PumpFunTradeEvent(e) => handle_pumpfun_trade(e), + DexEvent::RaydiumCpmmSwapEvent(e) => handle_raydium_swap(e), + _ => {} + } +} +``` + +### Pattern 3: Event Type Categorization + +**v1.0.0:** + +```rust +fn categorize_event(event: &DexEvent) -> &'static str { + match event { + DexEvent::PumpFunTradeEvent(_) + | DexEvent::PumpSwapBuyEvent(_) + | DexEvent::PumpSwapSellEvent(_) => "Trade", + + DexEvent::PumpFunCreateTokenEvent(_) + | DexEvent::PumpSwapCreatePoolEvent(_) => "Creation", + + DexEvent::RaydiumCpmmDepositEvent(_) + | DexEvent::RaydiumCpmmWithdrawEvent(_) => "Liquidity", + + _ => "Other", + } +} +``` + +## EventParser API Changes + +### Parsing Transactions + +**Before (v0.5.x):** + +```rust +let parser = Arc::new(EventParser::new(protocols, event_filter)); +parser.parse_encoded_confirmed_transaction_with_status_meta( + signature, + transaction, + Arc::new(|event: &Box| { + println!("{:?}", event); + }), +).await?; +``` + +**After (v1.0.0):** + +```rust +EventParser::parse_encoded_confirmed_transaction_with_status_meta( + &protocols, + event_filter.as_ref(), + signature, + transaction, + Arc::new(|event: &DexEvent| { + println!("{:?}", event); + }), +).await?; +``` + +The `EventParser` is now stateless with static methods, eliminating the need to create an instance. + +## Common Pitfalls + +### Pitfall 1: Forgetting to Handle All Variants + +❌ **Incorrect:** + +```rust +match event { + DexEvent::PumpFunTradeEvent(e) => { /* ... */ } + // Missing other variants! +} +``` + +✅ **Correct:** + +```rust +match event { + DexEvent::PumpFunTradeEvent(e) => { /* ... */ } + _ => {} // Handle or ignore other events +} +``` + +### Pitfall 2: Using Old Metadata Access Pattern + +❌ **Incorrect:** + +```rust +let sig = event.signature(); // Method doesn't exist anymore +``` + +✅ **Correct:** + +```rust +let sig = event.metadata().signature; +``` + +### Pitfall 3: Attempting to Use `match_event!` Macro + +❌ **Incorrect:** + +```rust +match_event!(event, { /* ... */ }); // Macro no longer exists +``` + +✅ **Correct:** + +```rust +match event { + DexEvent::PumpFunTradeEvent(e) => { /* ... */ } + _ => {} +} +``` + +## Benefits of the New System + +1. **Type Safety**: The compiler catches more errors at compile time +2. **Performance**: No dynamic dispatch overhead +3. **Simplicity**: Standard Rust patterns, no custom macros +4. **Better Tooling**: Full IDE support with autocomplete +5. **Easier Debugging**: Clearer stack traces and error messages +6. **Serialization**: Built-in `Serialize`/`Deserialize` support for all events diff --git a/MIGRATION_CN.md b/MIGRATION_CN.md new file mode 100644 index 0000000..b7f270d --- /dev/null +++ b/MIGRATION_CN.md @@ -0,0 +1,379 @@ +# 迁移指南:v0.5.x 到 v1.0.0 + +## 概述 + +版本 0.6.0 引入了一个重要的架构改进,从基于 trait 的事件系统过渡到基于 enum 的事件系统。此变更带来: + +- **更好的类型安全**: 编译时保证事件类型 +- **改进的性能**: 消除动态分发开销(不再使用 `Box`) +- **更简单的代码**: 标准 Rust 模式而不是自定义宏 +- **更好的 IDE 支持**: 完整的自动补全和类型推断 + +## 破坏性变更摘要 + +| 组件 | v0.5.x | v1.0.0 | +|-----------|--------|--------| +| 事件类型 | `Box` | `DexEvent`(枚举) | +| 回调签名 | `Fn(Box)` | `Fn(DexEvent)` | +| 事件匹配 | `match_event!` 宏 | 标准 `match` 表达式 | +| 元数据访问 | `.event_type()` | `.metadata().event_type` | +| 事件属性 | `.signature()` | `.metadata().signature` | + +## 迁移步骤 + +### 步骤 1:更新回调签名 + +**之前 (v0.5.x):** +```rust +use solana_streamer_sdk::streaming::event_parser::UnifiedEvent; + +let callback = |event: Box| { + println!("接收到事件: {:?}", event); +}; +``` + +**之后 (v1.0.0):** +```rust +use solana_streamer_sdk::streaming::event_parser::DexEvent; + +let callback = |event: DexEvent| { + println!("接收到事件: {:?}", event); +}; +``` + +### 步骤 2:更新事件匹配 + +**之前 (v0.5.x):** +```rust +use solana_streamer_sdk::match_event; + +match_event!(event, { + PumpFunTradeEvent => |e: PumpFunTradeEvent| { + println!("PumpFun 交易: {:?}", e); + }, + RaydiumCpmmSwapEvent => |e: RaydiumCpmmSwapEvent| { + println!("Raydium 交换: {:?}", e); + }, +}); +``` + +**之后 (v1.0.0):** +```rust +match event { + DexEvent::PumpFunTradeEvent(e) => { + println!("PumpFun 交易: {:?}", e); + } + DexEvent::RaydiumCpmmSwapEvent(e) => { + println!("Raydium 交换: {:?}", e); + } + _ => {} +} +``` + +### 步骤 3:更新元数据访问 + +**之前 (v0.5.x):** +```rust +let event_type = event.event_type(); +let signature = event.signature(); +let slot = event.slot(); +let protocol = event.protocol(); +``` + +**之后 (v1.0.0):** +```rust +let event_type = event.metadata().event_type; +let signature = event.metadata().signature; +let slot = event.metadata().slot; +let protocol = event.metadata().protocol; +``` + +### 步骤 4:更新导入语句 + +**之前 (v0.5.x):** +```rust +use solana_streamer_sdk::{ + match_event, + streaming::event_parser::{ + UnifiedEvent, + protocols::{ + pumpfun::{PumpFunTradeEvent, PumpFunCreateTokenEvent}, + raydium_cpmm::{RaydiumCpmmSwapEvent}, + }, + }, +}; +``` + +**之后 (v1.0.0):** +```rust +use solana_streamer_sdk::streaming::event_parser::{ + DexEvent, + protocols::{ + pumpfun::{PumpFunTradeEvent, PumpFunCreateTokenEvent}, + raydium_cpmm::{RaydiumCpmmSwapEvent}, + }, +}; +``` + +注意:`match_event!` 宏不再需要或可用。 + +## 完整示例迁移 + +### 之前 (v0.5.x) + +```rust +use solana_streamer_sdk::{ + match_event, + streaming::{ + event_parser::{ + UnifiedEvent, + protocols::{ + pumpfun::{PumpFunTradeEvent, PumpFunCreateTokenEvent}, + raydium_cpmm::RaydiumCpmmSwapEvent, + }, + }, + YellowstoneGrpc, + }, +}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let grpc = YellowstoneGrpc::new( + "grpc-endpoint".to_string(), + Some("api-key".to_string()), + )?; + + let callback = |event: Box| { + println!( + "事件类型: {:?}, 签名: {}", + event.event_type(), + event.signature() + ); + + match_event!(event, { + PumpFunTradeEvent => |e: PumpFunTradeEvent| { + println!("PumpFun 交易: {} SOL", e.sol_amount); + }, + PumpFunCreateTokenEvent => |e: PumpFunCreateTokenEvent| { + println!("新代币: {}", e.name); + }, + RaydiumCpmmSwapEvent => |e: RaydiumCpmmSwapEvent| { + println!("Raydium 交换"); + }, + }); + }; + + grpc.subscribe_events( + protocols, + event_filter, + tx_filter, + account_filter, + callback, + ).await?; + + Ok(()) +} +``` + +### 之后 (v1.0.0) + +```rust +use solana_streamer_sdk::streaming::{ + event_parser::{ + DexEvent, + protocols::{ + pumpfun::{PumpFunTradeEvent, PumpFunCreateTokenEvent}, + raydium_cpmm::RaydiumCpmmSwapEvent, + }, + }, + YellowstoneGrpc, +}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let grpc = YellowstoneGrpc::new( + "grpc-endpoint".to_string(), + Some("api-key".to_string()), + )?; + + let callback = |event: DexEvent| { + println!( + "事件类型: {:?}, 签名: {}", + event.metadata().event_type, + event.metadata().signature + ); + + match event { + DexEvent::PumpFunTradeEvent(e) => { + println!("PumpFun 交易: {} SOL", e.sol_amount); + } + DexEvent::PumpFunCreateTokenEvent(e) => { + println!("新代币: {}", e.name); + } + DexEvent::RaydiumCpmmSwapEvent(e) => { + println!("Raydium 交换"); + } + _ => {} + } + }; + + grpc.subscribe_events( + protocols, + event_filter, + tx_filter, + account_filter, + callback, + ).await?; + + Ok(()) +} +``` + +## 高级模式 + +### 模式 1:使用 Match 进行事件过滤 + +**v1.0.0:** +```rust +let callback = |event: DexEvent| { + // 只处理特定事件类型 + match event { + DexEvent::PumpFunTradeEvent(e) if e.is_buy => { + println!("买入: {} 代币", e.token_amount); + } + DexEvent::PumpFunTradeEvent(e) if !e.is_buy => { + println!("卖出: {} 代币", e.token_amount); + } + _ => {} // 忽略其他事件 + } +}; +``` + +### 模式 2:通用事件处理 + +**v1.0.0:** +```rust +fn process_event(event: DexEvent) { + let metadata = event.metadata(); + + println!("协议: {:?}", metadata.protocol); + println!("事件类型: {:?}", metadata.event_type); + println!("签名: {}", metadata.signature); + println!("插槽: {}", metadata.slot); + + // 处理特定事件类型 + match event { + DexEvent::PumpFunTradeEvent(e) => handle_pumpfun_trade(e), + DexEvent::RaydiumCpmmSwapEvent(e) => handle_raydium_swap(e), + _ => {} + } +} +``` + +### 模式 3:事件类型分类 + +**v1.0.0:** +```rust +fn categorize_event(event: &DexEvent) -> &'static str { + match event { + DexEvent::PumpFunTradeEvent(_) + | DexEvent::PumpSwapBuyEvent(_) + | DexEvent::PumpSwapSellEvent(_) => "交易", + + DexEvent::PumpFunCreateTokenEvent(_) + | DexEvent::PumpSwapCreatePoolEvent(_) => "创建", + + DexEvent::RaydiumCpmmDepositEvent(_) + | DexEvent::RaydiumCpmmWithdrawEvent(_) => "流动性", + + _ => "其他", + } +} +``` + +## EventParser API 变更 + +### 解析交易 + +**之前 (v0.5.x):** +```rust +let parser = Arc::new(EventParser::new(protocols, event_filter)); +parser.parse_encoded_confirmed_transaction_with_status_meta( + signature, + transaction, + Arc::new(|event: &Box| { + println!("{:?}", event); + }), +).await?; +``` + +**之后 (v1.0.0):** +```rust +EventParser::parse_encoded_confirmed_transaction_with_status_meta( + &protocols, + event_filter.as_ref(), + signature, + transaction, + Arc::new(|event: &DexEvent| { + println!("{:?}", event); + }), +).await?; +``` + +`EventParser` 现在是无状态的,使用静态方法,无需创建实例。 + +## 常见陷阱 + +### 陷阱 1:忘记处理所有变体 + +❌ **错误:** +```rust +match event { + DexEvent::PumpFunTradeEvent(e) => { /* ... */ } + // 缺少其他变体! +} +``` + +✅ **正确:** +```rust +match event { + DexEvent::PumpFunTradeEvent(e) => { /* ... */ } + _ => {} // 处理或忽略其他事件 +} +``` + +### 陷阱 2:使用旧的元数据访问模式 + +❌ **错误:** +```rust +let sig = event.signature(); // 此方法不再存在 +``` + +✅ **正确:** +```rust +let sig = event.metadata().signature; +``` + +### 陷阱 3:尝试使用 `match_event!` 宏 + +❌ **错误:** +```rust +match_event!(event, { /* ... */ }); // 宏不再存在 +``` + +✅ **正确:** +```rust +match event { + DexEvent::PumpFunTradeEvent(e) => { /* ... */ } + _ => {} +} +``` + +## 新系统的优势 + +1. **类型安全**: 编译器在编译时捕获更多错误 +2. **性能**: 无动态分发开销 +3. **简洁性**: 标准 Rust 模式,无自定义宏 +4. **更好的工具支持**: 完整的 IDE 自动补全支持 +5. **更易调试**: 更清晰的堆栈跟踪和错误消息 +6. **序列化**: 所有事件内置 `Serialize`/`Deserialize` 支持 diff --git a/README.md b/README.md index 2707c48..039e62b 100755 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ - [🚀 Project Features](#-project-features) - [⚡ Installation](#-installation) +- [🔄 Migration Guide](#-migration-guide) - [⚙️ Configuration System](#️-configuration-system) - [📚 Usage Examples](#-usage-examples) - [🔧 Supported Protocols](#-supported-protocols) @@ -108,74 +109,69 @@ Add the dependency to your `Cargo.toml`: ```toml # Add to your Cargo.toml -solana-streamer-sdk = { path = "./solana-streamer", version = "0.5.0" } +solana-streamer-sdk = { path = "./solana-streamer", version = "1.0.0" } ``` ### Use crates.io ```toml # Add to your Cargo.toml -solana-streamer-sdk = "0.5.0" +solana-streamer-sdk = "1.0.0" +``` + +## 🔄 Migration Guide + +### Migrating from v0.5.x to v1.0.0 + +Version 1.0.0 introduces a major architectural change from trait-based event handling to enum-based events. This provides better type safety, improved performance, and simpler code patterns. + +**Key Changes:** + +1. **Event Type Changed** - `Box` → `DexEvent` enum +2. **Callback Signature** - Callbacks now receive concrete `DexEvent` instead of trait objects +3. **Event Matching** - Use standard Rust `match` instead of `match_event!` macro +4. **Metadata Access** - Event properties now accessed through `.metadata()` method + +For detailed migration steps and code examples, see [MIGRATION.md](MIGRATION.md) or [MIGRATION_CN.md](MIGRATION_CN.md) (Chinese version). + +**Quick Migration Example:** + +```rust +// Old (v0.5.x) +let callback = |event: Box| { + println!("Event: {:?}", event.event_type()); +}; + +// New (v1.0.0) +let callback = |event: DexEvent| { + println!("Event: {:?}", event.metadata().event_type); +}; ``` ## ⚙️ Configuration System -### Preset Configurations - -The library provides three preset configurations optimized for different use cases: - -#### 1. High Throughput Configuration (`high_throughput()`) - -Optimized for high-concurrency scenarios, prioritizing throughput over latency: +You can customize client configuration: ```rust -let config = StreamClientConfig::high_throughput(); -// Or use convenience methods -let grpc = YellowstoneGrpc::new_high_throughput(endpoint, token)?; -let shred = ShredStreamGrpc::new_high_throughput(endpoint).await?; +use solana_streamer_sdk::streaming::grpc::ClientConfig; + +// Use default configuration +let grpc = YellowstoneGrpc::new(endpoint, token)?; + +// Or create custom configuration +let mut config = ClientConfig::default(); +config.enable_metrics = true; // Enable performance monitoring +config.connection.connect_timeout = 30; // 30 seconds +config.connection.request_timeout = 120; // 120 seconds + +let grpc = YellowstoneGrpc::new_with_config(endpoint, token, config)?; ``` -**Features:** -- **Backpressure Strategy**: Drop - drops messages during high load to avoid blocking -- **Buffer Size**: 5,000 permits to handle burst traffic -- **Use Case**: Scenarios where you need to process large volumes of data and can tolerate occasional message drops during peak loads - -#### 2. Low Latency Configuration (`low_latency()`) - -Optimized for real-time scenarios, prioritizing latency over throughput: - -```rust -let config = StreamClientConfig::low_latency(); -// Or use convenience methods -let grpc = YellowstoneGrpc::new_low_latency(endpoint, token)?; -let shred = ShredStreamGrpc::new_low_latency(endpoint).await?; -``` - -**Features:** -- **Backpressure Strategy**: Block - ensures no data loss -- **Buffer Size**: 4000 permits for balanced throughput and latency -- **Immediate Processing**: No buffering, processes events immediately -- **Use Case**: Scenarios where every millisecond counts and you cannot afford to lose any events, such as trading applications or real-time monitoring - - -### Custom Configuration - -You can also create custom configurations: - -```rust -let config = StreamClientConfig { - connection: ConnectionConfig { - connect_timeout: 30, - request_timeout: 120, - max_decoding_message_size: 20 * 1024 * 1024, // 20MB - }, - backpressure: BackpressureConfig { - permits: 2000, - strategy: BackpressureStrategy::Block, - }, - enable_metrics: true, -}; -``` +**Available Configuration Options:** +- `enable_metrics`: Enable/disable performance monitoring (default: false) +- `connection.connect_timeout`: Connection timeout in seconds (default: 10) +- `connection.request_timeout`: Request timeout in seconds (default: 60) +- `connection.max_decoding_message_size`: Maximum message size in bytes (default: 10MB) ## 📚 Usage Examples @@ -296,7 +292,7 @@ Note: Multiple subscription attempts on the same client return an error. ### Unified Event Interface -- **DexEvent Trait**: All protocol events implement a common interface +- **DexEvent Enum**: Type-safe enum containing all protocol events - **Protocol Enum**: Easy identification of event sources - **Event Factory**: Automatic event parsing and categorization diff --git a/README_CN.md b/README_CN.md index f009537..bd74ea1 100644 --- a/README_CN.md +++ b/README_CN.md @@ -45,6 +45,7 @@ - [🚀 项目特性](#-项目特性) - [⚡ 安装](#-安装) +- [🔄 迁移指南](#-迁移指南) - [⚙️ 配置系统](#️-配置系统) - [📚 使用示例](#-使用示例) - [🔧 支持的协议](#-支持的协议) @@ -107,74 +108,69 @@ git clone https://github.com/0xfnzero/solana-streamer ```toml # 添加到您的 Cargo.toml -solana-streamer-sdk = { path = "./solana-streamer", version = "0.5.0" } +solana-streamer-sdk = { path = "./solana-streamer", version = "1.0.0" } ``` ### 使用 crates.io ```toml # 添加到您的 Cargo.toml -solana-streamer-sdk = "0.5.0" +solana-streamer-sdk = "1.0.0" +``` + +## 🔄 迁移指南 + +### 从 v0.5.x 迁移到 v1.0.0 + +版本 1.0.0 引入了从基于 trait 的事件处理到基于 enum 的事件的重大架构变更。这提供了更好的类型安全性、改进的性能和更简单的代码模式。 + +**主要变更:** + +1. **事件类型变更** - `Box` → `DexEvent` 枚举 +2. **回调签名** - 回调现在接收具体的 `DexEvent` 而不是 trait 对象 +3. **事件匹配** - 使用标准 Rust `match` 而不是 `match_event!` 宏 +4. **元数据访问** - 事件属性现在通过 `.metadata()` 方法访问 + +详细的迁移步骤和代码示例,请参阅 [MIGRATION.md](MIGRATION.md) 或 [MIGRATION_CN.md](MIGRATION_CN.md)(中文版本)。 + +**快速迁移示例:** + +```rust +// 旧版 (v0.5.x) +let callback = |event: Box| { + println!("Event: {:?}", event.event_type()); +}; + +// 新版 (v1.0.0) +let callback = |event: DexEvent| { + println!("Event: {:?}", event.metadata().event_type); +}; ``` ## ⚙️ 配置系统 -### 预设配置 - -库提供了三种预设配置,针对不同的使用场景进行了优化: - -#### 1. 高吞吐量配置 (`high_throughput()`) - -专为高并发场景优化,优先考虑吞吐量而非延迟: +您可以自定义客户端配置: ```rust -let config = StreamClientConfig::high_throughput(); -// 或者使用便捷方法 -let grpc = YellowstoneGrpc::new_high_throughput(endpoint, token)?; -let shred = ShredStreamGrpc::new_high_throughput(endpoint).await?; +use solana_streamer_sdk::streaming::grpc::ClientConfig; + +// 使用默认配置 +let grpc = YellowstoneGrpc::new(endpoint, token)?; + +// 或创建自定义配置 +let mut config = ClientConfig::default(); +config.enable_metrics = true; // 启用性能监控 +config.connection.connect_timeout = 30; // 30 秒 +config.connection.request_timeout = 120; // 120 秒 + +let grpc = YellowstoneGrpc::new_with_config(endpoint, token, config)?; ``` -**特性:** -- **背压策略**: Drop(丢弃策略)- 在高负载时丢弃消息以避免阻塞 -- **缓冲区大小**: 5,000 个许可证,处理突发流量 -- **适用场景**: 需要处理大量数据且可以容忍在峰值负载时偶尔丢失消息的场景 - -#### 2. 低延迟配置 (`low_latency()`) - -专为实时场景优化,优先考虑延迟而非吞吐量: - -```rust -let config = StreamClientConfig::low_latency(); -// 或者使用便捷方法 -let grpc = YellowstoneGrpc::new_low_latency(endpoint, token)?; -let shred = ShredStreamGrpc::new_low_latency(endpoint).await?; -``` - -**特性:** -- **背压策略**: Block(阻塞策略)- 确保不丢失任何数据 -- **缓冲区大小**: 4000 个许可证,平衡吞吐量和延迟 -- **立即处理**: 不进行缓冲,立即处理事件 -- **适用场景**: 每毫秒都很重要且不能丢失任何事件的场景,如交易应用或实时监控 - - -### 自定义配置 - -您也可以创建自定义配置: - -```rust -let config = StreamClientConfig { - connection: ConnectionConfig { - connect_timeout: 30, - request_timeout: 120, - max_decoding_message_size: 20 * 1024 * 1024, // 20MB - }, - backpressure: BackpressureConfig { - permits: 2000, - strategy: BackpressureStrategy::Block, - }, - enable_metrics: true, -}; -``` +**可用配置选项:** +- `enable_metrics`: 启用/禁用性能监控(默认:false) +- `connection.connect_timeout`: 连接超时(秒)(默认:10) +- `connection.request_timeout`: 请求超时(秒)(默认:60) +- `connection.max_decoding_message_size`: 最大消息大小(字节)(默认:10MB) ## 📚 使用示例 @@ -295,7 +291,7 @@ grpc.update_subscription( ### 统一事件接口 -- **DexEvent Trait**: 所有协议事件实现通用接口 +- **DexEvent 枚举**: 包含所有协议事件的类型安全枚举 - **Protocol Enum**: 轻松识别事件来源 - **Event Factory**: 自动事件解析和分类 diff --git a/examples/pumpswap_pool_account_listen_example.rs b/examples/pumpswap_pool_account_listen_example.rs index 72f83e2..9bab93e 100644 --- a/examples/pumpswap_pool_account_listen_example.rs +++ b/examples/pumpswap_pool_account_listen_example.rs @@ -26,7 +26,7 @@ async fn main() -> Result<(), Box> { async fn test_grpc() -> Result<(), Box> { println!("Subscribing to Yellowstone gRPC events..."); // Create low-latency configuration - let mut config: ClientConfig = ClientConfig::low_latency(); + let mut config: ClientConfig = ClientConfig::default(); // Enable performance monitoring, has performance overhead, disabled by default config.enable_metrics = true; let grpc = YellowstoneGrpc::new_with_config( diff --git a/examples/shred_example.rs b/examples/shred_example.rs index c01b74d..6659aab 100644 --- a/examples/shred_example.rs +++ b/examples/shred_example.rs @@ -15,7 +15,7 @@ async fn test_shreds() -> Result<(), Box> { println!("Subscribing to ShredStream events..."); // Create low-latency configuration - let mut config = StreamClientConfig::low_latency(); + let mut config = StreamClientConfig::default(); // Enable performance monitoring, has performance overhead, disabled by default config.enable_metrics = true; let shred_stream = diff --git a/examples/token_balance_listen_example.rs b/examples/token_balance_listen_example.rs index b36e750..2e5dbbc 100644 --- a/examples/token_balance_listen_example.rs +++ b/examples/token_balance_listen_example.rs @@ -18,7 +18,7 @@ async fn main() -> Result<(), Box> { async fn test_grpc() -> Result<(), Box> { println!("Subscribing to Yellowstone gRPC events..."); // Create low-latency configuration - let mut config: ClientConfig = ClientConfig::low_latency(); + let mut config: ClientConfig = ClientConfig::default(); // Enable performance monitoring, has performance overhead, disabled by default config.enable_metrics = true; let grpc = YellowstoneGrpc::new_with_config( diff --git a/examples/token_decimals_listen_example.rs b/examples/token_decimals_listen_example.rs index 159db96..a192d7a 100644 --- a/examples/token_decimals_listen_example.rs +++ b/examples/token_decimals_listen_example.rs @@ -18,7 +18,7 @@ async fn main() -> Result<(), Box> { async fn test_grpc() -> Result<(), Box> { println!("Subscribing to Yellowstone gRPC events..."); // Create low-latency configuration - let mut config: ClientConfig = ClientConfig::low_latency(); + let mut config: ClientConfig = ClientConfig::default(); // Enable performance monitoring, has performance overhead, disabled by default config.enable_metrics = true; let grpc = YellowstoneGrpc::new_with_config( diff --git a/src/streaming/common/config.rs b/src/streaming/common/config.rs index de63689..8510940 100644 --- a/src/streaming/common/config.rs +++ b/src/streaming/common/config.rs @@ -35,12 +35,3 @@ impl Default for StreamClientConfig { Self { connection: ConnectionConfig::default(), enable_metrics: false } } } - -impl StreamClientConfig { - pub fn low_latency() -> Self { - Self::default() - } - pub fn high_throughput() -> Self { - Self::default() - } -}