Mercurial > hg > orthanc
comparison OrthancServer/main.cpp @ 3635:8c0ef729d5a8 storage-commitment
StorageCommitmentScpJob
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 29 Jan 2020 17:39:31 +0100 |
parents | 169d57e18b39 |
children | bce6ee64f2a4 |
comparison
equal
deleted
inserted
replaced
3634:103ee029982e | 3635:8c0ef729d5a8 |
---|---|
56 | 56 |
57 | 57 |
58 class OrthancStoreRequestHandler : public IStoreRequestHandler | 58 class OrthancStoreRequestHandler : public IStoreRequestHandler |
59 { | 59 { |
60 private: | 60 private: |
61 ServerContext& server_; | 61 ServerContext& context_; |
62 | 62 |
63 public: | 63 public: |
64 OrthancStoreRequestHandler(ServerContext& context) : | 64 OrthancStoreRequestHandler(ServerContext& context) : |
65 server_(context) | 65 context_(context) |
66 { | 66 { |
67 } | 67 } |
68 | 68 |
69 | 69 |
70 virtual void Handle(const std::string& dicomFile, | 70 virtual void Handle(const std::string& dicomFile, |
82 toStore.SetBuffer(dicomFile); | 82 toStore.SetBuffer(dicomFile); |
83 toStore.SetSummary(dicomSummary); | 83 toStore.SetSummary(dicomSummary); |
84 toStore.SetJson(dicomJson); | 84 toStore.SetJson(dicomJson); |
85 | 85 |
86 std::string id; | 86 std::string id; |
87 server_.Store(id, toStore); | 87 context_.Store(id, toStore); |
88 } | 88 } |
89 } | 89 } |
90 }; | 90 }; |
91 | 91 |
92 | 92 |
93 | 93 |
94 namespace Orthanc | |
95 { | |
96 class StorageCommitmentScpJob : public SetOfCommandsJob | |
97 { | |
98 private: | |
99 class LookupCommand : public SetOfCommandsJob::ICommand | |
100 { | |
101 private: | |
102 StorageCommitmentScpJob& that_; | |
103 std::string sopClassUid_; | |
104 std::string sopInstanceUid_; | |
105 | |
106 public: | |
107 LookupCommand(StorageCommitmentScpJob& that, | |
108 const std::string& sopClassUid, | |
109 const std::string& sopInstanceUid) : | |
110 that_(that), | |
111 sopClassUid_(sopClassUid), | |
112 sopInstanceUid_(sopInstanceUid) | |
113 { | |
114 } | |
115 | |
116 virtual bool Execute() | |
117 { | |
118 that_.LookupInstance(sopClassUid_, sopInstanceUid_); | |
119 return true; | |
120 } | |
121 | |
122 virtual void Serialize(Json::Value& target) const | |
123 { | |
124 target = Json::objectValue; | |
125 target["Type"] = "Lookup"; | |
126 target["SopClassUid"] = sopClassUid_; | |
127 target["SopInstanceUid"] = sopInstanceUid_; | |
128 } | |
129 }; | |
130 | |
131 class AnswerCommand : public SetOfCommandsJob::ICommand | |
132 { | |
133 private: | |
134 StorageCommitmentScpJob& that_; | |
135 | |
136 public: | |
137 AnswerCommand(StorageCommitmentScpJob& that) : | |
138 that_(that) | |
139 { | |
140 } | |
141 | |
142 virtual bool Execute() | |
143 { | |
144 that_.Answer(); | |
145 return true; | |
146 } | |
147 | |
148 virtual void Serialize(Json::Value& target) const | |
149 { | |
150 target = Json::objectValue; | |
151 target["Type"] = "Answer"; | |
152 } | |
153 }; | |
154 | |
155 class Unserializer : public SetOfCommandsJob::ICommandUnserializer | |
156 { | |
157 private: | |
158 StorageCommitmentScpJob& that_; | |
159 | |
160 public: | |
161 Unserializer(StorageCommitmentScpJob& that) : | |
162 that_(that) | |
163 { | |
164 } | |
165 | |
166 virtual ICommand* Unserialize(const Json::Value& source) const | |
167 { | |
168 std::cout << "===================================\n"; | |
169 std::cout << source.toStyledString(); | |
170 | |
171 /*DicomMap findAnswer; | |
172 findAnswer.Unserialize(source); | |
173 return new Command(that_, findAnswer);*/ | |
174 | |
175 throw OrthancException(ErrorCode_NotImplemented); | |
176 } | |
177 }; | |
178 | |
179 ServerContext& context_; | |
180 bool ready_; | |
181 std::string transactionUid_; | |
182 RemoteModalityParameters remoteModality_; | |
183 std::string calledAet_; | |
184 std::list<std::string> successSopClassUids_; | |
185 std::list<std::string> successSopInstanceUids_; | |
186 std::list<std::string> failedSopClassUids_; | |
187 std::list<std::string> failedSopInstanceUids_; | |
188 | |
189 void LookupInstance(const std::string& sopClassUid, | |
190 const std::string& sopInstanceUid) | |
191 { | |
192 bool success = false; | |
193 | |
194 try | |
195 { | |
196 std::vector<std::string> orthancId; | |
197 context_.GetIndex().LookupIdentifierExact(orthancId, ResourceType_Instance, DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUid); | |
198 | |
199 if (orthancId.size() == 1) | |
200 { | |
201 std::string a, b; | |
202 | |
203 ServerContext::DicomCacheLocker locker(context_, orthancId[0]); | |
204 if (locker.GetDicom().GetTagValue(a, DICOM_TAG_SOP_CLASS_UID) && | |
205 locker.GetDicom().GetTagValue(b, DICOM_TAG_SOP_INSTANCE_UID) && | |
206 a == sopClassUid && | |
207 b == sopInstanceUid) | |
208 { | |
209 success = true; | |
210 } | |
211 } | |
212 } | |
213 catch (OrthancException&) | |
214 { | |
215 } | |
216 | |
217 LOG(INFO) << " Storage commitment SCP job: " << (success ? "Success" : "Failure") | |
218 << " while looking for " << sopClassUid << " / " << sopInstanceUid; | |
219 | |
220 if (success) | |
221 { | |
222 successSopClassUids_.push_back(sopClassUid); | |
223 successSopInstanceUids_.push_back(sopInstanceUid); | |
224 } | |
225 else | |
226 { | |
227 failedSopClassUids_.push_back(sopClassUid); | |
228 failedSopInstanceUids_.push_back(sopInstanceUid); | |
229 } | |
230 } | |
231 | |
232 void Answer() | |
233 { | |
234 LOG(INFO) << " Storage commitment SCP job: Sending answer"; | |
235 | |
236 DicomUserConnection scu(calledAet_, remoteModality_); | |
237 scu.ReportStorageCommitment(transactionUid_, successSopClassUids_, successSopInstanceUids_, | |
238 failedSopClassUids_, failedSopInstanceUids_); | |
239 | |
240 /** | |
241 * "After the N-EVENT-REPORT has been sent, the Transaction UID is | |
242 * no longer active and shall not be reused for other | |
243 * transactions." | |
244 * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.3.html | |
245 **/ | |
246 } | |
247 | |
248 public: | |
249 StorageCommitmentScpJob(ServerContext& context, | |
250 const std::string& transactionUid, | |
251 const std::string& remoteAet, | |
252 const std::string& calledAet) : | |
253 context_(context), | |
254 ready_(false), | |
255 transactionUid_(transactionUid), | |
256 calledAet_(calledAet) | |
257 { | |
258 { | |
259 OrthancConfiguration::ReaderLock lock; | |
260 if (!lock.GetConfiguration().LookupDicomModalityUsingAETitle(remoteModality_, remoteAet)) | |
261 { | |
262 throw OrthancException(ErrorCode_InexistentItem, | |
263 "Unknown remote modality for storage commitment SCP: " + remoteAet); | |
264 } | |
265 } | |
266 } | |
267 | |
268 void AddInstance(const std::string& sopClassUid, | |
269 const std::string& sopInstanceUid) | |
270 { | |
271 if (ready_) | |
272 { | |
273 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
274 } | |
275 else | |
276 { | |
277 AddCommand(new LookupCommand(*this, sopClassUid, sopInstanceUid)); | |
278 } | |
279 } | |
280 | |
281 void MarkAsReady() | |
282 { | |
283 if (ready_) | |
284 { | |
285 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
286 } | |
287 else | |
288 { | |
289 AddCommand(new AnswerCommand(*this)); | |
290 ready_ = true; | |
291 } | |
292 } | |
293 | |
294 virtual void Stop(JobStopReason reason) | |
295 { | |
296 } | |
297 | |
298 virtual void GetJobType(std::string& target) | |
299 { | |
300 target = "StorageCommitmentScp"; | |
301 } | |
302 | |
303 virtual void GetPublicContent(Json::Value& value) | |
304 { | |
305 SetOfCommandsJob::GetPublicContent(value); | |
306 | |
307 value["LocalAet"] = calledAet_; | |
308 value["RemoteAet"] = remoteModality_.GetApplicationEntityTitle(); | |
309 value["TransactionUid"] = transactionUid_; | |
310 } | |
311 }; | |
312 } | |
313 | |
314 | |
94 class OrthancStorageCommitmentRequestHandler : public IStorageCommitmentRequestHandler | 315 class OrthancStorageCommitmentRequestHandler : public IStorageCommitmentRequestHandler |
95 { | 316 { |
96 private: | 317 private: |
97 ServerContext& server_; | 318 ServerContext& context_; |
98 | |
99 // TODO - Remove this | |
100 static void Toto(std::string* t, std::string* remotec) | |
101 { | |
102 try | |
103 { | |
104 std::auto_ptr<std::string> tt(t); | |
105 std::auto_ptr<std::string> remote(remotec); | |
106 | |
107 printf("Sleeping\n"); | |
108 boost::this_thread::sleep(boost::posix_time::milliseconds(100)); | |
109 printf("Connect back\n"); | |
110 | |
111 RemoteModalityParameters p; | |
112 | |
113 if (*remote == "ORTHANC") | |
114 { | |
115 p = RemoteModalityParameters("ORTHANC", "localhost", 4242, ModalityManufacturer_Generic); | |
116 } | |
117 else | |
118 { | |
119 p = RemoteModalityParameters("STGCMTSCU", "localhost", 11114, ModalityManufacturer_Generic); | |
120 } | |
121 | |
122 DicomUserConnection scu("ORTHANC", p); | |
123 | |
124 std::vector<std::string> a, b, c, d; | |
125 a.push_back("a"); b.push_back("b"); | |
126 a.push_back("c"); b.push_back("d"); | |
127 | |
128 scu.ReportStorageCommitment(tt->c_str(), a, b, c, d); | |
129 //scu.ReportStorageCommitment(tt->c_str(), a, b, a, b); | |
130 } | |
131 catch (OrthancException& e) | |
132 { | |
133 LOG(ERROR) << "EXCEPTION: " << e.What(); | |
134 } | |
135 | |
136 /** | |
137 * "After the N-EVENT-REPORT has been sent, the Transaction UID is | |
138 * no longer active and shall not be reused for other | |
139 * transactions." | |
140 * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.3.html | |
141 **/ | |
142 } | |
143 | 319 |
144 public: | 320 public: |
145 OrthancStorageCommitmentRequestHandler(ServerContext& context) : | 321 OrthancStorageCommitmentRequestHandler(ServerContext& context) : |
146 server_(context) | 322 context_(context) |
147 { | 323 { |
148 } | 324 } |
149 | 325 |
150 virtual void HandleRequest(const std::string& transactionUid, | 326 virtual void HandleRequest(const std::string& transactionUid, |
151 const std::vector<std::string>& referencedSopClassUids, | 327 const std::vector<std::string>& referencedSopClassUids, |
152 const std::vector<std::string>& referencedSopInstanceUids, | 328 const std::vector<std::string>& referencedSopInstanceUids, |
153 const std::string& remoteIp, | 329 const std::string& remoteIp, |
154 const std::string& remoteAet, | 330 const std::string& remoteAet, |
155 const std::string& calledAet) | 331 const std::string& calledAet) |
156 { | 332 { |
157 // TODO - Enqueue a Storage commitment job | 333 if (referencedSopClassUids.size() != referencedSopInstanceUids.size()) |
158 | 334 { |
159 boost::thread t(Toto, new std::string(transactionUid), new std::string(remoteAet)); | 335 throw OrthancException(ErrorCode_InternalError); |
160 | 336 } |
161 printf("HANDLE REQUEST\n"); | 337 |
338 std::auto_ptr<StorageCommitmentScpJob> job( | |
339 new StorageCommitmentScpJob(context_, transactionUid, remoteAet, calledAet)); | |
340 | |
341 for (size_t i = 0; i < referencedSopClassUids.size(); i++) | |
342 { | |
343 job->AddInstance(referencedSopClassUids[i], referencedSopInstanceUids[i]); | |
344 } | |
345 | |
346 job->MarkAsReady(); | |
347 | |
348 context_.GetJobsEngine().GetRegistry().Submit(job.release(), 0 /* default priority */); | |
162 } | 349 } |
163 | 350 |
164 virtual void HandleReport(const std::string& transactionUid, | 351 virtual void HandleReport(const std::string& transactionUid, |
165 const std::vector<std::string>& successSopClassUids, | 352 const std::vector<std::string>& successSopClassUids, |
166 const std::vector<std::string>& successSopInstanceUids, | 353 const std::vector<std::string>& successSopInstanceUids, |