# HG changeset patch # User Alain Mazy # Date 1666354467 -7200 # Node ID 8a9207933297c68e92b1dc98ed324d0b2321b9e7 # Parent 431ab61b576060c0f6f9092a48a8e9192ea6cc5b MoveStorageJob serialization diff -r 431ab61b5760 -r 8a9207933297 Common/MoveStorageJob.cpp --- a/Common/MoveStorageJob.cpp Thu Oct 20 15:14:39 2022 +0200 +++ b/Common/MoveStorageJob.cpp Fri Oct 21 14:14:27 2022 +0200 @@ -18,13 +18,14 @@ #include "MoveStorageJob.h" #include "Logging.h" +#include "StoragePlugin.h" MoveStorageJob::MoveStorageJob(const std::string& targetStorage, const std::vector& instances, const Json::Value& resourceForJobContent, bool cryptoEnabled) - : OrthancPlugins::OrthancJob("MoveStorage"), + : OrthancPlugins::OrthancJob(JOB_TYPE_MOVE_STORAGE), targetStorage_(targetStorage), instances_(instances), processedInstancesCount_(0), @@ -33,6 +34,24 @@ objectStorage_(NULL), cryptoEnabled_(cryptoEnabled) { + UpdateContent(resourceForJobContent); + + Json::Value serialized; + Serialize(serialized); + UpdateSerialized(serialized); +} + +void MoveStorageJob::Serialize(Json::Value& target) const +{ + target[KEY_CONTENT] = resourceForJobContent_; + target[KEY_TARGET_STORAGE] = targetStorage_; + target[KEY_INSTANCES] = Json::arrayValue; + + for (size_t i = 0; i < instances_.size(); ++i) + { + target[KEY_INSTANCES].append(instances_[i]); + } + } void MoveStorageJob::SetStorages(IStorage* fileSystemStorage, IStorage* objectStorage) @@ -124,12 +143,14 @@ { if (processedInstancesCount_ < instances_.size()) { - IStorage* sourceStorage = (targetStorage_ == "file-system" ? objectStorage_ : fileSystemStorage_); - IStorage* targetStorage = (targetStorage_ == "file-system" ? fileSystemStorage_ : objectStorage_); + IStorage* sourceStorage = (targetStorage_ == STORAGE_TYPE_FILE_SYSTEM ? objectStorage_ : fileSystemStorage_); + IStorage* targetStorage = (targetStorage_ == STORAGE_TYPE_FILE_SYSTEM ? fileSystemStorage_ : objectStorage_); if (MoveInstance(instances_[processedInstancesCount_], sourceStorage, targetStorage, cryptoEnabled_)) { processedInstancesCount_++; + UpdateProgress((float)processedInstancesCount_/(float)instances_.size()); + return OrthancPluginJobStepStatus_Continue; } else diff -r 431ab61b5760 -r 8a9207933297 Common/MoveStorageJob.h --- a/Common/MoveStorageJob.h Thu Oct 20 15:14:39 2022 +0200 +++ b/Common/MoveStorageJob.h Fri Oct 21 14:14:27 2022 +0200 @@ -37,6 +37,7 @@ IStorage* objectStorage_; bool cryptoEnabled_; + void Serialize(Json::Value& target) const; public: MoveStorageJob(const std::string& targetStorage, const std::vector& instances, diff -r 431ab61b5760 -r 8a9207933297 Common/StoragePlugin.cpp --- a/Common/StoragePlugin.cpp Thu Oct 20 15:14:39 2022 +0200 +++ b/Common/StoragePlugin.cpp Fri Oct 21 14:14:27 2022 +0200 @@ -45,6 +45,9 @@ #include #include #include "MoveStorageJob.h" +#include "StoragePlugin.h" +#include + static std::unique_ptr primaryStorage; static std::unique_ptr secondaryStorage; @@ -316,6 +319,23 @@ } +static MoveStorageJob* CreateMoveStorageJob(const std::string& targetStorage, const std::vector& instances, const Json::Value& resourcesForJobContent) +{ + std::unique_ptr job(new MoveStorageJob(targetStorage, instances, resourcesForJobContent, cryptoEnabled)); + + if (hybridMode == HybridMode_WriteToFileSystem) + { + job->SetStorages(primaryStorage.get(), secondaryStorage.get()); + } + else + { + job->SetStorages(secondaryStorage.get(), primaryStorage.get()); + } + + return job.release(); +} + + static void AddResourceForJobContent(Json::Value& resourcesForJobContent /* out */, Orthanc::ResourceType resourceType, const std::string& resourceId) { const char* resourceGroup = Orthanc::GetResourceTypeText(resourceType, true, true); @@ -350,33 +370,30 @@ std::vector instances; Json::Value resourcesForJobContent; - static const char* RESOURCES = "Resources"; - static const char* TARGET_STORAGE = "TargetStorage"; - if (requestPayload.type() != Json::objectValue || - !requestPayload.isMember(RESOURCES) || - requestPayload[RESOURCES].type() != Json::arrayValue) + !requestPayload.isMember(KEY_RESOURCES) || + requestPayload[KEY_RESOURCES].type() != Json::arrayValue) { throw Orthanc::OrthancException( Orthanc::ErrorCode_BadFileFormat, "A request to the move-storage endpoint must provide a JSON object " - "with the field \"" + std::string(RESOURCES) + + "with the field \"" + std::string(KEY_RESOURCES) + "\" containing an array of resources to be sent"); } - if (!requestPayload.isMember(TARGET_STORAGE) - || requestPayload[TARGET_STORAGE].type() != Json::stringValue - || (requestPayload[TARGET_STORAGE].asString() != "file-system" && requestPayload[TARGET_STORAGE].asString() != "object-storage")) + if (!requestPayload.isMember(KEY_TARGET_STORAGE) + || requestPayload[KEY_TARGET_STORAGE].type() != Json::stringValue + || (requestPayload[KEY_TARGET_STORAGE].asString() != STORAGE_TYPE_FILE_SYSTEM && requestPayload[KEY_TARGET_STORAGE].asString() != STORAGE_TYPE_OBJECT_STORAGE)) { throw Orthanc::OrthancException( Orthanc::ErrorCode_BadFileFormat, "A request to the move-storage endpoint must provide a JSON object " - "with the field \"" + std::string(TARGET_STORAGE) + - "\" set to \"file-system\" or \"object-storage\""); + "with the field \"" + std::string(KEY_TARGET_STORAGE) + + "\" set to \"" + std::string(STORAGE_TYPE_FILE_SYSTEM) + "\" or \"" + std::string(STORAGE_TYPE_OBJECT_STORAGE) + "\""); } - const std::string& targetStorage = requestPayload[TARGET_STORAGE].asString(); - const Json::Value& resources = requestPayload[RESOURCES]; + const std::string& targetStorage = requestPayload[KEY_TARGET_STORAGE].asString(); + const Json::Value& resources = requestPayload[KEY_RESOURCES]; // Extract information about all the child instances for (Json::Value::ArrayIndex i = 0; i < resources.size(); i++) @@ -413,10 +430,11 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } + AddResourceForJobContent(resourcesForJobContent, Orthanc::StringToResourceType(tmpResource["Type"].asString().c_str()), resource); + for (Json::Value::ArrayIndex j = 0; j < tmpInstances.size(); j++) { instances.push_back(tmpInstances[j]["ID"].asString()); - AddResourceForJobContent(resourcesForJobContent, Orthanc::StringToResourceType(tmpResource["Type"].asString().c_str()), resource); } } else @@ -427,20 +445,76 @@ OrthancPlugins::LogInfo("Moving " + boost::lexical_cast(instances.size()) + " instances to " + targetStorage); - std::unique_ptr job(new MoveStorageJob(targetStorage, instances, resourcesForJobContent, cryptoEnabled)); - - if (hybridMode == HybridMode_WriteToFileSystem) - { - job->SetStorages(primaryStorage.get(), secondaryStorage.get()); - } - else - { - job->SetStorages(secondaryStorage.get(), primaryStorage.get()); - } + std::unique_ptr job(CreateMoveStorageJob(targetStorage, instances, resourcesForJobContent)); OrthancPlugins::OrthancJob::SubmitFromRestApiPost(output, requestPayload, job.release()); } +OrthancPluginJob* JobUnserializer(const char* jobType, + const char* serialized) +{ + if (jobType == NULL || + serialized == NULL) + { + return NULL; + } + + std::string type(jobType); + + if (type != JOB_TYPE_MOVE_STORAGE) + { + return NULL; + } + + try + { + std::string tmp(serialized); + + Json::Value source; + if (Orthanc::Toolbox::ReadJson(source, tmp)) + { + std::unique_ptr job; + + if (type == JOB_TYPE_MOVE_STORAGE) + { + std::vector instances; + + for (size_t i = 0; i < source[KEY_INSTANCES].size(); ++i) + { + instances.push_back(source[KEY_INSTANCES][static_cast(i)].asString()); + } + + job.reset(CreateMoveStorageJob(source[KEY_TARGET_STORAGE].asString(), instances, source[KEY_CONTENT])); + } + + if (job.get() == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + else + { + return OrthancPlugins::OrthancJob::Create(job.release()); + } + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + } + catch (Orthanc::OrthancException& e) + { + LOG(ERROR) << "Error while unserializing a job from the " << StoragePluginFactory::GetStoragePluginName() << " plugin: " + << e.What(); + return NULL; + } + catch (...) + { + LOG(ERROR) << "Error while unserializing a job from the " << StoragePluginFactory::GetStoragePluginName() << " plugin"; + return NULL; + } +} + + extern "C" { ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) @@ -588,6 +662,7 @@ if (IsHybridModeEnabled()) { OrthancPlugins::RegisterRestCallback("/move-storage", true); + OrthancPluginRegisterJobsUnserializer(context, JobUnserializer); } } diff -r 431ab61b5760 -r 8a9207933297 Common/StoragePlugin.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Common/StoragePlugin.h Fri Oct 21 14:14:27 2022 +0200 @@ -0,0 +1,32 @@ +/** + * Transfers accelerator plugin for Orthanc + * Copyright (C) 2018-2021 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 . + **/ + + +#pragma once + + +static const char* const JOB_TYPE_MOVE_STORAGE = "MoveStorage"; + +static const char* const KEY_RESOURCES = "Resources"; +static const char* const KEY_TARGET_STORAGE = "TargetStorage"; +static const char* const KEY_INSTANCES = "Instances"; +static const char* const KEY_CONTENT = "Content"; + +static const char* const STORAGE_TYPE_FILE_SYSTEM = "file-system"; +static const char* const STORAGE_TYPE_OBJECT_STORAGE = "object-storage"; +