Mercurial > hg > orthanc-stone
comparison Applications/Platforms/WebAssembly/WebAssemblyOracle.cpp @ 1723:81273beabc9f
refactoring: WebAssemblyOracle::ProcessFetchResult()
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 01 Dec 2020 16:54:01 +0100 |
parents | 1393e3393a0b |
children | 9ac2a65d4172 |
comparison
equal
deleted
inserted
replaced
1722:802cb1272f3a | 1723:81273beabc9f |
---|---|
81 } | 81 } |
82 }; | 82 }; |
83 | 83 |
84 | 84 |
85 /** | 85 /** |
86 This object is created on the heap for every http request. | 86 This object is created on the heap for every http request. |
87 It is deleted in the success (or error) callbacks. | 87 It is deleted in the success (or error) callbacks. |
88 | 88 |
89 This object references the receiver of the request. Since this is a raw | 89 This object references the receiver of the request. Since this is a raw |
90 reference, we need additional checks to make sure we send the response to | 90 reference, we need additional checks to make sure we send the response to |
91 the same object, for the object can be deleted and a new one recreated at the | 91 the same object, for the object can be deleted and a new one recreated at the |
92 same address (it often happens in the [single-threaded] browser context). | 92 same address (it often happens in the [single-threaded] browser context). |
93 */ | 93 */ |
94 class WebAssemblyOracle::FetchContext : public boost::noncopyable | 94 class WebAssemblyOracle::FetchContext : public boost::noncopyable |
95 { | 95 { |
96 private: | 96 private: |
97 WebAssemblyOracle& oracle_; | 97 WebAssemblyOracle& oracle_; |
125 const std::string& GetExpectedContentType() const | 125 const std::string& GetExpectedContentType() const |
126 { | 126 { |
127 return expectedContentType_; | 127 return expectedContentType_; |
128 } | 128 } |
129 | 129 |
130 IMessageEmitter& GetEmitter() const | 130 void EmitException(const Orthanc::OrthancException& exception) |
131 { | 131 { |
132 return oracle_; | 132 assert(command_.get() != NULL); |
133 } | 133 OracleCommandExceptionMessage message(*command_, exception); |
134 | |
135 boost::weak_ptr<IObserver> GetReceiver() const | |
136 { | |
137 return receiver_; | |
138 } | |
139 | |
140 void EmitMessage(const IMessage& message) | |
141 { | |
142 if (Orthanc::Logging::IsTraceLevelEnabled()) | |
143 { | |
144 // Calling "receiver_.lock()" is expensive, hence the quick check if TRACE is enabled | |
145 LOG(TRACE) << "WebAssemblyOracle::FetchContext::EmitMessage receiver_ = " | |
146 << std::hex << receiver_.lock().get() << std::dec; | |
147 } | |
148 | |
149 oracle_.EmitMessage(receiver_, message); | 134 oracle_.EmitMessage(receiver_, message); |
150 } | 135 } |
151 | 136 |
152 IOracleCommand& GetCommand() const | 137 void ProcessFetchResult(const std::string& answer, |
153 { | 138 const HttpHeaders& headers) |
154 return *command_; | 139 { |
155 } | 140 assert(command_.get() != NULL); |
156 | 141 oracle_.ProcessFetchResult(receiver_, answer, headers, *command_); |
157 template <typename T> | 142 } |
158 const T& GetTypedCommand() const | |
159 { | |
160 return dynamic_cast<T&>(*command_); | |
161 } | |
162 | |
163 #if ORTHANC_ENABLE_DCMTK == 1 | |
164 void StoreInCache(const std::string& sopInstanceUid, | |
165 std::unique_ptr<Orthanc::ParsedDicomFile>& dicom, | |
166 size_t fileSize) | |
167 { | |
168 if (oracle_.dicomCache_.get()) | |
169 { | |
170 // Store it into the cache for future use | |
171 oracle_.dicomCache_->Acquire(BUCKET_SOP, sopInstanceUid, | |
172 dicom.release(), fileSize, true); | |
173 } | |
174 } | |
175 #endif | |
176 | 143 |
177 static void SuccessCallback(emscripten_fetch_t *fetch) | 144 static void SuccessCallback(emscripten_fetch_t *fetch) |
178 { | 145 { |
179 /** | 146 /** |
180 * Firstly, make a local copy of the fetched information, and | 147 * Firstly, make a local copy of the fetched information, and |
181 * free data associated with the fetch. | 148 * free data associated with the fetch. |
182 **/ | 149 **/ |
183 | 150 |
184 if (fetch->userData == NULL) | 151 if (fetch->userData == NULL) |
185 { | 152 { |
186 LOG(ERROR) << "WebAssemblyOracle::FetchContext::SuccessCallback fetch->userData is NULL!!!!!!!"; | 153 LOG(ERROR) << "WebAssemblyOracle::FetchContext::SuccessCallback fetch->userData is NULL!"; |
187 return; | 154 return; |
188 } | 155 } |
189 | 156 |
190 std::unique_ptr<FetchContext> context(reinterpret_cast<FetchContext*>(fetch->userData)); | 157 std::unique_ptr<FetchContext> context(reinterpret_cast<FetchContext*>(fetch->userData)); |
191 | 158 |
264 LOG(ERROR) << "WebAssemblyOracle::FetchContext::SuccessCallback: (context.get() == NULL)"; | 231 LOG(ERROR) << "WebAssemblyOracle::FetchContext::SuccessCallback: (context.get() == NULL)"; |
265 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 232 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
266 } | 233 } |
267 else | 234 else |
268 { | 235 { |
269 switch (context->GetCommand().GetType()) | 236 context->ProcessFetchResult(answer, headers); |
270 { | |
271 case IOracleCommand::Type_Http: | |
272 { | |
273 HttpCommand::SuccessMessage message(context->GetTypedCommand<HttpCommand>(), headers, answer); | |
274 context->EmitMessage(message); | |
275 break; | |
276 } | |
277 | |
278 case IOracleCommand::Type_OrthancRestApi: | |
279 { | |
280 LOG(TRACE) << "WebAssemblyOracle::FetchContext::SuccessCallback. About to call context->EmitMessage(message);"; | |
281 OrthancRestApiCommand::SuccessMessage message | |
282 (context->GetTypedCommand<OrthancRestApiCommand>(), headers, answer); | |
283 context->EmitMessage(message); | |
284 break; | |
285 } | |
286 | |
287 case IOracleCommand::Type_GetOrthancImage: | |
288 { | |
289 context->GetTypedCommand<GetOrthancImageCommand>().ProcessHttpAnswer | |
290 (context->GetReceiver(), context->GetEmitter(), answer, headers); | |
291 break; | |
292 } | |
293 | |
294 case IOracleCommand::Type_GetOrthancWebViewerJpeg: | |
295 { | |
296 context->GetTypedCommand<GetOrthancWebViewerJpegCommand>().ProcessHttpAnswer | |
297 (context->GetReceiver(), context->GetEmitter(), answer); | |
298 break; | |
299 } | |
300 | |
301 case IOracleCommand::Type_ParseDicomFromWado: | |
302 { | |
303 #if ORTHANC_ENABLE_DCMTK == 1 | |
304 const ParseDicomFromWadoCommand& command = | |
305 context->GetTypedCommand<ParseDicomFromWadoCommand>(); | |
306 | |
307 size_t fileSize; | |
308 std::unique_ptr<Orthanc::ParsedDicomFile> dicom | |
309 (ParseDicomSuccessMessage::ParseWadoAnswer(fileSize, answer, headers)); | |
310 | |
311 { | |
312 ParseDicomSuccessMessage message(command, command.GetSource(), *dicom, fileSize, true); | |
313 context->EmitMessage(message); | |
314 } | |
315 | |
316 context->StoreInCache(command.GetSopInstanceUid(), dicom, fileSize); | |
317 #else | |
318 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
319 #endif | |
320 break; | |
321 } | |
322 | |
323 default: | |
324 LOG(ERROR) << "Command type not implemented by the WebAssembly Oracle (in SuccessCallback): " | |
325 << context->GetCommand().GetType(); | |
326 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
327 } | |
328 } | 237 } |
329 } | 238 } |
330 catch (Orthanc::OrthancException& e) | 239 catch (Orthanc::OrthancException& e) |
331 { | 240 { |
332 LOG(INFO) << "Error while processing a fetch answer in the oracle: " << e.What(); | 241 LOG(INFO) << "Error while processing a fetch answer in the oracle: " << e.What(); |
333 | 242 context->EmitException(e); |
334 { | |
335 OracleCommandExceptionMessage message(context->GetCommand(), e); | |
336 context->EmitMessage(message); | |
337 } | |
338 } | 243 } |
339 } | 244 } |
340 | 245 |
341 static void FailureCallback(emscripten_fetch_t *fetch) | 246 static void FailureCallback(emscripten_fetch_t *fetch) |
342 { | 247 { |
356 << " | totalBytes = " << fetch->totalBytes | 261 << " | totalBytes = " << fetch->totalBytes |
357 << " | readyState = " << fetch->readyState; | 262 << " | readyState = " << fetch->readyState; |
358 } | 263 } |
359 #endif | 264 #endif |
360 | 265 |
361 { | 266 context->EmitException(Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol)); |
362 OracleCommandExceptionMessage message | |
363 (context->GetCommand(), Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol)); | |
364 context->EmitMessage(message); | |
365 } | |
366 | 267 |
367 /** | 268 /** |
368 * TODO - The following code leads to an infinite recursion, at | 269 * TODO - The following code leads to an infinite recursion, at |
369 * least with Firefox running on incognito mode => WHY? | 270 * least with Firefox running on incognito mode => WHY? |
370 **/ | 271 **/ |
410 void SetMethod(Orthanc::HttpMethod method) | 311 void SetMethod(Orthanc::HttpMethod method) |
411 { | 312 { |
412 method_ = method; | 313 method_ = method; |
413 } | 314 } |
414 | 315 |
316 Orthanc::HttpMethod GetMethod() const | |
317 { | |
318 return method_; | |
319 } | |
320 | |
415 void SetUrl(const std::string& url) | 321 void SetUrl(const std::string& url) |
416 { | 322 { |
417 url_ = url; | 323 url_ = url; |
418 } | 324 } |
419 | 325 |
326 const std::string& GetUrl() const | |
327 { | |
328 return url_; | |
329 } | |
330 | |
420 void SetBody(std::string& body /* will be swapped */) | 331 void SetBody(std::string& body /* will be swapped */) |
421 { | 332 { |
422 body_.swap(body); | 333 body_.swap(body); |
423 } | 334 } |
424 | 335 |
428 { | 339 { |
429 headers_[it->first] = it->second; | 340 headers_[it->first] = it->second; |
430 } | 341 } |
431 } | 342 } |
432 | 343 |
344 const HttpHeaders& GetHttpHeaders() const | |
345 { | |
346 return headers_; | |
347 } | |
348 | |
433 void SetTimeout(unsigned int timeout) | 349 void SetTimeout(unsigned int timeout) |
434 { | 350 { |
435 timeout_ = timeout; | 351 timeout_ = timeout; |
352 } | |
353 | |
354 unsigned int GetTimeout() const | |
355 { | |
356 return timeout_; | |
436 } | 357 } |
437 | 358 |
438 void SetCredentials(const std::string& username, | 359 void SetCredentials(const std::string& username, |
439 const std::string& password) | 360 const std::string& password) |
440 { | 361 { |
544 } | 465 } |
545 } | 466 } |
546 }; | 467 }; |
547 | 468 |
548 | 469 |
470 void WebAssemblyOracle::ProcessFetchResult(boost::weak_ptr<IObserver>& receiver, | |
471 const std::string& answer, | |
472 const HttpHeaders& headers, | |
473 const IOracleCommand& command) | |
474 { | |
475 switch (command.GetType()) | |
476 { | |
477 case IOracleCommand::Type_Http: | |
478 { | |
479 HttpCommand::SuccessMessage message(dynamic_cast<const HttpCommand&>(command), headers, answer); | |
480 EmitMessage(receiver, message); | |
481 break; | |
482 } | |
483 | |
484 case IOracleCommand::Type_OrthancRestApi: | |
485 { | |
486 LOG(TRACE) << "WebAssemblyOracle::FetchContext::SuccessCallback. About to call EmitMessage(message);"; | |
487 OrthancRestApiCommand::SuccessMessage message | |
488 (dynamic_cast<const OrthancRestApiCommand&>(command), headers, answer); | |
489 EmitMessage(receiver, message); | |
490 break; | |
491 } | |
492 | |
493 case IOracleCommand::Type_GetOrthancImage: | |
494 { | |
495 dynamic_cast<const GetOrthancImageCommand&>(command).ProcessHttpAnswer(receiver, *this, answer, headers); | |
496 break; | |
497 } | |
498 | |
499 case IOracleCommand::Type_GetOrthancWebViewerJpeg: | |
500 { | |
501 dynamic_cast<const GetOrthancWebViewerJpegCommand&>(command).ProcessHttpAnswer(receiver, *this, answer); | |
502 break; | |
503 } | |
504 | |
505 case IOracleCommand::Type_ParseDicomFromWado: | |
506 { | |
507 #if ORTHANC_ENABLE_DCMTK == 1 | |
508 const ParseDicomFromWadoCommand& c = dynamic_cast<const ParseDicomFromWadoCommand&>(command); | |
509 | |
510 size_t fileSize; | |
511 std::unique_ptr<Orthanc::ParsedDicomFile> dicom | |
512 (ParseDicomSuccessMessage::ParseWadoAnswer(fileSize, answer, headers)); | |
513 | |
514 { | |
515 ParseDicomSuccessMessage message(c, c.GetSource(), *dicom, fileSize, true); | |
516 EmitMessage(receiver, message); | |
517 } | |
518 | |
519 if (dicomCache_.get()) | |
520 { | |
521 // Store it into the cache for future use | |
522 dicomCache_->Acquire(BUCKET_SOP, c.GetSopInstanceUid(), dicom.release(), fileSize, true); | |
523 } | |
524 #else | |
525 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
526 #endif | |
527 break; | |
528 } | |
529 | |
530 default: | |
531 LOG(ERROR) << "Command type not implemented by the WebAssembly Oracle (in SuccessCallback): " | |
532 << command.GetType(); | |
533 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
534 } | |
535 } | |
536 | |
537 | |
549 void WebAssemblyOracle::SetOrthancUrl(FetchCommand& command, | 538 void WebAssemblyOracle::SetOrthancUrl(FetchCommand& command, |
550 const std::string& uri) const | 539 const std::string& uri) const |
551 { | 540 { |
552 if (isLocalOrthanc_) | 541 if (isLocalOrthanc_) |
553 { | 542 { |
601 SetOrthancUrl(fetch, command->GetUri()); | 590 SetOrthancUrl(fetch, command->GetUri()); |
602 fetch.AddHttpHeaders(command->GetHttpHeaders()); | 591 fetch.AddHttpHeaders(command->GetHttpHeaders()); |
603 fetch.SetTimeout(command->GetTimeout()); | 592 fetch.SetTimeout(command->GetTimeout()); |
604 | 593 |
605 if (command->GetMethod() == Orthanc::HttpMethod_Post || | 594 if (command->GetMethod() == Orthanc::HttpMethod_Post || |
606 command->GetMethod() == Orthanc::HttpMethod_Put) | 595 command->GetMethod() == Orthanc::HttpMethod_Put) |
607 { | 596 { |
608 std::string body; | 597 std::string body; |
609 command->SwapBody(body); | 598 command->SwapBody(body); |
610 fetch.SetBody(body); | 599 fetch.SetBody(body); |
611 } | 600 } |
783 | 772 |
784 case IOracleCommand::Type_ParseDicomFromWado: | 773 case IOracleCommand::Type_ParseDicomFromWado: |
785 #if ORTHANC_ENABLE_DCMTK == 1 | 774 #if ORTHANC_ENABLE_DCMTK == 1 |
786 Execute(receiver, dynamic_cast<ParseDicomFromWadoCommand*>(protection.release())); | 775 Execute(receiver, dynamic_cast<ParseDicomFromWadoCommand*>(protection.release())); |
787 #else | 776 #else |
788 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, | 777 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, |
789 "DCMTK must be enabled to parse DICOM files"); | 778 "DCMTK must be enabled to parse DICOM files"); |
790 #endif | 779 #endif |
791 break; | 780 break; |
792 | 781 |
793 default: | 782 default: |
794 LOG(ERROR) << "Command type not implemented by the WebAssembly Oracle (in Schedule): " | 783 LOG(ERROR) << "Command type not implemented by the WebAssembly Oracle (in Schedule): " |