소스 검색

docs: add comprehensive README for Pyth Lazer Rust client (#3097)

* docs: add comprehensive README for Pyth Lazer Rust client

Co-Authored-By: keyvan <keyvan@dourolabs.xyz>

* chore: bump pyth-lazer-client version to 8.2.2

Co-Authored-By: keyvan <keyvan@dourolabs.xyz>

* docs: update README version to 8.2.2

Co-Authored-By: keyvan <keyvan@dourolabs.xyz>

* chore: update Cargo.lock for version 8.2.2

Co-Authored-By: keyvan <keyvan@dourolabs.xyz>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: keyvan <keyvan@dourolabs.xyz>
devin-ai-integration[bot] 1 개월 전
부모
커밋
13b554e082
3개의 변경된 파일369개의 추가작업 그리고 2개의 파일을 삭제
  1. 1 1
      Cargo.lock
  2. 1 1
      lazer/sdk/rust/client/Cargo.toml
  3. 367 0
      lazer/sdk/rust/client/README.md

+ 1 - 1
Cargo.lock

@@ -5693,7 +5693,7 @@ dependencies = [
 
 [[package]]
 name = "pyth-lazer-client"
-version = "8.2.1"
+version = "8.2.2"
 dependencies = [
  "alloy-primitives 0.8.25",
  "anyhow",

+ 1 - 1
lazer/sdk/rust/client/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "pyth-lazer-client"
-version = "8.2.1"
+version = "8.2.2"
 edition = "2021"
 description = "A Rust client for Pyth Lazer"
 license = "Apache-2.0"

+ 367 - 0
lazer/sdk/rust/client/README.md

@@ -0,0 +1,367 @@
+# Pyth Lazer Rust Client
+
+A high-performance Rust client for connecting to [Pyth Lazer](https://pyth.network/) real-time data streams. This client provides reliable, low-latency access to Pyth's oracle price feeds with built-in redundancy and automatic failover.
+
+## Features
+
+- **Multiple redundant WebSocket connections** - Maintains 4 concurrent connections by default for high availability
+- **Automatic message deduplication** - Uses TTL-based caching to eliminate duplicate messages across connections
+- **Exponential backoff reconnection** - Automatically handles connection failures with configurable retry logic
+- **Flexible subscription options** - Support for multiple data formats (EVM, Solana, etc.) and delivery channels
+- **History API client** - Fetch symbol metadata and historical price information
+- **Type-safe API** - Strongly-typed Rust interface with comprehensive error handling
+
+## Installation
+
+Add the following to your `Cargo.toml`:
+
+```toml
+[dependencies]
+pyth-lazer-client = "8.2.2"
+pyth-lazer-protocol = "0.16.0"
+tokio = { version = "1", features = ["full"] }
+```
+
+## Authentication
+
+To use the Pyth Lazer client, you need an access token. Set your access token via the `LAZER_ACCESS_TOKEN` environment variable:
+
+```bash
+export LAZER_ACCESS_TOKEN="your_access_token_here"
+```
+
+Or provide it directly in your code:
+
+```rust
+use pyth_lazer_client::stream_client::PythLazerStreamClientBuilder;
+
+let access_token = std::env::var("LAZER_ACCESS_TOKEN")
+    .expect("LAZER_ACCESS_TOKEN not set");
+
+let client = PythLazerStreamClientBuilder::new(access_token)
+    .build()?;
+```
+
+## Quick Start
+
+Here's a minimal example to get started with streaming price feeds:
+
+```rust
+use pyth_lazer_client::stream_client::PythLazerStreamClientBuilder;
+use pyth_lazer_protocol::api::{SubscribeRequest, SubscriptionParams, SubscriptionParamsRepr, Channel};
+use pyth_lazer_protocol::{PriceFeedId, PriceFeedProperty};
+use pyth_lazer_protocol::time::FixedRate;
+
+#[tokio::main]
+async fn main() -> anyhow::Result<()> {
+    // Create and start the client
+    let mut client = PythLazerStreamClientBuilder::new(
+        std::env::var("LAZER_ACCESS_TOKEN")?
+    ).build()?;
+
+    let mut receiver = client.start().await?;
+
+    // Subscribe to price feeds
+    let subscribe_request = SubscribeRequest {
+        subscription_id: pyth_lazer_protocol::api::SubscriptionId(1),
+        params: SubscriptionParams::new(SubscriptionParamsRepr {
+            price_feed_ids: Some(vec![PriceFeedId(1), PriceFeedId(2)]),
+            symbols: None,
+            properties: vec![PriceFeedProperty::Price, PriceFeedProperty::Exponent],
+            formats: vec![pyth_lazer_protocol::api::Format::Solana],
+            delivery_format: pyth_lazer_protocol::api::DeliveryFormat::Json,
+            json_binary_encoding: pyth_lazer_protocol::api::JsonBinaryEncoding::Base64,
+            parsed: true,
+            channel: Channel::FixedRate(FixedRate::RATE_200_MS),
+            ignore_invalid_feeds: false,
+        })?,
+    };
+
+    client.subscribe(subscribe_request).await?;
+
+    // Process incoming messages
+    while let Some(response) = receiver.recv().await {
+        println!("Received update: {:?}", response);
+    }
+
+    Ok(())
+}
+```
+
+## Configuration
+
+The `PythLazerStreamClientBuilder` provides several configuration options:
+
+### Custom Endpoints
+
+Override the default production endpoints:
+
+```rust
+let client = PythLazerStreamClientBuilder::new(access_token)
+    .with_endpoints(vec![
+        "wss://pyth-lazer-0.dourolabs.app/v1/stream".parse()?,
+        "wss://pyth-lazer-1.dourolabs.app/v1/stream".parse()?,
+    ])
+    .build()?;
+```
+
+### Number of Connections
+
+Set the number of concurrent WebSocket connections (default: 4):
+
+```rust
+let client = PythLazerStreamClientBuilder::new(access_token)
+    .with_num_connections(2)
+    .build()?;
+```
+
+### Connection Timeout
+
+Configure the timeout for WebSocket operations (default: 5 seconds):
+
+```rust
+use std::time::Duration;
+
+let client = PythLazerStreamClientBuilder::new(access_token)
+    .with_timeout(Duration::from_secs(10))
+    .build()?;
+```
+
+### Exponential Backoff
+
+Customize the reconnection backoff strategy:
+
+```rust
+use pyth_lazer_client::backoff::PythLazerExponentialBackoffBuilder;
+
+let backoff = PythLazerExponentialBackoffBuilder::default()
+    .build();
+
+let client = PythLazerStreamClientBuilder::new(access_token)
+    .with_backoff(backoff)
+    .build()?;
+```
+
+### Channel Capacity
+
+Set the internal message buffer size (default: 1000):
+
+```rust
+let client = PythLazerStreamClientBuilder::new(access_token)
+    .with_channel_capacity(5000)
+    .build()?;
+```
+
+## Subscription Options
+
+### Channels
+
+Choose the update frequency for your price feeds:
+
+- **`Channel::RealTime`** - Receive updates as soon as they're available
+- **`Channel::FixedRate(FixedRate::RATE_50_MS)`** - Updates every 50ms
+- **`Channel::FixedRate(FixedRate::RATE_200_MS)`** - Updates every 200ms (recommended for most use cases)
+- **`Channel::FixedRate(FixedRate::RATE_1000_MS)`** - Updates every 1000ms
+
+```rust
+use pyth_lazer_protocol::api::Channel;
+use pyth_lazer_protocol::time::FixedRate;
+
+// Real-time updates
+let channel = Channel::RealTime;
+
+// Fixed rate updates
+let channel = Channel::FixedRate(FixedRate::RATE_200_MS);
+```
+
+### Formats
+
+Specify the signature format for the price data:
+
+- **`Format::Evm`** - EVM-compatible format with secp256k1 signatures
+- **`Format::Solana`** - Solana-compatible format with Ed25519 signatures
+- **`Format::LeEcdsa`** - Little-endian ECDSA format
+- **`Format::LeUnsigned`** - Little-endian unsigned format
+
+```rust
+use pyth_lazer_protocol::api::Format;
+
+let formats = vec![Format::Evm, Format::Solana];
+```
+
+### Delivery Format
+
+Choose how messages are delivered:
+
+- **`DeliveryFormat::Json`** - Receive updates as JSON text messages (default)
+- **`DeliveryFormat::Binary`** - Receive updates as binary messages (more efficient)
+
+```rust
+use pyth_lazer_protocol::api::DeliveryFormat;
+
+let delivery_format = DeliveryFormat::Binary;
+```
+
+### Properties
+
+Select which price feed properties to receive:
+
+- `PriceFeedProperty::Price` - Current price
+- `PriceFeedProperty::BestBidPrice` - Best bid price
+- `PriceFeedProperty::BestAskPrice` - Best ask price
+- `PriceFeedProperty::PublisherCount` - Number of contributing publishers
+- `PriceFeedProperty::Exponent` - Price exponent
+- `PriceFeedProperty::Confidence` - Confidence interval
+- `PriceFeedProperty::FundingRate` - Funding rate (for perpetual markets)
+- `PriceFeedProperty::FundingTimestamp` - Funding rate timestamp
+- `PriceFeedProperty::FundingRateInterval` - Funding rate update interval
+
+```rust
+use pyth_lazer_protocol::PriceFeedProperty;
+
+let properties = vec![
+    PriceFeedProperty::Price,
+    PriceFeedProperty::Exponent,
+    PriceFeedProperty::Confidence,
+];
+```
+
+### Identifying Price Feeds
+
+Subscribe to feeds using either price feed IDs or symbols:
+
+```rust
+// By price feed ID
+let params = SubscriptionParamsRepr {
+    price_feed_ids: Some(vec![PriceFeedId(1), PriceFeedId(2)]),
+    symbols: None,
+    // ... other fields
+};
+
+// By symbol
+let params = SubscriptionParamsRepr {
+    price_feed_ids: None,
+    symbols: Some(vec![
+        "Crypto.BTC/USD".to_string(),
+        "Crypto.ETH/USD".to_string(),
+    ]),
+    // ... other fields
+};
+```
+
+## Examples
+
+### Comprehensive Streaming Example
+
+See [`examples/subscribe_price_feeds.rs`](examples/subscribe_price_feeds.rs) for a complete example demonstrating:
+
+- Client configuration with multiple connections
+- Subscribing to price feeds with different formats
+- Processing JSON and binary updates
+- Verifying message signatures
+- Unsubscribing from feeds
+
+Run the example:
+
+```bash
+cargo run --example subscribe_price_feeds
+```
+
+### Symbol Metadata
+
+Fetch symbol metadata using the history client:
+
+```rust
+use pyth_lazer_client::history_client::{PythLazerHistoryClient, PythLazerHistoryClientConfig};
+
+let client = PythLazerHistoryClient::new(
+    PythLazerHistoryClientConfig::default()
+);
+
+// Get all symbol metadata
+let symbols = client.all_symbols_metadata().await?;
+
+// Or get an auto-updating handle
+let handle = client.all_symbols_metadata_handle().await?;
+let symbols = handle.symbols();
+```
+
+See [`examples/symbols.rs`](examples/symbols.rs) and [`examples/symbols_stream.rs`](examples/symbols_stream.rs) for complete examples.
+
+## History Client
+
+The `PythLazerHistoryClient` provides access to symbol metadata and historical price information:
+
+```rust
+use pyth_lazer_client::history_client::{PythLazerHistoryClient, PythLazerHistoryClientConfig};
+use std::time::Duration;
+
+let config = PythLazerHistoryClientConfig {
+    urls: vec!["https://history.pyth-lazer.dourolabs.app/".parse()?],
+    update_interval: Duration::from_secs(30),
+    request_timeout: Duration::from_secs(15),
+    cache_dir: Some("/tmp/pyth-lazer-cache".into()),
+    channel_capacity: 1000,
+};
+
+let client = PythLazerHistoryClient::new(config);
+
+// Fetch symbol metadata once
+let symbols = client.all_symbols_metadata().await?;
+
+// Or get an auto-updating handle that refreshes in the background
+let handle = client.all_symbols_metadata_handle().await?;
+
+// Or get a stream of updates
+let mut stream = client.all_symbols_metadata_stream().await?;
+while let Some(symbols) = stream.recv().await {
+    println!("Updated symbols: {} feeds", symbols.len());
+}
+```
+
+The history client supports:
+
+- **One-time fetches** - Get current data with `all_symbols_metadata()`
+- **Auto-updating handles** - Background updates with `all_symbols_metadata_handle()`
+- **Streaming updates** - Receive updates via channels with `all_symbols_metadata_stream()`
+- **Local caching** - Optional disk cache for offline access
+- **Fault tolerance** - Graceful fallback to cached data on network failures
+
+## API Reference
+
+### Main Types
+
+- **`PythLazerStreamClient`** - The main client for streaming price updates
+- **`PythLazerStreamClientBuilder`** - Builder for configuring the stream client
+- **`PythLazerHistoryClient`** - Client for fetching symbol metadata
+- **`SubscribeRequest`** - Subscription configuration
+- **`SubscriptionParams`** - Subscription parameters wrapper
+- **`AnyResponse`** - Enum for JSON or binary responses
+
+### Core Methods
+
+#### PythLazerStreamClient
+
+- `start() -> Result<Receiver<AnyResponse>>` - Start the client and return message receiver
+- `subscribe(request: SubscribeRequest) -> Result<()>` - Subscribe to price feeds
+- `unsubscribe(id: SubscriptionId) -> Result<()>` - Unsubscribe from a feed
+
+#### PythLazerHistoryClient
+
+- `all_symbols_metadata() -> Result<Vec<SymbolMetadata>>` - Fetch all symbols once
+- `all_symbols_metadata_handle() -> Result<SymbolMetadataHandle>` - Get auto-updating handle
+- `all_symbols_metadata_stream() -> Result<Receiver<Vec<SymbolMetadata>>>` - Get update stream
+
+For complete API documentation, visit [docs.rs/pyth-lazer-client](https://docs.rs/pyth-lazer-client).
+
+## License
+
+This project is licensed under the Apache-2.0 License. See the [LICENSE](../../../../LICENSE) file for details.
+
+## Resources
+
+- [Pyth Network Documentation](https://docs.pyth.network/)
+- [Pyth Lazer Overview](https://docs.pyth.network/price-feeds/lazer)
+- [API Reference](https://docs.rs/pyth-lazer-client)
+- [Examples](examples/)
+- [GitHub Repository](https://github.com/pyth-network/pyth-crosschain)