Mercurial > hg > orthanc-python
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 } |