1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "google/cloud/storage/client.h"
16 #include "google/cloud/storage/examples/storage_examples_common.h"
17 #include "google/cloud/storage/oauth2/google_credentials.h"
18 #include "google/cloud/storage/parallel_upload.h"
19 #include "google/cloud/storage/well_known_parameters.h"
20 #include "google/cloud/internal/getenv.h"
21 #include <fstream>
22 #include <iostream>
23 #include <map>
24 #include <sstream>
25 #include <string>
26 #include <thread>
27
28 namespace {
StartResumableUpload(google::cloud::storage::Client client,std::vector<std::string> const & argv)29 void StartResumableUpload(google::cloud::storage::Client client,
30 std::vector<std::string> const& argv) {
31 //! [start resumable upload]
32 namespace gcs = google::cloud::storage;
33 [](gcs::Client client, std::string const& bucket_name,
34 std::string const& object_name) {
35 gcs::ObjectWriteStream stream = client.WriteObject(
36 bucket_name, object_name, gcs::NewResumableUploadSession());
37 std::cout << "Created resumable upload: " << stream.resumable_session_id()
38 << "\n";
39 // As it is customary in C++, the destructor automatically closes the
40 // stream, that would finish the upload and create the object. For this
41 // example we want to restore the session as-if the application had crashed,
42 // where no destructors get called.
43 stream << "This data will not get uploaded, it is too small\n";
44 std::move(stream).Suspend();
45 }
46 //! [start resumable upload]
47 (std::move(client), argv.at(0), argv.at(1));
48 }
49
ResumeResumableUpload(google::cloud::storage::Client client,std::vector<std::string> const & argv)50 void ResumeResumableUpload(google::cloud::storage::Client client,
51 std::vector<std::string> const& argv) {
52 //! [resume resumable upload]
53 namespace gcs = google::cloud::storage;
54 using ::google::cloud::StatusOr;
55 [](gcs::Client client, std::string const& bucket_name,
56 std::string const& object_name, std::string const& session_id) {
57 // Restore a resumable upload stream, the library automatically queries the
58 // state of the upload and discovers the next expected byte.
59 gcs::ObjectWriteStream stream =
60 client.WriteObject(bucket_name, object_name,
61 gcs::RestoreResumableUploadSession(session_id));
62 if (!stream.IsOpen() && stream.metadata().ok()) {
63 std::cout << "The upload has already been finalized. The object "
64 << "metadata is: " << *stream.metadata() << "\n";
65 }
66 if (stream.next_expected_byte() == 0) {
67 // In this example we create a small object, smaller than the resumable
68 // upload quantum (256 KiB), so either all the data is there or not.
69 // Applications use `next_expected_byte()` to find the position in their
70 // input where they need to start uploading.
71 stream << R"""(
72 Lorem ipsum dolor sit amet, consectetur adipiscing
73 elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
74 ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
75 commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit
76 esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
77 non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
78 )""";
79 }
80
81 stream.Close();
82
83 StatusOr<gcs::ObjectMetadata> metadata = stream.metadata();
84 if (!metadata) throw std::runtime_error(metadata.status().message());
85 std::cout << "Upload completed, the new object metadata is: " << *metadata
86 << "\n";
87 }
88 //! [resume resumable upload]
89 (std::move(client), argv.at(0), argv.at(1), argv.at(2));
90 }
91
RunAll(std::vector<std::string> const & argv)92 void RunAll(std::vector<std::string> const& argv) {
93 namespace examples = ::google::cloud::storage::examples;
94 namespace gcs = ::google::cloud::storage;
95
96 if (!argv.empty()) throw examples::Usage{"auto"};
97 examples::CheckEnvironmentVariablesAreSet({
98 "GOOGLE_CLOUD_PROJECT",
99 "GOOGLE_CLOUD_CPP_STORAGE_TEST_BUCKET_NAME",
100 });
101 auto const project_id =
102 google::cloud::internal::GetEnv("GOOGLE_CLOUD_PROJECT").value();
103 auto const bucket_name = google::cloud::internal::GetEnv(
104 "GOOGLE_CLOUD_CPP_STORAGE_TEST_BUCKET_NAME")
105 .value();
106 auto generator = google::cloud::internal::DefaultPRNG(std::random_device{}());
107 auto const object_name =
108 examples::MakeRandomObjectName(generator, "ob-resumable-upload-");
109
110 auto client = gcs::Client::CreateDefaultClient().value();
111
112 std::cout << "\nRunning StartResumableUpload() example" << std::endl;
113 StartResumableUpload(client, {bucket_name, object_name});
114
115 std::cout << "\nCreating and capturing new resumable session id" << std::endl;
116 auto session_id = [&] {
117 auto stream = client.WriteObject(bucket_name, object_name,
118 gcs::NewResumableUploadSession());
119 auto id = stream.resumable_session_id();
120 std::move(stream).Suspend();
121 return id;
122 }();
123
124 std::cout << "\nRunning ResumeResumableUpload() example" << std::endl;
125 ResumeResumableUpload(client, {bucket_name, object_name, session_id});
126
127 (void)client.DeleteObject(bucket_name, object_name);
128 }
129
130 } // namespace
131
main(int argc,char * argv[])132 int main(int argc, char* argv[]) {
133 namespace examples = ::google::cloud::storage::examples;
134 auto make_entry = [](std::string const& name,
135 std::vector<std::string> arg_names,
136 examples::ClientCommand const& cmd) {
137 arg_names.insert(arg_names.begin(), {"<bucket-name>", "<object-name>"});
138 return examples::CreateCommandEntry(name, std::move(arg_names), cmd);
139 };
140
141 examples::Example example({
142 make_entry("start-resumable-upload", {}, StartResumableUpload),
143 make_entry("resume-resumable-upload", {"<session-id>"},
144 ResumeResumableUpload),
145 {"auto", RunAll},
146 });
147 return example.Run(argc, argv);
148 }
149