diff Sources/DicomScpCallbacks.cpp @ 157:a8408ef2b2d8

merge cmove2 -> default
author Alain Mazy <am@orthanc.team>
date Thu, 16 May 2024 10:38:22 +0200
parents 71d305c29cfa a6b4e0abe532
children 6fada29b6759
line wrap: on
line diff
--- a/Sources/DicomScpCallbacks.cpp	Sat Apr 06 17:28:00 2024 +0200
+++ b/Sources/DicomScpCallbacks.cpp	Thu May 16 10:38:22 2024 +0200
@@ -30,6 +30,12 @@
 static PyObject* moveScpCallback_ = NULL;
 static PyObject* worklistScpCallback_ = NULL;
 
+// version 2 of Move callbacks
+static PyObject* createMoveScpDriverCallback_ = NULL;
+static PyObject* getMoveSizeCallback_ = NULL;
+static PyObject* applyMoveCallback_ = NULL;
+static PyObject* freeMoveCallback_ = NULL;
+
 
 static PyObject *GetFindQueryTag(sdk_OrthancPluginFindQuery_Object* self,
                                  PyObject *args,
@@ -399,6 +405,226 @@
 }
 
 
+static void* CreateMoveCallback2(OrthancPluginResourceType resourceType,
+                                 const char *patientId,
+                                 const char *accessionNumber,
+                                 const char *studyInstanceUid,
+                                 const char *seriesInstanceUid,
+                                 const char *sopInstanceUid,
+                                 const char *originatorAet,
+                                 const char *sourceAet,
+                                 const char *targetAet,
+                                 uint16_t originatorId)
+{
+  assert(createMoveScpDriverCallback_ != NULL);
+
+  try
+  {
+    std::string _patientId, _accessionNumber, _studyInstanceUid, _seriesInstanceUid, _sopInstanceUid, _originatorAet, _sourceAet, _targetAet;
+    if (patientId != NULL)
+    {
+      _patientId.assign(patientId);
+    }
+
+    if (accessionNumber != NULL)
+    {
+      _accessionNumber.assign(accessionNumber);
+    }
+    
+    if (studyInstanceUid != NULL)
+    {
+      _studyInstanceUid.assign(studyInstanceUid);
+    }
+
+    if (seriesInstanceUid != NULL)
+    {
+      _seriesInstanceUid.assign(seriesInstanceUid);
+    }
+
+    if (sopInstanceUid != NULL)
+    {
+      _sopInstanceUid.assign(sopInstanceUid);
+    }
+
+    if (originatorAet != NULL)
+    {
+      _originatorAet.assign(originatorAet);
+    }
+
+    if (sourceAet != NULL)
+    {
+      _sourceAet.assign(sourceAet);
+    }
+
+    if (targetAet != NULL)
+    {
+      _targetAet.assign(targetAet);
+    }
+
+    PythonLock lock;
+
+    PythonObject kw(lock, PyDict_New());
+
+    std::string level;
+    switch (resourceType)
+    {
+      case OrthancPluginResourceType_Patient:
+        level = "PATIENT";
+        break;
+        
+      case OrthancPluginResourceType_Study:
+        level = "STUDY";
+        break;
+        
+      case OrthancPluginResourceType_Series:
+        level = "SERIES";
+        break;
+        
+      case OrthancPluginResourceType_Instance:
+        level = "INSTANCE";
+        break;
+
+      default:
+        throw OrthancPlugins::PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+    }
+
+    {
+      PythonString tmp(lock, level);
+      PyDict_SetItemString(kw.GetPyObject(), "Level", tmp.GetPyObject());
+    }
+
+    {
+      PythonString tmp(lock, _patientId);
+      PyDict_SetItemString(kw.GetPyObject(), "PatientID", tmp.GetPyObject());
+    }
+
+    {
+      PythonString tmp(lock, _accessionNumber);
+      PyDict_SetItemString(kw.GetPyObject(), "AccessionNumber", tmp.GetPyObject());
+    }
+
+    {
+      PythonString tmp(lock, _studyInstanceUid);
+      PyDict_SetItemString(kw.GetPyObject(), "StudyInstanceUID", tmp.GetPyObject());
+    }
+
+    {
+      PythonString tmp(lock, _seriesInstanceUid);
+      PyDict_SetItemString(kw.GetPyObject(), "SeriesInstanceUID", tmp.GetPyObject());
+    }
+
+    {
+      PythonString tmp(lock, _sopInstanceUid);
+      PyDict_SetItemString(kw.GetPyObject(), "SOPInstanceUID", tmp.GetPyObject());
+    }
+
+    {
+      PythonString tmp(lock, _originatorAet);
+      PyDict_SetItemString(kw.GetPyObject(), "OriginatorAET", tmp.GetPyObject());
+    }
+
+    {
+      PythonString tmp(lock, _sourceAet);
+      PyDict_SetItemString(kw.GetPyObject(), "SourceAET", tmp.GetPyObject());
+    }
+
+    {
+      PythonString tmp(lock, _targetAet);
+      PyDict_SetItemString(kw.GetPyObject(), "TargetAET", tmp.GetPyObject());
+    }
+
+    {
+      PythonObject tmp(lock, PyLong_FromUnsignedLong(originatorId));
+      PyDict_SetItemString(kw.GetPyObject(), "OriginatorID", tmp.GetPyObject());
+    }
+
+    PythonObject args(lock, PyTuple_New(0));
+
+    // Note: the result is not attached to the PythonLock because we want it to survive after this call since 
+    // the result is the python move driver that will be passed as first argument to GetMoveSize, Apply and Free.
+    // After the PyObject_Call, result's ref count is 1 -> no need to add a reference but we need to decref explicitely
+    // to delete the object at the end of the move.
+    PyObject* result = PyObject_Call(createMoveScpDriverCallback_, args.GetPyObject(), kw.GetPyObject());
+
+    OrthancPluginErrorCode code = lock.CheckCallbackSuccess("Python C-MOVE SCP callback (Create)");
+    if (code != OrthancPluginErrorCode_Success)
+    {
+      throw OrthancPlugins::PluginException(code);
+    }
+
+    return result;
+  }
+  catch (OrthancPlugins::PluginException& e)
+  {
+    return NULL;
+  }
+}
+
+
+static uint32_t GetMoveSize2(void *moveDriver)
+{
+  assert(moveDriver != NULL);
+  assert(getMoveSizeCallback_ != NULL);
+
+  PythonLock lock;
+
+  PythonObject args(lock, PyTuple_New(1));
+  PyTuple_SetItem(args.GetPyObject(), 0, reinterpret_cast<PyObject*>(moveDriver));
+  Py_INCREF(moveDriver);  // because PyTuple_SetItem steals a reference and we need to keep the object alive
+
+  PythonObject result(lock, PyObject_CallObject(getMoveSizeCallback_, args.GetPyObject()));
+
+  OrthancPluginErrorCode code = lock.CheckCallbackSuccess("Python C-MOVE SCP callback (GetMoveSize)");
+  if (code != OrthancPluginErrorCode_Success)
+  {
+    throw OrthancPlugins::PluginException(code);
+  }
+
+  if (!PyLong_Check(result.GetPyObject()))
+  {
+    throw OrthancPlugins::PluginException(OrthancPluginErrorCode_BadParameterType);
+  }
+
+  return static_cast<uint32_t>(PyLong_AsLong(result.GetPyObject()));
+}
+
+
+OrthancPluginErrorCode ApplyMove2(void *moveDriver)
+{
+  assert(moveDriver != NULL);
+  assert(applyMoveCallback_ != NULL);
+
+  PythonLock lock;
+
+  PythonObject args(lock, PyTuple_New(1));
+  PyTuple_SetItem(args.GetPyObject(), 0, reinterpret_cast<PyObject*>(moveDriver));
+  Py_INCREF(moveDriver);  // because PyTuple_SetItem steals a reference and we need to keep the object alive
+
+  PythonObject result(lock, PyObject_CallObject(applyMoveCallback_, args.GetPyObject()));
+
+  OrthancPluginErrorCode code = lock.CheckCallbackSuccess("Python C-MOVE SCP callback (Apply)");
+  return code;
+}
+
+   
+void FreeMove2(void *moveDriver)
+{
+  assert(moveDriver != NULL);
+
+  PythonLock lock;
+
+  PythonObject args(lock, PyTuple_New(1));
+  PyTuple_SetItem(args.GetPyObject(), 0, reinterpret_cast<PyObject*>(moveDriver));
+  Py_INCREF(moveDriver);  // because PyTuple_SetItem steals a reference and we need to keep the object alive
+
+  assert(freeMoveCallback_ != NULL);
+  PythonObject result(lock, PyObject_CallObject(freeMoveCallback_, args.GetPyObject()));
+
+  lock.CheckCallbackSuccess("Python C-MOVE SCP callback (Free)");
+
+  Py_DECREF(moveDriver); // remove the initial reference -> this will delete the Python Object when we exit this function
+}
+
 
 OrthancPluginErrorCode WorklistCallback(OrthancPluginWorklistAnswers *answers,
                                         const OrthancPluginWorklistQuery *query,
@@ -487,6 +713,25 @@
 }
 
 
+PyObject* RegisterMoveCallback2(PyObject* module, PyObject* args)
+{
+  // The GIL is locked at this point (no need to create "PythonLock")
+
+  class Registration : public ICallbackRegistration
+  {
+  public:
+    virtual void Register() ORTHANC_OVERRIDE
+    {
+      OrthancPluginRegisterMoveCallback(
+        OrthancPlugins::GetGlobalContext(), CreateMoveCallback2, GetMoveSize2, ApplyMove2, FreeMove2);
+    }
+  };
+
+  Registration registration;
+  return ICallbackRegistration::Apply4(
+    registration, args, createMoveScpDriverCallback_, getMoveSizeCallback_, applyMoveCallback_, freeMoveCallback_, "Python C-MOVE SCP callback (2)");
+}
+
 PyObject* RegisterWorklistCallback(PyObject* module, PyObject* args)
 {
   // The GIL is locked at this point (no need to create "PythonLock")
@@ -511,4 +756,9 @@
   ICallbackRegistration::Unregister(findScpCallback_);
   ICallbackRegistration::Unregister(moveScpCallback_);
   ICallbackRegistration::Unregister(worklistScpCallback_);
+
+  ICallbackRegistration::Unregister(createMoveScpDriverCallback_);
+  ICallbackRegistration::Unregister(getMoveSizeCallback_);
+  ICallbackRegistration::Unregister(applyMoveCallback_);
+  ICallbackRegistration::Unregister(freeMoveCallback_);
 }