changeset 91:6d501f826123

New generated code with resumable uploads.
author Lewin Bormann <lbo@spheniscida.de>
date Sat, 24 Oct 2020 21:46:34 +0200
parents e031af86de5b
children eb7dcf74f9fd
files drive_example/Cargo.lock drive_example/Cargo.toml drive_example/src/drive_v3_types.rs drive_example/src/main.rs
diffstat 4 files changed, 94 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/drive_example/Cargo.lock	Sat Oct 24 21:46:19 2020 +0200
+++ b/drive_example/Cargo.lock	Sat Oct 24 21:46:34 2020 +0200
@@ -33,6 +33,7 @@
 dependencies = [
  "anyhow",
  "chrono",
+ "futures",
  "hyper",
  "hyper-rustls",
  "log",
@@ -69,9 +70,9 @@
 
 [[package]]
 name = "base64"
-version = "0.12.3"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
+checksum = "53d1ccbaf7d9ec9537465a97bf19edc1a4e158ecb49fc16178202238c569cc42"
 
 [[package]]
 name = "bitflags"
@@ -151,7 +152,6 @@
  "env_logger",
  "hyper",
  "hyper-rustls",
- "rustls 0.17.0",
  "serde",
  "tokio",
 ]
@@ -395,7 +395,7 @@
  "futures-util",
  "hyper",
  "log",
- "rustls 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustls",
  "rustls-native-certs",
  "tokio",
  "tokio-rustls",
@@ -746,17 +746,6 @@
 [[package]]
 name = "rustls"
 version = "0.17.0"
-dependencies = [
- "base64 0.11.0",
- "log",
- "ring",
- "sct",
- "webpki",
-]
-
-[[package]]
-name = "rustls"
-version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c0d4a31f5d68413404705d6982529b0e11a9aacd4839d1d6222ee3b8cb4015e1"
 dependencies = [
@@ -774,7 +763,7 @@
 checksum = "a75ffeb84a6bd9d014713119542ce415db3a3e4748f0bfce1e1416cd224a23a5"
 dependencies = [
  "openssl-probe",
- "rustls 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustls",
  "schannel",
  "security-framework",
 ]
@@ -987,7 +976,7 @@
 checksum = "15cb62a0d2770787abc96e99c1cd98fcf17f94959f3af63ca85bdfb203f051b4"
 dependencies = [
  "futures-core",
- "rustls 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustls",
  "tokio",
  "webpki",
 ]
@@ -1239,7 +1228,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "749192b9464694a95dbaf0586e845c835b315e38d491aa2766a8477aaadb48ec"
 dependencies = [
- "base64 0.12.3",
+ "base64 0.12.1",
  "chrono",
  "futures",
  "http",
@@ -1247,7 +1236,7 @@
  "hyper-rustls",
  "log",
  "percent-encoding",
- "rustls 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustls",
  "seahash",
  "serde",
  "serde_json",
--- a/drive_example/Cargo.toml	Sat Oct 24 21:46:19 2020 +0200
+++ b/drive_example/Cargo.toml	Sat Oct 24 21:46:34 2020 +0200
@@ -12,7 +12,6 @@
 anyhow = "~1.0"
 serde = "~1.0"
 env_logger = "~0.8"
-rustls = { path = "/home/lbo/rust/rustls/rustls", version = "0.17" }
 hyper-rustls = "~0.20"
 hyper = "~0.13"
 tokio = { version = "~0.2", features = ["full"] }
--- a/drive_example/src/drive_v3_types.rs	Sat Oct 24 21:46:19 2020 +0200
+++ b/drive_example/src/drive_v3_types.rs	Sat Oct 24 21:46:34 2020 +0200
@@ -3944,9 +3944,8 @@
     } else {
         tok = self.authenticator.token(&self.scopes).await?;
     }
-    let mut url_params = format!("?uploadType=multipart&oauth_token={token}", token=tok.as_str());
-
-    url_params.push_str(&format!("{}", params));
+    let mut url_params = format!("?uploadType=multipart&oauth_token={token}{params}", token=tok.as_str(), params=params);
+
     if let Some(ref api_params) = &params.drive_params {
         url_params.push_str(&format!("{}", api_params));
     }
@@ -3959,6 +3958,42 @@
   }
 
 
+/// Creates a new file.
+///
+/// This method is a variant of `create()`, taking data for upload.
+pub async fn create_resumable_upload<'client>(
+    &'client mut self, params: &FilesCreateParams, req: &File) -> Result<ResumableUpload<'client, File>> {
+
+    let rel_path = "upload/drive/v3/files";
+    let path = "https://www.googleapis.com/".to_string() + &rel_path;
+    let tok;
+    if self.scopes.is_empty() {
+        let scopes = &["https://www.googleapis.com/auth/drive.file".to_string(),
+        ];
+        tok = self.authenticator.token(scopes).await?;
+    } else {
+        tok = self.authenticator.token(&self.scopes).await?;
+    }
+    let mut url_params = format!("?uploadType=resumable&oauth_token={token}{params}", token=tok.as_str(), params=params);
+    if let Some(ref api_params) = &params.drive_params {
+        url_params.push_str(&format!("{}", api_params));
+    }
+
+    let full_uri = path + &url_params;
+
+    let opt_request: Option<EmptyRequest> = None;
+    let opt_request = Some(req);
+    let (_resp, headers): (EmptyResponse, hyper::HeaderMap) = do_request_with_headers(&self.client, &full_uri, &[], "POST", opt_request).await?;
+    if let Some(dest) = headers.get(hyper::header::LOCATION) {
+        use std::convert::TryFrom;
+        Ok(ResumableUpload::new(hyper::Uri::try_from(dest.to_str()?)?, &self.client, 256*1024))
+    } else {
+        Err(Error::from(ApiError::RedirectError(format!("Resumable upload response didn't contain Location: {:?}", headers)))
+        .context(format!("{:?}", headers)))?
+    }
+  }
+
+
 /// Permanently deletes a file owned by the user without moving it to the trash. If the file belongs to a shared drive the user must be an organizer on the parent. If the target is a folder, all descendants owned by the user are also deleted.
 pub async fn delete(
     &mut self, params: &FilesDeleteParams) -> Result<()> {
@@ -4163,9 +4198,8 @@
     } else {
         tok = self.authenticator.token(&self.scopes).await?;
     }
-    let mut url_params = format!("?uploadType=multipart&oauth_token={token}", token=tok.as_str());
-
-    url_params.push_str(&format!("{}", params));
+    let mut url_params = format!("?uploadType=multipart&oauth_token={token}{params}", token=tok.as_str(), params=params);
+
     if let Some(ref api_params) = &params.drive_params {
         url_params.push_str(&format!("{}", api_params));
     }
@@ -4178,6 +4212,42 @@
   }
 
 
+/// Updates a file's metadata and/or content. This method supports patch semantics.
+///
+/// This method is a variant of `update()`, taking data for upload.
+pub async fn update_resumable_upload<'client>(
+    &'client mut self, params: &FilesUpdateParams, req: &File) -> Result<ResumableUpload<'client, File>> {
+
+    let rel_path = "upload/drive/v3/files/{fileId}";
+    let path = "https://www.googleapis.com/".to_string() + &rel_path;
+    let tok;
+    if self.scopes.is_empty() {
+        let scopes = &["https://www.googleapis.com/auth/drive.scripts".to_string(),
+        ];
+        tok = self.authenticator.token(scopes).await?;
+    } else {
+        tok = self.authenticator.token(&self.scopes).await?;
+    }
+    let mut url_params = format!("?uploadType=resumable&oauth_token={token}{params}", token=tok.as_str(), params=params);
+    if let Some(ref api_params) = &params.drive_params {
+        url_params.push_str(&format!("{}", api_params));
+    }
+
+    let full_uri = path + &url_params;
+
+    let opt_request: Option<EmptyRequest> = None;
+    let opt_request = Some(req);
+    let (_resp, headers): (EmptyResponse, hyper::HeaderMap) = do_request_with_headers(&self.client, &full_uri, &[], "PATCH", opt_request).await?;
+    if let Some(dest) = headers.get(hyper::header::LOCATION) {
+        use std::convert::TryFrom;
+        Ok(ResumableUpload::new(hyper::Uri::try_from(dest.to_str()?)?, &self.client, 256*1024))
+    } else {
+        Err(Error::from(ApiError::RedirectError(format!("Resumable upload response didn't contain Location: {:?}", headers)))
+        .context(format!("{:?}", headers)))?
+    }
+  }
+
+
 /// Subscribes to changes to a file
 pub async fn watch(
     &mut self, params: &FilesWatchParams, req: &Channel) -> Result<Channel> {
--- a/drive_example/src/main.rs	Sat Oct 24 21:46:19 2020 +0200
+++ b/drive_example/src/main.rs	Sat Oct 24 21:46:34 2020 +0200
@@ -26,27 +26,32 @@
 
 /// Upload a local file `f` to your drive.
 async fn upload_file(mut cl: drive::FilesService, f: &Path) -> anyhow::Result<()> {
-    cl.set_scopes(&[drive::DriveScopes::DriveFile]);
     let fname = f.file_name().unwrap().to_str().unwrap();
 
     let mut general_params = drive::DriveParams::default();
     general_params.fields = Some("*".to_string());
 
-    let data = hyper::body::Bytes::from(fs::read(&f)?);
     let mut params = drive::FilesCreateParams::default();
     params.drive_params = Some(general_params.clone());
     params.include_permissions_for_view = Some("published".to_string());
-    println!("{:?}", params);
     let mut file = drive::File::default();
     file.name = Some(fname.to_string());
 
     // Upload data using the upload version of create(). We obtain a `File` object.
     //
-    let resp = cl.create_upload(&params, &file, data).await?;
+    let resumable = cl.create_resumable_upload(&params, &file).await?;
+
+    let tokiofile = tokio::fs::OpenOptions::new().read(true).open(f).await?;
+    let resp = resumable.upload_file(tokiofile).await?;
 
     // If you used this method, no file content would be uploaded:
     // let resp = cl.create(&params, &file).await?;
-    println!("{:?}", resp);
+    println!(
+        "Uploaded file: {} (id = {}) with metadata: \n {:?}",
+        resp.name.as_ref().unwrap(),
+        resp.id.as_ref().unwrap(),
+        resp
+    );
 
     let file_id = resp.id.unwrap();