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): "