Mercurial > hg > orthanc-object-storage
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 } |