Mercurial > hg > orthanc-stone
diff Samples/WebAssembly/BasicMPR.cpp @ 825:9a6c7a5dcb76
reorganization
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 29 May 2019 15:45:15 +0200 |
parents | 15d493101c1e |
children | 2de01660debe |
line wrap: on
line diff
--- a/Samples/WebAssembly/BasicMPR.cpp Wed May 29 15:26:47 2019 +0200 +++ b/Samples/WebAssembly/BasicMPR.cpp Wed May 29 15:45:15 2019 +0200 @@ -27,6 +27,7 @@ #include "../../Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h" #include "../../Framework/OpenGL/WebAssemblyOpenGLContext.h" #include "../../Framework/Oracle/SleepOracleCommand.h" +#include "../../Framework/Oracle/WebAssemblyOracle.h" #include "../../Framework/Scene2D/GrayscaleStyleConfigurator.h" #include "../../Framework/Scene2D/OpenGLCompositor.h" #include "../../Framework/Scene2D/PanSceneTracker.h" @@ -392,462 +393,6 @@ } } }; - - - - - class WebAssemblyOracle : - public IOracle, - public IObservable - { - private: - typedef std::map<std::string, std::string> HttpHeaders; - - class Emitter : public IMessageEmitter - { - private: - WebAssemblyOracle& oracle_; - - public: - Emitter(WebAssemblyOracle& oracle) : - oracle_(oracle) - { - } - - virtual void EmitMessage(const IObserver& receiver, - const IMessage& message) - { - oracle_.EmitMessage(receiver, message); - } - }; - - - class FetchContext : public boost::noncopyable - { - private: - Emitter emitter_; - const IObserver& receiver_; - std::auto_ptr<IOracleCommand> command_; - std::string expectedContentType_; - - public: - FetchContext(WebAssemblyOracle& oracle, - const IObserver& receiver, - IOracleCommand* command, - const std::string& expectedContentType) : - emitter_(oracle), - receiver_(receiver), - command_(command), - expectedContentType_(expectedContentType) - { - if (command == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - } - - const std::string& GetExpectedContentType() const - { - return expectedContentType_; - } - - void EmitMessage(const IMessage& message) - { - emitter_.EmitMessage(receiver_, message); - } - - IMessageEmitter& GetEmitter() - { - return emitter_; - } - - const IObserver& GetReceiver() const - { - return receiver_; - } - - IOracleCommand& GetCommand() const - { - return *command_; - } - - template <typename T> - const T& GetTypedCommand() const - { - return dynamic_cast<T&>(*command_); - } - }; - - static void FetchSucceeded(emscripten_fetch_t *fetch) - { - /** - * Firstly, make a local copy of the fetched information, and - * free data associated with the fetch. - **/ - - std::auto_ptr<FetchContext> context(reinterpret_cast<FetchContext*>(fetch->userData)); - - std::string answer; - if (fetch->numBytes > 0) - { - answer.assign(fetch->data, fetch->numBytes); - } - - /** - * TODO - HACK - As of emscripten-1.38.31, the fetch API does - * not contain a way to retrieve the HTTP headers of the - * answer. We make the assumption that the "Content-Type" header - * of the response is the same as the "Accept" header of the - * query. This should be fixed in future versions of emscripten. - * https://github.com/emscripten-core/emscripten/pull/8486 - **/ - - HttpHeaders headers; - if (!context->GetExpectedContentType().empty()) - { - headers["Content-Type"] = context->GetExpectedContentType(); - } - - - emscripten_fetch_close(fetch); - - - /** - * Secondly, use the retrieved data. - **/ - - try - { - if (context.get() == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - else - { - switch (context->GetCommand().GetType()) - { - case IOracleCommand::Type_OrthancRestApi: - { - OrthancRestApiCommand::SuccessMessage message - (context->GetTypedCommand<OrthancRestApiCommand>(), headers, answer); - context->EmitMessage(message); - break; - } - - case IOracleCommand::Type_GetOrthancImage: - { - context->GetTypedCommand<GetOrthancImageCommand>().ProcessHttpAnswer - (context->GetEmitter(), context->GetReceiver(), answer, headers); - break; - } - - case IOracleCommand::Type_GetOrthancWebViewerJpeg: - { - context->GetTypedCommand<GetOrthancWebViewerJpegCommand>().ProcessHttpAnswer - (context->GetEmitter(), context->GetReceiver(), answer); - break; - } - - default: - LOG(ERROR) << "Command type not implemented by the WebAssembly Oracle: " - << context->GetCommand().GetType(); - } - } - } - catch (Orthanc::OrthancException& e) - { - LOG(ERROR) << "Error while processing a fetch answer in the oracle: " << e.What(); - } - } - - static void FetchFailed(emscripten_fetch_t *fetch) - { - std::auto_ptr<FetchContext> context(reinterpret_cast<FetchContext*>(fetch->userData)); - - LOG(ERROR) << "Fetching " << fetch->url << " failed, HTTP failure status code: " << fetch->status; - - /** - * TODO - The following code leads to an infinite recursion, at - * least with Firefox running on incognito mode => WHY? - **/ - //emscripten_fetch_close(fetch); // Also free data on failure. - } - - - class FetchCommand : public boost::noncopyable - { - private: - WebAssemblyOracle& oracle_; - const IObserver& receiver_; - std::auto_ptr<IOracleCommand> command_; - Orthanc::HttpMethod method_; - std::string uri_; - std::string body_; - HttpHeaders headers_; - unsigned int timeout_; - std::string expectedContentType_; - - public: - FetchCommand(WebAssemblyOracle& oracle, - const IObserver& receiver, - IOracleCommand* command) : - oracle_(oracle), - receiver_(receiver), - command_(command), - method_(Orthanc::HttpMethod_Get), - timeout_(0) - { - if (command == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - } - - void SetMethod(Orthanc::HttpMethod method) - { - method_ = method; - } - - void SetUri(const std::string& uri) - { - uri_ = uri; - } - - void SetBody(std::string& body /* will be swapped */) - { - body_.swap(body); - } - - void SetHttpHeaders(const HttpHeaders& headers) - { - headers_ = headers; - } - - void SetTimeout(unsigned int timeout) - { - timeout_ = timeout; - } - - void Execute() - { - if (command_.get() == NULL) - { - // Cannot call Execute() twice - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - emscripten_fetch_attr_t attr; - emscripten_fetch_attr_init(&attr); - - const char* method; - - switch (method_) - { - case Orthanc::HttpMethod_Get: - method = "GET"; - break; - - case Orthanc::HttpMethod_Post: - method = "POST"; - break; - - case Orthanc::HttpMethod_Delete: - method = "DELETE"; - break; - - case Orthanc::HttpMethod_Put: - method = "PUT"; - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - - strcpy(attr.requestMethod, method); - - attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY; - attr.onsuccess = FetchSucceeded; - attr.onerror = FetchFailed; - attr.timeoutMSecs = timeout_ * 1000; - - std::vector<const char*> headers; - headers.reserve(2 * headers_.size() + 1); - - std::string expectedContentType; - - for (HttpHeaders::const_iterator it = headers_.begin(); it != headers_.end(); ++it) - { - std::string key; - Orthanc::Toolbox::ToLowerCase(key, it->first); - - if (key == "accept") - { - expectedContentType = it->second; - } - - if (key != "accept-encoding") // Web browsers forbid the modification of this HTTP header - { - headers.push_back(it->first.c_str()); - headers.push_back(it->second.c_str()); - } - } - - headers.push_back(NULL); // Termination of the array of HTTP headers - - attr.requestHeaders = &headers[0]; - - if (!body_.empty()) - { - attr.requestDataSize = body_.size(); - attr.requestData = body_.c_str(); - } - - // Must be the last call to prevent memory leak on error - attr.userData = new FetchContext(oracle_, receiver_, command_.release(), expectedContentType); - emscripten_fetch(&attr, uri_.c_str()); - } - }; - - - void Execute(const IObserver& receiver, - OrthancRestApiCommand* command) - { - FetchCommand fetch(*this, receiver, command); - - fetch.SetMethod(command->GetMethod()); - fetch.SetUri(command->GetUri()); - fetch.SetHttpHeaders(command->GetHttpHeaders()); - fetch.SetTimeout(command->GetTimeout()); - - if (command->GetMethod() == Orthanc::HttpMethod_Put || - command->GetMethod() == Orthanc::HttpMethod_Put) - { - std::string body; - command->SwapBody(body); - fetch.SetBody(body); - } - - fetch.Execute(); - } - - - void Execute(const IObserver& receiver, - GetOrthancImageCommand* command) - { - FetchCommand fetch(*this, receiver, command); - - fetch.SetUri(command->GetUri()); - fetch.SetHttpHeaders(command->GetHttpHeaders()); - fetch.SetTimeout(command->GetTimeout()); - - fetch.Execute(); - } - - - void Execute(const IObserver& receiver, - GetOrthancWebViewerJpegCommand* command) - { - FetchCommand fetch(*this, receiver, command); - - fetch.SetUri(command->GetUri()); - fetch.SetHttpHeaders(command->GetHttpHeaders()); - fetch.SetTimeout(command->GetTimeout()); - - fetch.Execute(); - } - - - - class TimeoutContext - { - private: - WebAssemblyOracle& oracle_; - const IObserver& receiver_; - std::auto_ptr<SleepOracleCommand> command_; - - public: - TimeoutContext(WebAssemblyOracle& oracle, - const IObserver& receiver, - IOracleCommand* command) : - oracle_(oracle), - receiver_(receiver) - { - if (command == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - else - { - command_.reset(dynamic_cast<SleepOracleCommand*>(command)); - } - } - - void EmitMessage() - { - SleepOracleCommand::TimeoutMessage message(*command_); - oracle_.EmitMessage(receiver_, message); - } - }; - - - static void TimeoutCallback(void *userData) - { - std::auto_ptr<TimeoutContext> context(reinterpret_cast<TimeoutContext*>(userData)); - context->EmitMessage(); - } - - - - public: - WebAssemblyOracle(MessageBroker& broker) : - IObservable(broker) - { - } - - virtual void Schedule(const IObserver& receiver, - IOracleCommand* command) - { - std::auto_ptr<IOracleCommand> protection(command); - - if (command == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - - switch (command->GetType()) - { - case IOracleCommand::Type_OrthancRestApi: - Execute(receiver, dynamic_cast<OrthancRestApiCommand*>(protection.release())); - break; - - case IOracleCommand::Type_GetOrthancImage: - Execute(receiver, dynamic_cast<GetOrthancImageCommand*>(protection.release())); - break; - - case IOracleCommand::Type_GetOrthancWebViewerJpeg: - Execute(receiver, dynamic_cast<GetOrthancWebViewerJpegCommand*>(protection.release())); - break; - - case IOracleCommand::Type_Sleep: - { - unsigned int timeoutMS = dynamic_cast<SleepOracleCommand*>(command)->GetDelay(); - emscripten_set_timeout(TimeoutCallback, timeoutMS, new TimeoutContext(*this, receiver, protection.release())); - break; - } - - default: - LOG(ERROR) << "Command type not implemented by the WebAssembly Oracle: " << command->GetType(); - } - } - - virtual void Start() - { - } - - virtual void Stop() - { - } - }; } @@ -1008,7 +553,7 @@ } }; - //static TestSleep testSleep(broker_, oracle_); + static TestSleep testSleep(broker_, oracle_); } @@ -1052,7 +597,6 @@ emscripten_request_animation_frame_loop(OnAnimationFrame, NULL); - oracle_.Start(); loader_->LoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); } catch (Orthanc::OrthancException& e)