Skip to main content

tame_gcs/v1/objects/
download.rs

1use crate::{
2    common::{Conditionals, Projection, StandardQueryParameters},
3    error::Error,
4    response::ApiResponse,
5    types::ObjectIdentifier,
6};
7use std::io;
8
9#[derive(Default, Serialize)]
10#[serde(rename_all = "camelCase")]
11pub struct DownloadObjectOptional<'a> {
12    #[serde(flatten)]
13    pub standard_params: StandardQueryParameters<'a>,
14    /// If present, selects a specific revision of this object
15    /// (as opposed to the latest version, the default).
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub generation: Option<i64>,
18    #[serde(flatten)]
19    pub conditionals: Conditionals,
20    /// Set of properties to return. Defaults to `noAcl`, unless the object
21    /// resource specifies the acl property, when it defaults to full.
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub projection: Option<Projection>,
24    /// The project to be billed for this request. Required for Requester Pays buckets.
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub user_project: Option<&'a str>,
27}
28
29pub struct DownloadObjectResponse {
30    buffer: bytes::Bytes,
31}
32
33impl DownloadObjectResponse {
34    pub fn consume(self) -> bytes::Bytes {
35        self.buffer
36    }
37}
38
39impl ApiResponse<bytes::Bytes> for DownloadObjectResponse {}
40
41impl TryFrom<http::Response<bytes::Bytes>> for DownloadObjectResponse {
42    type Error = Error;
43
44    fn try_from(response: http::Response<bytes::Bytes>) -> Result<Self, Self::Error> {
45        let (_parts, body) = response.into_parts();
46
47        Ok(Self { buffer: body })
48    }
49}
50
51impl std::ops::Deref for DownloadObjectResponse {
52    type Target = [u8];
53
54    fn deref(&self) -> &[u8] {
55        self.buffer.as_ref()
56    }
57}
58
59impl io::Read for DownloadObjectResponse {
60    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
61        use bytes::Buf;
62
63        let buf_len = std::cmp::min(self.buffer.len(), buf.len());
64        let mut slice = self.buffer.split_to(buf_len);
65        slice.copy_to_slice(&mut buf[..buf_len]);
66
67        Ok(buf_len)
68    }
69}
70
71impl super::Object {
72    /// Downloads an object
73    ///
74    /// Required IAM Permissions: `storage.objects.get`, `storage.objects.getIamPolicy`*
75    ///
76    /// [Complete API Documentation](https://cloud.google.com/storage/docs/json_api/v1/objects/get)
77    pub fn download<'a, OID>(
78        &self,
79        id: &OID,
80        optional: Option<DownloadObjectOptional<'_>>,
81    ) -> Result<http::Request<std::io::Empty>, Error>
82    where
83        OID: ObjectIdentifier<'a> + ?Sized,
84    {
85        let mut uri = crate::__make_obj_url!(
86            "https://{}/storage/v1/b/{}/o/{}?alt=media",
87            self.authority,
88            id
89        );
90
91        let query = optional.unwrap_or_default();
92        let query_params = serde_urlencoded::to_string(query)?;
93        if !query_params.is_empty() {
94            uri.push('&');
95            uri.push_str(&query_params);
96        }
97
98        let req_builder = http::Request::builder();
99
100        Ok(req_builder.method("GET").uri(uri).body(std::io::empty())?)
101    }
102}