# HG changeset patch # User am@osimis.io # Date 1538139763 -7200 # Node ID 14ef1227120fe3dfeaf44f62d3d5b0f7b5cd0719 # Parent be2660b6e40a530363bef30d2ac635fc471360ef web services: better handling of failures diff -r be2660b6e40a -r 14ef1227120f Framework/Toolbox/IWebService.h --- a/Framework/Toolbox/IWebService.h Tue Sep 25 15:14:53 2018 +0200 +++ b/Framework/Toolbox/IWebService.h Fri Sep 28 15:02:43 2018 +0200 @@ -49,9 +49,9 @@ size_t answerSize_; Orthanc::IDynamicObject* payload_; HttpRequestSuccessMessage(const std::string& uri, - const void* answer, - size_t answerSize, - Orthanc::IDynamicObject* payload) + const void* answer, + size_t answerSize, + Orthanc::IDynamicObject* payload) : BaseMessage(), uri_(uri), answer_(answer), @@ -65,7 +65,7 @@ const std::string& uri_; Orthanc::IDynamicObject* payload_; HttpRequestErrorMessage(const std::string& uri, - Orthanc::IDynamicObject* payload) + Orthanc::IDynamicObject* payload) : BaseMessage(), uri_(uri), payload_(payload) @@ -86,14 +86,16 @@ const Headers& headers, Orthanc::IDynamicObject* payload, MessageHandler* successCallback, - MessageHandler* failureCallback) = 0; + MessageHandler* failureCallback = NULL, + unsigned int timeoutInSeconds = 60) = 0; virtual void PostAsync(const std::string& uri, const Headers& headers, const std::string& body, Orthanc::IDynamicObject* payload, MessageHandler* successCallback, - MessageHandler* failureCallback) = 0; + MessageHandler* failureCallback = NULL, + unsigned int timeoutInSeconds = 60) = 0; }; } diff -r be2660b6e40a -r 14ef1227120f Framework/Toolbox/MessagingToolbox.cpp --- a/Framework/Toolbox/MessagingToolbox.cpp Tue Sep 25 15:14:53 2018 +0200 +++ b/Framework/Toolbox/MessagingToolbox.cpp Fri Sep 28 15:02:43 2018 +0200 @@ -31,6 +31,7 @@ #include #include +#include namespace OrthancStone { @@ -114,6 +115,12 @@ target); } + void JsonToString(std::string& target, + const Json::Value& source) + { + Json::FastWriter writer; + target = writer.write(source); + } static void ParseJsonException(Json::Value& target, const std::string& source) diff -r be2660b6e40a -r 14ef1227120f Framework/Toolbox/MessagingToolbox.h --- a/Framework/Toolbox/MessagingToolbox.h Tue Sep 25 15:14:53 2018 +0200 +++ b/Framework/Toolbox/MessagingToolbox.h Fri Sep 28 15:02:43 2018 +0200 @@ -13,7 +13,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **/ @@ -38,6 +38,10 @@ const void* content, size_t size); + void JsonToString(std::string& target, + const Json::Value& source); + + void RestApiGet(Json::Value& target, OrthancPlugins::IOrthancConnection& orthanc, const std::string& uri); diff -r be2660b6e40a -r 14ef1227120f Framework/Toolbox/OrthancApiClient.cpp --- a/Framework/Toolbox/OrthancApiClient.cpp Tue Sep 25 15:14:53 2018 +0200 +++ b/Framework/Toolbox/OrthancApiClient.cpp Fri Sep 28 15:02:43 2018 +0200 @@ -22,6 +22,7 @@ #include "MessagingToolbox.h" #include +#include "Framework/Toolbox/MessagingToolbox.h" namespace OrthancStone { @@ -156,5 +157,16 @@ } + void OrthancApiClient::PostJsonAsyncExpectJson(const std::string& uri, + const Json::Value& data, + MessageHandler* successCallback, + MessageHandler* failureCallback, + Orthanc::IDynamicObject* payload) + { + std::string body; + MessagingToolbox::JsonToString(body, data); + return PostBinaryAsyncExpectJson(uri, body, successCallback, failureCallback, payload); + } + } diff -r be2660b6e40a -r 14ef1227120f Framework/Toolbox/OrthancApiClient.h --- a/Framework/Toolbox/OrthancApiClient.h Tue Sep 25 15:14:53 2018 +0200 +++ b/Framework/Toolbox/OrthancApiClient.h Fri Sep 28 15:02:43 2018 +0200 @@ -135,6 +135,12 @@ MessageHandler* failureCallback = NULL, Orthanc::IDynamicObject* payload = NULL); + // schedule a POST request expecting a JSON response. + void PostJsonAsyncExpectJson(const std::string& uri, + const Json::Value& data, + MessageHandler* successCallback, + MessageHandler* failureCallback = NULL, + Orthanc::IDynamicObject* payload = NULL); }; } diff -r be2660b6e40a -r 14ef1227120f Framework/Widgets/LayerWidget.cpp --- a/Framework/Widgets/LayerWidget.cpp Tue Sep 25 15:14:53 2018 +0200 +++ b/Framework/Widgets/LayerWidget.cpp Fri Sep 28 15:02:43 2018 +0200 @@ -548,6 +548,7 @@ { InvalidateLayer(index); } + EmitMessage(LayerWidget::ContentChangedMessage(*this)); } @@ -561,6 +562,7 @@ InvalidateLayer(index); } } + EmitMessage(LayerWidget::ContentChangedMessage(*this)); } @@ -588,6 +590,7 @@ //UpdateLayer(index, new SliceOutlineRenderer(slice), slice); } } + EmitMessage(LayerWidget::ContentChangedMessage(*this)); } diff -r be2660b6e40a -r 14ef1227120f Platforms/Generic/Oracle.cpp --- a/Platforms/Generic/Oracle.cpp Tue Sep 25 15:14:53 2018 +0200 +++ b/Platforms/Generic/Oracle.cpp Fri Sep 28 15:02:43 2018 +0200 @@ -66,7 +66,15 @@ if (item.get() != NULL) { IOracleCommand& command = dynamic_cast(*item); - command.Execute(); + try + { + command.Execute(); + } + catch (Orthanc::OrthancException& ex) + { + // this is probably a curl error that has been triggered. We may just ignore it. + // The command.success_ will stay at false and this will be handled in the command.Commit + } // Random sleeping to test //boost::this_thread::sleep(boost::posix_time::milliseconds(50 * (1 + rand() % 10))); diff -r be2660b6e40a -r 14ef1227120f Platforms/Generic/OracleWebService.h --- a/Platforms/Generic/OracleWebService.h Tue Sep 25 15:14:53 2018 +0200 +++ b/Platforms/Generic/OracleWebService.h Fri Sep 28 15:02:43 2018 +0200 @@ -13,7 +13,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **/ @@ -55,9 +55,10 @@ const Headers& headers, Orthanc::IDynamicObject* payload, // takes ownership MessageHandler* successCallback, // takes ownership - MessageHandler* failureCallback = NULL)// takes ownership + MessageHandler* failureCallback = NULL,// takes ownership + unsigned int timeoutInSeconds = 60) { - oracle_.Submit(new WebServiceGetCommand(broker_, successCallback, failureCallback, parameters_, uri, headers, payload, context_)); + oracle_.Submit(new WebServiceGetCommand(broker_, successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, payload, context_)); } virtual void PostAsync(const std::string& uri, @@ -65,19 +66,20 @@ const std::string& body, Orthanc::IDynamicObject* payload, // takes ownership MessageHandler* successCallback, // takes ownership - MessageHandler* failureCallback) // takes ownership + MessageHandler* failureCallback = NULL, // takes ownership + unsigned int timeoutInSeconds = 60) { - oracle_.Submit(new WebServicePostCommand(broker_, successCallback, failureCallback, parameters_, uri, headers, body, payload, context_)); + oracle_.Submit(new WebServicePostCommand(broker_, successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, body, payload, context_)); } void Start() { - oracle_.Start(); + oracle_.Start(); } void Stop() { - oracle_.Stop(); + oracle_.Stop(); } }; } diff -r be2660b6e40a -r 14ef1227120f Platforms/Generic/WebServiceCommandBase.cpp --- a/Platforms/Generic/WebServiceCommandBase.cpp Tue Sep 25 15:14:53 2018 +0200 +++ b/Platforms/Generic/WebServiceCommandBase.cpp Fri Sep 28 15:02:43 2018 +0200 @@ -31,6 +31,7 @@ const Orthanc::WebServiceParameters& parameters, const std::string& uri, const IWebService::Headers& headers, + unsigned int timeoutInSeconds, Orthanc::IDynamicObject* payload /* takes ownership */, NativeStoneApplicationContext& context) : IObservable(broker), @@ -40,7 +41,8 @@ uri_(uri), headers_(headers), payload_(payload), - context_(context) + context_(context), + timeoutInSeconds_(timeoutInSeconds) { } @@ -55,7 +57,7 @@ } else if (!success_ && failureCallback_.get() != NULL) { - successCallback_->Apply(IWebService::HttpRequestErrorMessage(uri_, payload_.release())); + failureCallback_->Apply(IWebService::HttpRequestErrorMessage(uri_, payload_.release())); } } diff -r be2660b6e40a -r 14ef1227120f Platforms/Generic/WebServiceCommandBase.h --- a/Platforms/Generic/WebServiceCommandBase.h Tue Sep 25 15:14:53 2018 +0200 +++ b/Platforms/Generic/WebServiceCommandBase.h Fri Sep 28 15:02:43 2018 +0200 @@ -46,6 +46,7 @@ bool success_; std::string answer_; NativeStoneApplicationContext& context_; + unsigned int timeoutInSeconds_; public: WebServiceCommandBase(MessageBroker& broker, @@ -54,8 +55,10 @@ const Orthanc::WebServiceParameters& parameters, const std::string& uri, const std::map& headers, + unsigned int timeoutInSeconds, Orthanc::IDynamicObject* payload /* takes ownership */, - NativeStoneApplicationContext& context); + NativeStoneApplicationContext& context + ); virtual void Execute() = 0; diff -r be2660b6e40a -r 14ef1227120f Platforms/Generic/WebServiceGetCommand.cpp --- a/Platforms/Generic/WebServiceGetCommand.cpp Tue Sep 25 15:14:53 2018 +0200 +++ b/Platforms/Generic/WebServiceGetCommand.cpp Fri Sep 28 15:02:43 2018 +0200 @@ -32,9 +32,10 @@ const Orthanc::WebServiceParameters& parameters, const std::string& uri, const IWebService::Headers& headers, + unsigned int timeoutInSeconds, Orthanc::IDynamicObject* payload /* takes ownership */, NativeStoneApplicationContext& context) : - WebServiceCommandBase(broker, successCallback, failureCallback, parameters, uri, headers, payload, context) + WebServiceCommandBase(broker, successCallback, failureCallback, parameters, uri, headers, timeoutInSeconds, payload, context) { } @@ -42,7 +43,7 @@ void WebServiceGetCommand::Execute() { Orthanc::HttpClient client(parameters_, uri_); - client.SetTimeout(60); + client.SetTimeout(timeoutInSeconds_); client.SetMethod(Orthanc::HttpMethod_Get); for (IWebService::Headers::const_iterator it = headers_.begin(); it != headers_.end(); it++ ) diff -r be2660b6e40a -r 14ef1227120f Platforms/Generic/WebServiceGetCommand.h --- a/Platforms/Generic/WebServiceGetCommand.h Tue Sep 25 15:14:53 2018 +0200 +++ b/Platforms/Generic/WebServiceGetCommand.h Fri Sep 28 15:02:43 2018 +0200 @@ -34,6 +34,7 @@ const Orthanc::WebServiceParameters& parameters, const std::string& uri, const IWebService::Headers& headers, + unsigned int timeoutInSeconds, Orthanc::IDynamicObject* payload /* takes ownership */, NativeStoneApplicationContext& context); diff -r be2660b6e40a -r 14ef1227120f Platforms/Generic/WebServicePostCommand.cpp --- a/Platforms/Generic/WebServicePostCommand.cpp Tue Sep 25 15:14:53 2018 +0200 +++ b/Platforms/Generic/WebServicePostCommand.cpp Fri Sep 28 15:02:43 2018 +0200 @@ -31,10 +31,11 @@ const Orthanc::WebServiceParameters& parameters, const std::string& uri, const IWebService::Headers& headers, + unsigned int timeoutInSeconds, const std::string& body, Orthanc::IDynamicObject* payload /* takes ownership */, NativeStoneApplicationContext& context) : - WebServiceCommandBase(broker, successCallback, failureCallback, parameters, uri, headers, payload, context), + WebServiceCommandBase(broker, successCallback, failureCallback, parameters, uri, headers, timeoutInSeconds, payload, context), body_(body) { } @@ -42,7 +43,7 @@ void WebServicePostCommand::Execute() { Orthanc::HttpClient client(parameters_, uri_); - client.SetTimeout(60); + client.SetTimeout(timeoutInSeconds_); client.SetMethod(Orthanc::HttpMethod_Post); client.GetBody().swap(body_); diff -r be2660b6e40a -r 14ef1227120f Platforms/Generic/WebServicePostCommand.h --- a/Platforms/Generic/WebServicePostCommand.h Tue Sep 25 15:14:53 2018 +0200 +++ b/Platforms/Generic/WebServicePostCommand.h Fri Sep 28 15:02:43 2018 +0200 @@ -37,6 +37,7 @@ const Orthanc::WebServiceParameters& parameters, const std::string& uri, const IWebService::Headers& headers, + unsigned int timeoutInSeconds, const std::string& body, Orthanc::IDynamicObject* payload /* takes ownership */, NativeStoneApplicationContext& context); diff -r be2660b6e40a -r 14ef1227120f Platforms/Wasm/Defaults.cpp --- a/Platforms/Wasm/Defaults.cpp Tue Sep 25 15:14:53 2018 +0200 +++ b/Platforms/Wasm/Defaults.cpp Fri Sep 28 15:02:43 2018 +0200 @@ -262,7 +262,7 @@ static std::string output; // we don't want the string to be deallocated when we return to JS code so we always use the same string (this is fine since JS is single-thread) printf("SendMessageToStoneApplication\n"); - printf(message); + printf("%s", message); if (applicationWasmAdapter.get() != NULL) { printf("sending message to C++\n"); diff -r be2660b6e40a -r 14ef1227120f Platforms/Wasm/WasmWebService.cpp --- a/Platforms/Wasm/WasmWebService.cpp Tue Sep 25 15:14:53 2018 +0200 +++ b/Platforms/Wasm/WasmWebService.cpp Fri Sep 28 15:02:43 2018 +0200 @@ -11,7 +11,8 @@ void* callableFailure, const char* uri, const char* headersInJsonString, - void* payload); + void* payload, + unsigned int timeoutInSeconds); extern void WasmWebService_PostAsync(void* callableSuccess, void* callableFailure, @@ -19,7 +20,8 @@ const char* headersInJsonString, const void* body, size_t bodySize, - void* payload); + void* payload, + unsigned int timeoutInSeconds); void EMSCRIPTEN_KEEPALIVE WasmWebService_NotifyError(void* failureCallable, @@ -100,29 +102,31 @@ } void WasmWebService::PostAsync(const std::string& relativeUri, - const Headers& headers, - const std::string& body, - Orthanc::IDynamicObject* payload, - MessageHandler* successCallable, - MessageHandler* failureCallable) + const Headers& headers, + const std::string& body, + Orthanc::IDynamicObject* payload, + MessageHandler* successCallable, + MessageHandler* failureCallable, + unsigned int timeoutInSeconds) { std::string uri = baseUri_ + relativeUri; std::string headersInJsonString; ToJsonString(headersInJsonString, headers); WasmWebService_PostAsync(successCallable, failureCallable, uri.c_str(), headersInJsonString.c_str(), - body.c_str(), body.size(), payload); + body.c_str(), body.size(), payload, timeoutInSeconds); } void WasmWebService::GetAsync(const std::string& relativeUri, - const Headers& headers, - Orthanc::IDynamicObject* payload, - MessageHandler* successCallable, - MessageHandler* failureCallable) + const Headers& headers, + Orthanc::IDynamicObject* payload, + MessageHandler* successCallable, + MessageHandler* failureCallable, + unsigned int timeoutInSeconds) { std::string uri = baseUri_ + relativeUri; std::string headersInJsonString; ToJsonString(headersInJsonString, headers); - WasmWebService_GetAsync(successCallable, failureCallable, uri.c_str(), headersInJsonString.c_str(), payload); + WasmWebService_GetAsync(successCallable, failureCallable, uri.c_str(), headersInJsonString.c_str(), payload, timeoutInSeconds); } } diff -r be2660b6e40a -r 14ef1227120f Platforms/Wasm/WasmWebService.h --- a/Platforms/Wasm/WasmWebService.h Tue Sep 25 15:14:53 2018 +0200 +++ b/Platforms/Wasm/WasmWebService.h Fri Sep 28 15:02:43 2018 +0200 @@ -41,14 +41,16 @@ const Headers& headers, Orthanc::IDynamicObject* payload, MessageHandler* successCallable, - MessageHandler* failureCallable); + MessageHandler* failureCallable = NULL, + unsigned int timeoutInSeconds = 60); virtual void PostAsync(const std::string& uri, const Headers& headers, const std::string& body, Orthanc::IDynamicObject* payload, MessageHandler* successCallable, - MessageHandler* failureCallable); + MessageHandler* failureCallable = NULL, + unsigned int timeoutInSeconds = 60); virtual void Start() { diff -r be2660b6e40a -r 14ef1227120f Platforms/Wasm/WasmWebService.js --- a/Platforms/Wasm/WasmWebService.js Tue Sep 25 15:14:53 2018 +0200 +++ b/Platforms/Wasm/WasmWebService.js Fri Sep 28 15:02:43 2018 +0200 @@ -1,5 +1,5 @@ mergeInto(LibraryManager.library, { - WasmWebService_GetAsync: function(callableSuccess, callableFailure, url, headersInJsonString, payload) { + WasmWebService_GetAsync: function(callableSuccess, callableFailure, url, headersInJsonString, payload, timeoutInSeconds) { // Directly use XMLHttpRequest (no jQuery) to retrieve the raw binary data // http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/ var xhr = new XMLHttpRequest(); @@ -8,6 +8,7 @@ xhr.open('GET', url_, true); xhr.responseType = 'arraybuffer'; + xhr.timeout = timeoutInSeconds * 1000; var headers = JSON.parse(headersInJsonString_); for (var key in headers) { xhr.setRequestHeader(key, headers[key]); @@ -30,11 +31,12 @@ xhr.send(); }, - WasmWebService_PostAsync: function(callableSuccess, callableFailure, url, headersInJsonString, body, bodySize, payload) { + WasmWebService_PostAsync: function(callableSuccess, callableFailure, url, headersInJsonString, body, bodySize, payload, timeoutInSeconds) { var xhr = new XMLHttpRequest(); var url_ = UTF8ToString(url); var headersInJsonString_ = UTF8ToString(headersInJsonString); xhr.open('POST', url_, true); + xhr.timeout = timeoutInSeconds * 1000; xhr.responseType = 'arraybuffer'; xhr.setRequestHeader('Content-type', 'application/octet-stream');