comparison Google/GoogleStoragePlugin.cpp @ 1:fc26a8fc54d5

initial release
author Alain Mazy <alain@mazy.be>
date Fri, 03 Jul 2020 10:08:44 +0200
parents
children 2a02b21f0a19
comparison
equal deleted inserted replaced
0:d7198e8f0d47 1:fc26a8fc54d5
1 /**
2 * Cloud storage plugins for Orthanc
3 * Copyright (C) 2017-2020 Osimis S.A., Belgium
4 *
5 * This program is free software: you can redistribute it and/or
6 * modify it under the terms of the GNU Affero General Public License
7 * as published by the Free Software Foundation, either version 3 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 **/
18
19 #include "GoogleStoragePlugin.h"
20
21 #include "google/cloud/storage/client.h"
22
23 // Create aliases to make the code easier to read.
24 namespace gcs = google::cloud::storage;
25
26 class Writer : public IStoragePlugin::IWriter
27 {
28 std::string path_;
29 gcs::Client client_;
30 std::string bucketName_;
31 gcs::ObjectWriteStream stream_;
32 public:
33 Writer(const std::string& bucketName, const std::string& path, gcs::Client& client)
34 : path_(path),
35 client_(client),
36 bucketName_(bucketName)
37 {
38 }
39
40 virtual ~Writer()
41 {
42 }
43
44 virtual void Write(const char* data, size_t size)
45 {
46 stream_ = client_.WriteObject(bucketName_, path_);
47
48 if (stream_)
49 {
50 stream_.write(data, size);
51 stream_.Close();
52
53 if (!stream_.metadata())
54 {
55 throw StoragePluginException("GoogleCloudStorage: error while writing file " + std::string(path_) + ": " + stream_.metadata().status().message());
56 }
57 }
58 else
59 {
60 throw StoragePluginException("GoogleCloudStorage: error while opening/writing file " + std::string(path_) + ": " + stream_.metadata().status().message());
61 }
62 }
63 };
64
65
66 class Reader : public IStoragePlugin::IReader
67 {
68 std::string path_;
69 gcs::Client client_;
70 std::string bucketName_;
71
72 public:
73 Reader(const std::string& bucketName, const std::string& path, gcs::Client& client)
74 : path_(path),
75 client_(client),
76 bucketName_(bucketName)
77 {
78 }
79
80 virtual ~Reader()
81 {
82
83 }
84 virtual size_t GetSize()
85 {
86 auto objectMetadata = client_.GetObjectMetadata(bucketName_, path_);
87
88 if (objectMetadata)
89 {
90 std::uint64_t fileSize = static_cast<int64_t>(objectMetadata->size());
91
92 return fileSize;
93 }
94 else
95 {
96 throw StoragePluginException("error while getting the size of " + std::string(path_) + ": " + objectMetadata.status().message());
97 }
98 }
99
100 virtual void Read(char* data, size_t size)
101 {
102 auto reader = client_.ReadObject(bucketName_, path_);
103
104 if (!reader)
105 {
106 throw StoragePluginException("error while opening/reading file " + std::string(path_) + ": " + reader.status().message());
107 }
108
109 reader.read(data, size);
110
111 if (!reader)
112 {
113 throw StoragePluginException("error while reading file " + std::string(path_) + ": " + reader.status().message());
114 }
115 }
116
117 };
118
119
120
121 const char* GoogleStoragePluginFactory::GetStoragePluginName()
122 {
123 return "Google Cloud Storage";
124 }
125
126 IStoragePlugin* GoogleStoragePluginFactory::CreateStoragePlugin(const OrthancPlugins::OrthancConfiguration& orthancConfig)
127 {
128 static const char* const PLUGIN_SECTION = "GoogleCloudStorage";
129 if (!orthancConfig.IsSection(PLUGIN_SECTION))
130 {
131 OrthancPlugins::LogWarning(std::string(GetStoragePluginName()) + " plugin, section missing. Plugin is not enabled.");
132 return nullptr;
133 }
134
135 OrthancPlugins::OrthancConfiguration pluginSection;
136 orthancConfig.GetSection(pluginSection, PLUGIN_SECTION);
137
138 std::string pathToGoogleCredentials;
139
140 if (!pluginSection.LookupStringValue(pathToGoogleCredentials, "ServiceAccountFile"))
141 {
142 OrthancPlugins::LogError("GoogleCloudStorage/ServiceAccountFile configuration missing. Unable to initialize plugin");
143 return nullptr;
144 }
145
146 std::string googleBucketName;
147 if (!pluginSection.LookupStringValue(googleBucketName, "BucketName"))
148 {
149 OrthancPlugins::LogError("GoogleCloudStorage/BucketName configuration missing. Unable to initialize plugin");
150 return nullptr;
151 }
152
153 // Use service account credentials from a JSON keyfile:
154 auto creds = gcs::oauth2::CreateServiceAccountCredentialsFromJsonFilePath(pathToGoogleCredentials);
155 if (!creds)
156 {
157 OrthancPlugins::LogError("GoogleCloudStorage plugin: unable to validate credentials. Check the ServiceAccountFile: " + creds.status().message());
158 return nullptr;
159 }
160
161 // Create a client to communicate with Google Cloud Storage.
162 google::cloud::StatusOr<gcs::Client> mainClient = gcs::Client(gcs::ClientOptions(*creds));
163
164 if (!mainClient)
165 {
166 OrthancPlugins::LogError("GoogleCloudStorage plugin: unable to create client: " + mainClient.status().message());
167 return nullptr;
168 }
169
170 return new GoogleStoragePlugin(googleBucketName, mainClient.value());
171 }
172
173 GoogleStoragePlugin::GoogleStoragePlugin(const std::string &bucketName, google::cloud::storage::Client& mainClient)
174 : bucketName_(bucketName),
175 mainClient_(mainClient)
176 {
177
178 }
179
180 IStoragePlugin::IWriter* GoogleStoragePlugin::GetWriterForObject(const char* uuid, OrthancPluginContentType type, bool encryptionEnabled)
181 {
182 return new Writer(bucketName_, GetPath(uuid, type, encryptionEnabled), mainClient_);
183 }
184
185 IStoragePlugin::IReader* GoogleStoragePlugin::GetReaderForObject(const char* uuid, OrthancPluginContentType type, bool encryptionEnabled)
186 {
187 return new Reader(bucketName_, GetPath(uuid, type, encryptionEnabled), mainClient_);
188 }
189
190 void GoogleStoragePlugin::DeleteObject(const char* uuid, OrthancPluginContentType type, bool encryptionEnabled)
191 {
192 gcs::Client client(mainClient_);
193
194 std::string path = GetPath(uuid, type, encryptionEnabled);
195
196 auto deletionStatus = client.DeleteObject(bucketName_, path);
197
198 if (!deletionStatus.ok())
199 {
200 throw StoragePluginException("GoogleCloudStorage: error while deleting file " + std::string(path) + ": " + deletionStatus.message());
201 }
202
203 }
204
205 std::string GoogleStoragePlugin::GetPath(const char* uuid, OrthancPluginContentType type, bool encryptionEnabled)
206 {
207 std::string path = std::string(uuid);
208
209 if (type == OrthancPluginContentType_Dicom)
210 {
211 path += ".dcm";
212 }
213 else if (type == OrthancPluginContentType_DicomAsJson)
214 {
215 path += ".json";
216 }
217 else
218 {
219 path += ".unk";
220 }
221
222 if (encryptionEnabled)
223 {
224 path += ".enc";
225 }
226 return path;
227 }