Mercurial > hg > orthanc
comparison OrthancServer/OrthancRestApi/OrthancRestModalities.cpp @ 2573:3372c5255333 jobs
StoreScuJob, Orthanc Explorer for jobs
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 09 May 2018 17:56:14 +0200 |
parents | 878b59270859 |
children | 055d7d4a823f |
comparison
equal
deleted
inserted
replaced
2570:2e879c796ec7 | 2573:3372c5255333 |
---|---|
42 #include "../Scheduler/StoreScuCommand.h" | 42 #include "../Scheduler/StoreScuCommand.h" |
43 #include "../Scheduler/StorePeerCommand.h" | 43 #include "../Scheduler/StorePeerCommand.h" |
44 #include "../QueryRetrieveHandler.h" | 44 #include "../QueryRetrieveHandler.h" |
45 #include "../ServerToolbox.h" | 45 #include "../ServerToolbox.h" |
46 | 46 |
47 | |
48 | |
49 namespace Orthanc | |
50 { | |
51 class InstancesIteratorJob : public IJob | |
52 { | |
53 private: | |
54 bool started_; | |
55 std::vector<std::string> instances_; | |
56 size_t position_; | |
57 | |
58 public: | |
59 InstancesIteratorJob() : | |
60 started_(false), | |
61 position_(0) | |
62 { | |
63 } | |
64 | |
65 void Reserve(size_t size) | |
66 { | |
67 if (started_) | |
68 { | |
69 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
70 } | |
71 else | |
72 { | |
73 instances_.reserve(size); | |
74 } | |
75 } | |
76 | |
77 size_t GetInstancesCount() const | |
78 { | |
79 return instances_.size(); | |
80 } | |
81 | |
82 void AddInstance(const std::string& instance) | |
83 { | |
84 if (started_) | |
85 { | |
86 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
87 } | |
88 else | |
89 { | |
90 instances_.push_back(instance); | |
91 } | |
92 } | |
93 | |
94 virtual void Start() | |
95 { | |
96 started_ = true; | |
97 } | |
98 | |
99 virtual float GetProgress() | |
100 { | |
101 if (instances_.size() == 0) | |
102 { | |
103 return 0; | |
104 } | |
105 else | |
106 { | |
107 return (static_cast<float>(position_) / | |
108 static_cast<float>(instances_.size())); | |
109 } | |
110 } | |
111 | |
112 bool IsStarted() const | |
113 { | |
114 return started_; | |
115 } | |
116 | |
117 bool IsDone() const | |
118 { | |
119 return (position_ >= instances_.size()); | |
120 } | |
121 | |
122 void Next() | |
123 { | |
124 if (IsDone()) | |
125 { | |
126 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
127 } | |
128 else | |
129 { | |
130 position_ += 1; | |
131 } | |
132 } | |
133 | |
134 const std::string& GetCurrentInstance() const | |
135 { | |
136 if (IsDone()) | |
137 { | |
138 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
139 } | |
140 else | |
141 { | |
142 return instances_[position_]; | |
143 } | |
144 } | |
145 }; | |
146 | |
147 | |
148 class StoreScuJob : public InstancesIteratorJob | |
149 { | |
150 private: | |
151 ServerContext& context_; | |
152 std::string localAet_; | |
153 RemoteModalityParameters remote_; | |
154 bool permissive_; | |
155 std::string moveOriginatorAet_; | |
156 uint16_t moveOriginatorId_; | |
157 std::auto_ptr<DicomUserConnection> connection_; | |
158 std::set<std::string> failedInstances_; | |
159 | |
160 void Open() | |
161 { | |
162 if (connection_.get() == NULL) | |
163 { | |
164 connection_.reset(new DicomUserConnection); | |
165 connection_->SetLocalApplicationEntityTitle(localAet_); | |
166 connection_->SetRemoteModality(remote_); | |
167 connection_->Open(); | |
168 } | |
169 } | |
170 | |
171 public: | |
172 StoreScuJob(ServerContext& context) : | |
173 context_(context), | |
174 localAet_("ORTHANC"), | |
175 permissive_(false), | |
176 moveOriginatorId_(0) // By default, not a C-MOVE | |
177 { | |
178 } | |
179 | |
180 void AddResource(const std::string& publicId) | |
181 { | |
182 typedef std::list<std::string> Instances; | |
183 | |
184 Instances instances; | |
185 context_.GetIndex().GetChildInstances(instances, publicId); | |
186 | |
187 Reserve(GetInstancesCount() + instances.size()); | |
188 | |
189 for (Instances::const_iterator it = instances.begin(); | |
190 it != instances.end(); ++it) | |
191 { | |
192 AddInstance(*it); | |
193 } | |
194 } | |
195 | |
196 const std::string& GetLocalAet() const | |
197 { | |
198 return localAet_; | |
199 } | |
200 | |
201 void SetLocalAet(const std::string& aet) | |
202 { | |
203 if (IsStarted()) | |
204 { | |
205 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
206 } | |
207 else | |
208 { | |
209 localAet_ = aet; | |
210 } | |
211 } | |
212 | |
213 const RemoteModalityParameters& GetRemoteModality() const | |
214 { | |
215 return remote_; | |
216 } | |
217 | |
218 void SetRemoteModality(const RemoteModalityParameters& remote) | |
219 { | |
220 if (IsStarted()) | |
221 { | |
222 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
223 } | |
224 else | |
225 { | |
226 remote_ = remote; | |
227 } | |
228 } | |
229 | |
230 bool IsPermissive() const | |
231 { | |
232 return permissive_; | |
233 } | |
234 | |
235 void SetPermissive(bool permissive) | |
236 { | |
237 if (IsStarted()) | |
238 { | |
239 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
240 } | |
241 else | |
242 { | |
243 permissive_ = permissive; | |
244 } | |
245 } | |
246 | |
247 bool HasMoveOriginator() const | |
248 { | |
249 return moveOriginatorId_ != 0; | |
250 } | |
251 | |
252 const std::string& GetMoveOriginatorAet() const | |
253 { | |
254 if (HasMoveOriginator()) | |
255 { | |
256 return moveOriginatorAet_; | |
257 } | |
258 else | |
259 { | |
260 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
261 } | |
262 } | |
263 | |
264 uint16_t GetMoveOriginatorId() const | |
265 { | |
266 if (HasMoveOriginator()) | |
267 { | |
268 return moveOriginatorId_; | |
269 } | |
270 else | |
271 { | |
272 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
273 } | |
274 } | |
275 | |
276 void SetMoveOriginator(const std::string& aet, | |
277 int id) | |
278 { | |
279 if (IsStarted()) | |
280 { | |
281 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
282 } | |
283 else if (id < 0 || | |
284 id >= 65536) | |
285 { | |
286 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
287 } | |
288 else | |
289 { | |
290 moveOriginatorId_ = static_cast<uint16_t>(id); | |
291 moveOriginatorAet_ = aet; | |
292 } | |
293 } | |
294 | |
295 virtual JobStepResult* ExecuteStep() | |
296 { | |
297 if (IsDone()) | |
298 { | |
299 return new JobStepResult(JobStepCode_Success); | |
300 } | |
301 | |
302 Open(); | |
303 | |
304 bool ok = false; | |
305 | |
306 try | |
307 { | |
308 std::string dicom; | |
309 context_.ReadDicom(dicom, GetCurrentInstance()); | |
310 | |
311 if (HasMoveOriginator()) | |
312 { | |
313 connection_->Store(dicom, moveOriginatorAet_, moveOriginatorId_); | |
314 } | |
315 else | |
316 { | |
317 connection_->Store(dicom); | |
318 } | |
319 | |
320 boost::this_thread::sleep(boost::posix_time::milliseconds(300)); | |
321 | |
322 ok = true; | |
323 } | |
324 catch (OrthancException& e) | |
325 { | |
326 } | |
327 | |
328 if (!ok) | |
329 { | |
330 if (permissive_) | |
331 { | |
332 failedInstances_.insert(GetCurrentInstance()); | |
333 } | |
334 else | |
335 { | |
336 return new JobStepResult(JobStepCode_Failure); | |
337 } | |
338 } | |
339 | |
340 Next(); | |
341 | |
342 if (IsDone()) | |
343 { | |
344 return new JobStepResult(JobStepCode_Success); | |
345 } | |
346 else | |
347 { | |
348 return new JobStepResult(JobStepCode_Continue); | |
349 } | |
350 } | |
351 | |
352 virtual void ReleaseResources() // For pausing jobs | |
353 { | |
354 connection_.reset(NULL); | |
355 } | |
356 | |
357 virtual void GetJobType(std::string& target) | |
358 { | |
359 target = "C-Store"; | |
360 } | |
361 | |
362 virtual void GetPublicContent(Json::Value& value) | |
363 { | |
364 value["LocalAet"] = localAet_; | |
365 value["RemoteAet"] = remote_.GetApplicationEntityTitle(); | |
366 | |
367 if (HasMoveOriginator()) | |
368 { | |
369 value["MoveOriginatorAET"] = GetMoveOriginatorAet(); | |
370 value["MoveOriginatorID"] = GetMoveOriginatorId(); | |
371 } | |
372 | |
373 Json::Value v = Json::arrayValue; | |
374 for (std::set<std::string>::const_iterator it = failedInstances_.begin(); | |
375 it != failedInstances_.end(); ++it) | |
376 { | |
377 v.append(*it); | |
378 } | |
379 | |
380 value["FailedInstances"] = v; | |
381 } | |
382 | |
383 virtual void GetInternalContent(Json::Value& value) | |
384 { | |
385 // TODO | |
386 } | |
387 }; | |
388 } | |
389 | |
390 | |
391 | |
392 | |
47 namespace Orthanc | 393 namespace Orthanc |
48 { | 394 { |
49 /*************************************************************************** | 395 /*************************************************************************** |
50 * DICOM C-Echo SCU | 396 * DICOM C-Echo SCU |
51 ***************************************************************************/ | 397 ***************************************************************************/ |
687 std::string localAet = Toolbox::GetJsonStringField(request, "LocalAet", context.GetDefaultLocalApplicationEntityTitle()); | 1033 std::string localAet = Toolbox::GetJsonStringField(request, "LocalAet", context.GetDefaultLocalApplicationEntityTitle()); |
688 bool permissive = Toolbox::GetJsonBooleanField(request, "Permissive", false); | 1034 bool permissive = Toolbox::GetJsonBooleanField(request, "Permissive", false); |
689 bool asynchronous = Toolbox::GetJsonBooleanField(request, "Asynchronous", false); | 1035 bool asynchronous = Toolbox::GetJsonBooleanField(request, "Asynchronous", false); |
690 std::string moveOriginatorAET = Toolbox::GetJsonStringField(request, "MoveOriginatorAet", context.GetDefaultLocalApplicationEntityTitle()); | 1036 std::string moveOriginatorAET = Toolbox::GetJsonStringField(request, "MoveOriginatorAet", context.GetDefaultLocalApplicationEntityTitle()); |
691 int moveOriginatorID = Toolbox::GetJsonIntegerField(request, "MoveOriginatorID", 0 /* By default, not a C-MOVE */); | 1037 int moveOriginatorID = Toolbox::GetJsonIntegerField(request, "MoveOriginatorID", 0 /* By default, not a C-MOVE */); |
1038 int priority = Toolbox::GetJsonIntegerField(request, "Priority", 0); | |
692 | 1039 |
693 if (moveOriginatorID < 0 || | 1040 if (moveOriginatorID < 0 || |
694 moveOriginatorID >= 65536) | 1041 moveOriginatorID >= 65536) |
695 { | 1042 { |
696 throw OrthancException(ErrorCode_ParameterOutOfRange); | 1043 throw OrthancException(ErrorCode_ParameterOutOfRange); |
697 } | 1044 } |
698 | 1045 |
699 RemoteModalityParameters p = Configuration::GetModalityUsingSymbolicName(remote); | 1046 RemoteModalityParameters p = Configuration::GetModalityUsingSymbolicName(remote); |
700 | 1047 |
1048 #if 1 | |
1049 std::auto_ptr<StoreScuJob> job(new StoreScuJob(context)); | |
1050 job->SetLocalAet(localAet); | |
1051 job->SetRemoteModality(p); | |
1052 job->SetPermissive(permissive); | |
1053 | |
1054 if (moveOriginatorID != 0) | |
1055 { | |
1056 job->SetMoveOriginator(moveOriginatorAET, static_cast<uint16_t>(moveOriginatorID)); | |
1057 } | |
1058 | |
1059 for (std::list<std::string>::const_iterator | |
1060 it = instances.begin(); it != instances.end(); ++it) | |
1061 { | |
1062 job->AddInstance(*it); | |
1063 } | |
1064 | |
1065 if (asynchronous) | |
1066 { | |
1067 // Asynchronous mode: Submit the job, but don't wait for its completion | |
1068 std::string id; | |
1069 context.GetJobsEngine().GetRegistry().Submit(id, job.release(), priority); | |
1070 | |
1071 Json::Value v; | |
1072 v["ID"] = id; | |
1073 call.GetOutput().AnswerJson(v); | |
1074 } | |
1075 else if (context.GetJobsEngine().GetRegistry().SubmitAndWait(job.release(), priority)) | |
1076 { | |
1077 // Synchronous mode: We have submitted and waited for completion | |
1078 call.GetOutput().AnswerBuffer("{}", "application/json"); | |
1079 } | |
1080 else | |
1081 { | |
1082 call.GetOutput().SignalError(HttpStatus_500_InternalServerError); | |
1083 } | |
1084 | |
1085 #else | |
701 ServerJob job; | 1086 ServerJob job; |
702 for (std::list<std::string>::const_iterator | 1087 for (std::list<std::string>::const_iterator |
703 it = instances.begin(); it != instances.end(); ++it) | 1088 it = instances.begin(); it != instances.end(); ++it) |
704 { | 1089 { |
705 std::auto_ptr<StoreScuCommand> command(new StoreScuCommand(context, localAet, p, permissive)); | 1090 std::auto_ptr<StoreScuCommand> command(new StoreScuCommand(context, localAet, p, permissive)); |
727 } | 1112 } |
728 else | 1113 else |
729 { | 1114 { |
730 call.GetOutput().SignalError(HttpStatus_500_InternalServerError); | 1115 call.GetOutput().SignalError(HttpStatus_500_InternalServerError); |
731 } | 1116 } |
1117 #endif | |
732 } | 1118 } |
733 | 1119 |
734 | 1120 |
735 /*************************************************************************** | 1121 /*************************************************************************** |
736 * DICOM C-Move SCU | 1122 * DICOM C-Move SCU |