# HG changeset patch # User Sebastien Jodogne # Date 1464182177 -7200 # Node ID 9b61701c35f20ae96497535c2f34dc1e47aca7c8 # Parent f9f2aa1cc594d17760fef6e750e7b8b90263fc93 New URI "/modalities/.../move" to issue C-Move SCU requests diff -r f9f2aa1cc594 -r 9b61701c35f2 NEWS --- a/NEWS Wed May 25 11:50:35 2016 +0200 +++ b/NEWS Wed May 25 15:16:17 2016 +0200 @@ -34,7 +34,8 @@ REST API -------- -* "MoveOriginatorID" can be specified for /modalities/.../store +* New URI "/modalities/.../move" to issue C-Move SCU requests +* "MoveOriginatorID" can be specified for "/modalities/.../store" Maintenance ----------- diff -r f9f2aa1cc594 -r 9b61701c35f2 OrthancServer/DicomProtocol/DicomUserConnection.cpp --- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp Wed May 25 11:50:35 2016 +0200 +++ b/OrthancServer/DicomProtocol/DicomUserConnection.cpp Wed May 25 15:16:17 2016 +0200 @@ -995,16 +995,9 @@ void DicomUserConnection::Move(const std::string& targetAet, + ResourceType level, const DicomMap& findResult) { - if (!findResult.HasTag(DICOM_TAG_QUERY_RETRIEVE_LEVEL)) - { - throw OrthancException(ErrorCode_InternalError); - } - - const std::string tmp = findResult.GetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL).GetContent(); - ResourceType level = StringToResourceType(tmp.c_str()); - DicomMap move; switch (level) { @@ -1035,6 +1028,21 @@ } + void DicomUserConnection::Move(const std::string& targetAet, + const DicomMap& findResult) + { + if (!findResult.HasTag(DICOM_TAG_QUERY_RETRIEVE_LEVEL)) + { + throw OrthancException(ErrorCode_InternalError); + } + + const std::string tmp = findResult.GetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL).GetContent(); + ResourceType level = StringToResourceType(tmp.c_str()); + + Move(targetAet, level, findResult); + } + + void DicomUserConnection::MovePatient(const std::string& targetAet, const std::string& patientId) { diff -r f9f2aa1cc594 -r 9b61701c35f2 OrthancServer/DicomProtocol/DicomUserConnection.h --- a/OrthancServer/DicomProtocol/DicomUserConnection.h Wed May 25 11:50:35 2016 +0200 +++ b/OrthancServer/DicomProtocol/DicomUserConnection.h Wed May 25 15:16:17 2016 +0200 @@ -148,6 +148,10 @@ const DicomMap& fields); void Move(const std::string& targetAet, + ResourceType level, + const DicomMap& findResult); + + void Move(const std::string& targetAet, const DicomMap& findResult); void MovePatient(const std::string& targetAet, diff -r f9f2aa1cc594 -r 9b61701c35f2 OrthancServer/FromDcmtkBridge.cpp --- a/OrthancServer/FromDcmtkBridge.cpp Wed May 25 11:50:35 2016 +0200 +++ b/OrthancServer/FromDcmtkBridge.cpp Wed May 25 15:16:17 2016 +0200 @@ -1735,4 +1735,30 @@ return result.release(); } + + + void FromDcmtkBridge::FromJson(DicomMap& target, + const Json::Value& source) + { + if (source.type() != Json::objectValue) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + target.Clear(); + + Json::Value::Members members = source.getMemberNames(); + + for (size_t i = 0; i < members.size(); i++) + { + const Json::Value& value = source[members[i]]; + + if (value.type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + target.SetValue(ParseTag(members[i]), value.asString()); + } + } } diff -r f9f2aa1cc594 -r 9b61701c35f2 OrthancServer/FromDcmtkBridge.h --- a/OrthancServer/FromDcmtkBridge.h Wed May 25 11:50:35 2016 +0200 +++ b/OrthancServer/FromDcmtkBridge.h Wed May 25 15:16:17 2016 +0200 @@ -160,5 +160,8 @@ static DcmFileFormat* LoadFromMemoryBuffer(const void* buffer, size_t size); + + static void FromJson(DicomMap& values, + const Json::Value& result); }; } diff -r f9f2aa1cc594 -r 9b61701c35f2 OrthancServer/OrthancRestApi/OrthancRestModalities.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp Wed May 25 11:50:35 2016 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp Wed May 25 15:16:17 2016 +0200 @@ -386,7 +386,7 @@ std::auto_ptr handler(new QueryRetrieveHandler(context)); handler->SetModality(call.GetUriComponent("id", "")); - handler->SetLevel(StringToResourceType(request["Level"].asString().c_str())); + handler->SetLevel(StringToResourceType(request["Level"].asCString())); if (request.isMember("Query")) { @@ -745,6 +745,76 @@ /*************************************************************************** + * DICOM C-Move SCU + ***************************************************************************/ + + static void DicomMove(RestApiPostCall& call) + { + ServerContext& context = OrthancRestApi::GetContext(call); + + Json::Value request; + + static const char* RESOURCES = "Resources"; + static const char* LEVEL = "Level"; + + if (!call.ParseJsonRequest(request) || + request.type() != Json::objectValue || + !request.isMember(RESOURCES) || + !request.isMember(LEVEL) || + request[RESOURCES].type() != Json::arrayValue || + request[LEVEL].type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + ResourceType level = StringToResourceType(request["Level"].asCString()); + + static const char* LOCAL_AET = "LocalAet"; + std::string localAet = context.GetDefaultLocalApplicationEntityTitle(); + if (request.isMember(LOCAL_AET)) + { + if (request[LOCAL_AET].type() == Json::stringValue) + { + localAet = request[LOCAL_AET].asString(); + } + else + { + throw OrthancException(ErrorCode_BadFileFormat); + } + } + + static const char* TARGET_AET = "TargetAet"; + std::string targetAet = context.GetDefaultLocalApplicationEntityTitle(); + if (request.isMember(TARGET_AET)) + { + if (request[TARGET_AET].type() == Json::stringValue) + { + targetAet = request[TARGET_AET].asString(); + } + else + { + throw OrthancException(ErrorCode_BadFileFormat); + } + } + + const RemoteModalityParameters source = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", "")); + + for (Json::Value::ArrayIndex i = 0; i < request[RESOURCES].size(); i++) + { + DicomMap resource; + FromDcmtkBridge::FromJson(resource, request[RESOURCES][i]); + + ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, source); + locker.GetConnection().Move(targetAet, level, resource); + } + + // Move has succeeded + call.GetOutput().AnswerBuffer("{}", "application/json"); + } + + + + /*************************************************************************** * Orthanc Peers => Store client ***************************************************************************/ @@ -936,6 +1006,7 @@ Register("/modalities/{id}/find-instance", DicomFindInstance); Register("/modalities/{id}/find", DicomFind); Register("/modalities/{id}/store", DicomStore); + Register("/modalities/{id}/move", DicomMove); // For Query/Retrieve Register("/modalities/{id}/query", DicomQuery);