Mercurial > hg > orthanc
annotate OrthancServer/Plugins/Samples/DelayedDeletion/Plugin.cpp @ 5031:eec3e4a91663 delayed-deletion
DelayedDeletion plugin: first version
author | Alain Mazy <am@osimis.io> |
---|---|
date | Tue, 21 Jun 2022 17:29:36 +0200 |
parents | c2ebc47f4f18 |
children | ae3f29be5ca5 |
rev | line source |
---|---|
5024 | 1 #include "PendingDeletionsDatabase.h" |
2 | |
3 #include "../../../../OrthancFramework/Sources/FileStorage/FilesystemStorage.h" | |
4 #include "../../../../OrthancFramework/Sources/Logging.h" | |
5 #include "../../../../OrthancFramework/Sources/MultiThreading/SharedMessageQueue.h" | |
6 #include "../../../../OrthancServer/Plugins/Engine/PluginsEnumerations.h" | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
7 #include "../../../../OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h" |
5024 | 8 |
9 #include <boost/thread.hpp> | |
10 | |
11 | |
12 class PendingDeletion : public Orthanc::IDynamicObject | |
13 { | |
14 private: | |
15 Orthanc::FileContentType type_; | |
16 std::string uuid_; | |
17 | |
18 public: | |
19 PendingDeletion(Orthanc::FileContentType type, | |
20 const std::string& uuid) : | |
21 type_(type), | |
22 uuid_(uuid) | |
23 { | |
24 } | |
25 | |
26 Orthanc::FileContentType GetType() const | |
27 { | |
28 return type_; | |
29 } | |
30 | |
31 const std::string& GetUuid() const | |
32 { | |
33 return uuid_; | |
34 } | |
35 }; | |
36 | |
37 | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
38 static const char* DELAYED_DELETION = "DelayedDeletion"; |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
39 static bool continue_ = false; |
5024 | 40 static Orthanc::SharedMessageQueue queue_; |
41 static std::unique_ptr<Orthanc::FilesystemStorage> storage_; | |
42 static std::unique_ptr<PendingDeletionsDatabase> db_; | |
43 static std::unique_ptr<boost::thread> deletionThread_; | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
44 static const char* databaseServerIdentifier_ = NULL; |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
45 static unsigned int throttleDelayMs_ = 0; |
5024 | 46 |
47 | |
48 static OrthancPluginErrorCode StorageCreate(const char* uuid, | |
49 const void* content, | |
50 int64_t size, | |
51 OrthancPluginContentType type) | |
52 { | |
53 try | |
54 { | |
55 storage_->Create(uuid, content, size, Orthanc::Plugins::Convert(type)); | |
56 return OrthancPluginErrorCode_Success; | |
57 } | |
58 catch (Orthanc::OrthancException& e) | |
59 { | |
60 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); | |
61 } | |
62 catch (...) | |
63 { | |
64 return OrthancPluginErrorCode_StorageAreaPlugin; | |
65 } | |
66 } | |
67 | |
68 | |
69 static OrthancPluginErrorCode StorageReadWhole(OrthancPluginMemoryBuffer64* target, // Memory buffer where to store the content of the file. It must be allocated by the plugin using OrthancPluginCreateMemoryBuffer64(). The core of Orthanc will free it. | |
70 const char* uuid, | |
71 OrthancPluginContentType type) | |
72 { | |
73 try | |
74 { | |
75 std::unique_ptr<Orthanc::IMemoryBuffer> buffer(storage_->Read(uuid, Orthanc::Plugins::Convert(type))); | |
76 | |
77 // copy from a buffer allocated on plugin's heap into a buffer allocated on core's heap | |
78 if (OrthancPluginCreateMemoryBuffer64(OrthancPlugins::GetGlobalContext(), target, buffer->GetSize()) != OrthancPluginErrorCode_Success) | |
79 { | |
80 OrthancPlugins::LogError("Delayed deletion plugin: error while reading object " + std::string(uuid) + ", cannot allocate memory of size " + boost::lexical_cast<std::string>(buffer->GetSize()) + " bytes"); | |
81 return OrthancPluginErrorCode_StorageAreaPlugin; | |
82 } | |
83 | |
84 memcpy(target->data, buffer->GetData(), buffer->GetSize()); | |
85 | |
86 return OrthancPluginErrorCode_Success; | |
87 } | |
88 catch (Orthanc::OrthancException& e) | |
89 { | |
90 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); | |
91 } | |
92 catch (...) | |
93 { | |
94 return OrthancPluginErrorCode_StorageAreaPlugin; | |
95 } | |
96 } | |
97 | |
98 | |
99 static OrthancPluginErrorCode StorageReadRange(OrthancPluginMemoryBuffer64* target, // Memory buffer where to store the content of the range. The memory buffer is allocated and freed by Orthanc. The length of the range of interest corresponds to the size of this buffer. | |
100 const char* uuid, | |
101 OrthancPluginContentType type, | |
102 uint64_t rangeStart) | |
103 { | |
104 try | |
105 { | |
106 std::unique_ptr<Orthanc::IMemoryBuffer> buffer(storage_->ReadRange(uuid, Orthanc::Plugins::Convert(type), rangeStart, rangeStart + target->size)); | |
107 | |
108 assert(buffer->GetSize() == target->size); | |
109 | |
110 memcpy(target->data, buffer->GetData(), buffer->GetSize()); | |
111 | |
112 return OrthancPluginErrorCode_Success; | |
113 } | |
114 catch (Orthanc::OrthancException& e) | |
115 { | |
116 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); | |
117 } | |
118 catch (...) | |
119 { | |
120 return OrthancPluginErrorCode_StorageAreaPlugin; | |
121 } | |
122 | |
123 return OrthancPluginErrorCode_Success; | |
124 } | |
125 | |
126 | |
127 static OrthancPluginErrorCode StorageRemove(const char* uuid, | |
128 OrthancPluginContentType type) | |
129 { | |
130 try | |
131 { | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
132 LOG(INFO) << "DelayedDeletion - Scheduling delayed deletion of " << uuid; |
5024 | 133 db_->Enqueue(uuid, Orthanc::Plugins::Convert(type)); |
134 | |
135 return OrthancPluginErrorCode_Success; | |
136 } | |
137 catch (Orthanc::OrthancException& e) | |
138 { | |
139 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); | |
140 } | |
141 catch (...) | |
142 { | |
143 return OrthancPluginErrorCode_StorageAreaPlugin; | |
144 } | |
145 } | |
146 | |
147 static void DeletionWorker() | |
148 { | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
149 static const unsigned int GRANULARITY = 100; // In milliseconds |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
150 |
5024 | 151 while (continue_) |
152 { | |
153 std::string uuid; | |
154 Orthanc::FileContentType type = Orthanc::FileContentType_Dicom; // Dummy initialization | |
155 | |
156 bool hasDeleted = false; | |
157 | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
158 while (continue_ && db_->Dequeue(uuid, type)) |
5024 | 159 { |
160 if (!hasDeleted) | |
161 { | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
162 LOG(INFO) << "DelayedDeletion - Starting to process the pending deletions"; |
5024 | 163 } |
164 | |
165 hasDeleted = true; | |
166 | |
167 try | |
168 { | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
169 LOG(INFO) << "DelayedDeletion - Asynchronous removal of file: " << uuid; |
5024 | 170 storage_->Remove(uuid, type); |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
171 |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
172 if (throttleDelayMs_ > 0) |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
173 { |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
174 boost::this_thread::sleep(boost::posix_time::milliseconds(throttleDelayMs_)); |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
175 } |
5024 | 176 } |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
177 catch (Orthanc::OrthancException& ex) |
5024 | 178 { |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
179 LOG(ERROR) << "DelayedDeletion - Cannot remove file: " << uuid << " " << ex.What(); |
5024 | 180 } |
181 } | |
182 | |
183 if (hasDeleted) | |
184 { | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
185 LOG(INFO) << "DelayedDeletion - All the pending deletions have been completed"; |
5024 | 186 } |
187 | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
188 boost::this_thread::sleep(boost::posix_time::milliseconds(GRANULARITY)); |
5024 | 189 } |
190 } | |
191 | |
192 | |
193 OrthancPluginErrorCode OnChangeCallback(OrthancPluginChangeType changeType, | |
194 OrthancPluginResourceType resourceType, | |
195 const char* resourceId) | |
196 { | |
197 switch (changeType) | |
198 { | |
199 case OrthancPluginChangeType_OrthancStarted: | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
200 assert(deletionThread_.get() == NULL); |
5024 | 201 |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
202 LOG(WARNING) << "DelayedDeletion - Starting the deletion thread"; |
5024 | 203 continue_ = true; |
204 deletionThread_.reset(new boost::thread(DeletionWorker)); | |
205 break; | |
206 | |
207 case OrthancPluginChangeType_OrthancStopped: | |
208 | |
209 if (deletionThread_.get() != NULL) | |
210 { | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
211 LOG(WARNING) << "DelayedDeletion - Stopping the deletion thread"; |
5024 | 212 continue_ = false; |
213 if (deletionThread_->joinable()) | |
214 { | |
215 deletionThread_->join(); | |
216 } | |
217 } | |
218 | |
219 break; | |
220 | |
221 default: | |
222 break; | |
223 } | |
224 | |
225 return OrthancPluginErrorCode_Success; | |
226 } | |
227 | |
228 | |
229 | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
230 void GetPluginStatus(OrthancPluginRestOutput* output, |
5024 | 231 const char* url, |
232 const OrthancPluginHttpRequest* request) | |
233 { | |
234 | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
235 Json::Value status; |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
236 status["FilesPendingDeletion"] = db_->GetSize(); |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
237 status["DatabaseServerIdentifier"] = databaseServerIdentifier_; |
5024 | 238 |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
239 std::string s = status.toStyledString(); |
5024 | 240 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), |
241 s.size(), "application/json"); | |
242 } | |
243 | |
244 | |
245 | |
246 extern "C" | |
247 { | |
248 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) | |
249 { | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
250 OrthancPlugins::SetGlobalContext(context); |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
251 Orthanc::Logging::InitializePluginContext(context); |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
252 |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
253 |
5024 | 254 /* Check the version of the Orthanc core */ |
255 if (OrthancPluginCheckVersion(context) == 0) | |
256 { | |
257 char info[1024]; | |
258 sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin", | |
259 context->orthancVersion, | |
260 ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, | |
261 ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, | |
262 ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); | |
263 OrthancPluginLogError(context, info); | |
264 return -1; | |
265 } | |
266 | |
267 OrthancPluginSetDescription(context, "Plugin removing files from storage asynchronously."); | |
268 | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
269 OrthancPlugins::OrthancConfiguration orthancConfig; |
5024 | 270 |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
271 if (!orthancConfig.IsSection(DELAYED_DELETION)) |
5024 | 272 { |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
273 LOG(WARNING) << "DelayedDeletion - plugin is loaded but not enabled (no \"DelayedDeletion\" section found in configuration)"; |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
274 return 0; |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
275 } |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
276 |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
277 OrthancPlugins::OrthancConfiguration delayedDeletionConfig; |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
278 orthancConfig.GetSection(delayedDeletionConfig, DELAYED_DELETION); |
5024 | 279 |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
280 if (delayedDeletionConfig.GetBooleanValue("Enable", true)) |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
281 { |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
282 databaseServerIdentifier_ = OrthancPluginGetDatabaseServerIdentifier(context); |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
283 throttleDelayMs_ = delayedDeletionConfig.GetUnsignedIntegerValue("ThrottleDelayMs", 0); // delay in ms |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
284 |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
285 |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
286 std::string pathStorage = orthancConfig.GetStringValue("StorageDirectory", "OrthancStorage"); |
5024 | 287 LOG(WARNING) << "DelayedDeletion - Path to the storage area: " << pathStorage; |
288 | |
289 storage_.reset(new Orthanc::FilesystemStorage(pathStorage)); | |
290 | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
291 boost::filesystem::path defaultDbPath = boost::filesystem::path(pathStorage) / (std::string("pending-deletions.") + databaseServerIdentifier_ + ".db"); |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
292 std::string dbPath = delayedDeletionConfig.GetStringValue("Path", defaultDbPath.string()); |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
293 |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
294 LOG(WARNING) << "DelayedDeletion - Path to the SQLite database: " << dbPath; |
5024 | 295 |
296 // This must run after the allocation of "storage_", to make sure | |
297 // that the folder actually exists | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
298 db_.reset(new PendingDeletionsDatabase(dbPath)); |
5024 | 299 |
300 OrthancPluginRegisterStorageArea2(context, StorageCreate, StorageReadWhole, StorageReadRange, StorageRemove); | |
301 | |
302 OrthancPluginRegisterOnChangeCallback(context, OnChangeCallback); | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
303 |
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
304 OrthancPlugins::RegisterRestCallback<GetPluginStatus>(std::string("/plugins/") + ORTHANC_PLUGIN_NAME + "/status", true); |
5024 | 305 } |
306 else | |
307 { | |
5031
eec3e4a91663
DelayedDeletion plugin: first version
Alain Mazy <am@osimis.io>
parents:
5024
diff
changeset
|
308 LOG(WARNING) << "DelayedDeletion - plugin is loaded but disabled (check your \"DelayedDeletion.Enable\" configuration)"; |
5024 | 309 } |
310 | |
311 return 0; | |
312 } | |
313 | |
314 ORTHANC_PLUGINS_API void OrthancPluginFinalize() | |
315 { | |
316 db_.reset(); | |
317 storage_.reset(); | |
318 } | |
319 | |
320 ORTHANC_PLUGINS_API const char* OrthancPluginGetName() | |
321 { | |
322 return ORTHANC_PLUGIN_NAME; | |
323 } | |
324 | |
325 ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() | |
326 { | |
327 return ORTHANC_PLUGIN_VERSION; | |
328 } | |
329 } |