|
4 | 4 |
|
5 | 5 | Client for the [Server-Sent Events] protocol (aka [EventSource]). |
6 | 6 |
|
| 7 | +This library focuses on the SSE protocol implementation. You provide the HTTP transport layer (hyper, reqwest, etc.), giving you full control over HTTP configuration like timeouts, TLS, and connection pooling. |
| 8 | + |
7 | 9 | [Server-Sent Events]: https://html.spec.whatwg.org/multipage/server-sent-events.html |
8 | 10 | [EventSource]: https://developer.mozilla.org/en-US/docs/Web/API/EventSource |
9 | 11 |
|
10 | 12 | ## Requirements |
11 | 13 |
|
12 | | -Requires tokio. |
| 14 | +* Tokio async runtime |
| 15 | +* An HTTP client library (hyper, reqwest, or custom) |
| 16 | + |
| 17 | +## Quick Start |
| 18 | + |
| 19 | +### 1. Add dependencies |
13 | 20 |
|
14 | | -## Usage |
| 21 | +```toml |
| 22 | +[dependencies] |
| 23 | +eventsource-client = "0.17" |
| 24 | +reqwest = { version = "0.12", features = ["stream"] } # or hyper v1 |
| 25 | +futures = "0.3" |
| 26 | +tokio = { version = "1", features = ["macros", "rt-multi-thread"] } |
| 27 | +``` |
| 28 | + |
| 29 | +### 2. Implement HttpTransport |
15 | 30 |
|
16 | | -Example that just prints the type of each event received: |
| 31 | +Use one of our example implementations: |
17 | 32 |
|
18 | 33 | ```rust |
19 | | -use eventsource_client as es; |
| 34 | +// See examples/reqwest_transport.rs for complete implementation |
| 35 | +use eventsource_client::{HttpTransport, ResponseFuture}; |
20 | 36 |
|
21 | | -let mut client = es::ClientBuilder::for_url("https://example.com/stream")? |
22 | | - .header("Authorization", "Basic username:password")? |
23 | | - .build(); |
| 37 | +struct ReqwestTransport { |
| 38 | + client: reqwest::Client, |
| 39 | +} |
24 | 40 |
|
25 | | -client |
26 | | - .stream() |
27 | | - .map_ok(|event| println!("got event: {:?}", event)) |
28 | | - .map_err(|err| eprintln!("error streaming events: {:?}", err)); |
| 41 | +impl HttpTransport for ReqwestTransport { |
| 42 | + fn request(&self, request: http::Request<()>) -> ResponseFuture { |
| 43 | + // Convert request and call HTTP client |
| 44 | + // See examples/ for full implementation |
| 45 | + } |
| 46 | +} |
29 | 47 | ``` |
30 | 48 |
|
31 | | -(Some boilerplate omitted for clarity; see [examples directory] for complete, |
32 | | -working code.) |
| 49 | +### 3. Use the client |
| 50 | + |
| 51 | +```rust |
| 52 | +use eventsource_client::{ClientBuilder, SSE}; |
| 53 | +use futures::TryStreamExt; |
| 54 | + |
| 55 | +#[tokio::main] |
| 56 | +async fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 57 | + // Create HTTP transport |
| 58 | + let transport = ReqwestTransport::new()?; |
| 59 | + |
| 60 | + // Build SSE client |
| 61 | + let client = ClientBuilder::for_url("https://example.com/stream")? |
| 62 | + .header("Authorization", "Bearer token")? |
| 63 | + .build_with_transport(transport); |
| 64 | + |
| 65 | + // Stream events |
| 66 | + let mut stream = client.stream(); |
| 67 | + |
| 68 | + while let Some(event) = stream.try_next().await? { |
| 69 | + match event { |
| 70 | + SSE::Event(evt) => println!("Event: {}", evt.event_type), |
| 71 | + SSE::Comment(c) => println!("Comment: {}", c), |
| 72 | + SSE::Connected(_) => println!("Connected!"), |
| 73 | + } |
| 74 | + } |
| 75 | + |
| 76 | + Ok(()) |
| 77 | +} |
| 78 | +``` |
33 | 79 |
|
34 | | -[examples directory]: https://github.com/launchdarkly/rust-eventsource-client/tree/main/eventsource-client/examples |
35 | 80 | ## Features |
36 | 81 |
|
37 | | -* tokio-based streaming client. |
38 | | -* Supports setting custom headers on the HTTP request (e.g. for endpoints |
39 | | - requiring authorization). |
40 | | -* Retry for failed connections. |
41 | | -* Reconnection if connection is interrupted, with exponential backoff. |
| 82 | +* **Pluggable HTTP transport** - Use any HTTP client (hyper, reqwest, or custom) |
| 83 | +* **Tokio-based streaming** - Efficient async/await support |
| 84 | +* **Custom headers** - Full control over HTTP requests |
| 85 | +* **Automatic reconnection** - Configurable exponential backoff |
| 86 | +* **Retry logic** - Handle transient failures gracefully |
| 87 | +* **Redirect following** - Automatic handling of HTTP redirects |
| 88 | +* **Last-Event-ID** - Resume streams from last received event |
| 89 | + |
| 90 | +## Migration from v0.16 |
| 91 | + |
| 92 | +If you're upgrading from v0.16 (which used hyper 0.14 internally), see [MIGRATION.md](MIGRATION.md) for a detailed migration guide. |
| 93 | + |
| 94 | +Key changes: |
| 95 | +- You must now provide an HTTP transport implementation |
| 96 | +- Removed `build()`, `build_http()`, and other hyper-specific methods |
| 97 | +- Use `build_with_transport(transport)` instead |
| 98 | +- Timeout configuration moved to your HTTP transport |
| 99 | + |
| 100 | +## Why Pluggable Transport? |
| 101 | + |
| 102 | +1. **Use latest HTTP clients** - Not locked to a specific HTTP library version |
| 103 | +2. **Full control** - Configure timeouts, TLS, proxies, etc. exactly as needed |
| 104 | +3. **Smaller library** - Focused on SSE protocol, not HTTP implementation |
| 105 | +4. **Flexibility** - Swap HTTP clients without changing SSE code |
| 106 | + |
| 107 | +## Architecture |
| 108 | + |
| 109 | +``` |
| 110 | +┌─────────────────────────────────────┐ |
| 111 | +│ Your Application │ |
| 112 | +└─────────────┬───────────────────────┘ |
| 113 | + │ |
| 114 | + ▼ |
| 115 | +┌─────────────────────────────────────┐ |
| 116 | +│ eventsource-client │ |
| 117 | +│ (SSE Protocol Implementation) │ |
| 118 | +└─────────────┬───────────────────────┘ |
| 119 | + │ HttpTransport trait |
| 120 | + ▼ |
| 121 | +┌─────────────────────────────────────┐ |
| 122 | +│ Your HTTP Client │ |
| 123 | +│ (hyper, reqwest, custom, etc.) │ |
| 124 | +└─────────────────────────────────────┘ |
| 125 | +``` |
42 | 126 |
|
43 | 127 | ## Stability |
44 | 128 |
|
|
0 commit comments