# HG changeset patch # User Sebastien Jodogne # Date 1579881983 -3600 # Node ID 8afc14fab01f7921e5be72d46410a05ae858dc74 # Parent 649489b9bfdb4b13ddfd5297edb96182877c1498 New sample plugin: ConnectivityChecks diff -r 649489b9bfdb -r 8afc14fab01f CMakeLists.txt --- a/CMakeLists.txt Thu Jan 23 18:00:08 2020 +0100 +++ b/CMakeLists.txt Fri Jan 24 17:06:23 2020 +0100 @@ -37,6 +37,7 @@ SET(BUILD_MODALITY_WORKLISTS ON CACHE BOOL "Whether to build the sample plugin to serve modality worklists") SET(BUILD_RECOVER_COMPRESSED_FILE ON CACHE BOOL "Whether to build the companion tool to recover files compressed using Orthanc") SET(BUILD_SERVE_FOLDERS ON CACHE BOOL "Whether to build the ServeFolders plugin") +SET(BUILD_CONNECTIVITY_CHECKS ON CACHE BOOL "Whether to build the ConnectivityChecks plugin") SET(ENABLE_PLUGINS ON CACHE BOOL "Enable plugins") SET(UNIT_TESTS_WITH_HTTP_CONNEXIONS ON CACHE BOOL "Allow unit tests to make HTTP requests") @@ -461,6 +462,65 @@ ##################################################################### +## Build the "ConnectivityChecks" plugin +##################################################################### + +if (ENABLE_PLUGINS AND BUILD_CONNECTIVITY_CHECKS) + include(ExternalProject) + + unset(Flags) + + if (CMAKE_TOOLCHAIN_FILE) + # Take absolute path to the toolchain + get_filename_component(TMP ${CMAKE_TOOLCHAIN_FILE} REALPATH BASE ${CMAKE_SOURCE_DIR}) + list(APPEND Flags -DCMAKE_TOOLCHAIN_FILE=${TMP}) + endif() + + if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") + list(APPEND Flags + -DLSB_CC=$ENV{LSB_CC} + -DLSB_CXX=$ENV{LSB_CXX} + ) + endif() + + externalproject_add(ConnectivityChecksProject + SOURCE_DIR "${ORTHANC_ROOT}/Plugins/Samples/ConnectivityChecks" + + CMAKE_ARGS + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DPLUGIN_VERSION=${ORTHANC_VERSION} + -DSTATIC_BUILD=${STATIC_BUILD} + -DUSE_LEGACY_JSONCPP=${USE_LEGACY_JSONCPP} + ${Flags} + + INSTALL_COMMAND "" # Skip the install step + ) + + ExternalProject_Get_Property(ConnectivityChecksProject binary_dir) + + if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + if (MSVC) + set(Prefix "") + else() + set(Prefix "lib") # MinGW + endif() + + install(FILES + ${binary_dir}/${Prefix}OrthancChecks.dll + DESTINATION "lib") + else() + list(GET CMAKE_FIND_LIBRARY_PREFIXES 0 Prefix) + list(GET CMAKE_FIND_LIBRARY_SUFFIXES 0 Suffix) + install(FILES + ${binary_dir}/${Prefix}OrthancChecks${Suffix} + ${binary_dir}/${Prefix}OrthancChecks${Suffix}.${ORTHANC_VERSION} + DESTINATION "share/orthanc/plugins") + endif() +endif() + + + +##################################################################### ## Build the companion tool to recover files compressed using Orthanc ##################################################################### diff -r 649489b9bfdb -r 8afc14fab01f NEWS --- a/NEWS Thu Jan 23 18:00:08 2020 +0100 +++ b/NEWS Fri Jan 24 17:06:23 2020 +0100 @@ -1,6 +1,11 @@ Pending changes in the mainline =============================== +Plugins +------- + +* New sample plugin: "ConnectivityChecks" + REST API -------- diff -r 649489b9bfdb -r 8afc14fab01f Plugins/Samples/ConnectivityChecks/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/ConnectivityChecks/CMakeLists.txt Fri Jan 24 17:06:23 2020 +0100 @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 2.8) + +project(ConnectivityChecks) + +SET(PLUGIN_NAME "connectivity-checks" CACHE STRING "Name of the plugin") +SET(PLUGIN_VERSION "mainline" CACHE STRING "Version of the plugin") + +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../Resources/CMake/OrthancFrameworkParameters.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../Resources/CMake/OrthancFrameworkConfiguration.cmake) + +include(JavaScriptLibraries.cmake) + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + execute_process( + COMMAND + ${PYTHON_EXECUTABLE} ${ORTHANC_ROOT}/Resources/WindowsResources.py + ${PLUGIN_VERSION} ConnectivityChecks ConnectivityChecks.dll "Orthanc plugin to serve additional folders" + ERROR_VARIABLE Failure + OUTPUT_FILE ${AUTOGENERATED_DIR}/ConnectivityChecks.rc + ) + + if (Failure) + message(FATAL_ERROR "Error while computing the version information: ${Failure}") + endif() + + list(APPEND ADDITIONAL_RESOURCES ${AUTOGENERATED_DIR}/ConnectivityChecks.rc) +endif() + +EmbedResources( + WEB_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/WebResources + LIBRARIES ${JAVASCRIPT_LIBS_DIR} + ) + +add_definitions( + -DHAS_ORTHANC_EXCEPTION=1 + -DORTHANC_ENABLE_LOGGING_PLUGIN=1 + -DORTHANC_PLUGIN_NAME="${PLUGIN_NAME}" + -DORTHANC_PLUGIN_VERSION="${PLUGIN_VERSION}" + ) + +include_directories( + ${ORTHANC_ROOT}/Plugins/Include/ + ) + +add_library(OrthancChecks SHARED + ${ADDITIONAL_RESOURCES} + ${AUTOGENERATED_SOURCES} + ${ORTHANC_CORE_SOURCES_DEPENDENCIES} + ${ORTHANC_ROOT}/Core/Enumerations.cpp + ${ORTHANC_ROOT}/Core/Logging.cpp + ${ORTHANC_ROOT}/Core/SystemToolbox.cpp + ${ORTHANC_ROOT}/Core/Toolbox.cpp + Plugin.cpp + ) + +set_target_properties( + OrthancChecks PROPERTIES + VERSION ${PLUGIN_VERSION} + SOVERSION ${PLUGIN_VERSION} + ) diff -r 649489b9bfdb -r 8afc14fab01f Plugins/Samples/ConnectivityChecks/JavaScriptLibraries.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/ConnectivityChecks/JavaScriptLibraries.cmake Fri Jan 24 17:06:23 2020 +0100 @@ -0,0 +1,42 @@ +set(BASE_URL "http://orthanc.osimis.io/ThirdPartyDownloads") + +DownloadPackage( + "da0189f7c33bf9f652ea65401e0a3dc9" + "${BASE_URL}/dicom-web/bootstrap-4.3.1.zip" + "${CMAKE_CURRENT_BINARY_DIR}/bootstrap-4.3.1") + +DownloadPackage( + "8242afdc5bd44105d9dc9e6535315484" + "${BASE_URL}/dicom-web/vuejs-2.6.10.tar.gz" + "${CMAKE_CURRENT_BINARY_DIR}/vue-2.6.10") + +DownloadPackage( + "3e2b4e1522661f7fcf8ad49cb933296c" + "${BASE_URL}/dicom-web/axios-0.19.0.tar.gz" + "${CMAKE_CURRENT_BINARY_DIR}/axios-0.19.0") + +DownloadFile( + "220afd743d9e9643852e31a135a9f3ae" + "${BASE_URL}/jquery-3.4.1.min.js") + + +set(JAVASCRIPT_LIBS_DIR ${CMAKE_CURRENT_BINARY_DIR}/javascript-libs) +file(MAKE_DIRECTORY ${JAVASCRIPT_LIBS_DIR}) + +file(COPY + ${CMAKE_CURRENT_BINARY_DIR}/axios-0.19.0/dist/axios.min.js + ${CMAKE_CURRENT_BINARY_DIR}/axios-0.19.0/dist/axios.min.map + ${CMAKE_CURRENT_BINARY_DIR}/bootstrap-4.3.1/dist/js/bootstrap.min.js + ${CMAKE_CURRENT_BINARY_DIR}/bootstrap-4.3.1/dist/js/bootstrap.min.js.map + ${CMAKE_CURRENT_BINARY_DIR}/vue-2.6.10/dist/vue.min.js + ${CMAKE_SOURCE_DIR}/ThirdPartyDownloads/jquery-3.4.1.min.js + DESTINATION + ${JAVASCRIPT_LIBS_DIR}/js + ) + +file(COPY + ${CMAKE_CURRENT_BINARY_DIR}/bootstrap-4.3.1/dist/css/bootstrap.min.css + ${CMAKE_CURRENT_BINARY_DIR}/bootstrap-4.3.1/dist/css/bootstrap.min.css.map + DESTINATION + ${JAVASCRIPT_LIBS_DIR}/css + ) diff -r 649489b9bfdb -r 8afc14fab01f Plugins/Samples/ConnectivityChecks/Plugin.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/ConnectivityChecks/Plugin.cpp Fri Jan 24 17:06:23 2020 +0100 @@ -0,0 +1,124 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include +#include + +#include "../../../Core/OrthancException.h" +#include "../../../Core/SystemToolbox.h" + +#define ROOT_URI "/connectivity-checks" + + +static OrthancPluginContext* context_ = NULL; + + +template +static OrthancPluginErrorCode ServeStaticResource(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) +{ + if (request->method != OrthancPluginHttpMethod_Get) + { + OrthancPluginSendMethodNotAllowed(context_, output, "GET"); + return OrthancPluginErrorCode_Success; + } + + std::string path = "/" + std::string(request->groups[0]); + std::string mime = Orthanc::EnumerationToString(Orthanc::SystemToolbox::AutodetectMimeType(path)); + + try + { + std::string s; + Orthanc::EmbeddedResources::GetDirectoryResource(s, DIRECTORY, path.c_str()); + + const char* resource = s.size() ? s.c_str() : NULL; + OrthancPluginAnswerBuffer(context_, output, resource, s.size(), mime.c_str()); + } + catch (Orthanc::OrthancException&) + { + std::string s = "Unknown static resource in plugin: " + std::string(request->groups[0]); + OrthancPluginLogError(context_, s.c_str()); + OrthancPluginSendHttpStatusCode(context_, output, 404); + } + + return OrthancPluginErrorCode_Success; +} + + + +extern "C" +{ + ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c) + { + context_ = c; + + /* Check the version of the Orthanc core */ + if (OrthancPluginCheckVersion(c) == 0) + { + char info[256]; + sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin", + c->orthancVersion, + ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, + ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, + ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); + OrthancPluginLogError(context_, info); + return -1; + } + + /* Register the callbacks */ + OrthancPluginSetDescription(context_, "Utilities to check connectivity to DICOM modalities and Orthanc peers."); + OrthancPluginSetRootUri(context_, ROOT_URI "/app/index.html"); + OrthancPluginRegisterRestCallback(context_, ROOT_URI "/libs/(.*)", ServeStaticResource); + OrthancPluginRegisterRestCallback(context_, ROOT_URI "/app/(.*)", ServeStaticResource); + + return 0; + } + + + ORTHANC_PLUGINS_API void OrthancPluginFinalize() + { + } + + + ORTHANC_PLUGINS_API const char* OrthancPluginGetName() + { + return ORTHANC_PLUGIN_NAME; + } + + + ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() + { + return ORTHANC_PLUGIN_VERSION; + } +} diff -r 649489b9bfdb -r 8afc14fab01f Plugins/Samples/ConnectivityChecks/WebResources/app.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/ConnectivityChecks/WebResources/app.js Fri Jan 24 17:06:23 2020 +0100 @@ -0,0 +1,145 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +new Vue({ + el: '#app', + data: { + dicomNodes: {}, + peers: [], + canTestPeers: false, + dicomWebServers: [] + }, + methods: { + toggle: function (todo) { + todo.done = !todo.done + }, + + testDicomModalities: function () { + console.log('testing DICOM modalities'); + axios + .get('../../modalities?expand') + .then(response => { + this.dicomNodes = response.data; + for (let alias of Object.keys(this.dicomNodes)) { + this.dicomNodes[alias]['alias'] = alias; + this.dicomNodes[alias]['status'] = 'testing'; + axios + .post('../../modalities/' + alias + '/echo') + .then(response => { + this.dicomNodes[alias]['status'] = 'ok'; + this.$forceUpdate(); + }) + .catch(response => { + this.dicomNodes[alias]['status'] = 'ko'; + this.$forceUpdate(); + }) + } + }) + }, + + testOrthancPeers: function () { + console.log('testing Orthanc peers'); + axios + .get('../../peers?expand') + .then(response => { + this.peers = response.data; + for (let alias of Object.keys(this.peers)) { + this.peers[alias]['alias'] = alias; + + if (this.canTestPeers) { + this.peers[alias]['status'] = 'testing'; + axios + .get('../../peers/' + alias + '/system') // introduced in ApiVersion 5 only ! + .then(response => { + this.peers[alias]['status'] = 'ok'; + this.$forceUpdate(); + }) + .catch(response => { + this.peers[alias]['status'] = 'ko'; + this.$forceUpdate(); + }) + } + else { + this.peers[alias]['status'] = 'unknown'; + this.$forceUpdate(); + } + } + }) + }, + + testDicomWebServers: function () { + console.log('testing Dicom-web servers'); + axios + .get('../../dicom-web/servers?expand') + .then(response => { + this.dicomWebServers = response.data; + for (let alias of Object.keys(this.dicomWebServers)) { + this.dicomWebServers[alias]['alias'] = alias; + this.dicomWebServers[alias]['status'] = 'testing'; + + // perform a dummy qido-rs to test the connectivity + axios + .post('../../dicom-web/servers/' + alias + '/qido', { + 'Uri' : '/studies', + 'Arguments' : { + '00100010' : 'CONNECTIVITY^CHECKS' + } + }) + .then(response => { + this.dicomWebServers[alias]['status'] = 'ok'; + this.$forceUpdate(); + }) + .catch(response => { + this.dicomWebServers[alias]['status'] = 'ko'; + this.$forceUpdate(); + }) + } + }) + }, + + }, + computed: { + }, + mounted() { + axios + .get('../../system') + .then(response => { + this.canTestPeers = response.data.ApiVersion >= 5; + this.testDicomModalities(); + if (this.canTestPeers) { + this.testOrthancPeers(); + } + this.testDicomWebServers(); + }) + } +}) diff -r 649489b9bfdb -r 8afc14fab01f Plugins/Samples/ConnectivityChecks/WebResources/index.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/ConnectivityChecks/WebResources/index.html Fri Jan 24 17:06:23 2020 +0100 @@ -0,0 +1,100 @@ + + + + + + + + Orthanc Connectivity checks + + + + +
+

DICOM nodes

+ + + + + + + + + + + + + + + + + + + + + +
AliasAETHostPortStatus
{{node.alias}}{{node.AET}}{{node.Host}}{{node.Port}}ConnectedDisconnected +
+ Testing... +
+
+ +

Orthanc peers

+ + + + + + + + + + + + + + + + + + +
AliasUrlStatus
{{node.alias}}{{node.Url}}ConnectedDisconnected + Can not test the peers connectivity with this version of Orthanc + +
+ Testing... +
+
+ +

DicomWeb servers

+ + + + + + + + + + + + + + + + + +
AliasUrlStatus
{{node.alias}}{{node.Url}}ConnectedDisconnected +
+ Testing... +
+
+
+ + + + + + + + diff -r 649489b9bfdb -r 8afc14fab01f Plugins/Samples/ConnectivityChecks/WebResources/style.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/ConnectivityChecks/WebResources/style.css Fri Jan 24 17:06:23 2020 +0100 @@ -0,0 +1,13 @@ +.connected { + background-color: darkgreen; + color: white; +} + +.disconnected { + background-color: darkred; + color: white; +} + +.unknown { + background-color: gold; +}