diff Framework/TransferBucket.cpp @ 0:95226b754d9e

initial release
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 17 Sep 2018 11:34:55 +0200
parents
children 7e207ade2f1a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/TransferBucket.cpp	Mon Sep 17 11:34:55 2018 +0200
@@ -0,0 +1,229 @@
+/**
+ * Transfers accelerator plugin for Orthanc
+ * Copyright (C) 2018 Osimis, 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 "TransferBucket.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+
+namespace OrthancPlugins
+{
+  TransferBucket::TransferBucket() :
+    totalSize_(0),
+    extensible_(true)
+  {
+  }
+
+    
+  TransferBucket::TransferBucket(const Json::Value& serialized) :
+    totalSize_(0),
+    extensible_(false)
+  {
+    if (serialized.type() != Json::arrayValue)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
+
+    chunks_.reserve(serialized.size());
+
+    for (Json::Value::ArrayIndex i = 0; i < serialized.size(); i++)
+    {
+      if (serialized[i].type() != Json::objectValue ||
+          !serialized[i].isMember(KEY_ID) ||
+          !serialized[i].isMember(KEY_OFFSET) ||
+          !serialized[i].isMember(KEY_SIZE) ||
+          serialized[i][KEY_ID].type() != Json::stringValue ||
+          serialized[i][KEY_OFFSET].type() != Json::stringValue ||
+          serialized[i][KEY_SIZE].type() != Json::stringValue)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+      }
+      else
+      {
+        try
+        {
+          Chunk chunk;
+          chunk.instanceId_ = serialized[i][KEY_ID].asString();
+          chunk.offset_ = boost::lexical_cast<size_t>(serialized[i][KEY_OFFSET].asString());
+          chunk.size_ = boost::lexical_cast<size_t>(serialized[i][KEY_SIZE].asString());
+
+          chunks_.push_back(chunk);
+          totalSize_ += chunk.size_;
+        }
+        catch (boost::bad_lexical_cast&)
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+        }
+      }
+    }
+  }
+
+
+  void TransferBucket::Serialize(Json::Value& target) const
+  {
+    target = Json::arrayValue;
+
+    for (size_t i = 0; i < chunks_.size(); i++)
+    {
+      Json::Value item = Json::objectValue;
+      item[KEY_ID] = chunks_[i].instanceId_;
+      item[KEY_OFFSET] = boost::lexical_cast<std::string>(chunks_[i].offset_);
+      item[KEY_SIZE] = boost::lexical_cast<std::string>(chunks_[i].size_);
+      target.append(item);
+    }
+  }
+    
+  void TransferBucket::Clear()
+  {
+    chunks_.clear();
+    totalSize_ = 0;
+    extensible_ = true;
+  }
+    
+    
+  void TransferBucket::AddChunk(const DicomInstanceInfo& instance,
+                                size_t chunkOffset,
+                                size_t chunkSize)
+  {
+    if (chunkOffset + chunkSize > instance.GetSize())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    if (!extensible_)
+    {
+      LOG(ERROR) << "Cannot add a new chunk after a truncated instance";
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+      
+    if (!chunks_.empty() &&
+        chunkOffset != 0)
+    {
+      LOG(ERROR) << "Only the first chunk can have non-zero offset in a transfer bucket";
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    if (chunkSize == 0)
+    {
+      // Ignore empty chunks
+      return;
+    }
+
+    if (!chunks_.empty() &&
+        chunkSize != instance.GetSize())
+    {
+      // Prevents adding new chunk after an incomplete instance
+      extensible_ = false;
+    }
+
+    Chunk chunk;
+    chunk.instanceId_ = instance.GetId();
+    chunk.offset_ = chunkOffset;
+    chunk.size_ = chunkSize;
+
+    chunks_.push_back(chunk);
+    totalSize_ += chunkSize;
+  }
+    
+
+  const std::string& TransferBucket::GetChunkInstanceId(size_t index) const
+  {
+    if (index >= chunks_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      return chunks_[index].instanceId_;
+    }
+  }
+
+  
+  size_t TransferBucket::GetChunkOffset(size_t index) const
+  {
+    if (index >= chunks_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      return chunks_[index].offset_;
+    }
+  }
+
+  
+  size_t TransferBucket::GetChunkSize(size_t index) const
+  {
+    if (index >= chunks_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      return chunks_[index].size_;
+    }
+  }
+
+  
+  void TransferBucket::ComputePullUri(std::string& uri,
+                                      BucketCompression compression) const
+  {
+    if (chunks_.empty())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+
+    bool first = true;
+    uri = std::string(URI_CHUNKS) + "/";
+
+    for (size_t i = 0; i < chunks_.size(); i++)
+    {
+      if (first)
+      {
+        first = false;
+      }
+      else
+      {
+        uri += ".";
+      }
+
+      uri += chunks_[i].instanceId_;
+
+      assert(i == 0 || chunks_[i].offset_ == 0);
+    }
+
+    uri += ("?offset=" + boost::lexical_cast<std::string>(chunks_[0].offset_) +
+            "&size=" + boost::lexical_cast<std::string>(totalSize_));
+
+    switch (compression)
+    {
+      case BucketCompression_None:
+        uri += "&compression=none";
+        break;
+
+      case BucketCompression_Gzip:
+        uri += "&compression=gzip";
+        break;
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+  }
+}