+1
Cargo.lock
+1
Cargo.lock
+2
-1
crates/jacquard-common/Cargo.toml
+2
-1
crates/jacquard-common/Cargo.toml
···
81
81
features = ["arithmetic"]
82
82
83
83
[dev-dependencies]
84
-
tokio = { version = "1", features = ["macros", "rt"] }
84
+
tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] }
85
+
futures-lite = "2.6"
85
86
86
87
[package.metadata.docs.rs]
87
88
features = [ "crypto-k256", "crypto-k256", "crypto-p256"]
+27
crates/jacquard-common/examples/streaming_download.rs
+27
crates/jacquard-common/examples/streaming_download.rs
···
1
+
//! Example: Download large file using streaming
2
+
#![cfg(all(feature = "streaming", feature = "reqwest-client"))]
3
+
4
+
use jacquard_common::http_client::HttpClientExt;
5
+
6
+
#[tokio::main]
7
+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
8
+
let client = reqwest::Client::new();
9
+
10
+
let request = http::Request::builder()
11
+
.uri("https://httpbin.org/bytes/1024")
12
+
.body(vec![])
13
+
.unwrap();
14
+
15
+
let response = client.send_http_streaming(request).await?;
16
+
println!("Status: {}", response.status());
17
+
println!("Headers: {:?}", response.headers());
18
+
19
+
let (_parts, _body) = response.into_parts();
20
+
println!("Received streaming response body (ByteStream)");
21
+
22
+
// Note: To iterate over chunks, use futures_lite::StreamExt on the pinned inner stream:
23
+
// let mut stream = Box::pin(body.into_inner());
24
+
// while let Some(chunk) = stream.as_mut().try_next().await? { ... }
25
+
26
+
Ok(())
27
+
}
+33
crates/jacquard-common/examples/streaming_upload.rs
+33
crates/jacquard-common/examples/streaming_upload.rs
···
1
+
//! Example: Upload data using streaming request body
2
+
#![cfg(all(feature = "streaming", feature = "reqwest-client"))]
3
+
4
+
use jacquard_common::http_client::HttpClientExt;
5
+
use futures::stream;
6
+
use bytes::Bytes;
7
+
8
+
#[tokio::main]
9
+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
10
+
let client = reqwest::Client::new();
11
+
12
+
// Create a stream of data chunks
13
+
let chunks = vec![
14
+
Bytes::from("Hello, "),
15
+
Bytes::from("streaming "),
16
+
Bytes::from("world!"),
17
+
];
18
+
let body_stream = stream::iter(chunks);
19
+
20
+
// Build request and split into parts
21
+
let request = http::Request::builder()
22
+
.method(http::Method::POST)
23
+
.uri("https://httpbin.org/post")
24
+
.body(())
25
+
.unwrap();
26
+
27
+
let (parts, _) = request.into_parts();
28
+
29
+
let response = client.send_http_bidirectional(parts, body_stream).await?;
30
+
println!("Status: {}", response.status());
31
+
32
+
Ok(())
33
+
}
+42
crates/jacquard-common/src/stream.rs
+42
crates/jacquard-common/src/stream.rs
···
1
1
//! Stream abstractions for HTTP request/response bodies
2
+
//!
3
+
//! This module provides platform-agnostic streaming types for handling large
4
+
//! payloads efficiently without loading everything into memory.
5
+
//!
6
+
//! # Features
7
+
//!
8
+
//! - [`ByteStream`]: Streaming response bodies
9
+
//! - [`ByteSink`]: Streaming request bodies
10
+
//! - [`StreamError`]: Concrete error type for streaming operations
11
+
//!
12
+
//! # Platform Support
13
+
//!
14
+
//! Uses `n0-future` for platform-agnostic async streams that work on both
15
+
//! native and WASM targets without requiring `Send` bounds on WASM.
16
+
//!
17
+
//! # Examples
18
+
//!
19
+
//! ## Streaming Download
20
+
//!
21
+
//! ```no_run
22
+
//! # #[cfg(all(feature = "streaming", feature = "reqwest-client"))]
23
+
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
24
+
//! use jacquard_common::http_client::{HttpClient, HttpClientExt};
25
+
//! use futures_lite::StreamExt;
26
+
//!
27
+
//! let client = reqwest::Client::new();
28
+
//! let request = http::Request::builder()
29
+
//! .uri("https://example.com/large-file")
30
+
//! .body(vec![])
31
+
//! .unwrap();
32
+
//!
33
+
//! let response = client.send_http_streaming(request).await?;
34
+
//! let (_parts, body) = response.into_parts();
35
+
//! let mut stream = Box::pin(body.into_inner());
36
+
//!
37
+
//! // Use futures_lite::StreamExt for iteration
38
+
//! while let Some(chunk) = stream.as_mut().try_next().await? {
39
+
//! // Process chunk without loading entire file into memory
40
+
//! }
41
+
//! # Ok(())
42
+
//! # }
43
+
//! ```
2
44
3
45
use std::error::Error;
4
46
use std::fmt;