Mercurial > hg > orthanc-object-storage
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Google/GoogleStoragePlugin.cpp Fri Jul 03 10:08:44 2020 +0200 @@ -0,0 +1,227 @@ +/** + * Cloud storage plugins for Orthanc + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#include "GoogleStoragePlugin.h" + +#include "google/cloud/storage/client.h" + +// Create aliases to make the code easier to read. +namespace gcs = google::cloud::storage; + +class Writer : public IStoragePlugin::IWriter +{ + std::string path_; + gcs::Client client_; + std::string bucketName_; + gcs::ObjectWriteStream stream_; +public: + Writer(const std::string& bucketName, const std::string& path, gcs::Client& client) + : path_(path), + client_(client), + bucketName_(bucketName) + { + } + + virtual ~Writer() + { + } + + virtual void Write(const char* data, size_t size) + { + stream_ = client_.WriteObject(bucketName_, path_); + + if (stream_) + { + stream_.write(data, size); + stream_.Close(); + + if (!stream_.metadata()) + { + throw StoragePluginException("GoogleCloudStorage: error while writing file " + std::string(path_) + ": " + stream_.metadata().status().message()); + } + } + else + { + throw StoragePluginException("GoogleCloudStorage: error while opening/writing file " + std::string(path_) + ": " + stream_.metadata().status().message()); + } + } +}; + + +class Reader : public IStoragePlugin::IReader +{ + std::string path_; + gcs::Client client_; + std::string bucketName_; + +public: + Reader(const std::string& bucketName, const std::string& path, gcs::Client& client) + : path_(path), + client_(client), + bucketName_(bucketName) + { + } + + virtual ~Reader() + { + + } + virtual size_t GetSize() + { + auto objectMetadata = client_.GetObjectMetadata(bucketName_, path_); + + if (objectMetadata) + { + std::uint64_t fileSize = static_cast<int64_t>(objectMetadata->size()); + + return fileSize; + } + else + { + throw StoragePluginException("error while getting the size of " + std::string(path_) + ": " + objectMetadata.status().message()); + } + } + + virtual void Read(char* data, size_t size) + { + auto reader = client_.ReadObject(bucketName_, path_); + + if (!reader) + { + throw StoragePluginException("error while opening/reading file " + std::string(path_) + ": " + reader.status().message()); + } + + reader.read(data, size); + + if (!reader) + { + throw StoragePluginException("error while reading file " + std::string(path_) + ": " + reader.status().message()); + } + } + +}; + + + +const char* GoogleStoragePluginFactory::GetStoragePluginName() +{ + return "Google Cloud Storage"; +} + +IStoragePlugin* GoogleStoragePluginFactory::CreateStoragePlugin(const OrthancPlugins::OrthancConfiguration& orthancConfig) +{ + static const char* const PLUGIN_SECTION = "GoogleCloudStorage"; + if (!orthancConfig.IsSection(PLUGIN_SECTION)) + { + OrthancPlugins::LogWarning(std::string(GetStoragePluginName()) + " plugin, section missing. Plugin is not enabled."); + return nullptr; + } + + OrthancPlugins::OrthancConfiguration pluginSection; + orthancConfig.GetSection(pluginSection, PLUGIN_SECTION); + + std::string pathToGoogleCredentials; + + if (!pluginSection.LookupStringValue(pathToGoogleCredentials, "ServiceAccountFile")) + { + OrthancPlugins::LogError("GoogleCloudStorage/ServiceAccountFile configuration missing. Unable to initialize plugin"); + return nullptr; + } + + std::string googleBucketName; + if (!pluginSection.LookupStringValue(googleBucketName, "BucketName")) + { + OrthancPlugins::LogError("GoogleCloudStorage/BucketName configuration missing. Unable to initialize plugin"); + return nullptr; + } + + // Use service account credentials from a JSON keyfile: + auto creds = gcs::oauth2::CreateServiceAccountCredentialsFromJsonFilePath(pathToGoogleCredentials); + if (!creds) + { + OrthancPlugins::LogError("GoogleCloudStorage plugin: unable to validate credentials. Check the ServiceAccountFile: " + creds.status().message()); + return nullptr; + } + + // Create a client to communicate with Google Cloud Storage. + google::cloud::StatusOr<gcs::Client> mainClient = gcs::Client(gcs::ClientOptions(*creds)); + + if (!mainClient) + { + OrthancPlugins::LogError("GoogleCloudStorage plugin: unable to create client: " + mainClient.status().message()); + return nullptr; + } + + return new GoogleStoragePlugin(googleBucketName, mainClient.value()); +} + +GoogleStoragePlugin::GoogleStoragePlugin(const std::string &bucketName, google::cloud::storage::Client& mainClient) + : bucketName_(bucketName), + mainClient_(mainClient) +{ + +} + +IStoragePlugin::IWriter* GoogleStoragePlugin::GetWriterForObject(const char* uuid, OrthancPluginContentType type, bool encryptionEnabled) +{ + return new Writer(bucketName_, GetPath(uuid, type, encryptionEnabled), mainClient_); +} + +IStoragePlugin::IReader* GoogleStoragePlugin::GetReaderForObject(const char* uuid, OrthancPluginContentType type, bool encryptionEnabled) +{ + return new Reader(bucketName_, GetPath(uuid, type, encryptionEnabled), mainClient_); +} + +void GoogleStoragePlugin::DeleteObject(const char* uuid, OrthancPluginContentType type, bool encryptionEnabled) +{ + gcs::Client client(mainClient_); + + std::string path = GetPath(uuid, type, encryptionEnabled); + + auto deletionStatus = client.DeleteObject(bucketName_, path); + + if (!deletionStatus.ok()) + { + throw StoragePluginException("GoogleCloudStorage: error while deleting file " + std::string(path) + ": " + deletionStatus.message()); + } + +} + +std::string GoogleStoragePlugin::GetPath(const char* uuid, OrthancPluginContentType type, bool encryptionEnabled) +{ + std::string path = std::string(uuid); + + if (type == OrthancPluginContentType_Dicom) + { + path += ".dcm"; + } + else if (type == OrthancPluginContentType_DicomAsJson) + { + path += ".json"; + } + else + { + path += ".unk"; + } + + if (encryptionEnabled) + { + path += ".enc"; + } + return path; +}