Skip to main content

UploadClient

Struct UploadClient 

Source
pub struct UploadClient { /* private fields */ }
Expand description

Upload client for Baidu NetDisk

Implementations§

Source§

impl UploadClient

Source

pub fn new(http_client: HttpClient, token_getter: Arc<dyn TokenGetter>) -> Self

Create a new UploadClient instance

Usually you don’t need to call this directly - use BaiduNetDiskClient::upload() instead.

Source

pub fn http_client(&self) -> &HttpClient

Get a reference to the internal HTTP client

Source

pub async fn precreate( &self, options: PrecreateOptions, ) -> NetDiskResult<PrecreateResponse>

Precreate an upload session

Initiates an upload session and checks which chunks (if any) already exist on the server. This is the first step of the multi-step upload process.

Examples found in repository?
examples/upload_precreate.rs (line 82)
43async fn main() -> Result<(), Box<dyn std::error::Error>> {
44    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
45
46    let client = BaiduNetDiskClient::builder().build()?;
47    info!("Client created successfully");
48
49    client.load_token_from_env()?;
50    info!("Token loaded successfully");
51
52    let args: Vec<String> = std::env::args().collect();
53
54    if args.len() < 3 {
55        println!("Usage: {} <local_file> <remote_path>", args[0]);
56        println!("Example: {} test.txt /apps/test/test.txt", args[0]);
57        return Ok(());
58    }
59
60    let local_file = &args[1];
61    let remote_path = &args[2];
62
63    println!("=== Baidu NetDisk Preupload Test ===");
64    println!("Local file: {}", local_file);
65    println!("Remote path: {}", remote_path);
66    println!();
67
68    let (file_size, block_list) = get_file_md5blocks(local_file, 4 * 1024 * 1024)?;
69    let file_md5 = calculate_md5(local_file)?;
70
71    println!("File size: {} bytes", file_size);
72    println!("File MD5: {}", file_md5);
73    println!("Block count: {}", block_list.len());
74    println!("Block list: {:?}", block_list);
75    println!();
76
77    let options = PrecreateOptions::new(remote_path, file_size, block_list)
78        .content_md5(&file_md5)
79        .rtype(1);
80
81    println!("Sending precreate request...");
82    match client.upload().precreate(options).await {
83        Ok(response) => {
84            println!("Precreate success!");
85            println!("  Upload ID: {}", response.uploadid);
86            println!("  Path: {:?}", response.path);
87            println!("  Return type: {}", response.return_type);
88            println!("  Block list to upload: {:?}", response.block_list);
89        }
90        Err(e) => {
91            println!("Precreate failed: {}", e);
92        }
93    }
94
95    Ok(())
96}
Source§

impl UploadClient

Source

pub async fn locate_upload( &self, path: &str, uploadid: &str, ) -> NetDiskResult<LocateUploadResponse>

Locate upload domain

Gets the upload domain before uploading chunks. This is required before uploading file data.

According to Baidu NetDisk API documentation, the servers are sorted by proximity and speed. The first server is recommended as the default choice for optimal upload performance.

§Example
use baidu_netdisk_sdk::BaiduNetDiskClient;

let client = BaiduNetDiskClient::builder().build()?;
client.load_token_from_env()?;

let response = client.upload()
    .locate_upload("/apps/appName/filename.jpg", "P1-MTAuMjI4LjQzLjMxOjE1OTU4NTg==")
    .await?;

// Get the first HTTPS server (recommended by Baidu for optimal performance)
if let Some(server) = response.get_first_https_server() {
    println!("Upload server: {}", server);
}
Source

pub async fn upload_chunk( &self, options: UploadChunkOptions, server_url: Option<&str>, ) -> NetDiskResult<UploadChunkResponse>

Upload a single chunk

If server_url is not provided, the default server https://c3.pcs.baidu.com will be used.

Source

pub async fn upload_chunks_parallel( &self, remote_path: &str, uploadid: &str, chunks: Vec<(u32, Vec<u8>)>, max_concurrency: usize, server_url: Option<&str>, ) -> NetDiskResult<Vec<(u32, String)>>

Upload multiple chunks in parallel

If server_url is not provided, the default server https://c3.pcs.baidu.com will be used.

Source

pub async fn create_file( &self, options: CreateFileOptions, ) -> NetDiskResult<CreateFileResponse>

Create the final file on the server

This is the final step of the upload process, which merges all uploaded chunks into a single file.

Source§

impl UploadClient

Source

pub async fn upload_file<P: AsRef<Path>>( &self, local_path: P, remote_path: &str, ) -> NetDiskResult<CreateFileResponse>

Upload a file from local path (simple API)

This is the simplest way to upload a file. It handles everything automatically:

  • Opens and reads the file
  • Calculates MD5 for each chunk
  • Uploads missing chunks in parallel
  • Creates the final file on the server
§Example
use baidu_netdisk_sdk::BaiduNetDiskClient;

let client = BaiduNetDiskClient::builder().build()?;
client.load_token_from_env()?;

let response = client.upload()
    .upload_file("test.txt", "/remote/test.txt")
    .await?;

println!("Uploaded: {} ({} bytes)", response.path, response.size);
§See Also
Examples found in repository?
examples/upload_file.rs (line 32)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::init();
7
8    let client = BaiduNetDiskClient::builder().build()?;
9    info!("Client created successfully");
10
11    client.load_token_from_env()?;
12    info!("Token loaded successfully");
13
14    let args: Vec<String> = std::env::args().collect();
15
16    if args.len() < 3 {
17        println!("Usage: {} <local_file> <remote_path>", args[0]);
18        println!("Example: {} test.txt /apps/test/test.txt", args[0]);
19        return Ok(());
20    }
21
22    let local_file = &args[1];
23    let remote_path = &args[2];
24
25    println!("=== Baidu NetDisk File Upload (Simple) ===");
26    println!("Local file: {}", local_file);
27    println!("Remote path: {}", remote_path);
28    println!();
29
30    let start_time = std::time::Instant::now();
31
32    let response = client.upload().upload_file(local_file, remote_path).await?;
33
34    println!("File uploaded successfully!");
35    println!("  FS ID: {}", response.fs_id);
36    println!("  Server filename: {:?}", response.server_filename);
37    println!("  Path: {}", response.path);
38    println!("  Size: {} bytes", response.size);
39    println!("  Category: {}", response.category);
40    println!("  MD5: {}", response.md5.unwrap_or_default());
41    println!("  Upload time: {:?}", start_time.elapsed());
42
43    Ok(())
44}
Source

pub async fn upload_file_with_options<P: AsRef<Path>>( &self, local_path: P, remote_path: &str, options: SimpleUploadOptions, ) -> NetDiskResult<CreateFileResponse>

Upload a file from local path with custom options

Use this method to customize upload behavior:

  • chunk_size: Size of each chunk (default: 4MB)
  • max_concurrency: Maximum parallel uploads (default: 10)
  • r#type: File type hint (default: 1)
§Example
use baidu_netdisk_sdk::{BaiduNetDiskClient, upload::SimpleUploadOptions};

let client = BaiduNetDiskClient::builder().build()?;
client.load_token_from_env()?;

let options = SimpleUploadOptions::default()
    .chunk_size(8 * 1024 * 1024)  // 8MB chunks
    .max_concurrency(20);         // 20 parallel uploads

let response = client.upload()
    .upload_file_with_options("large_video.mp4", "/remote/video.mp4", options)
    .await?;

println!("Uploaded: {}", response.path);
Examples found in repository?
examples/upload_file_options.rs (line 56)
6async fn main() -> Result<(), Box<dyn std::error::Error>> {
7    env_logger::init();
8
9    let client = BaiduNetDiskClient::builder().build()?;
10    info!("Client created successfully");
11
12    client.load_token_from_env()?;
13    info!("Token loaded successfully");
14
15    let args: Vec<String> = std::env::args().collect();
16
17    if args.len() < 3 {
18        println!(
19            "Usage: {} <local_file> <remote_path> [chunk_size] [concurrency]",
20            args[0]
21        );
22        println!("Example: {} test.mp4 /upload/video.mp4 8388608 20", args[0]);
23        println!("  - chunk_size: bytes per chunk (default: 4194304 = 4MB)");
24        println!("  - concurrency: parallel uploads (default: 10)");
25        return Ok(());
26    }
27
28    let local_file = &args[1];
29    let remote_path = &args[2];
30
31    let chunk_size: usize = args
32        .get(3)
33        .and_then(|s| s.parse().ok())
34        .unwrap_or(4 * 1024 * 1024);
35    let concurrency: usize = args.get(4).and_then(|s| s.parse().ok()).unwrap_or(10);
36
37    let options = SimpleUploadOptions::default()
38        .chunk_size(chunk_size)
39        .max_concurrency(concurrency);
40
41    println!("=== Baidu NetDisk File Upload (Custom Options) ===");
42    println!("Local file: {}", local_file);
43    println!("Remote path: {}", remote_path);
44    println!(
45        "Chunk size: {} bytes ({:.2} MB)",
46        chunk_size,
47        chunk_size as f64 / 1024.0 / 1024.0
48    );
49    println!("Concurrency: {}", concurrency);
50    println!();
51
52    let start_time = std::time::Instant::now();
53
54    let response = client
55        .upload()
56        .upload_file_with_options(local_file, remote_path, options)
57        .await?;
58
59    println!("File uploaded successfully!");
60    println!("  FS ID: {}", response.fs_id);
61    println!("  Path: {}", response.path);
62    println!("  Size: {} bytes", response.size);
63    println!("  Category: {}", response.category);
64    println!("  MD5: {}", response.md5.unwrap_or_default());
65    println!("  Upload time: {:?}", start_time.elapsed());
66
67    Ok(())
68}
Source

pub async fn upload_reader<R: Read + Seek>( &self, reader: &mut R, file_size: u64, remote_path: &str, ) -> NetDiskResult<CreateFileResponse>

Upload from a Reader with seek support (streaming API)

This is a lower-level API that accepts any Read + Seek reader. Useful for:

  • Custom file wrapping (e.g., encrypted files)
  • Upload from memory-mapped files
  • Testing with custom readers
§Example
use baidu_netdisk_sdk::BaiduNetDiskClient;
use std::io::BufReader;

let client = BaiduNetDiskClient::builder().build()?;
client.load_token_from_env()?;

let file = std::fs::File::open("test.txt")?;
let metadata = file.metadata()?;
let file_size = metadata.len();

let reader = BufReader::new(file);
let mut reader = reader;  // mutable for rewind

let response = client.upload()
    .upload_reader(&mut reader, file_size, "/remote/test.txt")
    .await?;

println!("Uploaded: {}", response.path);
§Memory Usage

Memory is bounded by batch size (max_concurrency * 2 * chunk_size), approximately 80MB by default, regardless of file size.

Examples found in repository?
examples/upload_reader.rs (line 48)
6async fn main() -> Result<(), Box<dyn std::error::Error>> {
7    env_logger::init();
8
9    let client = BaiduNetDiskClient::builder().build()?;
10    info!("Client created successfully");
11
12    client.load_token_from_env()?;
13    info!("Token loaded successfully");
14
15    let args: Vec<String> = std::env::args().collect();
16
17    let local_file = if args.len() >= 2 {
18        &args[1]
19    } else {
20        println!("Usage: {} <local_file> [remote_path]", args[0]);
21        println!("Example: {} test.txt /upload/test.txt", args[0]);
22        return Ok(());
23    };
24
25    let remote_path = if args.len() >= 3 {
26        &args[2]
27    } else {
28        "/upload/test_reader.txt"
29    };
30
31    println!("=== Baidu NetDisk Reader Upload ===");
32    println!("Local file: {}", local_file);
33    println!("Remote path: {}", remote_path);
34    println!();
35
36    let file = std::fs::File::open(local_file)?;
37    let metadata = file.metadata()?;
38    let file_size = metadata.len();
39
40    println!("File size: {} bytes", file_size);
41
42    let mut reader = BufReader::new(file);
43
44    let start_time = std::time::Instant::now();
45
46    let response = client
47        .upload()
48        .upload_reader(&mut reader, file_size, remote_path)
49        .await?;
50
51    println!("File uploaded successfully!");
52    println!("  FS ID: {}", response.fs_id);
53    println!("  Server filename: {:?}", response.server_filename);
54    println!("  Path: {}", response.path);
55    println!("  Size: {} bytes", response.size);
56    println!("  Category: {}", response.category);
57    println!("  MD5: {}", response.md5.unwrap_or_default());
58    println!("  Upload time: {:?}", start_time.elapsed());
59
60    Ok(())
61}
Source

pub async fn upload_reader_with_options<R: Read + Seek>( &self, reader: &mut R, file_size: u64, remote_path: &str, options: SimpleUploadOptions, ) -> NetDiskResult<CreateFileResponse>

Upload from a Reader with custom options

§Example
use baidu_netdisk_sdk::{BaiduNetDiskClient, upload::SimpleUploadOptions};

let client = BaiduNetDiskClient::builder().build()?;
client.load_token_from_env()?;

let options = SimpleUploadOptions::default()
    .chunk_size(8 * 1024 * 1024)
    .max_concurrency(20);

let file = std::fs::File::open("test.txt")?;
let metadata = file.metadata()?;
let file_size = metadata.len();

let mut reader = std::io::BufReader::new(file);
let response = client.upload()
    .upload_reader_with_options(&mut reader, file_size, "/remote/test.txt", options)
    .await?;

println!("Uploaded: {}", response.path);
Source

pub async fn upload_bytes( &self, data: &[u8], remote_path: &str, ) -> NetDiskResult<CreateFileResponse>

Upload bytes from memory (simple API)

Use this method when you already have the data in memory. For large data, consider using UploadClient::upload_file or UploadClient::upload_reader instead to avoid loading the entire data into memory.

§Example
use baidu_netdisk_sdk::BaiduNetDiskClient;

let client = BaiduNetDiskClient::builder().build()?;
client.load_token_from_env()?;

let data = b"Hello, World!";
let response = client.upload()
    .upload_bytes(data, "/remote/hello.txt")
    .await?;

println!("Uploaded: {}", response.path);
§Memory Note

The entire data slice will be held in memory during upload. For large files, use UploadClient::upload_file which streams from disk.

Examples found in repository?
examples/upload_bytes.rs (line 31)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::init();
7
8    let client = BaiduNetDiskClient::builder().build()?;
9    info!("Client created successfully");
10
11    client.load_token_from_env()?;
12    info!("Token loaded successfully");
13
14    let args: Vec<String> = std::env::args().collect();
15
16    let remote_path = if args.len() >= 2 {
17        &args[1]
18    } else {
19        "/upload/hello_bytes.txt"
20    };
21
22    println!("=== Baidu NetDisk Bytes Upload (Simple) ===");
23    println!("Remote path: {}", remote_path);
24    println!();
25
26    let test_data = b"Hello from upload_bytes! This is a simple byte array upload test.";
27    println!("Uploading {} bytes of data...", test_data.len());
28
29    let start_time = std::time::Instant::now();
30
31    let response = client.upload().upload_bytes(test_data, remote_path).await?;
32
33    println!("Bytes uploaded successfully!");
34    println!("  FS ID: {}", response.fs_id);
35    println!("  Server filename: {:?}", response.server_filename);
36    println!("  Path: {}", response.path);
37    println!("  Size: {} bytes", response.size);
38    println!("  Category: {}", response.category);
39    println!("  MD5: {}", response.md5.unwrap_or_default());
40    println!("  Upload time: {:?}", start_time.elapsed());
41
42    Ok(())
43}
Source

pub async fn upload_bytes_with_options( &self, data: &[u8], remote_path: &str, options: SimpleUploadOptions, ) -> NetDiskResult<CreateFileResponse>

Upload bytes from memory with custom options

§Example
use baidu_netdisk_sdk::{BaiduNetDiskClient, upload::SimpleUploadOptions};

let client = BaiduNetDiskClient::builder().build()?;
client.load_token_from_env()?;

let options = SimpleUploadOptions::default()
    .chunk_size(8 * 1024 * 1024)
    .max_concurrency(20);

let data = b"Hello, World!";
let response = client.upload()
    .upload_bytes_with_options(data, "/remote/hello.txt", options)
    .await?;

println!("Uploaded: {}", response.path);

Trait Implementations§

Source§

impl Clone for UploadClient

Source§

fn clone(&self) -> UploadClient

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for UploadClient

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more