changeset 84:8a9207933297

MoveStorageJob serialization
author Alain Mazy <am@osimis.io>
date Fri, 21 Oct 2022 14:14:27 +0200
parents 431ab61b5760
children 7ace942ede26
files Common/MoveStorageJob.cpp Common/MoveStorageJob.h Common/StoragePlugin.cpp Common/StoragePlugin.h
diffstat 4 files changed, 156 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- 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<std::string>& 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
--- 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<std::string>& instances,
--- 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 <Logging.h>
 #include <SystemToolbox.h>
 #include "MoveStorageJob.h"
+#include "StoragePlugin.h"
+#include <Toolbox.h>
+
 
 static std::unique_ptr<IStorage> primaryStorage;
 static std::unique_ptr<IStorage> secondaryStorage;
@@ -316,6 +319,23 @@
 }
 
 
+static MoveStorageJob* CreateMoveStorageJob(const std::string& targetStorage, const std::vector<std::string>& instances, const Json::Value& resourcesForJobContent)
+{
+  std::unique_ptr<MoveStorageJob> 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<std::string> 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<std::string>(instances.size()) + " instances to " + targetStorage);
 
-  std::unique_ptr<MoveStorageJob> 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<MoveStorageJob> 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<OrthancPlugins::OrthancJob> job;
+
+      if (type == JOB_TYPE_MOVE_STORAGE)
+      {
+        std::vector<std::string> instances;
+
+        for (size_t i = 0; i < source[KEY_INSTANCES].size(); ++i)
+        {
+          instances.push_back(source[KEY_INSTANCES][static_cast<int>(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<MoveStorage>("/move-storage", true);
+          OrthancPluginRegisterJobsUnserializer(context, JobUnserializer);
         }
 
       }
--- /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 <http://www.gnu.org/licenses/>.
+ **/
+
+
+#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";
+