Mercurial > hg > orthanc-python
comparison Sources/ReceivedInstanceCallback.cpp @ 99:465bf098554b
new callback: orthanc.RegisterReceivedInstanceCallback()
author | Alain Mazy <am@osimis.io> |
---|---|
date | Tue, 14 Dec 2021 10:06:16 +0100 |
parents | |
children | e2b2e1d4e1bb |
comparison
equal
deleted
inserted
replaced
98:62f2731094ae | 99:465bf098554b |
---|---|
1 /** | |
2 * Python plugin for Orthanc | |
3 * Copyright (C) 2020-2021 Osimis S.A., Belgium | |
4 * | |
5 * This program is free software: you can redistribute it and/or | |
6 * modify it under the terms of the GNU Affero General Public License | |
7 * as published by the Free Software Foundation, either version 3 of | |
8 * the License, or (at your option) any later version. | |
9 * | |
10 * This program is distributed in the hope that it will be useful, but | |
11 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Affero General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Affero General Public License | |
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 **/ | |
18 | |
19 | |
20 #include "ReceivedInstanceCallback.h" | |
21 | |
22 #include "../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h" | |
23 #include "ICallbackRegistration.h" | |
24 #include "PythonString.h" | |
25 | |
26 #include <Compatibility.h> // For std::unique_ptr<> | |
27 | |
28 static PyObject* receivedInstanceCallback_ = NULL; | |
29 | |
30 | |
31 static OrthancPluginReceivedInstanceCallbackResult ReceivedInstanceCallback( | |
32 const void* receivedDicomBuffer, | |
33 uint64_t receivedDicomBufferSize, | |
34 void** modifiedDicomBuffer, | |
35 uint64_t* modifiedDicomBufferSize) | |
36 { | |
37 try | |
38 { | |
39 PythonLock lock; | |
40 | |
41 PythonObject args(lock, PyTuple_New(1)); | |
42 | |
43 PyTuple_SetItem(args.GetPyObject(), 0, PyBytes_FromStringAndSize(reinterpret_cast<const char*>(receivedDicomBuffer), receivedDicomBufferSize)); | |
44 | |
45 PythonObject result(lock, PyObject_CallObject(receivedInstanceCallback_, args.GetPyObject())); | |
46 | |
47 std::string traceback; | |
48 if (lock.HasErrorOccurred(traceback)) | |
49 { | |
50 OrthancPlugins::LogError("Error in the Python received instance callback, traceback:\n" + traceback); | |
51 return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs; | |
52 } | |
53 else if (!PyTuple_Check(result.GetPyObject()) || PyTuple_Size(result.GetPyObject()) != 2) | |
54 { | |
55 OrthancPlugins::LogError("The Python received instance callback has not returned a tuple as expected"); | |
56 return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs; | |
57 } | |
58 else | |
59 { | |
60 PyObject* returnCode = PyTuple_GET_ITEM(result.GetPyObject(), 0); | |
61 PyObject* modifiedDicom = PyTuple_GET_ITEM(result.GetPyObject(), 1); | |
62 | |
63 if (!PyLong_Check(returnCode)) | |
64 { | |
65 OrthancPlugins::LogError("The Python received instance callback has not returned an int as the first element of the return tuple"); | |
66 return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs; | |
67 } | |
68 | |
69 OrthancPluginReceivedInstanceCallbackResult resultCode = static_cast<OrthancPluginReceivedInstanceCallbackResult>(PyLong_AsLong(returnCode)); | |
70 | |
71 if (resultCode == OrthancPluginReceivedInstanceCallbackResult_KeepAsIs || | |
72 resultCode == OrthancPluginReceivedInstanceCallbackResult_Discard) | |
73 { | |
74 return resultCode; | |
75 } | |
76 | |
77 char* pythonBuffer = NULL; | |
78 Py_ssize_t pythonSize = 0; | |
79 if (PyBytes_AsStringAndSize(modifiedDicom, &pythonBuffer, &pythonSize) == 1) | |
80 { | |
81 OrthancPlugins::LogError("Cannot access the byte buffer returned by the Python received instance callback"); | |
82 return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs; | |
83 } | |
84 else | |
85 { | |
86 if (pythonSize == 0) | |
87 { | |
88 *modifiedDicomBuffer = NULL; | |
89 *modifiedDicomBufferSize = 0; | |
90 return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs; | |
91 } | |
92 else | |
93 { | |
94 *modifiedDicomBuffer = malloc(pythonSize); | |
95 *modifiedDicomBufferSize = pythonSize; | |
96 if (*modifiedDicomBuffer == NULL) | |
97 { | |
98 OrthancPlugins::LogError("Cannot allocate memory in the Python received instance callback"); | |
99 return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs; | |
100 } | |
101 | |
102 memcpy(*modifiedDicomBuffer, pythonBuffer, pythonSize); | |
103 return OrthancPluginReceivedInstanceCallbackResult_Modified; | |
104 } | |
105 } | |
106 } | |
107 } | |
108 catch (OrthancPlugins::PluginException& e) | |
109 { | |
110 OrthancPlugins::LogError("Error in the Python received instance callback: " + std::string(e.What(OrthancPlugins::GetGlobalContext()))); | |
111 } | |
112 | |
113 return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs; | |
114 } | |
115 | |
116 | |
117 PyObject* RegisterReceivedInstanceCallback(PyObject* module, PyObject* args) | |
118 { | |
119 // The GIL is locked at this point (no need to create "PythonLock") | |
120 | |
121 class Registration : public ICallbackRegistration | |
122 { | |
123 public: | |
124 virtual void Register() ORTHANC_OVERRIDE | |
125 { | |
126 OrthancPluginRegisterReceivedInstanceCallback( | |
127 OrthancPlugins::GetGlobalContext(), ReceivedInstanceCallback); | |
128 } | |
129 }; | |
130 | |
131 Registration registration; | |
132 return ICallbackRegistration::Apply( | |
133 registration, args, receivedInstanceCallback_, "Python received instance callback"); | |
134 } | |
135 | |
136 | |
137 void FinalizeReceivedInstanceCallback() | |
138 { | |
139 ICallbackRegistration::Unregister(receivedInstanceCallback_); | |
140 } |