]> git.proxmox.com Git - proxmox-backup.git/blame - src/client/backup_reader.rs
src/client/backup_reader.rs: add download_manifest
[proxmox-backup.git] / src / client / backup_reader.rs
CommitLineData
9e490a74
DM
1use failure::*;
2use std::io::Write;
3use std::sync::Arc;
4
5use chrono::{DateTime, Utc};
6use serde_json::{json, Value};
7
8use proxmox::tools::digest_to_hex;
9
10use crate::tools::futures::Canceller;
296c50ba 11use crate::backup::*;
9e490a74
DM
12
13use super::{HttpClient, H2Client};
14
913acb41 15/// Backup Reader
9e490a74
DM
16pub struct BackupReader {
17 h2: H2Client,
18 canceller: Canceller,
296c50ba 19 crypt_config: Option<Arc<CryptConfig>>,
9e490a74
DM
20}
21
22impl Drop for BackupReader {
23
24 fn drop(&mut self) {
25 self.canceller.cancel();
26 }
27}
28
29impl BackupReader {
30
296c50ba
DM
31 fn new(h2: H2Client, canceller: Canceller, crypt_config: Option<Arc<CryptConfig>>) -> Arc<Self> {
32 Arc::new(Self { h2, canceller, crypt_config})
9e490a74
DM
33 }
34
913acb41 35 /// Create a new instance by upgrading the connection at '/api2/json/reader'
9e490a74
DM
36 pub async fn start(
37 client: HttpClient,
296c50ba 38 crypt_config: Option<Arc<CryptConfig>>,
9e490a74
DM
39 datastore: &str,
40 backup_type: &str,
41 backup_id: &str,
42 backup_time: DateTime<Utc>,
43 debug: bool,
44 ) -> Result<Arc<BackupReader>, Error> {
45
46 let param = json!({
47 "backup-type": backup_type,
48 "backup-id": backup_id,
49 "backup-time": backup_time.timestamp(),
50 "store": datastore,
51 "debug": debug,
52 });
53 let req = HttpClient::request_builder(client.server(), "GET", "/api2/json/reader", Some(param)).unwrap();
54
55 let (h2, canceller) = client.start_h2_connection(req, String::from(PROXMOX_BACKUP_READER_PROTOCOL_ID_V1!())).await?;
56
296c50ba 57 Ok(BackupReader::new(h2, canceller, crypt_config))
9e490a74
DM
58 }
59
913acb41 60 /// Execute a GET request
9e490a74
DM
61 pub async fn get(
62 &self,
63 path: &str,
64 param: Option<Value>,
65 ) -> Result<Value, Error> {
66 self.h2.get(path, param).await
67 }
68
913acb41 69 /// Execute a PUT request
9e490a74
DM
70 pub async fn put(
71 &self,
72 path: &str,
73 param: Option<Value>,
74 ) -> Result<Value, Error> {
75 self.h2.put(path, param).await
76 }
77
913acb41 78 /// Execute a POST request
9e490a74
DM
79 pub async fn post(
80 &self,
81 path: &str,
82 param: Option<Value>,
83 ) -> Result<Value, Error> {
84 self.h2.post(path, param).await
85 }
86
913acb41 87 /// Execute a GET request and send output to a writer
9e490a74
DM
88 pub async fn download<W: Write + Send>(
89 &self,
90 file_name: &str,
91 output: W,
92 ) -> Result<W, Error> {
93 let path = "download";
94 let param = json!({ "file-name": file_name });
95 self.h2.download(path, Some(param), output).await
96 }
97
913acb41
DM
98 /// Execute a special GET request and send output to a writer
99 ///
100 /// This writes random data, and is only useful to test download speed.
9e490a74
DM
101 pub async fn speedtest<W: Write + Send>(
102 &self,
103 output: W,
104 ) -> Result<W, Error> {
105 self.h2.download("speedtest", None, output).await
106 }
107
913acb41 108 /// Download a specific chunk
9e490a74
DM
109 pub async fn download_chunk<W: Write + Send>(
110 &self,
111 digest: &[u8; 32],
112 output: W,
113 ) -> Result<W, Error> {
114 let path = "chunk";
115 let param = json!({ "digest": digest_to_hex(digest) });
116 self.h2.download(path, Some(param), output).await
117 }
118
119 pub fn force_close(self) {
120 self.canceller.cancel();
121 }
296c50ba
DM
122
123 /// Download backup manifest (index.json)
124 pub async fn download_manifest(&self) -> Result<Value, Error> {
125
126 let raw_data = self.download(INDEX_BLOB_NAME, Vec::with_capacity(64*1024)).await?;
127 let blob = DataBlob::from_raw(raw_data)?;
128 blob.verify_crc()?;
129 let data = blob.decode(self.crypt_config.as_ref().map(Arc::as_ref))?;
130 let result: Value = serde_json::from_slice(&data[..])?;
131 Ok(result)
132 }
9e490a74 133}