# HG changeset patch # User Benjamin Golinvaux # Date 1556543388 -7200 # Node ID 70992b38aa8ae064c79b6b01105d90d8c66009e8 # Parent 03c4b998fcd0ec8a9925fc6213a962c364697c4f new routable logging system in STDIO mode + flag support (with no value) in StartupParametersBuilder + 80 col indent diff -r 03c4b998fcd0 -r 70992b38aa8a Applications/Generic/NativeStoneApplicationRunner.cpp --- a/Applications/Generic/NativeStoneApplicationRunner.cpp Mon Apr 29 14:40:01 2019 +0200 +++ b/Applications/Generic/NativeStoneApplicationRunner.cpp Mon Apr 29 15:09:48 2019 +0200 @@ -81,11 +81,13 @@ generic.add_options() ("help", "Display this help and exit") ("verbose", "Be verbose in logs") - ("orthanc", boost::program_options::value()->default_value("http://localhost:8042/"), + ("orthanc", boost::program_options::value()-> + default_value("http://localhost:8042/"), "URL to the Orthanc server") ("username", "Username for the Orthanc server") ("password", "Password for the Orthanc server") - ("https-verify", boost::program_options::value()->default_value(true), "Check HTTPS certificates") + ("https-verify", boost::program_options::value()-> + default_value(true), "Check HTTPS certificates") ; options.add(generic); @@ -102,13 +104,15 @@ try { - boost::program_options::store(boost::program_options::command_line_parser(argc, argv). - options(options).run(), parameters); + boost::program_options::store( + boost::program_options::command_line_parser(argc, argv). + options(options).run(), parameters); boost::program_options::notify(parameters); } catch (boost::program_options::error& e) { - LOG(ERROR) << "Error while parsing the command-line arguments: " << e.what(); + LOG(ERROR) << + "Error while parsing the command-line arguments: " << e.what(); error = true; } @@ -120,12 +124,11 @@ if (error || parameters.count("help")) { std::cout << std::endl - << "Usage: " << argv[0] << " [OPTION]..." - << std::endl - << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research." - << std::endl << std::endl - << "Demonstration application of Orthanc Stone in native environment." - << std::endl; + << "Usage: " << argv[0] << " [OPTION]..." << std::endl + << "Orthanc, lightweight, RESTful DICOM server for healthcare " + << "and medical research." << std::endl << std::endl + << "Demonstration application of Orthanc Stone in native " + << "environment." << std::endl; std::cout << options << "\n"; return error ? -1 : 0; @@ -138,21 +141,24 @@ Orthanc::HttpClient::ConfigureSsl(false, ""); } + LOG(ERROR) << "???????? if (parameters.count(\"verbose\"))"; if (parameters.count("verbose")) { + LOG(ERROR) << "parameters.count(\"verbose\") != 0"; Orthanc::Logging::EnableInfoLevel(true); LOG(INFO) << "Verbose logs are enabled"; } +` LOG(ERROR) << "???????? if (parameters.count(\"trace\"))"; if (parameters.count("trace")) { + LOG(ERROR) << "parameters.count(\"trace\") != 0"; Orthanc::Logging::EnableTraceLevel(true); VLOG(1) << "Trace logs are enabled"; } ParseCommandLineOptions(parameters); - bool success = true; try { @@ -169,17 +175,20 @@ if (parameters.count("username") && parameters.count("password")) { - webServiceParameters.SetCredentials(parameters["username"].as(), - parameters["password"].as()); + webServiceParameters.SetCredentials(parameters["username"]. + as(), + parameters["password"].as()); } - LOG(WARNING) << "URL to the Orthanc REST API: " << webServiceParameters.GetUrl(); + LOG(WARNING) << "URL to the Orthanc REST API: " << + webServiceParameters.GetUrl(); { OrthancPlugins::OrthancHttpConnection orthanc(webServiceParameters); if (!MessagingToolbox::CheckOrthancVersion(orthanc)) { - LOG(ERROR) << "Your version of Orthanc is incompatible with Stone of Orthanc, please upgrade"; + LOG(ERROR) << "Your version of Orthanc is incompatible with Stone of " + << "Orthanc, please upgrade"; throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); } } @@ -196,11 +205,15 @@ NativeStoneApplicationContext context(broker_); { - Oracle oracle(6); // use multiple threads to execute asynchronous tasks like download content + // use multiple threads to execute asynchronous tasks like + // download content + Oracle oracle(6); oracle.Start(); { - OracleWebService webService(broker_, oracle, webServiceParameters, context); + OracleWebService webService( + broker_, oracle, webServiceParameters, context); + context.SetWebService(webService); context.SetOrthancBaseUrl(webServiceParameters.GetUrl()); @@ -255,5 +268,4 @@ return (success ? 0 : -1); } - } diff -r 03c4b998fcd0 -r 70992b38aa8a Applications/Samples/rt-viewer-demo/main.cpp --- a/Applications/Samples/rt-viewer-demo/main.cpp Mon Apr 29 14:40:01 2019 +0200 +++ b/Applications/Samples/rt-viewer-demo/main.cpp Mon Apr 29 15:09:48 2019 +0200 @@ -546,6 +546,24 @@ void ParseParameters(const boost::program_options::variables_map& parameters) { + // Generic + { + if (parameters.count("verbose")) + { + Orthanc::Logging::EnableInfoLevel(true); + LOG(INFO) << "Verbose logs (info) are enabled"; + } + } + + { + if (parameters.count("trace")) + { + LOG(INFO) << "parameters.count(\"trace\") != 0"; + Orthanc::Logging::EnableTraceLevel(true); + VLOG(1) << "Trace logs (debug) are enabled"; + } + } + // CT series { @@ -570,12 +588,14 @@ if (parameters.count("dose-series") != 1) { LOG(ERROR) << "the RTDOSE series is missing"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + throw Orthanc::OrthancException( + Orthanc::ErrorCode_ParameterOutOfRange); } doseSeries_ = parameters["ct"].as(); #endif LOG(ERROR) << "the RTSTRUCT instance is missing"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + throw Orthanc::OrthancException( + Orthanc::ErrorCode_ParameterOutOfRange); } } @@ -592,26 +612,40 @@ if (parameters.count("struct-series") != 1) { LOG(ERROR) << "the RTSTRUCT series is missing"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + throw Orthanc::OrthancException( + Orthanc::ErrorCode_ParameterOutOfRange); } - structSeries_ = parametersstruct - series"].as(); + structSeries_ = parameters["struct-series"].as(); #endif LOG(ERROR) << "the RTSTRUCT instance is missing"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + throw Orthanc::OrthancException( + Orthanc::ErrorCode_ParameterOutOfRange); } } } - virtual void DeclareStartupOptions(boost::program_options::options_description& options) + virtual void DeclareStartupOptions( + boost::program_options::options_description& options) { - boost::program_options::options_description generic("RtViewerDemo options. Please note that some of these options are mutually exclusive"); + boost::program_options::options_description generic( + "RtViewerDemo options. Please note that some of these options " + "are mutually exclusive"); generic.add_options() - ("ct-series", boost::program_options::value(),"Orthanc ID of the CT series") - ("dose-instance", boost::program_options::value(), "Orthanc ID of the RTDOSE instance (incompatible with dose-series)") - ("dose-series", boost::program_options::value(), "NOT IMPLEMENTED YET. Orthanc ID of the RTDOSE series (incompatible with dose-instance)") - ("struct-instance", boost::program_options::value(), "Orthanc ID of the RTSTRUCT instance (incompatible with struct-series)") - ("struct-series", boost::program_options::value(), "NOT IMPLEMENTED YET. Orthanc ID of the RTSTRUCT (incompatible with struct-instance)") - ("smooth", boost::program_options::value()->default_value(true),"Enable bilinear image smoothing") + ("ct-series", boost::program_options::value(), + "Orthanc ID of the CT series") + ("dose-instance", boost::program_options::value(), + "Orthanc ID of the RTDOSE instance (incompatible with dose-series)") + ("dose-series", boost::program_options::value(), + "NOT IMPLEMENTED YET. Orthanc ID of the RTDOSE series (incompatible" + " with dose-instance)") + ("struct-instance", boost::program_options::value(), + "Orthanc ID of the RTSTRUCT instance (incompatible with struct-" + "series)") + ("struct-series", boost::program_options::value(), + "NOT IMPLEMENTED YET. Orthanc ID of the RTSTRUCT (incompatible with" + " struct-instance)") + ("smooth", boost::program_options::value()->default_value(true), + "Enable bilinear image smoothing") ; options.add(generic); @@ -637,8 +671,10 @@ ct_.reset(new OrthancStone::OrthancVolumeImage( IObserver::GetBroker(), context->GetOrthancApiClient(), false)); ct_->ScheduleLoadSeries(ctSeries_); - //ct_->ScheduleLoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // IBA - //ct_->ScheduleLoadSeries("03677739-1d8bca40-db1daf59-d74ff548-7f6fc9c0"); // 0522c0001 TCIA + //ct_->ScheduleLoadSeries( + // "a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // IBA + //ct_->ScheduleLoadSeries( + // "03677739-1d8bca40-db1daf59-d74ff548-7f6fc9c0"); // 0522c0001 TCIA } if (!doseSeries_.empty() || @@ -665,8 +701,10 @@ dose_->ScheduleLoadInstance(doseInstance_); } - //dose_->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // IBA 1 - //dose_->ScheduleLoadInstance("269f26f4-0c83eeeb-2e67abbd-5467a40f-f1bec90c"); // 0522c0001 TCIA + //dose_->ScheduleLoadInstance( + //"830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // IBA 1 + //dose_->ScheduleLoadInstance( + //"269f26f4-0c83eeeb-2e67abbd-5467a40f-f1bec90c"); //0522c0001 TCIA } if (!structInstance_.empty()) @@ -676,8 +714,10 @@ struct_->ScheduleLoadInstance(structInstance_); - //struct_->ScheduleLoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"); // IBA - //struct_->ScheduleLoadInstance("17cd032b-ad92a438-ca05f06a-f9e96668-7e3e9e20"); // 0522c0001 TCIA + //struct_->ScheduleLoadInstance( + //"54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"); // IBA + //struct_->ScheduleLoadInstance( + //"17cd032b-ad92a438-ca05f06a-f9e96668-7e3e9e20"); // 0522c0001 TCIA } mainWidget_ = new LayoutWidget("main-layout"); diff -r 03c4b998fcd0 -r 70992b38aa8a Applications/Wasm/StartupParametersBuilder.cpp --- a/Applications/Wasm/StartupParametersBuilder.cpp Mon Apr 29 14:40:01 2019 +0200 +++ b/Applications/Wasm/StartupParametersBuilder.cpp Mon Apr 29 15:09:48 2019 +0200 @@ -1,43 +1,66 @@ #include "StartupParametersBuilder.h" +#include namespace OrthancStone { - void StartupParametersBuilder::Clear() { - startupParameters_.clear(); - } + void StartupParametersBuilder::Clear() + { + startupParameters_.clear(); + } + + void StartupParametersBuilder::SetStartupParameter( + const char* name, + const char* value) + { + startupParameters_.push_back(std::make_tuple(name, value)); + } - void StartupParametersBuilder::SetStartupParameter(const char* name, const char* value) { - startupParameters_.push_back(std::make_tuple(name, value)); + void StartupParametersBuilder::GetStartupParameters( + boost::program_options::variables_map& parameters, + const boost::program_options::options_description& options) + { + std::vector argvStrings(startupParameters_.size() + 1); + // argv mirrors pointers to the internal argvStrings buffers. + // ****************************************************** + // THIS IS HIGHLY DANGEROUS SO BEWARE!!!!!!!!!!!!!! + // ****************************************************** + std::vector argv(startupParameters_.size() + 1); + + int argCounter = 0; + argvStrings[argCounter] = "Toto.exe"; + argv[argCounter] = argvStrings[argCounter].c_str(); + + argCounter++; + + std::string cmdLine = ""; + for ( StartupParameters::const_iterator it = startupParameters_.begin(); + it != startupParameters_.end(); + it++) + { + std::stringstream argSs; + + argSs << "--" << std::get<0>(*it); + if(std::get<1>(*it).length() > 0) + argSs << "=" << std::get<1>(*it); + + argvStrings[argCounter] = argSs.str(); + cmdLine = cmdLine + " " + argvStrings[argCounter]; + argv[argCounter] = argvStrings[argCounter].c_str(); + argCounter++; } - void StartupParametersBuilder::GetStartupParameters(boost::program_options::variables_map& parameters, const boost::program_options::options_description& options) { - - const char* argv[startupParameters_.size() + 1]; - int argCounter = 0; - argv[0] = "Toto.exe"; - argCounter++; - - std::string cmdLine = ""; - for (StartupParameters::const_iterator it = startupParameters_.begin(); it != startupParameters_.end(); it++) { - char* arg = new char[128]; - snprintf(arg, 128, "--%s=%s", std::get<0>(*it).c_str(), std::get<1>(*it).c_str()); - argv[argCounter] = arg; - cmdLine = cmdLine + " --" + std::get<0>(*it) + "=" + std::get<1>(*it); - argCounter++; - } + std::cout << "simulated cmdLine = \"" << cmdLine.c_str() << "\"\n"; - printf("simulated cmdLine = %s\n", cmdLine.c_str()); - - try - { - boost::program_options::store(boost::program_options::command_line_parser(argCounter, argv). - options(options).run(), parameters); - boost::program_options::notify(parameters); - } - catch (boost::program_options::error& e) - { - printf("Error while parsing the command-line arguments: %s\n", e.what()); - } - + try + { + boost::program_options::store( + boost::program_options::command_line_parser(argCounter, argv.data()). + options(options).run(), parameters); + boost::program_options::notify(parameters); } -} \ No newline at end of file + catch (boost::program_options::error& e) + { + std::cerr << "Error while parsing the command-line arguments: " << + e.what() << std::endl; } + } +} diff -r 03c4b998fcd0 -r 70992b38aa8a Applications/Wasm/StartupParametersBuilder.h --- a/Applications/Wasm/StartupParametersBuilder.h Mon Apr 29 14:40:01 2019 +0200 +++ b/Applications/Wasm/StartupParametersBuilder.h Mon Apr 29 15:09:48 2019 +0200 @@ -43,8 +43,12 @@ public: void Clear(); + // Please note that if a parameter is a flag-style one, the value that + // is passed should be an empty string void SetStartupParameter(const char* name, const char* value); - void GetStartupParameters(boost::program_options::variables_map& parameters_, const boost::program_options::options_description& options); + void GetStartupParameters( + boost::program_options::variables_map& parameters_, + const boost::program_options::options_description& options); }; } diff -r 03c4b998fcd0 -r 70992b38aa8a Platforms/Wasm/Defaults.cpp --- a/Platforms/Wasm/Defaults.cpp Mon Apr 29 14:40:01 2019 +0200 +++ b/Platforms/Wasm/Defaults.cpp Mon Apr 29 15:09:48 2019 +0200 @@ -5,9 +5,12 @@ #include #include "Framework/Widgets/TestCairoWidget.h" #include +#include +#include +#include + #include -#include "Applications/Wasm/StartupParametersBuilder.h" -#include "Platforms/Wasm/WasmPlatformApplicationAdapter.h" + static unsigned int width_ = 0; static unsigned int height_ = 0; @@ -88,6 +91,10 @@ printf("StartWasmApplication\n"); + Orthanc::Logging::SetErrorWarnInfoTraceLoggingFunctions( + stone_console_error, stone_console_warning, + stone_console_info, stone_console_trace); + // recreate a command line from uri arguments and parse it boost::program_options::variables_map parameters; boost::program_options::options_description options; @@ -106,6 +113,16 @@ printf("StartWasmApplication - completed\n"); } + bool EMSCRIPTEN_KEEPALIVE WasmIsTraceLevelEnabled() + { + return Orthanc::Logging::IsTraceLevelEnabled(); + } + + bool EMSCRIPTEN_KEEPALIVE WasmIsInfoLevelEnabled() + { + return Orthanc::Logging::IsInfoLevelEnabled(); + } + void EMSCRIPTEN_KEEPALIVE WasmDoAnimation() { for (auto viewport : viewports_) { diff -r 03c4b998fcd0 -r 70992b38aa8a Platforms/Wasm/Defaults.h --- a/Platforms/Wasm/Defaults.h Mon Apr 29 14:40:01 2019 +0200 +++ b/Platforms/Wasm/Defaults.h Mon Apr 29 15:09:48 2019 +0200 @@ -18,7 +18,11 @@ extern void ScheduleWebViewportRedrawFromCpp(ViewportHandle cppViewportHandle); extern void UpdateStoneApplicationStatusFromCppWithString(const char* statusUpdateMessage); extern void UpdateStoneApplicationStatusFromCppWithSerializedMessage(const char* statusUpdateMessage); - + extern void stone_console_error(const char*); + extern void stone_console_warning(const char*); + extern void stone_console_info(const char*); + extern void stone_console_trace(const char*); + // C++ methods accessible from JS extern void EMSCRIPTEN_KEEPALIVE CreateWasmApplication(ViewportHandle cppViewportHandle); extern void EMSCRIPTEN_KEEPALIVE SetStartupParameter(const char* keyc, const char* value); diff -r 03c4b998fcd0 -r 70992b38aa8a Platforms/Wasm/default-library.js --- a/Platforms/Wasm/default-library.js Mon Apr 29 14:40:01 2019 +0200 +++ b/Platforms/Wasm/default-library.js Mon Apr 29 15:09:48 2019 +0200 @@ -1,21 +1,49 @@ // this file contains the JS method you want to expose to C++ code mergeInto(LibraryManager.library, { + ScheduleWebViewportRedrawFromCpp: function(cppViewportHandle) { window.ScheduleWebViewportRedraw(cppViewportHandle); }, + CreateWasmViewportFromCpp: function(htmlCanvasId) { return window.CreateWasmViewport(htmlCanvasId); }, + // each time the StoneApplication updates its status, it may signal it // through this method. i.e, to change the status of a button in the web interface UpdateStoneApplicationStatusFromCppWithString: function(statusUpdateMessage) { var statusUpdateMessage_ = UTF8ToString(statusUpdateMessage); window.UpdateWebApplicationWithString(statusUpdateMessage_); }, + // same, but with a serialized message UpdateStoneApplicationStatusFromCppWithSerializedMessage: function(statusUpdateMessage) { var statusUpdateMessage_ = UTF8ToString(statusUpdateMessage); window.UpdateWebApplicationWithSerializedMessage(statusUpdateMessage_); + }, + + // These functions are called from C++ (through an extern declaration) + // and call the standard logger that, here, routes to the console. + + stone_console_error : function(message) { + var text = UTF8ToString(message); + window.errorFromCpp(text); + }, + + stone_console_warning : function(message) { + var text = UTF8ToString(message); + window.warningFromCpp(text); + }, + + stone_console_info: function(message) { + var text = UTF8ToString(message); + window.infoFromCpp(text); + }, + + stone_console_trace : function(message) { + var text = UTF8ToString(message); + window.debugFromCpp(text); } + }); diff -r 03c4b998fcd0 -r 70992b38aa8a Platforms/Wasm/logger.ts --- a/Platforms/Wasm/logger.ts Mon Apr 29 14:40:01 2019 +0200 +++ b/Platforms/Wasm/logger.ts Mon Apr 29 15:09:48 2019 +0200 @@ -10,6 +10,10 @@ this._debug(LogSource.Typescript, ...args); } + public debugFromCpp(...args: any[]): void { + this._debug(LogSource.Cpp, ...args); + } + public info(...args: any[]): void { this._info(LogSource.Typescript, ...args); } @@ -22,6 +26,10 @@ this._warning(LogSource.Typescript, ...args); } + public warningFromCpp(message: string): void { + this._warning(LogSource.Cpp, message); + } + public error(...args: any[]): void { this._error(LogSource.Typescript, ...args); } @@ -31,13 +39,25 @@ } public _debug(source: LogSource, ...args: any[]): void { - var output = this.getOutput(source, args); - console.debug(...output); + if (( window).IsTraceLevelEnabled) + { + if (( window).IsTraceLevelEnabled()) + { + var output = this.getOutput(source, args); + console.debug(...output); + } + } } private _info(source: LogSource, ...args: any[]): void { - var output = this.getOutput(source, args); - console.info(...output); + if (( window).IsInfoLevelEnabled) + { + if (( window).IsInfoLevelEnabled()) + { + var output = this.getOutput(source, args); + console.info(...output); + } + } } public _warning(source: LogSource, ...args: any[]): void { @@ -88,3 +108,4 @@ } export var defaultLogger: StandardConsoleLogger = new TimeConsoleLogger(); + diff -r 03c4b998fcd0 -r 70992b38aa8a Platforms/Wasm/stone-framework-loader.ts --- a/Platforms/Wasm/stone-framework-loader.ts Mon Apr 29 14:40:01 2019 +0200 +++ b/Platforms/Wasm/stone-framework-loader.ts Mon Apr 29 15:09:48 2019 +0200 @@ -59,6 +59,11 @@ { Logger.defaultLogger.debug('Initializing WebAssembly Module'); + ( window).errorFromCpp = function(text:any) { Logger.defaultLogger.errorFromCpp(text); }; + ( window).warningFromCpp = function(text:any) { Logger.defaultLogger.warningFromCpp(text); }; + ( window).infoFromCpp = function(text:any) { Logger.defaultLogger.infoFromCpp(text); }; + ( window).debugFromCpp = function(text:any) { Logger.defaultLogger.debugFromCpp(text); }; + // ( window). ( window).StoneFrameworkModule = { preRun: [ diff -r 03c4b998fcd0 -r 70992b38aa8a Platforms/Wasm/wasm-application-runner.ts --- a/Platforms/Wasm/wasm-application-runner.ts Mon Apr 29 14:40:01 2019 +0200 +++ b/Platforms/Wasm/wasm-application-runner.ts Mon Apr 29 15:09:48 2019 +0200 @@ -27,7 +27,8 @@ WasmDoAnimation(); } - setTimeout(DoAnimationThread, 100); // Update the viewport content every 100ms if need be + // Update the viewport content every 100ms if need be + setTimeout(DoAnimationThread, 100); } function GetUriParameters(): Map { @@ -42,10 +43,12 @@ var tmp = tokens[i].split('='); if (tmp.length == 2) { result[tmp[0]] = decodeURIComponent(tmp[1]); + } else if(tmp.length == 1) { + // if there is no '=', we treat ot afterwards as a flag-style param + result[tmp[0]] = ""; } } - - return result; + return result; } else { return new Map(); @@ -65,6 +68,8 @@ for (let key in parameters) { if (parameters.hasOwnProperty(key)) { + Logger.defaultLogger.debug( + `About to call SetStartupParameter("${key}","${parameters[key]}")`); SetStartupParameter(key, parameters[key]); } } @@ -92,6 +97,8 @@ CreateCppViewport = ( window).StoneFrameworkModule.cwrap('CreateCppViewport', 'number', []); ReleaseCppViewport = ( window).StoneFrameworkModule.cwrap('ReleaseCppViewport', null, ['number']); StartWasmApplication = ( window).StoneFrameworkModule.cwrap('StartWasmApplication', null, ['string']); + ( window).IsTraceLevelEnabled = ( window).StoneFrameworkModule.cwrap('WasmIsTraceLevelEnabled', 'boolean', null); + ( window).IsInfoLevelEnabled = ( window).StoneFrameworkModule.cwrap('WasmIsInfoLevelEnabled', 'boolean', null); ( window).WasmWebService_NotifyCachedSuccess = ( window).StoneFrameworkModule.cwrap('WasmWebService_NotifyCachedSuccess', null, ['number']); ( window).WasmWebService_NotifySuccess = ( window).StoneFrameworkModule.cwrap('WasmWebService_NotifySuccess', null, ['number', 'string', 'array', 'number', 'number']);