comparison Sources/StorageArea.cpp @ 79:068551520123

New Python function: "orthanc.RegisterStorageArea()"
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 12 Aug 2021 17:52:17 +0200
parents
children ad31ac9a6fef
comparison
equal deleted inserted replaced
78:2b9d82366e3a 79:068551520123
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 "StorageArea.h"
21
22 #include "../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h"
23 #include "PythonString.h"
24
25
26 static PyObject* createCallback_ = NULL;
27 static PyObject* readCallback_ = NULL;
28 static PyObject* removeCallback_ = NULL;
29
30
31 static OrthancPluginErrorCode RunCallback(PythonLock& lock,
32 PyObject* callback,
33 PythonObject& args,
34 const std::string& name)
35 {
36 PythonObject result(lock, PyObject_CallObject(callback, args.GetPyObject()));
37
38 std::string traceback;
39 if (lock.HasErrorOccurred(traceback))
40 {
41 OrthancPlugins::LogError("Error in the Python " + name + " callback, traceback:\n" + traceback);
42 return OrthancPluginErrorCode_Plugin;
43 }
44 else
45 {
46 return OrthancPluginErrorCode_Success;
47 }
48 }
49
50
51 static OrthancPluginErrorCode StorageCreate(const char *uuid,
52 const void *content,
53 int64_t size,
54 OrthancPluginContentType type)
55 {
56 try
57 {
58 if (createCallback_ == NULL)
59 {
60 throw OrthancPlugins::PluginException(OrthancPluginErrorCode_InternalError);
61 }
62
63 PythonLock lock;
64
65 PythonObject args(lock, PyTuple_New(3));
66
67 PythonString str(lock, uuid);
68 PyTuple_SetItem(args.GetPyObject(), 0, str.Release());
69 PyTuple_SetItem(args.GetPyObject(), 1, PyLong_FromLong(type));
70 PyTuple_SetItem(args.GetPyObject(), 2, PyBytes_FromStringAndSize(reinterpret_cast<const char*>(content), size));
71
72 return RunCallback(lock, createCallback_, args, "StorageCreate");
73 }
74 catch (OrthancPlugins::PluginException& e)
75 {
76 return e.GetErrorCode();
77 }
78 }
79
80
81 static OrthancPluginErrorCode StorageRead(void **content,
82 int64_t *size,
83 const char *uuid,
84 OrthancPluginContentType type)
85 {
86 try
87 {
88 if (readCallback_ == NULL)
89 {
90 throw OrthancPlugins::PluginException(OrthancPluginErrorCode_InternalError);
91 }
92
93 PythonLock lock;
94
95 PythonObject args(lock, PyTuple_New(2));
96
97 PythonString str(lock, uuid);
98 PyTuple_SetItem(args.GetPyObject(), 0, str.Release());
99 PyTuple_SetItem(args.GetPyObject(), 1, PyLong_FromLong(type));
100
101 PythonObject result(lock, PyObject_CallObject(readCallback_, args.GetPyObject()));
102
103 std::string traceback;
104 if (lock.HasErrorOccurred(traceback))
105 {
106 OrthancPlugins::LogError("Error in the Python StorageRead callback, traceback:\n" + traceback);
107 return OrthancPluginErrorCode_Plugin;
108 }
109 else if (!PyBytes_Check(result.GetPyObject()))
110 {
111 OrthancPlugins::LogError("The Python StorageRead callback has not returned a byte array as expected");
112 return OrthancPluginErrorCode_Plugin;
113 }
114 else
115 {
116 char* pythonBuffer = NULL;
117 Py_ssize_t pythonSize = 0;
118 if (PyBytes_AsStringAndSize(result.GetPyObject(), &pythonBuffer, &pythonSize) == 1)
119 {
120 OrthancPlugins::LogError("Cannot access the byte buffer returned by the Python StorageRead callback");
121 return OrthancPluginErrorCode_Plugin;
122 }
123 else
124 {
125 if (pythonSize == 0)
126 {
127 *content = NULL;
128 *size = 0;
129 }
130 else
131 {
132 *content = malloc(pythonSize);
133 *size = pythonSize;
134 if (*content == NULL)
135 {
136 return OrthancPluginErrorCode_NotEnoughMemory;
137 }
138
139 memcpy(*content, pythonBuffer, pythonSize);
140 }
141
142 return OrthancPluginErrorCode_Success;
143 }
144 }
145 }
146 catch (OrthancPlugins::PluginException& e)
147 {
148 return e.GetErrorCode();
149 }
150 }
151
152
153 static OrthancPluginErrorCode StorageRemove(const char *uuid,
154 OrthancPluginContentType type)
155 {
156 try
157 {
158 if (removeCallback_ == NULL)
159 {
160 throw OrthancPlugins::PluginException(OrthancPluginErrorCode_InternalError);
161 }
162
163 PythonLock lock;
164
165 PythonObject args(lock, PyTuple_New(2));
166
167 PythonString str(lock, uuid);
168 PyTuple_SetItem(args.GetPyObject(), 0, str.Release());
169 PyTuple_SetItem(args.GetPyObject(), 1, PyLong_FromLong(type));
170
171 return RunCallback(lock, removeCallback_, args, "StorageRemove");
172 }
173 catch (OrthancPlugins::PluginException& e)
174 {
175 return e.GetErrorCode();
176 }
177 }
178
179
180 PyObject* RegisterStorageArea(PyObject* module, PyObject* args)
181 {
182 // The GIL is locked at this point (no need to create "PythonLock")
183
184 PyObject* a = NULL;
185 PyObject* b = NULL;
186 PyObject* c = NULL;
187
188 if (!PyArg_ParseTuple(args, "OOO", &a, &b, &c) ||
189 a == NULL ||
190 b == NULL ||
191 c == NULL)
192 {
193 PyErr_SetString(PyExc_ValueError, "Expected three callback functions to register a custom storage area");
194 return NULL;
195 }
196 else if (createCallback_ != NULL ||
197 readCallback_ != NULL ||
198 removeCallback_ != NULL)
199 {
200 PyErr_SetString(PyExc_RuntimeError, "Cannot register twice a custom storage area");
201 return NULL;
202 }
203 else
204 {
205 OrthancPlugins::LogInfo("Registering a custom storage area in Python");
206
207 OrthancPluginRegisterStorageArea(OrthancPlugins::GetGlobalContext(),
208 StorageCreate, StorageRead, StorageRemove);
209
210 createCallback_ = a;
211 Py_XINCREF(createCallback_);
212
213 readCallback_ = b;
214 Py_XINCREF(readCallback_);
215
216 removeCallback_ = c;
217 Py_XINCREF(removeCallback_);
218
219 Py_INCREF(Py_None);
220 return Py_None;
221 }
222 }
223
224
225 void FinalizeStorageArea()
226 {
227 PythonLock lock;
228
229 if (createCallback_ != NULL)
230 {
231 Py_XDECREF(createCallback_);
232 }
233
234 if (readCallback_ != NULL)
235 {
236 Py_XDECREF(readCallback_);
237 }
238
239 if (removeCallback_ != NULL)
240 {
241 Py_XDECREF(removeCallback_);
242 }
243 }