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