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,