tame_gcs/v1/objects/rewrite.rs
1use crate::{
2 common::{Conditionals, Projection, StandardQueryParameters},
3 error::Error,
4 response::ApiResponse,
5 types::ObjectIdentifier,
6};
7
8#[derive(Default, Serialize)]
9#[serde(rename_all = "camelCase")]
10pub struct RewriteObjectOptional<'a> {
11 #[serde(flatten)]
12 pub standard_params: StandardQueryParameters<'a>,
13 /// Resource name of the Cloud KMS key that will be used to encrypt the
14 /// object. The Cloud KMS key must be located in same location as the object.
15 ///
16 /// If the parameter is not specified, the method uses the destination
17 /// bucket's default encryption key, if any, or the Google-managed encryption
18 /// key.
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub destination_kms_key_name: Option<String>,
21 /// Apply a predefined set of access controls to the destination object.
22 ///
23 /// Acceptable values are:
24 ///
25 /// * authenticatedRead: Object owner gets OWNER access, and
26 /// allAuthenticatedUsers get READER access.
27 /// * bucketOwnerFullControl: Object owner gets OWNER access, and project
28 /// team owners get OWNER access.
29 /// * bucketOwnerRead: Object owner gets OWNER access, and project team
30 /// owners get READER access.
31 /// * private: Object owner gets OWNER access.
32 /// * projectPrivate: Object owner gets OWNER access, and project team
33 /// members get access according to their roles.
34 /// * publicRead: Object owner gets OWNER access, and allUsers get READER access.
35 ///
36 /// If iamConfiguration.uniformBucketLevelAccess.enabled is set to true,
37 /// requests that include this parameter fail with a 400 Bad Request response.
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub destination_predefined_acl: Option<String>,
40 #[serde(flatten, skip_serializing_if = "Option::is_none")]
41 pub destination_conditionals: Option<Conditionals>,
42 /// Makes the operation conditional on whether the source object's
43 /// generation matches the given value.
44 #[serde(skip_serializing_if = "Option::is_none")]
45 pub if_source_generation_match: Option<i64>,
46 /// Makes the operation conditional on whether the source object's
47 /// generation does not match the given value.
48 #[serde(skip_serializing_if = "Option::is_none")]
49 pub if_source_generation_not_match: Option<i64>,
50 /// Makes the operation conditional on whether the source object's current
51 /// metageneration matches the given value.
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub if_source_metageneration_match: Option<i64>,
54 /// Makes the operation conditional on whether the source object's current
55 /// metageneration does not match the given value.
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub if_source_metageneration_not_match: Option<i64>,
58 /// The maximum number of bytes that will be rewritten per rewrite request.
59 /// Most callers shouldn't need to specify this parameter - it is primarily
60 /// in place to support testing. If specified the value must be an integral
61 /// multiple of 1 MiB (1048576). Also, this only applies to requests where
62 /// the source and destination span locations and/or storage classes.
63 /// Finally, this value must not change across rewrite calls else you'll get
64 /// an error that the rewriteToken is invalid.
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub max_bytes_rewritten_per_call: Option<i64>,
67 /// Set of properties to return. Defaults to `noAcl`, unless the object
68 /// resource specifies the acl property, when it defaults to full.
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub projection: Option<Projection>,
71 /// If present, selects a specific revision of the source object (as opposed
72 /// to the latest version, the default).
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub source_generation: Option<i64>,
75}
76
77#[derive(Deserialize)]
78#[serde(rename_all = "camelCase")]
79pub struct RewriteObjectResponse {
80 /// The number of bytes that have been rewritten thusfar
81 #[serde(deserialize_with = "crate::objects::from_str")]
82 pub total_bytes_rewritten: u64,
83 /// The total size of the original source object
84 #[serde(deserialize_with = "crate::objects::from_str")]
85 pub object_size: u64,
86 /// Indicates if the rewrite is finished or not
87 pub done: bool,
88 /// If done is false, this will be `Some` and it must be specified in each
89 /// additional rewrite call until done is true
90 pub rewrite_token: Option<String>,
91 #[serde(rename = "resource")]
92 pub metadata: Option<super::Metadata>,
93}
94
95impl ApiResponse<bytes::Bytes> for RewriteObjectResponse {}
96
97impl<B> TryFrom<http::Response<B>> for RewriteObjectResponse
98where
99 B: AsRef<[u8]>,
100{
101 type Error = Error;
102
103 fn try_from(response: http::Response<B>) -> Result<Self, Self::Error> {
104 let (_parts, body) = response.into_parts();
105 Ok(serde_json::from_slice(body.as_ref())?)
106 }
107}
108
109impl super::Object {
110 /// Rewrites a source object to a destination object. Optionally overrides metadata.
111 ///
112 /// Required IAM Permissions:
113 /// * `storage.objects.create` (for the destination bucket)
114 /// * `storage.objects.delete` (for the destination bucket)
115 /// * `storage.objects.get` (for the source bucket)
116 ///
117 /// [Complete API Documentation](https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite)
118 pub fn rewrite<'a, OID>(
119 &self,
120 source: &OID,
121 destination: &OID,
122 rewrite_token: Option<String>,
123 metadata: Option<&super::Metadata>,
124 optional: Option<RewriteObjectOptional<'_>>,
125 ) -> Result<http::Request<std::io::Cursor<Vec<u8>>>, Error>
126 where
127 OID: ObjectIdentifier<'a> + ?Sized,
128 {
129 let mut uri = format!(
130 "https://{}/storage/v1/b/{}/o/{}/rewriteTo/b/{}/o/{}",
131 self.authority.as_str(),
132 percent_encoding::percent_encode(
133 source.bucket().as_ref(),
134 crate::util::PATH_ENCODE_SET
135 ),
136 percent_encoding::percent_encode(
137 source.object().as_ref(),
138 crate::util::PATH_ENCODE_SET
139 ),
140 percent_encoding::percent_encode(
141 destination.bucket().as_ref(),
142 crate::util::PATH_ENCODE_SET
143 ),
144 percent_encoding::percent_encode(
145 destination.object().as_ref(),
146 crate::util::PATH_ENCODE_SET
147 )
148 );
149
150 let query = optional.unwrap_or_default();
151 let query_params = serde_urlencoded::to_string(query)?;
152 if !query_params.is_empty() || rewrite_token.is_some() {
153 uri.push('?');
154
155 if let Some(rt) = rewrite_token {
156 uri.push_str("rewriteToken=");
157 uri.push_str(&rt);
158
159 if !query_params.is_empty() {
160 uri.push('&');
161 }
162 }
163
164 if !query_params.is_empty() {
165 uri.push_str(&query_params);
166 }
167 }
168
169 let mut req_builder = http::Request::builder();
170
171 let body = match metadata {
172 Some(metadata) => {
173 let md = serde_json::to_vec(&metadata)?;
174 let len = md.len();
175
176 req_builder = req_builder
177 .header("content-type", "application/json")
178 .header("content-length", len);
179
180 std::io::Cursor::new(md)
181 }
182 None => std::io::Cursor::new(Vec::new()),
183 };
184
185 Ok(req_builder.method("POST").uri(uri).body(body)?)
186 }
187}