Skip to main content

AirLibrary/Client/AirClient/
DownloadFile.rs

1//! `AirClient::DownloadFile` - downloads a single file via the Air
2//! daemon's `DownloaderService` and writes it to a local filesystem path.
3//!
4//! Server-side handles HTTP-layer retries, redirects, and resume; the
5//! gRPC call returns only after the local file is fully written (or the
6//! download fails). For incremental delivery see
7//! [`AirClient::DownloadStream`].
8
9use std::collections::HashMap;
10
11use tonic::Request;
12
13use crate::{
14	AirError,
15	Client::AirClient::{AirClient, FileInfo},
16	Vine::Generated::air::DownloadRequest,
17	dev_log,
18};
19
20impl AirClient {
21	/// Downloads a file.
22	///
23	/// # Arguments
24	///
25	/// - `request_id` - opaque correlation id.
26	/// - `url` - HTTPS URL of the file.
27	/// - `destination_path` - local filesystem path the file writes to.
28	/// - `checksum` - SHA-256 hex string; empty disables verification.
29	/// - `headers` - extra HTTP headers.
30	pub async fn DownloadFile(
31		&self,
32
33		request_id:String,
34
35		url:String,
36
37		destination_path:String,
38
39		checksum:String,
40
41		headers:HashMap<String, String>,
42	) -> Result<FileInfo::Struct, AirError> {
43		dev_log!("grpc", "[AirClient] Downloading file from: {}", url);
44
45		let RequestPayload = DownloadRequest { request_id, url, destination_path, checksum, headers };
46
47		let Client = self
48			.Client()
49			.ok_or_else(|| AirError::Network("Air client not initialized".to_string()))?;
50
51		let mut ClientGuard = Client.lock().await;
52
53		match ClientGuard.download_file(Request::new(RequestPayload)).await {
54			Ok(Response) => {
55				let Response = Response.into_inner();
56
57				if Response.success {
58					dev_log!("grpc", "[AirClient] File downloaded successfully to: {}", Response.file_path);
59
60					Ok(FileInfo::Struct {
61						file_path:Response.file_path,
62						file_size:Response.file_size,
63						checksum:Response.checksum,
64					})
65				} else {
66					dev_log!("grpc", "error: [AirClient] File download failed: {}", Response.error);
67
68					Err(AirError::Network(Response.error))
69				}
70			},
71
72			Err(Status) => {
73				dev_log!("grpc", "error: [AirClient] Download file RPC error: {}", Status);
74
75				Err(AirError::Network(format!("Download file RPC error: {}", Status)))
76			},
77		}
78	}
79}