pax_global_header00006660000000000000000000000064146407706700014525gustar00rootroot0000000000000052 comment=8ecc026ade0ec6af6d6d0b23879a25a7534300ca xeus-zmq-3.1.0/000077500000000000000000000000001464077067000133175ustar00rootroot00000000000000xeus-zmq-3.1.0/.github/000077500000000000000000000000001464077067000146575ustar00rootroot00000000000000xeus-zmq-3.1.0/.github/workflows/000077500000000000000000000000001464077067000167145ustar00rootroot00000000000000xeus-zmq-3.1.0/.github/workflows/main.yml000066400000000000000000000061451464077067000203710ustar00rootroot00000000000000name: CI on: workflow_dispatch: push: branches: - main pull_request: branches: - main jobs: unix: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-20.04, ubuntu-22.04, macos-12, macos-13] xeus_static_dependencies: [0] xeus_build_shared_lib: [1] include: - os: ubuntu-20.04 xeus_static_dependencies: 1 xeus_build_shared_lib: 0 - os: ubuntu-22.04 xeus_static_dependencies: 1 xeus_build_shared_lib: 0 steps: - uses: actions/checkout@v4 - name: Install micromamba uses: mamba-org/setup-micromamba@v1 with: environment-file: environment-dev.yml environment-name: xeus-zmq init-shell: bash - name: Create build directory shell: bash -l {0} run: mkdir -p build - name: Configure cmake shell: bash -l {0} run: | cmake .. \ -DXEUS_ZMQ_BUILD_TESTS=ON \ -DCMAKE_PREFIX_PATH=$CONDA_PREFIX \ -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX \ -DXEUS_STATIC_DEPENDENCIES=${{ matrix.xeus_static_dependencies }} \ -DXEUS_BUILD_SHARED_LIBS=${{ matrix.xeus_build_shared_lib }} working-directory: build - name: Build shell: bash -l {0} run: make -j ${{ runner.os == 'macOS' && 3 || 4 }} working-directory: build - name: Test xeus-zmq uses: nick-invision/retry@v3 with: timeout_minutes: 4 max_attempts: 4 shell: bash command: | cd build/test ctest --output-on-failure - name: Install xeus-zmq shell: bash -l {0} run: make install working-directory: build win: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ windows-2019, windows-2022 ] steps: - uses: actions/checkout@v4 - name: Install micromamba uses: mamba-org/setup-micromamba@v1 with: environment-file: environment-dev.yml environment-name: xeus-zmq init-shell: cmd.exe - name: Make build directory run: mkdir build - name: Configure cmake shell: cmd /C call {0} run: | cmake .. ^ -G Ninja ^ -DCMAKE_BUILD_TYPE=Release ^ -DXEUS_ZMQ_BUILD_TESTS=ON ^ -DDEPENDENCY_SEARCH_PREFIX="%CONDA_PREFIX%\Library" ^ -DCMAKE_PREFIX_PATH="%CONDA_PREFIX%\Library" ^ -DCMAKE_INSTALL_PREFIX="%CONDA_PREFIX%" working-directory: build - name: Build shell: cmd /C call {0} run: | set CL=/MP ninja install working-directory: build - name: ctest uses: nick-invision/retry@v3 with: timeout_minutes: 4 max_attempts: 4 shell: cmd command: | set PATH=%CONDA_PREFIX%;%CONDA_PREFIX%\\Scripts;%CONDA_PREFIX%\\Library;%CONDA_PREFIX%\\Library\\bin;%PATH% cd build ctest --output-on-failure xeus-zmq-3.1.0/.gitignore000066400000000000000000000005631464077067000153130ustar00rootroot00000000000000# Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod *.smod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app build/ test/__pycache__/ # Documentation build artefacts docs/CMakeCache.txt docs/xml/ docs/build/ xeus-zmq-3.1.0/CMakeLists.txt000066400000000000000000000410241464077067000160600ustar00rootroot00000000000000############################################################################ # Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou # # Copyright (c) 2016, QuantStack # # # # Distributed under the terms of the BSD 3-Clause License. # # # # The full license is in the file LICENSE, distributed with this software. # ############################################################################ cmake_minimum_required(VERSION 3.8) project(xeus-zmq) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}") set(XEUS_ZMQ_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) set(XEUS_ZMQ_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) set(XEUS_ZMQ_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test) # Versionning # =========== # Project version file(STRINGS "${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xeus-zmq.hpp" xeus_zmq_version_defines REGEX "#define XEUS_ZMQ_VERSION_(MAJOR|MINOR|PATCH)") foreach(ver ${xeus_zmq_version_defines}) if(ver MATCHES "#define XEUS_ZMQ_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$") set(XEUS_ZMQ_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "") endif() endforeach() set(XEUS_ZMQ_VERSION ${XEUS_ZMQ_VERSION_MAJOR}.${XEUS_ZMQ_VERSION_MINOR}.${XEUS_ZMQ_VERSION_PATCH}) message(STATUS "xeus-zmq version: v${XEUS_ZMQ_VERSION}") # Binary version # See the following URL for explanations about the binary versionning # https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info file(STRINGS "${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xeus-zmq.hpp" xeus_zmq_version_defines REGEX "#define XEUS_ZMQ_BINARY_(CURRENT|REVISION|AGE)") foreach(ver ${xeus_zmq_version_defines}) if(ver MATCHES "#define XEUS_ZMQ_BINARY_(CURRENT|REVISION|AGE) +([^ ]+)$") set(XEUS_ZMQ_BINARY_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "") endif() endforeach() set(XEUS_ZMQ_BINARY_VERSION ${XEUS_ZMQ_BINARY_CURRENT}.${XEUS_ZMQ_BINARY_REVISION}.${XEUS_ZMQ_BINARY_AGE}) message(STATUS "xeus-zmq binary version: v${XEUS_ZMQ_BINARY_VERSION}") # Build options # ============= # Compilation options option(XEUS_ZMQ_BUILD_SHARED_LIBS "Build xeus shared library." ON) option(XEUS_ZMQ_BUILD_STATIC_LIBS "Build xeus static library (default if BUILD_SHARED_LIBS is OFF)." ON) option(XEUS_ZMQ_STATIC_DEPENDENCIES "link statically with xeus dependencies" OFF) # Test options option(XEUS_ZMQ_BUILD_TESTS "xeus test suite" OFF) # Option to build without libsodium option(XEUS_ZMQ_BUILD_WITHOUT_LIBSODIUM "Build xeus-zmq without libsodium" OFF) # Static build configuration # ========================== if (XEUS_ZMQ_STATIC_DEPENDENCIES) set(CPPZMQ_TARGET_NAME cppzmq-static) set(XEUS_TARGET_NAME xeus-static) set(OPENSSL_USE_STATIC_LIBS ON CACHE BOOL "Linking statically with OpenSSL") else() set(CPPZMQ_TARGET_NAME cppzmq) set(XEUS_TARGET_NAME xeus) set(OPENSSL_USE_STATIC_LIBS OFF CACHE BOOL "Not linking statically with OpenSSL") endif() # Print build configuration # ========================== message(STATUS "XEUS_ZMQ_BUILD_SHARED_LIBS: ${XEUS_ZMQ_BUILD_SHARED_LIBS}") message(STATUS "XEUS_ZMQ_BUILD_STATIC_LIBS: ${XEUS_ZMQ_BUILD_STATIC_LIBS}") message(STATUS "XEUS_ZMQ_STATIC_DEPENDENCIES: ${XEUS_ZMQ_STATIC_DEPENDENCIES}") message(STATUS "XEUS_ZMQ_BUILD_TESTS: ${XEUS_ZMQ_BUILD_TESTS}") # Dependencies # ============ set(xeus_REQUIRED_VERSION 5.0.0) set(nlohmann_json_REQUIRED_VERSION 3.11.3) set(cppzmq_REQUIRED_VERSION 4.8.1) set(zeromq_REQUIRED_VERSION 4.3.2) if (NOT TARGET xeus AND NOT TARGET xeus-static) find_package(xeus ${xeus_REQUIRED_VERSION} REQUIRED) message(STATUS "Found xeus ${xeus_VERSION}") endif () if (NOT TARGET nlohmann_json) find_package(nlohmann_json ${nlohmann_json_REQUIRED_VERSION} REQUIRED) message(STATUS "Found nlohmann_json ${nlohmann_json_VERSION}") endif () if (NOT TARGET cppzmq AND NOT TARGET cppzmq-static) find_package(cppzmq ${cppzmq_REQUIRED_VERSION} REQUIRED) message(STATUS "Found cppzmq ${cppzmq_VERSION}") endif () if (NOT TARGET libzmq AND NOT TARGET libzmq-static) if (WIN32) find_package(zeromq ${zeromq_REQUIRED_VERSION} REQUIRED) else () find_package(zeromq ${zeromq_REQUIRED_VERSION} QUIET) if (NOT ZeroMQ_FOUND) message(STATUS "CMake libzmq package not found, trying again with pkg-config") find_package(PkgConfig) pkg_check_modules(ZeroMQ libzmq>=${zeromq_REQUIRED_VERSION} REQUIRED) set(ZeroMQ_VERSION ${PC_LIBZMQ_VERSION}) find_library(ZeroMQ_LIBRARY NAMES libzmq.so libzmq.dylib libzmq.dll PATHS ${PC_LIBZMQ_LIBDIR} ${PC_LIBZMQ_LIBRARY_DIRS}) find_library(ZeroMQ_STATIC_LIBRARY NAMES libzmq-static.a libzmq.a libzmq.dll.a PATHS ${PC_LIBZMQ_LIBDIR} ${PC_LIBZMQ_LIBRARY_DIRS}) message(STATUS "STATIC_LIBRARY" {ZeroMQ_LIBRARY}) message(STATUS "STATIC_STATIC_LIBRARY" {ZeroMQ_STATIC_LIBRARY}) endif () endif () endif () find_package(OpenSSL REQUIRED) # Source files # ============ set(XEUS_ZMQ_HEADERS ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xclient_zmq.hpp ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xcontrol_default_runner.hpp ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xcontrol_runner.hpp ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xdap_tcp_client.hpp ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xdebugger_base.hpp ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xeus-zmq.hpp ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xmiddleware.hpp ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xserver_zmq.hpp ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xserver_zmq_split.hpp ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xshell_default_runner.hpp ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xshell_runner.hpp ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xthread.hpp ${XEUS_ZMQ_INCLUDE_DIR}/xeus-zmq/xzmq_context.hpp ) set(XEUS_ZMQ_SOURCES ${XEUS_ZMQ_SOURCE_DIR}/client/xclient_zmq.cpp ${XEUS_ZMQ_SOURCE_DIR}/client/xclient_messenger.hpp ${XEUS_ZMQ_SOURCE_DIR}/client/xclient_messenger.cpp ${XEUS_ZMQ_SOURCE_DIR}/client/xclient_zmq_impl.hpp ${XEUS_ZMQ_SOURCE_DIR}/client/xclient_zmq_impl.cpp ${XEUS_ZMQ_SOURCE_DIR}/client/xdealer_channel.hpp ${XEUS_ZMQ_SOURCE_DIR}/client/xdealer_channel.cpp ${XEUS_ZMQ_SOURCE_DIR}/client/xheartbeat_client.hpp ${XEUS_ZMQ_SOURCE_DIR}/client/xheartbeat_client.cpp ${XEUS_ZMQ_SOURCE_DIR}/client/xiopub_client.hpp ${XEUS_ZMQ_SOURCE_DIR}/client/xiopub_client.cpp ${XEUS_ZMQ_SOURCE_DIR}/common/xauthentication.cpp ${XEUS_ZMQ_SOURCE_DIR}/common/xauthentication.hpp ${XEUS_ZMQ_SOURCE_DIR}/common/xmiddleware.cpp ${XEUS_ZMQ_SOURCE_DIR}/common/xmiddleware_impl.hpp ${XEUS_ZMQ_SOURCE_DIR}/common/xzmq_context.cpp ${XEUS_ZMQ_SOURCE_DIR}/common/xzmq_serializer.cpp ${XEUS_ZMQ_SOURCE_DIR}/common/xzmq_serializer.hpp ${XEUS_ZMQ_SOURCE_DIR}/debugger/xdap_tcp_client.cpp ${XEUS_ZMQ_SOURCE_DIR}/debugger/xdap_tcp_client_impl.cpp ${XEUS_ZMQ_SOURCE_DIR}/debugger/xdap_tcp_client_impl.hpp ${XEUS_ZMQ_SOURCE_DIR}/debugger/xdebugger_base.cpp ${XEUS_ZMQ_SOURCE_DIR}/debugger/xdebugger_middleware.cpp ${XEUS_ZMQ_SOURCE_DIR}/debugger/xdebugger_middleware.hpp ${XEUS_ZMQ_SOURCE_DIR}/server/xcontrol_default_runner.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xcontrol_runner.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xcontrol.hpp ${XEUS_ZMQ_SOURCE_DIR}/server/xcontrol.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xheartbeat.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xheartbeat.hpp ${XEUS_ZMQ_SOURCE_DIR}/server/xpublisher.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xpublisher.hpp ${XEUS_ZMQ_SOURCE_DIR}/server/xserver_control_main.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xserver_control_main.hpp ${XEUS_ZMQ_SOURCE_DIR}/server/xserver_shell_main.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xserver_shell_main.hpp ${XEUS_ZMQ_SOURCE_DIR}/server/xserver_zmq_default.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xserver_zmq_default.hpp ${XEUS_ZMQ_SOURCE_DIR}/server/xserver_zmq_impl.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xserver_zmq_impl.hpp ${XEUS_ZMQ_SOURCE_DIR}/server/xserver_zmq_split.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xserver_zmq_split_impl.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xserver_zmq_split_impl.hpp ${XEUS_ZMQ_SOURCE_DIR}/server/xserver_zmq.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xshell.hpp ${XEUS_ZMQ_SOURCE_DIR}/server/xshell.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xshell_default_runner.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xshell_runner.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xtrivial_messenger.hpp ${XEUS_ZMQ_SOURCE_DIR}/server/xtrivial_messenger.cpp ${XEUS_ZMQ_SOURCE_DIR}/server/xzmq_messenger.hpp ${XEUS_ZMQ_SOURCE_DIR}/server/xzmq_messenger.cpp ) # Targets and link # ================ # Binaries that link with xeus-zmq must be able to find and load # libzmq. However, since xeus-zmq privately links with libzmq, # we need to tell cmake to append to rpath directories containing # linked libraries. set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) include(CheckCXXCompilerFlag) string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) if (XEUS_ZMQ_STATIC_DEPENDENCIES AND NOT MSVC AND NOT APPLE AND NOT XEUS_ZMQ_BUILD_WITHOUT_LIBSODIUM) # Explicitly finds and links with libsodium.a # because it is not exported as a dependency by # the static build of libzmq. Remove this when # it is fixed upstream. set(sodium_USE_STATIC_LIBS ON) find_package(sodium REQUIRED) endif () macro(xeus_zmq_create_target target_name linkage output_name) string(TOUPPER "${linkage}" linkage_upper) if (NOT ${linkage_upper} MATCHES "^(SHARED|STATIC)$") message(FATAL_ERROR "Invalid library linkage: ${linkage}") endif () # Output # ====== add_library(${target_name} ${linkage_upper} ${XEUS_ZMQ_SOURCES} ${XEUS_ZMQ_HEADERS}) target_include_directories( ${target_name} PUBLIC $ $ ) target_link_libraries( ${target_name} PUBLIC nlohmann_json::nlohmann_json PUBLIC ${XEUS_TARGET_NAME} PRIVATE ${CPPZMQ_TARGET_NAME} PRIVATE OpenSSL::Crypto ) if (NOT MSVC) if (APPLE) target_link_libraries(${target_name} PUBLIC "-framework CoreFoundation") else () if (XEUS_ZMQ_STATIC_DEPENDENCIES) target_link_libraries(${target_name} PUBLIC ${sodium_LIBRARY_RELEASE}) endif () endif () endif () if (UNIX) # CMake does not compute the version number of so files as libtool # does on Linux. Strictly speaking, we should exclude FreeBSD and # Apple from this, but that would require having different version # numbers depending on the platform. We prefer to follow the # libtool pattern everywhere. math(EXPR XEUS_ZMQ_BINARY_COMPATIBLE "${XEUS_ZMQ_BINARY_CURRENT} - ${XEUS_ZMQ_BINARY_AGE}") set_target_properties( ${target_name} PROPERTIES PUBLIC_HEADER "${XEUS_ZMQ_HEADERS}" COMPILE_OPTIONS "-fvisibility=hidden" COMPILE_DEFINITIONS "XEUS_ZMQ_EXPORTS" PREFIX "" VERSION "${XEUS_ZMQ_BINARY_COMPATIBLE}.${XEUS_ZMQ_BINARY_REVISION}.${XEUS_ZMQ_BINARY_AGE}" SOVERSION ${XEUS_ZMQ_BINARY_COMPATIBLE} OUTPUT_NAME "lib${output_name}" ) else() set_target_properties( ${target_name} PROPERTIES PUBLIC_HEADER "${XEUS_ZMQ_HEADERS}" COMPILE_DEFINITIONS "XEUS_ZMQ_EXPORTS" PREFIX "" VERSION ${XEUS_ZMQ_BINARY_VERSION} SOVERSION ${XEUS_ZMQ_BINARY_CURRENT} OUTPUT_NAME "lib${output_name}" ) endif() # Compilation flags # ================= target_compile_features(${target_name} PRIVATE cxx_std_17) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") target_compile_options(${target_name} PUBLIC -Wunused-parameter -Wextra -Wreorder) message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") endif() if (${linkage_upper} STREQUAL "STATIC") target_compile_definitions(${target_name} PUBLIC XEUS_ZMQ_STATIC_LIB) endif () if (MSVC) target_compile_definitions(${target_name} PUBLIC -DNOMINMAX) target_compile_options(${target_name} PUBLIC /DGUID_WINDOWS /MP /bigobj) target_compile_options(${target_name} PUBLIC /wd4251 /wd4996) elseif (APPLE) target_compile_definitions(${target_name} PUBLIC -DGUID_CFUUID) else () target_compile_definitions(${target_name} PUBLIC -DGUID_LIBUUID) endif () if (XEUS_ZMQ_STATIC_DEPENDENCIES) if (CMAKE_DL_LIBS) target_link_libraries(${target_name} PRIVATE ${CMAKE_DL_LIBS}) endif () if (UNIX AND NOT APPLE) target_link_libraries(${target_name} PRIVATE util rt) endif () endif () endmacro() set(xeus_zmq_targets "") if (XEUS_ZMQ_BUILD_SHARED_LIBS) xeus_zmq_create_target(xeus-zmq SHARED xeus-zmq) if(CMAKE_TARGET_SYSTEM MATCHES "Linux" AND OPENSSL_USE_STATIC_LIBS) # Do not reexport OpenSSL symbols from xeus, for libraries # Prevents conflicts with other versions of OpenSSL # loaded in the same process namespace, which can cause # crashes if the versions are not compatible. set_target_properties(xeus-zmq PROPERTIES LINK_FLAGS "-Wl,--exclude-libs,libcrypto.a") endif() list(APPEND xeus_zmq_targets xeus-zmq) endif () if (XEUS_ZMQ_BUILD_STATIC_LIBS) # On Windows, a static library should use a different output name # to avoid the conflict with the import library of a shared one. if (CMAKE_HOST_WIN32) xeus_zmq_create_target(xeus-zmq-static STATIC xeus-zmq-static) else () xeus_zmq_create_target(xeus-zmq-static STATIC xeus-zmq) endif () list(APPEND xeus_zmq_targets xeus-zmq-static) endif () # Tests # ===== # We need to control from outside whether we enable testing or not. We cannot # rely on BUILD_TESTING since it doe snot exist until CTest is included. include(CTest) if(XEUS_ZMQ_BUILD_TESTS) set(BUILD_TESTING ON) message(STATUS "tests enabled") else () set(BUILD_TESTING OFF) message(STATUS "tests disabled") endif() if(BUILD_TESTING) add_subdirectory(test) endif() # Installation # ============ include(GNUInstallDirs) include(CMakePackageConfigHelpers) set(XEUS_ZMQ_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE STRING "install path for xeus-zmqConfig.cmake") install(TARGETS ${xeus_zmq_targets} EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/xeus-zmq) # Makes the project importable from the build directory export(EXPORT ${PROJECT_NAME}-targets FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake") # Configure 'xeusConfig.cmake' for a build tree set(XEUS_ZMQ_CONFIG_CODE "####### Expanded from \@XEUS_CONFIG_CODE\@ #######\n") set(XEUS_ZMQ_CONFIG_CODE "${XEUS_ZMQ_CONFIG_CODE}set(CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/cmake;\${CMAKE_MODULE_PATH}\")\n") set(XEUS_ZMQ_CONFIG_CODE "${XEUS_ZMQ_CONFIG_CODE}##################################################") configure_package_config_file(${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION ${PROJECT_BINARY_DIR}) # Configure 'xeusConfig.cmake' for an install tree set(XEUS_ZMQ_CONFIG_CODE "") configure_package_config_file(${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION ${XEUS_ZMQ_CMAKECONFIG_INSTALL_DIR}) write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${XEUS_ZMQ_VERSION} COMPATIBILITY AnyNewerVersion) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake DESTINATION ${XEUS_ZMQ_CMAKECONFIG_INSTALL_DIR}) install(EXPORT ${PROJECT_NAME}-targets FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${XEUS_ZMQ_CMAKECONFIG_INSTALL_DIR}) xeus-zmq-3.1.0/CONTRIBUTING.md000066400000000000000000000031601464077067000155500ustar00rootroot00000000000000# Contributing to Xeus Xeus and xeus-zmq are subprojects of Project Jupyter and subject to the [Jupyter governance](https://github.com/jupyter/governance) and [Code of conduct](https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md). ## General Guidelines For general documentation about contributing to Jupyter projects, see the [Project Jupyter Contributor Documentation](https://jupyter.readthedocs.io/en/latest/contributor/content-contributor.html). ## Community The Xeus team organizes public video meetings. The schedule for future meetings and minutes of past meetings can be found on our [team compass](https://jupyter-xeus.github.io/). ## Setting up a development environment First, you need to fork the project. Then setup your environment: ```bash # create a new conda environment conda create -f environment-dev.yml conda activate xeus-zmq # download Xeus from your GitHub fork git clone https://github.com//xeus-zmq.git ``` You may also want to install a C++ compiler, cmake, and pkg-config from conda if they are not available on your system. Pkg-config is required at build time for locating zeromq and OpenSSL. ## Building and installing xeus-zmq ```bash # Create a directory for building mkdir build && cd build # Generate the makefile with cmake cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_PREFIX_PATH=$CONDA_PREFIX -D CMAKE_INSTALL_PREFIX=$CONDA_PREFIX -D CMAKE_INSTALL_LIBDIR=lib -D XEUS_ZMQ_BUILD_TESTS=ON .. # Build and install make install -j2 ``` ## Running the tests To run ctests, from the build directory, type ```bash cd build/test ctest --output-on-failure ``` xeus-zmq-3.1.0/LICENSE000066400000000000000000000027601464077067000143310ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2022, Jupyter Xeus All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. xeus-zmq-3.1.0/README.md000066400000000000000000000123661464077067000146060ustar00rootroot00000000000000# xeus-zmq [![GithubActions](https://github.com/jupyter-xeus/xeus-zmq/actions/workflows/main.yml/badge.svg)](https://github.com/jupyter-xeus/xeus-zmq/actions/workflows/main.yml) [![Documentation Status](https://readthedocs.org/projects/xeus-zmq/badge/?version=latest)](https://xeus-zmq.readthedocs.io/en/latest/?badge=latest) [![Join the Gitter Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/QuantStack/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ZeroMQ-based middleware for xeus ## Introduction `xeus-zmq` provides various implementations of the [xserver](https://github.com/jupyter-xeus/xeus/blob/main/include/xeus/xserver.hpp) API from `xeus`, based on the [ZeroMQ library](https://zeromq.org/). These implementations all conform to the [Jupyter Kernel Protocol specification](https://jupyter-client.readthedocs.io/en/stable/messaging.html). ## Installation `xeus-zmq` has been packaged on all platforms for the mamba (or conda) package manager. ``` mamba install xeus-zmq -c conda-forge ``` ## Documentation The documentation can be found with that of xeus at http://xeus-zmq.readthedocs.io/ ## Usage `xeus-zmq` provides server building functions that can be passed to the kernel constructor: ```cpp #include #include #include "xeus/xkernel.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus-zmq/xzmq_context.hpp" #include "xeus-zmq/xserver_zmq.hpp" #include "xmock_interpreter.hpp" int main(int argc, char* argv[]) { std::string file_name = (argc == 1) ? "connection.json" : argv[2]; xeus::xconfiguration config = xeus::load_configuration(file_name); auto context = xeus::make_zmq_context(); using interpreter_ptr = std::unique_ptr; interpreter_ptr interpreter = interpreter_ptr(new my_custom_interpreter()); xeus::xkernel kernel(config, xeus::get_user_name(), std::move(context), std::move(interpreter), xeus::make_xserver_default); std::cout << "starting kernel" << std::endl; kernel.start(); return 0; } ``` See the [documentation](http://xeus.readthedocs.io/) for an exhaustive list of the available functions. ### Building from sources `xeus-zmq` depends on the following libraries: [xeus](https://github.com/jupyter-xeus/xeus), [`ZeroMQ`](https://github.com/zeromq/libzmq), [`cppzmq`](https://github.com/zeromq/cppzmq), [`OpenSSL`](https://github.com/openssl/openssl), and [`nlohmann_json`](https://github.com/nlohmann/json). | xeus-zmq | xeus | ZeroMQ | cppzmq | nlohmann json | OpenSSL | |----------|---------|---------|---------|---------------|---------| | main | ^5.0.0 | ^4.2.5 | ^4.8.1 | ^3.11.3 | ^3.0 | | 3.x | ^5.0.0 | ^4.2.5 | ^4.8.1 | ^3.11.3 | ^3.0 | Versions prior to version 3 depend have an additional dependency on [xtl](https://github.com/xtensor-stack/xtl). | xeus-zmq | xeus | ZeroMQ | cppzmq | nlohmann json | OpenSSL | xtl | |----------|---------|---------|---------|---------------|---------|----------------| | main | ^4.0.0 | ^4.2.5 | ^4.8.1 | ^3.11.3 | ^3.0 | >=0.7.0,<0.8.0 | | 2.0.0 | ^4.0.0 | ^4.2.5 | ^4.8.1 | ^3.11.3 | ^3.0 | >=0.7.0,<0.8.0 | | 1.x | ^3.0.0 | ^4.2.5 | ^4.8.1 | ^3.2.0 | ^3.0 | >=0.7.0,<0.8.0 | We have packaged all these dependencies on conda-forge. The simplest way to install them is to run: ```bash mamba install cmake pkg-config zeromq cppzmq OpenSSL nlohmann_json=3.11.2 xeus -c conda-forge ``` Once you have installed the dependencies, you can build and install `xeus-zmq`: ```bash cmake -D CMAKE_BUILD_TYPE=Release make make install ``` ## Installing the Dependencies from Source The dependencies can also be installed from source. Simply clone the directories and run the following cmake (cmake >= 3.8) and make instructions. ### xeus [xeus](https://github.com/jupyter-xeus/xeus) is the core implementation of the Jupyter kernel protocol. ```bash cmake -D CMAKE_BUILD_TYPE=Rlease make make install ``` ### ZeroMQ [ZeroMQ](https://github.com/zeromq/libzmq) is the messaging library underlying the Jupyter kernel protocol. ```bash cmake -D WITH_PERF_TOOL=OFF -D ZMQ_BUILD_TESTS=OFF -D ENABLE_CPACK=OFF -D CMAKE_BUILD_TYPE=Release make make install ``` ## OpenSSL [OpenSSL](https://www.openssl.org/) is packaged for most package managers (apt-get, rpm, mamba). We recommend making use of an off-the-shelf build of OpenSSL for your system. For more information on building OpenSSL, check out the official [OpenSSL wiki](https://wiki.openssl.org/index.php/Compilation_and_Installation). ### cppzmq [cppzmq](https://github.com/zeromq/cppzmq) is a header only library: ```bash cmake -D CMAKE_BUILD_TYPE=Release make install ``` ### json for modern cpp [nlohmann_json](https://github.com/nlohmann/json) is a header only library ```bash cmake make install ``` ## Contributing See [CONTRIBUTING.md](./CONTRIBUTING.md) to know how to contribute and set up a development environment. ## License We use a shared copyright model that enables all contributors to maintain the copyright on their contributions. This software is licensed under the BSD-3-Clause license. See the [LICENSE](LICENSE) file for details. xeus-zmq-3.1.0/cmake/000077500000000000000000000000001464077067000143775ustar00rootroot00000000000000xeus-zmq-3.1.0/cmake/Findsodium.cmake000066400000000000000000000250261464077067000175070ustar00rootroot00000000000000# Written in 2016 by Henrik Steffen Gaßmann # # To the extent possible under law, the author(s) have dedicated all copyright # and related and neighboring rights to this software to the public domain # worldwide. This software is distributed without any warranty. # # You should have received a copy of the CC0 Public Domain Dedication along with # this software. If not, see # # http://creativecommons.org/publicdomain/zero/1.0/ # # ############################################################################## # Tries to find the local libsodium installation. # # On Windows the sodium_DIR environment variable is used as a default hint which # can be overridden by setting the corresponding cmake variable. # # Once done the following variables will be defined: # # sodium_FOUND sodium_INCLUDE_DIR sodium_LIBRARY_DEBUG sodium_LIBRARY_RELEASE # sodium_VERSION_STRING # # Furthermore an imported "sodium" target is created. # if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") set(_GCC_COMPATIBLE 1) endif() # static library option if(NOT DEFINED sodium_USE_STATIC_LIBS) option(sodium_USE_STATIC_LIBS "enable to statically link against sodium" OFF) endif() if(NOT (sodium_USE_STATIC_LIBS EQUAL sodium_USE_STATIC_LIBS_LAST)) unset(sodium_LIBRARY CACHE) unset(sodium_LIBRARY_DEBUG CACHE) unset(sodium_LIBRARY_RELEASE CACHE) unset(sodium_DLL_DEBUG CACHE) unset(sodium_DLL_RELEASE CACHE) set(sodium_USE_STATIC_LIBS_LAST ${sodium_USE_STATIC_LIBS} CACHE INTERNAL "internal change tracking variable") endif() # ############################################################################## # UNIX if(UNIX OR CMAKE_SYSTEM_NAME STREQUAL "Generic") # import pkg-config find_package(PkgConfig QUIET) if(PKG_CONFIG_FOUND) pkg_check_modules(sodium_PKG QUIET libsodium) endif() if(sodium_USE_STATIC_LIBS) if(sodium_PKG_STATIC_LIBRARIES) foreach(_libname ${sodium_PKG_STATIC_LIBRARIES}) if(NOT _libname MATCHES "^lib.*\\.a$") # ignore strings already ending # with .a list(INSERT sodium_PKG_STATIC_LIBRARIES 0 "lib${_libname}.a") endif() endforeach() list(REMOVE_DUPLICATES sodium_PKG_STATIC_LIBRARIES) else() # if pkgconfig for libsodium doesn't provide static lib info, then # override PKG_STATIC here.. set(sodium_PKG_STATIC_LIBRARIES libsodium.a) endif() set(XPREFIX sodium_PKG_STATIC) else() if(sodium_PKG_LIBRARIES STREQUAL "") set(sodium_PKG_LIBRARIES sodium) endif() set(XPREFIX sodium_PKG) endif() find_path(sodium_INCLUDE_DIR sodium.h HINTS ${${XPREFIX}_INCLUDE_DIRS}) find_library(sodium_LIBRARY_DEBUG NAMES ${${XPREFIX}_LIBRARIES} HINTS ${${XPREFIX}_LIBRARY_DIRS}) find_library(sodium_LIBRARY_RELEASE NAMES ${${XPREFIX}_LIBRARIES} HINTS ${${XPREFIX}_LIBRARY_DIRS}) # ############################################################################ # Windows elseif(WIN32) set(sodium_DIR "$ENV{sodium_DIR}" CACHE FILEPATH "sodium install directory") mark_as_advanced(sodium_DIR) find_path(sodium_INCLUDE_DIR sodium.h HINTS ${sodium_DIR} PATH_SUFFIXES include) if(MSVC) # detect target architecture file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/arch.c" [=[ #if defined _M_IX86 #error ARCH_VALUE x86_32 #elif defined _M_X64 #error ARCH_VALUE x86_64 #endif #error ARCH_VALUE unknown ]=]) try_compile(_UNUSED_VAR "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/arch.c" OUTPUT_VARIABLE _COMPILATION_LOG) string(REGEX REPLACE ".*ARCH_VALUE ([a-zA-Z0-9_]+).*" "\\1" _TARGET_ARCH "${_COMPILATION_LOG}") # construct library path if(_TARGET_ARCH STREQUAL "x86_32") string(APPEND _PLATFORM_PATH "Win32") elseif(_TARGET_ARCH STREQUAL "x86_64") string(APPEND _PLATFORM_PATH "x64") else() message( FATAL_ERROR "the ${_TARGET_ARCH} architecture is not supported by Findsodium.cmake." ) endif() string(APPEND _PLATFORM_PATH "/$$CONFIG$$") if(MSVC_VERSION LESS 1900) math(EXPR _VS_VERSION "${MSVC_VERSION} / 10 - 60") else() math(EXPR _VS_VERSION "${MSVC_VERSION} / 10 - 50") endif() string(APPEND _PLATFORM_PATH "/v${_VS_VERSION}") if(sodium_USE_STATIC_LIBS) string(APPEND _PLATFORM_PATH "/static") else() string(APPEND _PLATFORM_PATH "/dynamic") endif() string(REPLACE "$$CONFIG$$" "Debug" _DEBUG_PATH_SUFFIX "${_PLATFORM_PATH}") string(REPLACE "$$CONFIG$$" "Release" _RELEASE_PATH_SUFFIX "${_PLATFORM_PATH}") find_library(sodium_LIBRARY_DEBUG libsodium.lib HINTS ${sodium_DIR} PATH_SUFFIXES ${_DEBUG_PATH_SUFFIX}) find_library(sodium_LIBRARY_RELEASE libsodium.lib HINTS ${sodium_DIR} PATH_SUFFIXES ${_RELEASE_PATH_SUFFIX}) if(NOT sodium_USE_STATIC_LIBS) set(CMAKE_FIND_LIBRARY_SUFFIXES_BCK ${CMAKE_FIND_LIBRARY_SUFFIXES}) set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll") find_library(sodium_DLL_DEBUG libsodium HINTS ${sodium_DIR} PATH_SUFFIXES ${_DEBUG_PATH_SUFFIX}) find_library(sodium_DLL_RELEASE libsodium HINTS ${sodium_DIR} PATH_SUFFIXES ${_RELEASE_PATH_SUFFIX}) set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_BCK}) endif() elseif(_GCC_COMPATIBLE) if(sodium_USE_STATIC_LIBS) find_library(sodium_LIBRARY_DEBUG libsodium.a HINTS ${sodium_DIR} PATH_SUFFIXES lib) find_library(sodium_LIBRARY_RELEASE libsodium.a HINTS ${sodium_DIR} PATH_SUFFIXES lib) else() find_library(sodium_LIBRARY_DEBUG libsodium.dll.a HINTS ${sodium_DIR} PATH_SUFFIXES lib) find_library(sodium_LIBRARY_RELEASE libsodium.dll.a HINTS ${sodium_DIR} PATH_SUFFIXES lib) file(GLOB _DLL LIST_DIRECTORIES false RELATIVE "${sodium_DIR}/bin" "${sodium_DIR}/bin/libsodium*.dll") find_library(sodium_DLL_DEBUG ${_DLL} libsodium HINTS ${sodium_DIR} PATH_SUFFIXES bin) find_library(sodium_DLL_RELEASE ${_DLL} libsodium HINTS ${sodium_DIR} PATH_SUFFIXES bin) endif() else() message(FATAL_ERROR "this platform is not supported by FindSodium.cmake") endif() # ############################################################################ # unsupported else() message(FATAL_ERROR "this platform is not supported by FindSodium.cmake") endif() # ############################################################################## # common stuff # extract sodium version if(sodium_INCLUDE_DIR) set(_VERSION_HEADER "${sodium_INCLUDE_DIR}/sodium/version.h") if(EXISTS "${_VERSION_HEADER}") file(READ "${_VERSION_HEADER}" _VERSION_HEADER_CONTENT) string(REGEX REPLACE ".*define[ \t]+SODIUM_VERSION_STRING[^\"]+\"([^\"]+)\".*" "\\1" sodium_VERSION_STRING "${_VERSION_HEADER_CONTENT}") set(sodium_VERSION_STRING "${sodium_VERSION_STRING}") endif() endif() # communicate results include(FindPackageHandleStandardArgs) find_package_handle_standard_args(sodium REQUIRED_VARS sodium_LIBRARY_RELEASE sodium_LIBRARY_DEBUG sodium_INCLUDE_DIR VERSION_VAR sodium_VERSION_STRING) # mark file paths as advanced mark_as_advanced(sodium_INCLUDE_DIR) mark_as_advanced(sodium_LIBRARY_DEBUG) mark_as_advanced(sodium_LIBRARY_RELEASE) if(WIN32) mark_as_advanced(sodium_DLL_DEBUG) mark_as_advanced(sodium_DLL_RELEASE) endif() # create imported target if(sodium_USE_STATIC_LIBS) set(_LIB_TYPE STATIC) else() set(_LIB_TYPE SHARED) endif() add_library(sodium ${_LIB_TYPE} IMPORTED) set_target_properties(sodium PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${sodium_INCLUDE_DIR}" IMPORTED_LINK_INTERFACE_LANGUAGES "C") if(sodium_USE_STATIC_LIBS) set_target_properties(sodium PROPERTIES INTERFACE_COMPILE_DEFINITIONS "SODIUM_STATIC" IMPORTED_LOCATION "${sodium_LIBRARY_RELEASE}" IMPORTED_LOCATION_DEBUG "${sodium_LIBRARY_DEBUG}") else() if(UNIX) set_target_properties(sodium PROPERTIES IMPORTED_LOCATION "${sodium_LIBRARY_RELEASE}" IMPORTED_LOCATION_DEBUG "${sodium_LIBRARY_DEBUG}") elseif(WIN32) set_target_properties(sodium PROPERTIES IMPORTED_IMPLIB "${sodium_LIBRARY_RELEASE}" IMPORTED_IMPLIB_DEBUG "${sodium_LIBRARY_DEBUG}") if(NOT (sodium_DLL_DEBUG MATCHES ".*-NOTFOUND")) set_target_properties(sodium PROPERTIES IMPORTED_LOCATION_DEBUG "${sodium_DLL_DEBUG}") endif() if(NOT (sodium_DLL_RELEASE MATCHES ".*-NOTFOUND")) set_target_properties(sodium PROPERTIES IMPORTED_LOCATION_RELWITHDEBINFO "${sodium_DLL_RELEASE}" IMPORTED_LOCATION_MINSIZEREL "${sodium_DLL_RELEASE}" IMPORTED_LOCATION_RELEASE "${sodium_DLL_RELEASE}") endif() endif() endif() xeus-zmq-3.1.0/docs/000077500000000000000000000000001464077067000142475ustar00rootroot00000000000000xeus-zmq-3.1.0/docs/Doxyfile000066400000000000000000000004511464077067000157550ustar00rootroot00000000000000PROJECT_NAME = "xeus-zmq" XML_OUTPUT = xml INPUT = ../include GENERATE_LATEX = NO GENERATE_MAN = NO GENERATE_RTF = NO CASE_SENSE_NAMES = NO GENERATE_HTML = NO GENERATE_XML = YES RECURSIVE = YES QUIET = YES JAVADOC_AUTOBRIEF = YES xeus-zmq-3.1.0/docs/Makefile000066400000000000000000000147261464077067000157210ustar00rootroot00000000000000# You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext api default: html help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: doxygen $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: doxygen $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: doxygen $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: doxygen $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: doxygen $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: doxygen $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." epub: doxygen $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: doxygen $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: doxygen $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: doxygen $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: doxygen $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: doxygen $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: doxygen $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: doxygen $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: doxygen $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: doxygen $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: doxygen $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: doxygen $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." coverage: doxygen $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." xml: doxygen $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: doxygen $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." xeus-zmq-3.1.0/docs/environment.yml000066400000000000000000000001371464077067000173370ustar00rootroot00000000000000name: xeus-zmq-docs channels: - conda-forge dependencies: - breathe - sphinx_rtd_theme xeus-zmq-3.1.0/docs/make.bat000066400000000000000000000161651464077067000156650ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source set I18NSPHINXOPTS=%SPHINXOPTS% source if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled echo. coverage to run coverage check of the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) REM Check if sphinx-build is available and fallback to Python version if any %SPHINXBUILD% 1>NUL 2>NUL if errorlevel 9009 goto sphinx_python goto sphinx_ok :sphinx_python set SPHINXBUILD=python -m sphinx.__init__ %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) :sphinx_ok if "%1" == "html" ( doxygen %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\packagename.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\packagename.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "coverage" ( %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage if errorlevel 1 exit /b 1 echo. echo.Testing of coverage in the sources finished, look at the ^ results in %BUILDDIR%/coverage/python.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end xeus-zmq-3.1.0/docs/source/000077500000000000000000000000001464077067000155475ustar00rootroot00000000000000xeus-zmq-3.1.0/docs/source/_static/000077500000000000000000000000001464077067000171755ustar00rootroot00000000000000xeus-zmq-3.1.0/docs/source/_static/main_stylesheet.css000066400000000000000000000000741464077067000231050ustar00rootroot00000000000000.wy-nav-content{ max-width: 1000px; margin: auto; } xeus-zmq-3.1.0/docs/source/conf.py000066400000000000000000000015361464077067000170530ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import subprocess on_rtd = os.environ.get('READTHEDOCS', None) == 'True' if on_rtd: subprocess.call('cd ..; doxygen', shell=True) import sphinx_rtd_theme html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] def setup(app): app.add_css_file("main_stylesheet.css") extensions = ['breathe', 'sphinx_rtd_theme'] breathe_projects = { 'xeus-zmq': '../xml' } templates_path = ['_templates'] html_static_path = ['_static'] source_suffix = '.rst' master_doc = 'index' project = 'xeus-zmq' copyright = '2016, Johan Mabille and Sylvain Corlay' author = 'Johan Mabille and Sylvain Corlay' html_logo = 'quantstack-white.svg' exclude_patterns = [] highlight_language = 'c++' pygments_style = 'sphinx' todo_include_todos = False htmlhelp_basename = 'xeuszmqdoc' xeus-zmq-3.1.0/docs/source/index.rst000066400000000000000000000023061464077067000174110ustar00rootroot00000000000000.. Copyright (c) 2022, Johan Mabille and Sylvain Corlay Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. ======== XEUS-ZMQ ======== ZeroMQ-based middleware for xeus Introduction ------------ ``xeus-zmq`` provides various implementations of the `xserver`_ API from ``xeus``, based on the `ZeroMQ library`_. These implementations all conform to the `Jupyter Kernel Protocol specification`_. It also provides a client framework that can be used to build Jupyter clients, and basic blocks to build a debugger for Jupyter kernels. Licensing --------- We use a shared copyright model that enables all contributors to maintain the copyright on their contributions. This software is licensed under the BSD-3-Clause license. See the LICENSE file for details. .. toctree:: :caption: INSTALLATION :maxdepth: 2 installation .. toctree:: :caption: USAGE :maxdepth: 2 usage server .. _xserver: https://github.com/jupyter-xeus/xeus/blob/main/include/xeus/xserver.hpp .. _ZeroMQ library: https://zeromq.org/ .. _Jupyter Kernel Protocol specification: https://jupyter-client.readthedocs.io/en/stable/messaging.html xeus-zmq-3.1.0/docs/source/installation.rst000066400000000000000000000035071464077067000210070ustar00rootroot00000000000000.. Copyright (c) 2022, Johan Mabille and Sylvain Corlay Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Installation ============ With mamba or conda ------------------- ``xeus-zmq`` has been packaged for the mamba (or conda) package manager. To ensure that the installation works, it is preferable to install ``xeus-zmq`` in a fresh environment. It is also needed to use a `miniforge`_ or `miniconda`_ installation because with the full `anaconda`_ you may have a conflict with the ``ZeroMQ`` library already installed in the distribution. The safest usage is to create an environment named ``xeus-env`` .. code:: bash mamba create -n xeus-env mamba activate xeus-env Then you can install ``xeus-zmq`` and its dependencies in this freshly created environment: .. code:: bash mamba install xeus-zmq -c conda-forge From source ----------- ``xeus-zmq`` depends on the following libraries: - libzmq_ - cppzmq_ - OpenSSL_ - nlohmann_json_ - xeus_ We have packaged all these dependencies on conda-forge. The simplest way to install them is to run: .. code:: bash mamba env create -f environment-dev.yml -n xeus-env mamba activate xeus-env You can then build and install ``xeus-zmq``: .. code:: bash cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DCMAKE_PREFIX_PATH=$CONDA_PREFIX make make install .. _miniforge: https://github.com/conda-forge/miniforge#mambaforge .. _miniconda: https://docs.anaconda.com/free/miniconda .. _anaconda: https://www.anaconda.com .. _libzmq: https://github.com/zeromq/libzmq .. _cppzmq: https://github.com/zeromq/cppzmq .. _OpenSSL: https://github.com/OpenSSL/OpenSSL .. _nlohmann_json: https://github.com/nlohmann/json .. _xeus: https://github.com/jupyter-xeus/xeus xeus-zmq-3.1.0/docs/source/quantstack-white.svg000066400000000000000000000116361464077067000215730ustar00rootroot00000000000000 image/svg+xmlxeus-zmq-3.1.0/docs/source/server.rst000066400000000000000000000134641464077067000176170ustar00rootroot00000000000000.. Copyright (c) 2022, Johan Mabille and Sylvain Corlay Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Server ====== `xeus-zmq` provides two families of implementations for the `xeus server API`_: - ``xserver_zmq``, where a single thread polls both the shell and the control channels. The default implementation is ``xserver_zmq_default`` and can be instantiated via the ``make_xserver_default`` function. - ``xserver_zmq_split``, where the shell and the control channels have dedicated threads. `xeus-zmq` provides two implementations for this family, ``xserver_shell_main`` and ``xserver_control_main``, which can be instantiated via the ``make_xserver_shell_main`` and the ``make_xserver_control_main`` functions respectively. xserver_zmq_default internals ----------------------------- The internals of the ``xserver_zmq_default`` class are illustrated in the following diagram: .. image:: server.svg :alt: server The default server is made of three threads communicating through internal `ZeroMQ` sockets. The main thread is responsible for polling both ``shell`` and ``controller`` channels. When a message is received on one of these channels, the corresponding callback is invoked. Any code executed in the interpreter will be executed by the main thread. If the ``publish`` method is called, the main thread sends a message to the publisher thread. Having a dedicated thread for publishing messages makes this operation a non-blocking one. When the kernel's main thread needs to publish a message, it simply sends it to the publisher thread through an internal socket and continues its execution. The publisher thread will poll its internal socket and forward the messages to the ``publisher`` channel. The last thread is the heartbeat. It is responsible for notifying the client that the kernel is still alive. This is done by sending messages on the ``heartbeat`` channel at a regular rate. The main thread is also connected to the publisher and the heartbeat threads through internal ``controller`` channels. These are used to send ``stop`` messages to the subthread and to cleanly stop the kernel. Extending the default implementation ------------------------------------ The default implementation performs a blocking poll of the channels, which can be a limitation in some use cases. For instance, you may way want to poll within an event loop to allow asynchronous execution of code. ``xeus-zmq`` makes it possible to extend the default implementation by inheriting from the `xserver_zmq class`_. It provides utility methods to poll, read and send messages, so that defining a new server does not require a lot of code. ``TODO``: link to the xeus-qt example when it has been upgraded to xeus-zmq 2.0 xserver_control_main internals ------------------------------ The ``xserver_control_main`` class is an alternative implementation of the server API, its internals are illustrated in the following diagram: .. image:: server_control.svg :alt: server_control This server runs four threads that communicate through internal `ZeroMQ` sockets. The main thread is responsible for polling the ``control`` channel while a dedicated thread listens on the ``shell`` channel. Having separated threads for the ``control`` and ``shell`` channel makes it possible to send messages on a channel while the kernel is already processing a message on the other channel. For instance one can send on the ``control`` channel a request to interrupt a computation running on the ``shell``. The control thread is also connected to the shell, the publisher and the heartbeat threads through internal ``controller`` channels. Similar to ``xserver_zmq``, these are used to send ``stop`` messages to the subthread and to stop the kernel in a clean way. The rest of the implementation is also similar to that of ``xserver_zmq``. xserver_shell_main internals ---------------------------- The ``xserver_shell_main`` class is almost identical to the ``xserver_control_main`` class, except that the main thread listens on the ``shell`` channel as illustrated in the following diagram: .. image:: server_main.svg :alt: server_main Extending xserver_zmq_split --------------------------- Like the default implementation, the ``xserver_control_main`` and ``xserver_shell_main`` servers perform a blocking poll on each channel. It is possible to provide a different execution model for both kinds of servers. However, the process to accomplish this slightly differs from the process of extending the default implementation. Instead of inheriting from the `xserver_zmq_split class`_, one can provide independent execution models for the control channel and the shell channel by inheriting from the `xcontrol_runner class`_ and the `xshell_runner class`_ respectively. .. code:: // xcustom_runner.hpp #include "xeus-zmq/xshell_runner.hpp" class xcustom_runner final : public xshell_runner { public: xcustom_runner(event_loop loop); ~xcustom_runner() override = default; private: void run_impl() override; event_loop p_loop{ nullptr }; }; .. code:: // xcustom_runner.cpp # include "xcustom_runner.hpp" void xcustom_runner::run_impl() { // Add custom execution model here // Example: p_loop->run_forever(); } .. _xeus server API: https://xeus.readthedocs.io/en/latest/server.html#public-api .. _xserver_zmq class: https://github.com/jupyter-xeus/xeus-zmq/blob/main/include/xeus-zmq/xserver_zmq.hpp .. _xserver_zmq_split class: https://github.com/jupyter-xeus/xeus-zmq/blob/main/include/xeus-zmq/xserver_zmq_split.hpp .. _xcontrol_runner class: https://github.com/jupyter-xeus/xeus-zmq/blob/main/include/xeus-zmq/xcontrol_runner.hpp .. _xshell_runner class: https://github.com/jupyter-xeus/xeus-zmq/blob/main/include/xeus-zmq/xshell_runner.hpp xeus-zmq-3.1.0/docs/source/server.svg000066400000000000000000001033771464077067000176110ustar00rootroot00000000000000
Main Thread
(xserver_zmq)
[Not supported by viewer]
Publisher Thread
(xpublisher)
Publisher Thread<br>(xpublisher)<br>
Heartbeat Thread
(xheartbeat)
Heartbeat Thread<br>(xheartbeat)<br>
Server
Server
Client
Client
publisher_controller
publisher_controller
controller
controller
publisher_pub
publisher_pub
listener
listener
publisher
publisher
heartbeat_controller
heartbeat_controller
controller
controller
heartbeat
heartbeat
controller
controller
Shell (code, input, output...)
Shell (code, input, output...)<br>
Control (shutdown, restart)
Control (shutdown, restart)
Heartbeat
Heartbeat
shell
shell
stdin
stdin
router
[Not supported by viewer]
router
[Not supported by viewer]
router
[Not supported by viewer]
req
req<br>
req
req<br>
pub
pub<br>
rep
rep<br>
sub
sub
pub
pub<br>
rep
rep<br>
router
router<br>
dealer
[Not supported by viewer]
dealer
[Not supported by viewer]
req
[Not supported by viewer]
sub
[Not supported by viewer]
dealer
[Not supported by viewer]
xeus-zmq-3.1.0/docs/source/server_control.svg000066400000000000000000001371111464077067000213420ustar00rootroot00000000000000
Main Thread
(xcontrol)
Main Thread...
Publisher Thread
(xpublisher)
Publisher Thread...
Heartbeat Thread
(xheartbeat)
Heartbeat Threa...
Server
Server
Client
Client
publisher_controller
publisher_controller
controller
controller
publisher_pub
publisher_pub
listener
listener
publisher
publisher
heartbeat_controller
heartbeat_controller
controller
controller
heartbeat
heartbeat
controller
controller
Shell (code, input, output...)
Shell (code, input, output...)
Control (shutdown, restart)
Control (shutdown, restart)
Heartbeat
Heartbeat
shell
shell
stdin
stdin
router
router
router
router
router
router
req
req
req
req
pub
pub
rep
rep
sub
sub
pub
pub
rep
rep
router
router
dealer
dealer
dealer
dealer
req
req
sub
sub
dealer
dealer
shell_controller
shell_controller
pub
pub
controller
controller
publisher_pub
publisher_pub
xshell thread
(xshell)
xshell thread...
req
req
rep
rep
Viewer does not support full SVG 1.1
xeus-zmq-3.1.0/docs/source/server_main.svg000066400000000000000000001370751464077067000206170ustar00rootroot00000000000000
xcontrol thread
(xcontrol)
xcontrol thread...
Publisher Thread
(xpublisher)
Publisher Thread...
Heartbeat Thread
(xheartbeat)
Heartbeat Threa...
Server
Server
Client
Client
publisher_controller
publisher_controller
controller
controller
publisher_pub
publisher_pub
listener
listener
publisher
publisher
heartbeat_controller
heartbeat_controller
controller
controller
heartbeat
heartbeat
controller
controller
Shell (code, input, output...)
Shell (code, input, output...)
Control (shutdown, restart)
Control (shutdown, restart)
Heartbeat
Heartbeat
shell
shell
stdin
stdin
router
router
router
router
router
router
req
req
req
req
pub
pub
rep
rep
sub
sub
pub
pub
rep
rep
router
router
dealer
dealer
dealer
dealer
req
req
sub
sub
dealer
dealer
shell_controller
shell_controller
pub
pub
controller
controller
publisher_pub
publisher_pub
Main thread
(xshell)
Main thread...
req
req
rep
rep
Viewer does not support full SVG 1.1
xeus-zmq-3.1.0/docs/source/usage.rst000066400000000000000000000071071464077067000174120ustar00rootroot00000000000000.. Copyright (c) 2022, Johan Mabille and Sylvain Corlay Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Usage ===== Instantiating a server ---------------------- `xeus-zmq` provides server building functions that can be passed to the kernel constructor: .. code:: #include #include #include "xeus/xkernel.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus-zmq/xzmq_context.hpp" #include "xeus-zmq/xserver_zmq.hpp" #include "xmock_interpreter.hpp" int main(int argc, char* argv[]) { std::string file_name = (argc == 1) ? "connection.json" : argv[2]; xeus::xconfiguration config = xeus::load_configuration(file_name); auto context = xeus::make_zmq_context(); using interpreter_ptr = std::unique_ptr; interpreter_ptr interpreter = interpreter_ptr(new my_custom_interpreter()); xeus::xkernel kernel(config, xeus::get_user_name(), std::move(context), std::move(interpreter), xeus::make_xserver_default); std::cout << "starting kernel" << std::endl; kernel.start(); return 0; } `xeus-zmq` provides three different implementations for the server: - ``xserver_zmq_default`` is the default server implementation; it runs three threads, one for publishing, one for the heartbeat messages, and the main thread for handling the shell, control and stdin sockets. To instantiate this implementation, include ``xserver_zmq.hpp`` and call the ``make_xserver_default`` function. - ``xserver_control_main`` runs an additional thread for handling the shell and the stdin sockets. Therefore, the main thread only listens to the control socket. This allows us to easily implement interruption of code execution. This server is required if you want to plug a debugger in the kernel. To instantiate this implementation, include ``xserver_zmq_split.hpp`` and call the ``make_xserver_control_main`` function. - ``xserver_shell_main`` is similar to ``xserver_control_main`` except that the main thread handles the shell and the stdin sockets while the additional thread listens to the control socket. This server is required if you want to plug a debugger that does not support native threads and requires the code to be run by the main thread. To instantiate this implementation, include ``xserver_zmq_split.hpp`` and call the ``make_xserver_shell_main`` function. Instantiating a client ---------------------- `xeus-zmq` provides client building functions that can be used by custom clients and end users. For starters on usage, have a look at our `ipc client class`_ and the `ipc client implementation file`_. `xeus-zmq` currently provides a single implementation for the client: - ``xclient_zmq`` is the primary client implementation, it runs two threads, one for sending a "ping" message to the heartbeat every 100ms, and one for polling the iopub socket and pushing the received message into a queue. The main thread waits for messages by either popping messages from the queue or polling the shell and the control sockets for received messages. To instantiate this implementation, include ``xclient_zmq.hpp`` and call the ``make_xclient_zmq`` function. .. _ipc client class: https://github.com/jupyter-xeus/xeus-zmq/blob/main/test/xipc_client.hpp .. _ipc client implementation file: https://github.com/jupyter-xeus/xeus-zmq/blob/main/test/client_ipc.cpp xeus-zmq-3.1.0/environment-dev.yml000066400000000000000000000005511464077067000171630ustar00rootroot00000000000000name: xeus-zmq channels: - conda-forge dependencies: # Build dependencies - cmake - cxx-compiler - pkg-config - ninja # Host dependencies - zeromq - zeromq-static - cppzmq - xeus>=5.0.0,<6.0 - OpenSSL - libopenssl-static - nlohmann_json=3.11.3 # Test dependencies - doctest >= 2.4.6 - pytest - jupyter_kernel_test>=0.6,<0.7 xeus-zmq-3.1.0/example/000077500000000000000000000000001464077067000147525ustar00rootroot00000000000000xeus-zmq-3.1.0/example/.gitignore000066400000000000000000000000641464077067000167420ustar00rootroot00000000000000build/* share/jupyter/kernels/my_kernel/kernel.json xeus-zmq-3.1.0/example/CMakeLists.txt000066400000000000000000000053141464077067000175150ustar00rootroot00000000000000############################################################################ # Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou # # Copyright (c) 2016, QuantStack # # # # Distributed under the terms of the BSD 3-Clause License. # # # # The full license is in the file LICENSE, distributed with this software. # ############################################################################ cmake_minimum_required(VERSION 3.4.3) project(my_kernel) set(EXECUTABLE_NAME my_kernel) # Configuration # ============= include(GNUInstallDirs) # We generate the kernel.json file, given the installation prefix and the executable name configure_file ( "${CMAKE_CURRENT_SOURCE_DIR}/share/jupyter/kernels/my_kernel/kernel.json.in" "${CMAKE_CURRENT_SOURCE_DIR}/share/jupyter/kernels/my_kernel/kernel.json" ) option(XEUS_STATIC_DEPENDENCIES "link statically with xeus dependencies" OFF) if (XEUS_STATIC_DEPENDENCIES) set(xeus-zmq_target "xeus-zmq-static") else () set(xeus-zmq_target "xeus-zmq") endif () # Dependencies # ============ # Be sure to use recent versions set(xeus-zmq_REQUIRED_VERSION 1.0.2) find_package(xeus-zmq ${xeus-zmq_REQUIRED_VERSION} REQUIRED) find_package(Threads) # Flags # ===== include(CheckCXXCompilerFlag) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") CHECK_CXX_COMPILER_FLAG("-std=c++14" HAS_CPP14_FLAG) if (HAS_CPP14_FLAG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") else() message(FATAL_ERROR "Unsupported compiler -- xeus requires C++14 support!") endif() endif() # Target and link # =============== # my_kernel source files set(MY_KERNEL_SRC src/custom_interpreter.cpp src/custom_interpreter.hpp ) # My kernel executable add_executable(${EXECUTABLE_NAME} src/main.cpp ${MY_KERNEL_SRC} ) target_link_libraries(${EXECUTABLE_NAME} PRIVATE ${xeus-zmq_target} Threads::Threads) set_target_properties(${EXECUTABLE_NAME} PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE ) # Installation # ============ # Install my_kernel install(TARGETS ${EXECUTABLE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) # Configuration and data directories for jupyter and my_kernel set(XJUPYTER_DATA_DIR "share/jupyter" CACHE STRING "Jupyter data directory") # Install Jupyter kernelspecs set(MY_KERNELSPEC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/share/jupyter/kernels) install(DIRECTORY ${MY_KERNELSPEC_DIR} DESTINATION ${XJUPYTER_DATA_DIR} PATTERN "*.in" EXCLUDE) xeus-zmq-3.1.0/example/share/000077500000000000000000000000001464077067000160545ustar00rootroot00000000000000xeus-zmq-3.1.0/example/share/jupyter/000077500000000000000000000000001464077067000175565ustar00rootroot00000000000000xeus-zmq-3.1.0/example/share/jupyter/kernels/000077500000000000000000000000001464077067000212215ustar00rootroot00000000000000xeus-zmq-3.1.0/example/share/jupyter/kernels/my_kernel/000077500000000000000000000000001464077067000232065ustar00rootroot00000000000000xeus-zmq-3.1.0/example/share/jupyter/kernels/my_kernel/kernel.json.in000066400000000000000000000003101464077067000257600ustar00rootroot00000000000000{ "display_name": "my_kernel", "argv": [ "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/@EXECUTABLE_NAME@", "-f", "{connection_file}" ], "language": "python" } xeus-zmq-3.1.0/example/src/000077500000000000000000000000001464077067000155415ustar00rootroot00000000000000xeus-zmq-3.1.0/example/src/custom_interpreter.cpp000066400000000000000000000101511464077067000222000ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include "nlohmann/json.hpp" #include "xeus/xhelper.hpp" #include "custom_interpreter.hpp" namespace nl = nlohmann; namespace custom { nl::json custom_interpreter::execute_request_impl(int execution_counter, // Typically the cell number const std::string& /*code*/, // Code to execute bool /*silent*/, bool /*store_history*/, nl::json /*user_expressions*/, bool /*allow_stdin*/) { // You can use the C-API of your target language for executing the code, // e.g. `PyRun_String` for the Python C-API // `luaL_dostring` for the Lua C-API // Use this method for publishing the execution result to the client, // this method takes the ``execution_counter`` as first argument, // the data to publish (mime type data) as second argument and metadata // as third argument. // Replace "Hello World !!" by what you want to be displayed under the execution cell nl::json pub_data; pub_data["text/plain"] = "Hello World !!"; publish_execution_result(execution_counter, std::move(pub_data), nl::json::object()); // You can also use this method for publishing errors to the client, if the code // failed to execute // publish_execution_error(error_name, error_value, error_traceback); publish_execution_error("TypeError", "123", {"!@#$", "*(*"}); return xeus::create_successful_reply(); } void custom_interpreter::configure_impl() { // Perform some operations } nl::json custom_interpreter::complete_request_impl(const std::string& code, int cursor_pos) { // Code starts with 'H', it could be the following completion if (code[0] == 'H') { return xeus::create_complete_reply({"Hello", "Hey", "Howdy"}, 5, cursor_pos); } // No completion result else { return xeus::create_complete_reply({}, cursor_pos, cursor_pos); } } nl::json custom_interpreter::inspect_request_impl(const std::string& code, int /*cursor_pos*/, int /*detail_level*/) { nl::json result; if (code.compare("print") == 0) { return xeus::create_inspect_reply(true, {"text/plain", "Print objects to the text stream file, [...]"}); } else { return xeus::create_inspect_reply(); } } nl::json custom_interpreter::is_complete_request_impl(const std::string& /*code*/) { return xeus::create_is_complete_reply("complete"); } nl::json custom_interpreter::kernel_info_request_impl() { return xeus::create_info_reply("", "my_kernel", "0.1.0", "python", "3.7", "text/x-python", ".py"); } void custom_interpreter::shutdown_request_impl() { std::cout << "Bye!!" << std::endl; } } xeus-zmq-3.1.0/example/src/custom_interpreter.hpp000066400000000000000000000035541464077067000222160ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef CUSTOM_INTERPRETER #define CUSTOM_INTERPRETER #include "xeus/xinterpreter.hpp" #include "nlohmann/json.hpp" using xeus::xinterpreter; namespace nl = nlohmann; namespace custom { class custom_interpreter : public xinterpreter { public: custom_interpreter() = default; virtual ~custom_interpreter() = default; private: void configure_impl() override; nl::json execute_request_impl(int execution_counter, const std::string& code, bool silent, bool store_history, nl::json user_expressions, bool allow_stdin) override; nl::json complete_request_impl(const std::string& code, int cursor_pos) override; nl::json inspect_request_impl(const std::string& code, int cursor_pos, int detail_level) override; nl::json is_complete_request_impl(const std::string& code) override; nl::json kernel_info_request_impl() override; void shutdown_request_impl() override; }; } #endif xeus-zmq-3.1.0/example/src/main.cpp000066400000000000000000000026511464077067000171750ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include "xeus/xkernel.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus-zmq/xserver_zmq.hpp" #include "custom_interpreter.hpp" int main(int argc, char* argv[]) { // Load configuration file std::string file_name = (argc == 1) ? "connection.json" : argv[2]; xeus::xconfiguration config = xeus::load_configuration(file_name); auto context = xeus::make_context(); // Create interpreter instance using interpreter_ptr = std::unique_ptr; interpreter_ptr interpreter = interpreter_ptr(new custom::custom_interpreter()); // Create kernel instance and start it xeus::xkernel kernel(config, xeus::get_user_name(), std::move(context), std::move(interpreter), xeus::make_xserver_default); kernel.start(); return 0; } xeus-zmq-3.1.0/include/000077500000000000000000000000001464077067000147425ustar00rootroot00000000000000xeus-zmq-3.1.0/include/xeus-zmq/000077500000000000000000000000001464077067000165335ustar00rootroot00000000000000xeus-zmq-3.1.0/include/xeus-zmq/xclient_zmq.hpp000066400000000000000000000045731464077067000216120ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_CLIENT_ZMQ_HPP #define XEUS_CLIENT_ZMQ_HPP #include #include #include "xeus/xeus_context.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus/xmessage.hpp" #include "xeus-zmq.hpp" namespace xeus { class xclient_zmq_impl; class XEUS_ZMQ_API xclient_zmq { public: using listener = std::function; using iopub_listener = std::function; using kernel_status_listener = std::function; explicit xclient_zmq(std::unique_ptr impl); ~xclient_zmq(); void connect(); void start(); void stop_channels(); void send_on_shell(xmessage msg); void send_on_control(xmessage msg); // APIs for receiving on a specified channel std::optional receive_on_shell(bool blocking = true); std::optional receive_on_control(bool blocking = true); std::size_t iopub_queue_size() const; std::optional pop_iopub_message(); // APIs for receiving on all channels void register_shell_listener(const listener& l); void register_control_listener(const listener& l); void register_iopub_listener(const iopub_listener& l); void register_kernel_status_listener(const kernel_status_listener& l); void wait_for_message(); private: std::unique_ptr p_client_impl; }; XEUS_ZMQ_API std::unique_ptr make_xclient_zmq(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh = nl::json::error_handler_t::strict); } #endif xeus-zmq-3.1.0/include/xeus-zmq/xcontrol_default_runner.hpp000066400000000000000000000021251464077067000242110ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_CONTROL_DEFAULT_RUNNER_HPP #define XEUS_CONTROL_DEFAULT_RUNNER_HPP #include "xeus-zmq.hpp" #include "xcontrol_runner.hpp" namespace xeus { class XEUS_ZMQ_API xcontrol_default_runner final : public xcontrol_runner { public: xcontrol_default_runner() = default; ~xcontrol_default_runner() override = default; private: void run_impl() override; void stop_impl() override; bool m_request_stop; }; } #endif xeus-zmq-3.1.0/include/xeus-zmq/xcontrol_runner.hpp000066400000000000000000000032251464077067000225070ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_CONTROL_RUNNER_HPP #define XEUS_CONTROL_RUNNER_HPP #include #include "xeus/xmessage.hpp" #include "xeus-zmq.hpp" #include "xmiddleware.hpp" namespace xeus { class xserver_zmq_split; class XEUS_ZMQ_API xcontrol_runner { public: virtual ~xcontrol_runner() = default; xcontrol_runner(const xcontrol_runner&) = delete; xcontrol_runner& operator=(const xcontrol_runner&) = delete; xcontrol_runner(xcontrol_runner&&) = delete; xcontrol_runner& operator=(xcontrol_runner&&) = delete; void register_server(xserver_zmq_split& server); void run(); void stop(); protected: xcontrol_runner() = default; fd_t get_control_fd() const; std::optional read_control(int flags = 0); void stop_channels(); void notify_control_listener(xmessage message); private: virtual void run_impl() = 0; virtual void stop_impl() = 0; xserver_zmq_split* p_server = nullptr; }; } #endif xeus-zmq-3.1.0/include/xeus-zmq/xdap_tcp_client.hpp000066400000000000000000000060441464077067000224100ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_DAP_TCP_CLIENT_HPP #define XEUS_DAP_TCP_CLIENT_HPP #include #include #include #include "nlohmann/json.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus/xeus_context.hpp" #include "xeus-zmq.hpp" namespace nl = nlohmann; namespace xeus { enum class dap_tcp_type { client, server }; enum class dap_init_type { sequential, parallel }; struct XEUS_ZMQ_API xdap_tcp_configuration { dap_tcp_type m_dap_tcp_type; dap_init_type m_dap_init_type; std::string m_user_name; std::string m_session_id; xdap_tcp_configuration(dap_tcp_type adap_tcp_type, dap_init_type adap_init_type, const std::string& user_name, const std::string& session_id); }; class xdap_tcp_client_impl; class XEUS_ZMQ_API xdap_tcp_client { public: static constexpr const char* HEADER = "Content-Length: "; static constexpr size_t HEADER_LENGTH = 16; static constexpr const char* SEPARATOR = "\r\n\r\n"; static constexpr size_t SEPARATOR_LENGTH = 4; using event_callback = std::function; virtual ~xdap_tcp_client(); xdap_tcp_client(const xdap_tcp_client&) = delete; xdap_tcp_client& operator=(const xdap_tcp_client&) = delete; xdap_tcp_client(xdap_tcp_client&&) = delete; xdap_tcp_client& operator=(xdap_tcp_client&&) = delete; void start_debugger(std::string tcp_end_point, std::string publisher_end_point, std::string controller_end_point, std::string controller_header_end_point); protected: xdap_tcp_client(xcontext& context, const xeus::xconfiguration& config, int socket_linger, const xdap_tcp_configuration& dap_config, const event_callback& cb); void forward_event(nl::json message); void send_dap_request(nl::json message); using message_condition = std::function; nl::json wait_for_message(const message_condition& condition); private: virtual void handle_event(nl::json message) = 0; std::unique_ptr p_impl; }; } #endif xeus-zmq-3.1.0/include/xeus-zmq/xdebugger_base.hpp000066400000000000000000000113551464077067000222170ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2018, Martin Renou, Johan Mabille, Sylvain Corlay, and * * Wolf Vollprecht * * Copyright (c) 2018, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_DEBUGGER_BASE_HPP #define XEUS_DEBUGGER_BASE_HPP #include #include #include #include #include #include #include #include #include "nlohmann/json.hpp" #include "xeus/xdebugger.hpp" #include "xeus/xeus_context.hpp" #include "xeus-zmq.hpp" namespace xeus { struct XEUS_ZMQ_API xdebugger_info { std::size_t m_hash_seed; std::string m_tmp_file_prefix; std::string m_tmp_file_suffix; bool m_rich_rendering; std::vector m_exception_paths; bool m_copy_to_globals; xdebugger_info(std::size_t hash_seed, const std::string& tmp_file_prefix, const std::string& tmp_file_suffix, bool rich_rendering = false, std::vector exception_paths = {}, bool copy_to_globals = false); }; class xdebugger_middleware; class XEUS_ZMQ_API xdebugger_base : public xdebugger { public: virtual ~xdebugger_base(); protected: xdebugger_base(xcontext& context); bool is_started() const; std::function get_event_callback(); /********************* * Requests handling * *********************/ using request_handler_t = std::function; void register_request_handler(const std::string& command, const request_handler_t& handler, bool require_started); nl::json debug_info_request(const nl::json& message); nl::json dump_cell_request(const nl::json& message); nl::json set_breakpoints_request(const nl::json& message); nl::json source_request(const nl::json& message); nl::json stack_trace_request(const nl::json& message); nl::json variables_request(const nl::json& message); nl::json forward_message(const nl::json& message); /******************* * Events handling * *******************/ using event_handler_t = std::function; void register_event_handler(const std::string& event, const event_handler_t& handler); void continued_event(const nl::json& message); void stopped_event(const nl::json& message); const std::set& get_stopped_threads() const; /******************* * Middleware APIs * *******************/ void bind_sockets(const std::string& header_end_point, const std::string& request_end_point); void unbind_sockets(const std::string& header_end_point, const std::string& request_end_point); std::string send_recv_header(const std::string& header); std::string send_recv_request(const std::string& request); protected: virtual nl::json variables_request_impl(const nl::json& message); private: void handle_event(const nl::json& message); nl::json process_request_impl(const nl::json& header, const nl::json& message) override; virtual bool start() = 0; virtual void stop() = 0; virtual xdebugger_info get_debugger_info() const = 0; virtual std::string get_cell_temporary_file(const std::string& code) const = 0; std::unique_ptr p_middleware; using request_handler_map_t = std::map; request_handler_map_t m_started_handler; request_handler_map_t m_request_handler; using event_handler_map_t = std::map; event_handler_map_t m_event_handler; using breakpoint_list_t = std::map>; breakpoint_list_t m_breakpoint_list; std::set m_stopped_threads; std::mutex m_stopped_mutex; bool m_is_started; }; } #endif xeus-zmq-3.1.0/include/xeus-zmq/xeus-zmq.hpp000066400000000000000000000026411464077067000210400ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_ZMQ_EXPORT_HPP #define XEUS_ZMQ_EXPORT_HPP #ifdef _WIN32 #ifdef XEUS_ZMQ_STATIC_LIB #define XEUS_ZMQ_API #else #ifdef XEUS_ZMQ_EXPORTS #define XEUS_ZMQ_API __declspec(dllexport) #else #define XEUS_ZMQ_API __declspec(dllimport) #endif #endif #else #define XEUS_ZMQ_API __attribute__((visibility("default"))) #endif // Project version #define XEUS_ZMQ_VERSION_MAJOR 3 #define XEUS_ZMQ_VERSION_MINOR 1 #define XEUS_ZMQ_VERSION_PATCH 0 // Binary version // See the following URL for explanations about the binary versionning // https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info #define XEUS_ZMQ_BINARY_CURRENT 7 #define XEUS_ZMQ_BINARY_REVISION 0 #define XEUS_ZMQ_BINARY_AGE 1 #endif xeus-zmq-3.1.0/include/xeus-zmq/xmiddleware.hpp000066400000000000000000000026111464077067000215510ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_MIDDLEWARE_HPP #define XEUS_MIDDLEWARE_HPP #include #include "xeus-zmq.hpp" namespace xeus { // Duplicate definition for cppzmq #if defined _WIN64 using fd_t = __int64; #elif defined _WIN32 using fd_t = unsinged int; #else using fd_t = int; #endif XEUS_ZMQ_API std::string get_controller_end_point(const std::string& channel); XEUS_ZMQ_API std::string get_publisher_end_point(); XEUS_ZMQ_API std::string get_end_point(const std::string& transport, const std::string& ip, const std::string& port); XEUS_ZMQ_API int get_socket_linger(); XEUS_ZMQ_API std::string find_free_port(std::size_t max_tries = 100, int start = 49152, int stop = 65536); } #endif xeus-zmq-3.1.0/include/xeus-zmq/xserver_zmq.hpp000066400000000000000000000050141464077067000216310ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_SERVER_ZMQ_HPP #define XEUS_SERVER_ZMQ_HPP #include #include "xeus/xeus_context.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus/xserver.hpp" #include "xeus-zmq.hpp" namespace xeus { class xserver_zmq_impl; class XEUS_ZMQ_API xserver_zmq : public xserver { public: ~xserver_zmq() override; using xserver::notify_internal_listener; protected: xserver_zmq(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh); // API for inheriting classes void start_publisher_thread(); void start_heartbeat_thread(); void stop_channels(); void set_request_stop(bool stop); bool is_stopped() const; // The following methods must be called in the same thread using message_channel = std::pair; std::optional poll_channels(long timeout); void send_shell_message(xmessage msg); void send_control_message(xmessage msg); private: // Implementation of xserver virtual methods xcontrol_messenger& get_control_messenger_impl() override; void send_shell_impl(xmessage msg) override; void send_control_impl(xmessage msg) override; void send_stdin_impl(xmessage msg) override; void publish_impl(xpub_message msg, channel c) override; void abort_queue_impl(const listener& l, long polling_interval) override; void update_config_impl(xconfiguration& config) const override; std::unique_ptr p_impl; }; XEUS_ZMQ_API std::unique_ptr make_xserver_default(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh = nl::json::error_handler_t::strict); } #endif xeus-zmq-3.1.0/include/xeus-zmq/xserver_zmq_split.hpp000066400000000000000000000107241464077067000230500ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_SERVER_ZMQ_SPLIT_HPP #define XEUS_SERVER_ZMQ_SPLIT_HPP #include #include "xeus/xeus_context.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus/xserver.hpp" #include "xeus-zmq.hpp" #include "xcontrol_runner.hpp" #include "xmiddleware.hpp" #include "xshell_runner.hpp" #include "xthread.hpp" namespace xeus { class xserver_zmq_split_impl; class XEUS_ZMQ_API xserver_zmq_split : public xserver { public: ~xserver_zmq_split() override; // API for xcontrol_runner using xserver::notify_control_listener; fd_t get_control_fd() const; std::optional read_control(int flags); void send_control_message(xmessage msg); void stop_channels(); // API for xshell_runner using xserver::notify_shell_listener; std::string notify_internal_listener(std::string message); fd_t get_shell_fd() const; fd_t get_shell_controller_fd() const; std::optional poll_shell_channels(long timeout); std::optional read_shell(int flags); void send_shell_message(xmessage msg); std::optional read_shell_controller(int flags); void send_shell_controller(std::string message); protected: using control_runner_ptr = std::unique_ptr; using shell_runner_ptr = std::unique_ptr; xserver_zmq_split(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh, control_runner_ptr control, shell_runner_ptr shell); // API for inheriting classes void start_publisher_thread(); void start_heartbeat_thread(); void start_control_thread(); void run_control(); void start_shell_thread(); void run_shell(); private: // Implementation of xserver virtual methods xcontrol_messenger& get_control_messenger_impl() override; void send_shell_impl(xmessage msg) override; void send_control_impl(xmessage msg) override; void send_stdin_impl(xmessage msg) override; void publish_impl(xpub_message msg, channel c) override; void stop_impl() override; void abort_queue_impl(const listener& l, long polling_interval) override; void update_config_impl(xconfiguration& config) const override; std::unique_ptr p_impl; control_runner_ptr p_control_runner; shell_runner_ptr p_shell_runner; xthread m_control_thread; xthread m_shell_thread; nl::json::error_handler_t m_error_handler; }; XEUS_ZMQ_API std::unique_ptr make_xserver_control_main(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh = nl::json::error_handler_t::strict); XEUS_ZMQ_API std::unique_ptr make_xserver_control(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh, std::unique_ptr control, std::unique_ptr shell); XEUS_ZMQ_API std::unique_ptr make_xserver_shell_main(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh = nl::json::error_handler_t::strict); XEUS_ZMQ_API std::unique_ptr make_xserver_shell(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh, std::unique_ptr control, std::unique_ptr shell); } #endif xeus-zmq-3.1.0/include/xeus-zmq/xshell_default_runner.hpp000066400000000000000000000017761464077067000236530ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_SHELL_DEFAULT_RUNNER_HPP #define XEUS_SHELL_DEFAULT_RUNNER_HPP #include "xeus-zmq.hpp" #include "xshell_runner.hpp" namespace xeus { class XEUS_ZMQ_API xshell_default_runner final : public xshell_runner { public: xshell_default_runner() = default; ~xshell_default_runner() override = default; private: void run_impl() override; }; } #endif xeus-zmq-3.1.0/include/xeus-zmq/xshell_runner.hpp000066400000000000000000000041141464077067000221340ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_SHELL_RUNNER_HPP #define XEUS_SHELL_RUNNER_HPP #include #include #include "xeus/xmessage.hpp" #include "xeus/xserver.hpp" #include "xeus-zmq.hpp" #include "xmiddleware.hpp" namespace xeus { class xserver_zmq_split; class XEUS_ZMQ_API xshell_runner { public: virtual ~xshell_runner() = default; xshell_runner(const xshell_runner&) = delete; xshell_runner& operator=(const xshell_runner&) = delete; xshell_runner(xshell_runner&&) = delete; xshell_runner& operator=(xshell_runner&&) = delete; void register_server(xserver_zmq_split& server); void run(); protected: xshell_runner() = default; fd_t get_shell_fd() const; fd_t get_shell_controller_fd() const; using optional_channel = std::optional; optional_channel poll_channels(long timeout = -1); std::optional read_shell(int flags = 0); std::optional read_shell(optional_channel chan, int flags = 0); std::optional read_controller(int flags = 0); std::optional read_controller(optional_channel chan, int flags = 0); void send_controller(std::string message); void notify_shell_listener(xmessage message); std::string notify_internal_listener(std::string message); private: virtual void run_impl() = 0; xserver_zmq_split* p_server = nullptr; }; } #endif xeus-zmq-3.1.0/include/xeus-zmq/xthread.hpp000066400000000000000000000060161464077067000207060ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_THREAD_HPP #define XEUS_THREAD_HPP #include #include namespace xeus { /** * Joining std::thread */ class xthread { public: using id = std::thread::id; using native_handle_type = std::thread::native_handle_type; xthread() noexcept = default; // Last arguments SFINAE out copy constructor template , xthread>::value>> explicit xthread(Function&& f, Args&&... args); ~xthread(); xthread(const xthread&) = delete; xthread& operator=(const xthread&) = delete; xthread(xthread&&) = default; xthread& operator=(xthread&&); bool joinable() const noexcept; id get_id() const noexcept; native_handle_type native_handle(); static unsigned int hardware_concurrency() noexcept; void join(); void detach(); void swap(xthread& other) noexcept; private: std::thread m_thread; }; /************************** * xthread implementation * **************************/ template inline xthread::xthread(Function&& func, Args&&... args) : m_thread{ std::forward(func), std::forward(args)... } { } inline xthread::~xthread() { if (joinable()) { join(); } } inline xthread& xthread::operator=(xthread&& rhs) { if (joinable()) { join(); } m_thread = std::move(rhs.m_thread); return *this; } inline bool xthread::joinable() const noexcept { return m_thread.joinable(); } inline xthread::id xthread::get_id() const noexcept { return m_thread.get_id(); } inline xthread::native_handle_type xthread::native_handle() { return m_thread.native_handle(); } inline unsigned int xthread::hardware_concurrency() noexcept { return std::thread::hardware_concurrency(); } inline void xthread::join() { m_thread.join(); } inline void xthread::detach() { m_thread.detach(); } inline void xthread::swap(xthread& other) noexcept { m_thread.swap(other.m_thread); } } #endif xeus-zmq-3.1.0/include/xeus-zmq/xzmq_context.hpp000066400000000000000000000003401464077067000220040ustar00rootroot00000000000000#ifndef XZMQ_CONTEXT_HPP #define XZMQ_CONTEXT_HPP #include #include "xeus/xeus_context.hpp" #include "xeus-zmq.hpp" namespace xeus { XEUS_ZMQ_API std::unique_ptr make_zmq_context(); } #endif xeus-zmq-3.1.0/readthedocs.yml000066400000000000000000000001731464077067000163300ustar00rootroot00000000000000version: 2 build: os: "ubuntu-22.04" tools: python: "mambaforge-22.9" conda: environment: docs/environment.yml xeus-zmq-3.1.0/src/000077500000000000000000000000001464077067000141065ustar00rootroot00000000000000xeus-zmq-3.1.0/src/client/000077500000000000000000000000001464077067000153645ustar00rootroot00000000000000xeus-zmq-3.1.0/src/client/xclient_messenger.cpp000066400000000000000000000034371464077067000216150ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "nlohmann/json.hpp" #include "xeus-zmq/xmiddleware.hpp" #include "xclient_messenger.hpp" namespace nl = nlohmann; namespace xeus { xclient_messenger::xclient_messenger(zmq::context_t& context) : m_iopub_controller(context, zmq::socket_type::req) , m_heartbeat_controller(context, zmq::socket_type::req) { } xclient_messenger::~xclient_messenger() { } void xclient_messenger::connect() { m_iopub_controller.set(zmq::sockopt::linger, get_socket_linger()); m_iopub_controller.connect(get_controller_end_point("iopub")); m_heartbeat_controller.set(zmq::sockopt::linger, get_socket_linger()); m_heartbeat_controller.connect(get_controller_end_point("heartbeat")); } void xclient_messenger::stop_channels() { zmq::message_t stop_msg("stop", 4); zmq::message_t response; // Wait for iopub answer m_iopub_controller.send(stop_msg, zmq::send_flags::none); (void)m_iopub_controller.recv(response); // Wait for heartbeat answer m_heartbeat_controller.send(stop_msg, zmq::send_flags::none); (void)m_heartbeat_controller.recv(response); } } xeus-zmq-3.1.0/src/client/xclient_messenger.hpp000066400000000000000000000020221464077067000216070ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_CLIENT_MESSENGER_HPP #define XEUS_CLIENT_MESSENGER_HPP #include namespace xeus { class xclient_messenger { public: explicit xclient_messenger(zmq::context_t& context); virtual ~xclient_messenger(); void connect(); void stop_channels(); private: zmq::socket_t m_iopub_controller; zmq::socket_t m_heartbeat_controller; }; } #endifxeus-zmq-3.1.0/src/client/xclient_zmq.cpp000066400000000000000000000057701464077067000204360ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xeus-zmq/xclient_zmq.hpp" #include "xclient_zmq_impl.hpp" namespace xeus { xclient_zmq::xclient_zmq(std::unique_ptr impl) : p_client_impl(std::move(impl)) { } // Has to be in the cpp because incomplete // types are used in unique_ptr in the header xclient_zmq::~xclient_zmq() = default; void xclient_zmq::connect() { p_client_impl->connect(); } void xclient_zmq::start() { p_client_impl->start(); } void xclient_zmq::stop_channels() { p_client_impl->stop_channels(); } void xclient_zmq::send_on_shell(xmessage msg) { p_client_impl->send_on_shell(std::move(msg)); } void xclient_zmq::send_on_control(xmessage msg) { p_client_impl->send_on_control(std::move(msg)); } std::optional xclient_zmq::receive_on_shell(bool blocking) { return p_client_impl->receive_on_shell(blocking); } std::optional xclient_zmq::receive_on_control(bool blocking) { return p_client_impl->receive_on_control(blocking); } std::size_t xclient_zmq::iopub_queue_size() const { return p_client_impl->iopub_queue_size(); } std::optional xclient_zmq::pop_iopub_message() { return p_client_impl->pop_iopub_message(); } void xclient_zmq::register_shell_listener(const listener& l) { p_client_impl->register_shell_listener(l); } void xclient_zmq::register_control_listener(const listener& l) { p_client_impl->register_control_listener(l); } void xclient_zmq::register_iopub_listener(const iopub_listener& l) { p_client_impl->register_iopub_listener(l); } void xclient_zmq::register_kernel_status_listener(const kernel_status_listener& l) { p_client_impl->register_kernel_status_listener(l); } void xclient_zmq::wait_for_message() { p_client_impl->wait_for_message(); } std::unique_ptr make_xclient_zmq(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh) { auto impl = std::make_unique(context.get_wrapped_context(), config, eh); return std::make_unique(std::move(impl)); } } xeus-zmq-3.1.0/src/client/xclient_zmq_impl.cpp000066400000000000000000000146611464077067000214560ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include "xclient_zmq_impl.hpp" #include "../common/xauthentication.hpp" #include "../common/xzmq_serializer.hpp" namespace xeus { namespace { constexpr std::size_t max_retry = 3; constexpr long heartbeat_timeout = std::chrono::milliseconds(90).count(); } xclient_zmq_impl::xclient_zmq_impl(zmq::context_t& context, const xeus::xconfiguration& config, nl::json::error_handler_t eh) : p_auth(make_xauthentication(config.m_signature_scheme, config.m_key)) , m_shell_client(context, config.m_transport, config.m_ip, config.m_shell_port) , m_control_client(context, config.m_transport, config.m_ip, config.m_control_port) , m_iopub_client(context, config, this) , m_heartbeat_client(context, config, max_retry, heartbeat_timeout) , p_messenger(context) , m_error_handler(eh) { } // Has to be in the cpp because incomplete // types are used in unique_ptr in the header xclient_zmq_impl::~xclient_zmq_impl() { m_iopub_thread.join(); m_heartbeat_thread.join(); } void xclient_zmq_impl::send_on_shell(xmessage msg) { zmq::multipart_t wire_msg = xzmq_serializer::serialize(std::move(msg), *p_auth, m_error_handler); m_shell_client.send_message(wire_msg); } void xclient_zmq_impl::send_on_control(xmessage msg) { zmq::multipart_t wire_msg = xzmq_serializer::serialize(std::move(msg), *p_auth, m_error_handler); m_control_client.send_message(wire_msg); } std::optional xclient_zmq_impl::receive_on_shell(bool blocking) { std::optional wire_msg = m_shell_client.receive_message(blocking); if (wire_msg.has_value()) { return deserialize(wire_msg.value()); } else { return std::nullopt; } } std::optional xclient_zmq_impl::receive_on_control(bool blocking) { std::optional wire_msg = m_control_client.receive_message(blocking); if (wire_msg.has_value()) { return deserialize(wire_msg.value()); } else { return std::nullopt; } } void xclient_zmq_impl::register_shell_listener(const listener& l) { m_shell_listener = l; } void xclient_zmq_impl::register_control_listener(const listener& l) { m_control_listener = l; } std::size_t xclient_zmq_impl::iopub_queue_size() const { return m_iopub_client.iopub_queue_size(); } std::optional xclient_zmq_impl::pop_iopub_message() { return m_iopub_client.pop_iopub_message(); } void xclient_zmq_impl::register_iopub_listener(const iopub_listener& l) { m_iopub_listener = l; } void xclient_zmq_impl::register_kernel_status_listener(const kernel_status_listener& l) { m_heartbeat_client.register_kernel_status_listener(l); } void xclient_zmq_impl::connect() { p_messenger.connect(); } void xclient_zmq_impl::stop_channels() { p_messenger.stop_channels(); } void xclient_zmq_impl::notify_shell_listener(xmessage msg) { m_shell_listener(std::move(msg)); } void xclient_zmq_impl::notify_control_listener(xmessage msg) { m_control_listener(std::move(msg)); } void xclient_zmq_impl::notify_iopub_listener(xpub_message msg) { m_iopub_listener(std::move(msg)); } void xclient_zmq_impl::notify_kernel_dead(bool status) { m_heartbeat_client.notify_kernel_dead(status); } void xclient_zmq_impl::poll(long timeout) { zmq::multipart_t wire_msg; zmq::pollitem_t items[] = { { m_shell_client.get_socket(), 0, ZMQ_POLLIN, 0 }, { m_control_client.get_socket(), 0, ZMQ_POLLIN, 0 } }; while (true) { zmq::poll(&items[0], 2, std::chrono::milliseconds(timeout)); try { if (items[0].revents & ZMQ_POLLIN) { wire_msg.recv(m_shell_client.get_socket()); xmessage msg = deserialize(wire_msg); notify_shell_listener(std::move(msg)); return; } if (items[1].revents & ZMQ_POLLIN) { wire_msg.recv(m_control_client.get_socket()); xmessage msg = deserialize(wire_msg); notify_control_listener(std::move(msg)); return; } } catch (std::exception& e) { std::cerr << e.what() << std::endl; } } } void xclient_zmq_impl::wait_for_message() { std::optional pending_message = pop_iopub_message(); if (pending_message.has_value()) { notify_iopub_listener(std::move(*pending_message)); } else { poll(-1); } } void xclient_zmq_impl::start() { start_iopub_thread(); start_heartbeat_thread(); } void xclient_zmq_impl::start_iopub_thread() { m_iopub_thread = std::move(xthread(&xiopub_client::run, &m_iopub_client)); } void xclient_zmq_impl::start_heartbeat_thread() { m_heartbeat_thread = std::move(xthread(&xheartbeat_client::run, &m_heartbeat_client)); } xmessage xclient_zmq_impl::deserialize(zmq::multipart_t& wire_msg) const { return xzmq_serializer::deserialize(wire_msg, *p_auth); } xpub_message xclient_zmq_impl::deserialize_iopub(zmq::multipart_t& wire_msg) const { return xzmq_serializer::deserialize_iopub(wire_msg, *p_auth); } } xeus-zmq-3.1.0/src/client/xclient_zmq_impl.hpp000066400000000000000000000067611464077067000214650ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_CLIENT_ZMQ_IMPL_HPP #define XEUS_CLIENT_ZMQ_IMPL_HPP #include #include "zmq.hpp" #include "xeus/xeus_context.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus/xmessage.hpp" #include "xeus-zmq/xthread.hpp" #include "xdealer_channel.hpp" #include "xiopub_client.hpp" #include "xheartbeat_client.hpp" #include "xclient_messenger.hpp" namespace xeus { class xauthentication; class xclient_zmq_impl { public: using listener = std::function; using iopub_listener = std::function; using kernel_status_listener = std::function; xclient_zmq_impl(zmq::context_t& context, const xconfiguration& config, nl::json::error_handler_t eh); ~xclient_zmq_impl(); xclient_zmq_impl(const xclient_zmq_impl&) = delete; xclient_zmq_impl& operator=(const xclient_zmq_impl&) = delete; xclient_zmq_impl(xclient_zmq_impl&&) = delete; xclient_zmq_impl& operator=(xclient_zmq_impl&&) = delete; // shell channel void send_on_shell(xmessage msg); std::optional receive_on_shell(bool blocking); void register_shell_listener(const listener& l); // control channel void send_on_control(xmessage msg); std::optional receive_on_control(bool blocking); void register_control_listener(const listener& l); // iopub channel std::size_t iopub_queue_size() const; std::optional pop_iopub_message(); void register_iopub_listener(const iopub_listener& l); // heartbeat channel void register_kernel_status_listener(const kernel_status_listener& l); // client messenger void connect(); void stop_channels(); void wait_for_message(); void start(); xmessage deserialize(zmq::multipart_t& wire_msg) const; xpub_message deserialize_iopub(zmq::multipart_t& wire_msg) const; private: void start_iopub_thread(); void start_heartbeat_thread(); void poll(long timeout); void notify_shell_listener(xmessage msg); void notify_control_listener(xmessage msg); void notify_iopub_listener(xpub_message msg); void notify_kernel_dead(bool status); using authentication_ptr = std::unique_ptr; authentication_ptr p_auth; xdealer_channel m_shell_client; xdealer_channel m_control_client; xiopub_client m_iopub_client; xheartbeat_client m_heartbeat_client; xclient_messenger p_messenger; nl::json::error_handler_t m_error_handler; listener m_shell_listener; listener m_control_listener; iopub_listener m_iopub_listener; xthread m_iopub_thread; xthread m_heartbeat_thread; }; } #endif xeus-zmq-3.1.0/src/client/xdealer_channel.cpp000066400000000000000000000036011464077067000212040ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xeus-zmq/xmiddleware.hpp" #include "xdealer_channel.hpp" namespace xeus { xdealer_channel::xdealer_channel(zmq::context_t& context, const std::string& transport, const std::string& ip, const std::string& port) : m_socket(context, zmq::socket_type::dealer) , m_dealer_end_point("") { m_dealer_end_point = get_end_point(transport, ip, port); m_socket.connect(m_dealer_end_point); } xdealer_channel::~xdealer_channel() { m_socket.disconnect(m_dealer_end_point); } void xdealer_channel::send_message(zmq::multipart_t& message) { message.send(m_socket); } std::optional xdealer_channel::receive_message(bool blocking) { zmq::multipart_t wire_msg; zmq::recv_flags flags = zmq::recv_flags::none; if (!blocking) { flags = zmq::recv_flags::dontwait; } if (wire_msg.recv(m_socket, static_cast(flags))) { return wire_msg; } else { return std::nullopt; } } zmq::socket_t& xdealer_channel::get_socket() { return m_socket; } } xeus-zmq-3.1.0/src/client/xdealer_channel.hpp000066400000000000000000000024111464077067000212070ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_DEALER_CHANNEL_HPP #define XEUS_DEALER_CHANNEL_HPP #include "zmq.hpp" #include "zmq_addon.hpp" namespace xeus { class xdealer_channel { public: xdealer_channel(zmq::context_t& context, const std::string& transport, const std::string& ip, const std::string& port); ~xdealer_channel(); void send_message(zmq::multipart_t& message); std::optional receive_message(bool blocking); zmq::socket_t& get_socket(); private: zmq::socket_t m_socket; std::string m_dealer_end_point; }; } #endif xeus-zmq-3.1.0/src/client/xheartbeat_client.cpp000066400000000000000000000070071464077067000215610ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include "xheartbeat_client.hpp" #include "xclient_zmq_impl.hpp" #include "../common/xmiddleware_impl.hpp" namespace xeus { xheartbeat_client::xheartbeat_client(zmq::context_t& context, const xeus::xconfiguration& config, const std::size_t max_retry, const long timeout) : m_heartbeat(context, zmq::socket_type::req) , m_controller(context, zmq::socket_type::rep) , m_max_retry(max_retry) , m_heartbeat_timeout(timeout) , m_heartbeat_end_point("") , m_request_stop(false) { m_heartbeat_end_point = get_end_point(config.m_transport, config.m_ip, config.m_hb_port); m_heartbeat.connect(m_heartbeat_end_point); init_socket(m_controller, get_controller_end_point("heartbeat")); } xheartbeat_client::~xheartbeat_client() { m_heartbeat.disconnect(m_heartbeat_end_point); } void xheartbeat_client::send_heartbeat_message() { zmq::message_t ping_msg("ping", 4); m_heartbeat.send(ping_msg, zmq::send_flags::none); } bool xheartbeat_client::wait_for_answer(long timeout) { zmq::pollitem_t items[] = { { m_heartbeat, 0, ZMQ_POLLIN, 0 }, { m_controller, 0, ZMQ_POLLIN, 0 } }; zmq::poll(&items[0], 2, std::chrono::milliseconds(timeout)); try { if (items[0].revents & ZMQ_POLLIN) { zmq::multipart_t wire_msg; wire_msg.recv(m_heartbeat); } if (items[1].revents & ZMQ_POLLIN) { // stop message zmq::multipart_t wire_msg; wire_msg.recv(m_controller); wire_msg.send(m_controller); m_request_stop = true; } return true; } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return false; } void xheartbeat_client::register_kernel_status_listener(const kernel_status_listener& l) { m_kernel_status_listener = l; } void xheartbeat_client::notify_kernel_dead(bool status) { m_kernel_status_listener(status); } void xheartbeat_client::run() { std::size_t retry_count = 0; while(!m_request_stop) { send_heartbeat_message(); if(!wait_for_answer(m_heartbeat_timeout)) { if (retry_count < m_max_retry) { ++retry_count; } else { notify_kernel_dead(true); break; } } else { retry_count = 0; } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } } xeus-zmq-3.1.0/src/client/xheartbeat_client.hpp000066400000000000000000000032271464077067000215660ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_HEARTBEAT_CLIENT_HPP #define XEUS_HEARTBEAT_CLIENT_HPP #include #include "zmq.hpp" #include "xeus/xkernel_configuration.hpp" namespace xeus { class xheartbeat_client { public: using kernel_status_listener = std::function; xheartbeat_client(zmq::context_t& context, const xeus::xconfiguration& config, const std::size_t max_retry, const long timeout); ~xheartbeat_client(); void run(); void register_kernel_status_listener(const kernel_status_listener& l); void notify_kernel_dead(bool status); private: void send_heartbeat_message(); bool wait_for_answer(long timeout); zmq::socket_t m_heartbeat; zmq::socket_t m_controller; kernel_status_listener m_kernel_status_listener; const std::size_t m_max_retry; const long m_heartbeat_timeout; std::string m_heartbeat_end_point; bool m_request_stop; }; } #endif xeus-zmq-3.1.0/src/client/xiopub_client.cpp000066400000000000000000000062711464077067000207420ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include "xiopub_client.hpp" #include "xclient_zmq_impl.hpp" #include "../common/xmiddleware_impl.hpp" #include "../common/xzmq_serializer.hpp" namespace xeus { xiopub_client::xiopub_client(zmq::context_t& context, const xeus::xconfiguration& config, xclient_zmq_impl* client) : m_iopub(context, zmq::socket_type::sub) , m_controller(context, zmq::socket_type::rep) , m_iopub_end_point("") , p_client_impl(client) { m_iopub_end_point = get_end_point(config.m_transport, config.m_ip, config.m_iopub_port); m_iopub.connect(m_iopub_end_point); m_iopub.set(zmq::sockopt::subscribe, ""); init_socket(m_controller, get_controller_end_point("iopub")); } xiopub_client::~xiopub_client() { m_iopub.disconnect(m_iopub_end_point); } std::size_t xiopub_client::iopub_queue_size() const { std::lock_guard guard(m_queue_mutex); return m_message_queue.size(); } std::optional xiopub_client::pop_iopub_message() { std::lock_guard guard(m_queue_mutex); if (!m_message_queue.empty()) { xpub_message msg = std::move(m_message_queue.back()); m_message_queue.pop(); return msg; } else { return std::nullopt; } } void xiopub_client::run() { zmq::pollitem_t items[] = { { m_iopub, 0, ZMQ_POLLIN, 0 }, { m_controller, 0, ZMQ_POLLIN, 0 } }; while (true) { zmq::poll(&items[0], 2, std::chrono::milliseconds(-1)); try { if (items[0].revents & ZMQ_POLLIN) { zmq::multipart_t wire_msg; wire_msg.recv(m_iopub); xpub_message msg = p_client_impl->deserialize_iopub(wire_msg); { std::lock_guard guard(m_queue_mutex); m_message_queue.push(std::move(msg)); } } if (items[1].revents & ZMQ_POLLIN) { // stop message zmq::multipart_t wire_msg; wire_msg.recv(m_controller); wire_msg.send(m_controller); break; } } catch (std::exception& e) { std::cerr << e.what() << std::endl; } } } } xeus-zmq-3.1.0/src/client/xiopub_client.hpp000066400000000000000000000027021464077067000207420ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_IOPUB_CLIENT_HPP #define XEUS_IOPUB_CLIENT_HPP #include #include #include "zmq.hpp" #include "xeus/xmessage.hpp" #include "xeus/xkernel_configuration.hpp" namespace xeus { class xclient_zmq_impl; class xiopub_client { public: xiopub_client(zmq::context_t& context, const xeus::xconfiguration& config, xclient_zmq_impl* client); ~xiopub_client(); std::size_t iopub_queue_size() const; std::optional pop_iopub_message(); void run(); private: zmq::socket_t m_iopub; zmq::socket_t m_controller; std::string m_iopub_end_point; std::queue m_message_queue; mutable std::mutex m_queue_mutex; xclient_zmq_impl* p_client_impl; }; } #endif xeus-zmq-3.1.0/src/common/000077500000000000000000000000001464077067000153765ustar00rootroot00000000000000xeus-zmq-3.1.0/src/common/xauthentication.cpp000066400000000000000000000250221464077067000213120ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include #include #include #include #include #include #if OPENSSL_VERSION_NUMBER < 0x30000000L #include #include #else #include #include #include #include #include #endif #include "xeus/xstring_utils.hpp" #include "xauthentication.hpp" namespace xeus { // xraw_buffer implementation xraw_buffer::xraw_buffer(const unsigned char* data, size_t size) : m_data(data), m_size(size) { } const unsigned char* xraw_buffer::data() const { return m_data; } size_t xraw_buffer::size() const { return m_size; } // Specialization of xauthentication using OpenSSL. class openssl_xauthentication : public xauthentication { public: openssl_xauthentication(const std::string& scheme, const std::string& key); virtual ~openssl_xauthentication(); private: std::string sign_impl(const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const override; bool verify_impl(const xraw_buffer& signature, const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const override; std::string compute_hex_signature(const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const; std::string m_key; #if OPENSSL_VERSION_NUMBER < 0x30000000L const EVP_MD* m_evp; HMAC_CTX* m_hmac; #else std::string m_hash_name; OSSL_PARAM m_ossl_params[2]; EVP_MAC* m_evp_mac; EVP_MAC_CTX* m_evp_mac_ctx; #endif mutable std::mutex m_mac_mutex; }; // Specialization of xauthentication without any signature checking. class no_xauthentication : public xauthentication { public: no_xauthentication() = default; virtual ~no_xauthentication() = default; private: std::string sign_impl(const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const override; bool verify_impl(const xraw_buffer& signature, const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const override; }; std::string xauthentication::sign(const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const { return sign_impl(header, parent_header, meta_data, content); } bool xauthentication::verify(const xraw_buffer& signature, const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const { return verify_impl(signature, header, parent_header, meta_data, content); } std::unique_ptr make_xauthentication(const std::string& scheme, const std::string& key) { if (scheme == "none") { return std::make_unique(); } else { return std::make_unique(scheme, key); } } #if OPENSSL_VERSION_NUMBER < 0x30000000L inline const EVP_MD* asevp(const std::string& scheme) { static const std::map schemes = { {"hmac-md5", EVP_md5}, {"hmac-sha1", EVP_sha1}, // MDC2 is disabled by default unless enable-mdc2 is specified // {"hmac-mdc2", EVP_mdc2}, {"hmac-ripemd160", EVP_ripemd160}, #if OPENSSL_VERSION_NUMBER >= 0x10100000L {"hmac-blake2b512", EVP_blake2b512}, {"hmac-blake2s256", EVP_blake2s256}, #endif {"hmac-sha224", EVP_sha224}, {"hmac-sha256", EVP_sha256}, {"hmac-sha384", EVP_sha384}, {"hmac-sha512", EVP_sha512} }; return schemes.at(scheme)(); } #endif openssl_xauthentication::openssl_xauthentication(const std::string& scheme, const std::string& key) : m_key(key) #if OPENSSL_VERSION_NUMBER < 0x30000000L , m_evp(asevp(scheme)) #else , m_evp_mac(nullptr) , m_evp_mac_ctx(nullptr) #endif { #if OPENSSL_VERSION_NUMBER < 0x10100000L // OpenSSL 1.0.x m_hmac = new HMAC_CTX(); HMAC_CTX_init(m_hmac); #elif OPENSSL_VERSION_NUMBER < 0x30000000L m_hmac = HMAC_CTX_new(); #else m_hash_name = scheme.substr(5); std::transform(m_hash_name.begin(), m_hash_name.end(), m_hash_name.begin(), [](unsigned char c) { return std::toupper(c); }); m_ossl_params[0] = OSSL_PARAM_construct_utf8_string("digest", const_cast(m_hash_name.c_str()), std::size_t(0)); m_ossl_params[1] = OSSL_PARAM_construct_end(); m_evp_mac = EVP_MAC_fetch(nullptr, "hmac", nullptr); if (!m_evp_mac) { throw std::runtime_error("Could not fetch evp_mac"); } m_evp_mac_ctx = EVP_MAC_CTX_new(m_evp_mac); if (!m_evp_mac_ctx) { throw std::runtime_error("Could not allocate evp_mac_ctx"); } #endif } openssl_xauthentication::~openssl_xauthentication() { #if OPENSSL_VERSION_NUMBER < 0x10100000L // OpenSSL 1.0.x HMAC_CTX_cleanup(m_hmac); #elif OPENSSL_VERSION_NUMBER < 0x30000000L HMAC_CTX_free(m_hmac); #else EVP_MAC_CTX_free(m_evp_mac_ctx); EVP_MAC_free(m_evp_mac); #endif } std::string openssl_xauthentication::sign_impl(const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const { std::lock_guard lock(m_mac_mutex); std::string hex_sig = compute_hex_signature(header, parent_header, meta_data, content); return hex_sig; } bool openssl_xauthentication::verify_impl(const xraw_buffer& signature, const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const { std::lock_guard lock(m_mac_mutex); std::string hex_sig = compute_hex_signature(header, parent_header, meta_data, content); auto cmp = CRYPTO_memcmp(reinterpret_cast(hex_sig.c_str()), signature.data(), hex_sig.size()); return cmp == 0; } std::string openssl_xauthentication::compute_hex_signature(const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const { #if OPENSSL_VERSION_NUMBER < 0x30000000L HMAC_Init_ex(m_hmac, m_key.c_str(), m_key.size(), m_evp, nullptr); HMAC_Update(m_hmac, header.data(), header.size()); HMAC_Update(m_hmac, parent_header.data(), parent_header.size()); HMAC_Update(m_hmac, meta_data.data(), meta_data.size()); HMAC_Update(m_hmac, content.data(), content.size()); auto sig = std::vector(EVP_MD_size(m_evp)); HMAC_Final(m_hmac, sig.data(), nullptr); #else EVP_MAC_init(m_evp_mac_ctx, reinterpret_cast(m_key.c_str()), m_key.size(), m_ossl_params); EVP_MAC_update(m_evp_mac_ctx, header.data(), header.size()); EVP_MAC_update(m_evp_mac_ctx, parent_header.data(), parent_header.size()); EVP_MAC_update(m_evp_mac_ctx, meta_data.data(), meta_data.size()); EVP_MAC_update(m_evp_mac_ctx, content.data(), content.size()); size_t final_size(0); // Computes the final size EVP_MAC_final(m_evp_mac_ctx, nullptr, &final_size, size_t(0)); auto sig = std::vector(final_size); EVP_MAC_final(m_evp_mac_ctx, sig.data(), &final_size, sig.size()); #endif return hex_string(sig); } std::string no_xauthentication::sign_impl(const xraw_buffer& /*header*/, const xraw_buffer& /*parent_header*/, const xraw_buffer& /*meta_data*/, const xraw_buffer& /*content*/) const { return std::string(); } bool no_xauthentication::verify_impl(const xraw_buffer& /*signature*/, const xraw_buffer& /*header*/, const xraw_buffer& /*parent_header*/, const xraw_buffer& /*meta_data*/, const xraw_buffer& /*content*/) const { return true; } } xeus-zmq-3.1.0/src/common/xauthentication.hpp000066400000000000000000000052131464077067000213170ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_AUTHENTICATION_HPP #define XEUS_AUTHENTICATION_HPP #include #include namespace xeus { class xraw_buffer { public: xraw_buffer(const unsigned char* data, size_t size); const unsigned char* data() const; size_t size() const; private: const unsigned char* m_data; size_t m_size; }; class xauthentication { public: virtual ~xauthentication() = default; xauthentication(const xauthentication&) = delete; xauthentication& operator=(const xauthentication&) = delete; xauthentication(xauthentication&&) = delete; xauthentication& operator=(xauthentication&&) = delete; std::string sign(const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const; bool verify(const xraw_buffer& signature, const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const; protected: xauthentication() = default; private: virtual std::string sign_impl(const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const = 0; virtual bool verify_impl(const xraw_buffer& signature, const xraw_buffer& header, const xraw_buffer& parent_header, const xraw_buffer& meta_data, const xraw_buffer& content) const = 0; }; std::unique_ptr make_xauthentication(const std::string& scheme, const std::string& key); } #endif xeus-zmq-3.1.0/src/common/xmiddleware.cpp000066400000000000000000000067521464077067000204210ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include #include "zmq_addon.hpp" #include "xmiddleware_impl.hpp" namespace xeus { std::string get_controller_end_point(const std::string& channel) { return "inproc://" + channel + "_controller"; } std::string get_publisher_end_point() { return "inproc://publisher"; } std::string get_end_point(const std::string& transport, const std::string& ip, const std::string& port) { char sep = (transport == "tcp") ? ':' : '-'; return transport + "://" + ip + sep + port; } int get_socket_linger() { return 1000; } std::string find_free_port_impl(zmq::socket_t& socket, const std::string& transport, const std::string& ip, std::size_t max_tries, int start, int stop) { std::random_device r; std::default_random_engine generator(r()); std::uniform_int_distribution distribution(start, stop); std::size_t tries(0); std::string rd_port; do { rd_port = std::to_string(distribution(generator)); } while (++tries <= max_tries && zmq_bind(socket, get_end_point(transport, ip, rd_port).c_str()) != 0); if(tries > max_tries) { rd_port = ""; } return rd_port; } void init_socket(zmq::socket_t& socket, const std::string& transport, const std::string& ip, const std::string& port) { socket.set(zmq::sockopt::linger, get_socket_linger()); if (!port.empty()) { socket.bind(get_end_point(transport, ip, port)); } else { find_free_port_impl(socket, transport, ip, 100, 49152, 65536); } } void init_socket(zmq::socket_t& socket, const std::string& end_point) { socket.set(zmq::sockopt::linger, get_socket_linger()); socket.bind(end_point); } std::string get_socket_port(const zmq::socket_t& socket) { std::string end_point = socket.get(zmq::sockopt::last_endpoint, 32); return end_point.substr(end_point.find_last_of(":") + 1); } std::string find_free_port(std::size_t max_tries, int start, int stop) { static const std::string transport = "tcp"; static const std::string ip = "127.0.0.1"; zmq::context_t ctx; zmq::socket_t socket(ctx, zmq::socket_type::req); std::string port = find_free_port_impl(socket, transport, ip, max_tries, start, stop); socket.unbind(get_end_point(transport, ip, port)); return port; } } xeus-zmq-3.1.0/src/common/xmiddleware_impl.hpp000066400000000000000000000021301464077067000214310ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_MIDDLEWARE_IMPL_HPP #define XEUS_MIDDLEWARE_IMPL_HPP #include #include "zmq.hpp" #include "xeus-zmq/xmiddleware.hpp" namespace xeus { void init_socket(zmq::socket_t& socket, const std::string& transport, const std::string& ip, const std::string& port); void init_socket(zmq::socket_t& socket, const std::string& end_point); std::string get_socket_port(const zmq::socket_t& socket); } #endif xeus-zmq-3.1.0/src/common/xzmq_context.cpp000066400000000000000000000003321464077067000206430ustar00rootroot00000000000000#include "zmq.hpp" #include "xeus-zmq/xzmq_context.hpp" namespace xeus { std::unique_ptr make_zmq_context() { return std::unique_ptr(new xcontext_impl()); } } xeus-zmq-3.1.0/src/common/xzmq_serializer.cpp000066400000000000000000000172351464077067000213420ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xzmq_serializer.hpp" namespace xeus { namespace { const std::string DELIMITER = ""; bool is_delimiter(zmq::message_t& frame) { std::size_t frame_size = frame.size(); if (frame_size != DELIMITER.size()) { return false; } std::string check(frame.data(), frame_size); return check == DELIMITER; } xraw_buffer make_raw_buffer(zmq::message_t& msg) { return xraw_buffer(msg.data(), msg.size()); } void parse_zmq_message(const zmq::message_t& msg, nl::json& json) { const char* buf = msg.data(); json = nl::json::parse(buf, buf + msg.size()); } zmq::message_t write_zmq_message(const nl::json& json, nl::json::error_handler_t error_handler) { std::string buffer = json.dump(-1, ' ', false, error_handler); return zmq::message_t(buffer.c_str(), buffer.size()); } void serialize_message_base(xmessage_base&& msg, const xauthentication& auth, nl::json::error_handler_t error_handler, zmq::multipart_t& wire_msg) { zmq::message_t header = write_zmq_message(msg.header(), error_handler); zmq::message_t parent_header = write_zmq_message(msg.parent_header(), error_handler); zmq::message_t metadata = write_zmq_message(msg.metadata(), error_handler); zmq::message_t content = write_zmq_message(msg.content(), error_handler); std::string sig = auth.sign(make_raw_buffer(header), make_raw_buffer(parent_header), make_raw_buffer(metadata), make_raw_buffer(content)); zmq::message_t signature(sig.begin(), sig.end()); wire_msg.add(std::move(signature)); wire_msg.add(std::move(header)); wire_msg.add(std::move(parent_header)); wire_msg.add(std::move(metadata)); wire_msg.add(std::move(content)); // was not const and could only be called on rvalues. for (const binary_buffer& buffer : std::move(msg).buffers()) { wire_msg.add(zmq::message_t(buffer.data(), buffer.size())); } } xmessage_base_data deserialize_message_base(zmq::multipart_t& wire_msg, const xauthentication& auth) { zmq::message_t signature = wire_msg.pop(); zmq::message_t header = wire_msg.pop(); zmq::message_t parent_header = wire_msg.pop(); zmq::message_t metadata = wire_msg.pop(); zmq::message_t content = wire_msg.pop(); xmessage_base_data data; parse_zmq_message(header, data.m_header); parse_zmq_message(parent_header, data.m_parent_header); parse_zmq_message(metadata, data.m_metadata); parse_zmq_message(content, data.m_content); while (!wire_msg.empty()) { zmq::message_t msg = wire_msg.pop(); const char* buf = msg.data(); data.m_buffers.emplace_back(buf, buf + msg.size()); } // TODO: should we verify with buffers if (!auth.verify(make_raw_buffer(signature), make_raw_buffer(header), make_raw_buffer(parent_header), make_raw_buffer(metadata), make_raw_buffer(content))) { throw std::runtime_error("ERROR: Signatures don't match"); } return data; } void serialize_zmq_id(const xmessage& msg, zmq::multipart_t& wire_msg) { auto app = [&wire_msg](const std::string& uid) { wire_msg.add(zmq::message_t(uid.begin(), uid.end())); }; std::for_each(msg.identities().begin(), msg.identities().end(), app); wire_msg.add(zmq::message_t(DELIMITER.begin(), DELIMITER.end())); } xmessage::guid_list deserialize_zmq_id(zmq::multipart_t& wire_msg) { xmessage::guid_list zmq_id; zmq::message_t frame = wire_msg.pop(); // ZMQ identites while (!is_delimiter(frame) && wire_msg.size() != 0) { zmq_id.emplace_back(frame.data(), frame.size()); frame = wire_msg.pop(); } // if wire_msg is empty, that means frame doesn't contain if (wire_msg.size() == 0) { throw std::runtime_error("ERROR: Delimiter not present in message"); } return zmq_id; } void serialize_topic(const xpub_message& msg, zmq::multipart_t& wire_msg) { wire_msg.add(zmq::message_t(msg.topic().begin(), msg.topic().end())); wire_msg.add(zmq::message_t(DELIMITER.begin(), DELIMITER.end())); } std::string deserialize_topic(zmq::multipart_t& wire_msg) { zmq::message_t topic_msg = wire_msg.pop(); std::string topic = std::string(topic_msg.data(), topic_msg.size()); wire_msg.pop(); return topic; } } zmq::multipart_t xzmq_serializer::serialize(xmessage&& msg, const xauthentication& auth, nl::json::error_handler_t error_handler) { zmq::multipart_t wire_msg; serialize_zmq_id(msg, wire_msg); serialize_message_base(std::move(msg), auth, error_handler, wire_msg); return wire_msg; } xmessage xzmq_serializer::deserialize(zmq::multipart_t& wire_msg, const xauthentication& auth) { xmessage::guid_list zmq_id = deserialize_zmq_id(wire_msg); xmessage_base_data data = deserialize_message_base(wire_msg, auth); return xmessage(zmq_id, std::move(data)); } zmq::multipart_t xzmq_serializer::serialize_iopub(xpub_message&& msg, const xauthentication& auth, nl::json::error_handler_t error_handler) { zmq::multipart_t wire_msg; serialize_topic(msg, wire_msg); serialize_message_base(std::move(msg), auth, error_handler, wire_msg); return wire_msg; } xpub_message xzmq_serializer::deserialize_iopub(zmq::multipart_t& wire_msg, const xauthentication& auth) { std::string topic = deserialize_topic(wire_msg); xmessage_base_data data = deserialize_message_base(wire_msg, auth); return xpub_message(topic, std::move(data)); } } xeus-zmq-3.1.0/src/common/xzmq_serializer.hpp000066400000000000000000000031671464077067000213460ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_ZMQ_SERIALIZER_HPP #define XEUS_ZMQ_SERIALIZER_HPP #include "zmq_addon.hpp" #include "xeus/xmessage.hpp" #include "xauthentication.hpp" namespace xeus { class xzmq_serializer { public: static zmq::multipart_t serialize(xmessage&& msg, const xauthentication& auth, nl::json::error_handler_t error_handler = nl::json::error_handler_t::strict); static xmessage deserialize(zmq::multipart_t& wire_msg, const xauthentication& auth); static zmq::multipart_t serialize_iopub(xpub_message&& msg, const xauthentication& auth, nl::json::error_handler_t error_handler = nl::json::error_handler_t::strict); static xpub_message deserialize_iopub(zmq::multipart_t& wire_msg, const xauthentication& auth); }; } #endif xeus-zmq-3.1.0/src/debugger/000077500000000000000000000000001464077067000156725ustar00rootroot00000000000000xeus-zmq-3.1.0/src/debugger/xdap_tcp_client.cpp000066400000000000000000000056341464077067000215460ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "zmq_addon.hpp" #include "nlohmann/json.hpp" #include "xeus/xmessage.hpp" #include "xeus-zmq/xdap_tcp_client.hpp" #include "xdap_tcp_client_impl.hpp" #include "../common/xzmq_serializer.hpp" namespace xeus { /********************************* * xdap_tcp_client implemenation * *********************************/ xdap_tcp_configuration::xdap_tcp_configuration(dap_tcp_type adap_tcp_type, dap_init_type adap_init_type, const std::string& user_name, const std::string& session_id) : m_dap_tcp_type(adap_tcp_type) , m_dap_init_type(adap_init_type) , m_user_name(user_name) , m_session_id(session_id) { } xdap_tcp_client::xdap_tcp_client(xcontext& context, const xeus::xconfiguration& config, int socket_linger, const xdap_tcp_configuration& dap_config, const event_callback& cb) : p_impl(new xdap_tcp_client_impl( context, config, socket_linger, dap_config, cb, [this](nl::json message) { handle_event(std::move(message)); } )) { } xdap_tcp_client::~xdap_tcp_client() = default; void xdap_tcp_client::start_debugger(std::string tcp_end_point, std::string publisher_end_point, std::string controller_end_point, std::string controller_header_end_point) { p_impl->start_debugger( tcp_end_point, publisher_end_point, controller_end_point, controller_header_end_point ); } void xdap_tcp_client::forward_event(nl::json message) { p_impl->forward_event(std::move(message)); } void xdap_tcp_client::send_dap_request(nl::json message) { p_impl->send_dap_request(std::move(message)); } nl::json xdap_tcp_client::wait_for_message(const message_condition& condition) { return p_impl->wait_for_message(condition); } } xeus-zmq-3.1.0/src/debugger/xdap_tcp_client_impl.cpp000066400000000000000000000352231464077067000225640ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "zmq_addon.hpp" #include "nlohmann/json.hpp" #include "xeus/xmessage.hpp" #include "xdap_tcp_client_impl.hpp" #include "../common/xzmq_serializer.hpp" namespace xeus { xdap_tcp_client_impl::xdap_tcp_client_impl( xcontext& context, const xeus::xconfiguration& config, int socket_linger, const xdap_tcp_configuration& dap_config, const event_callback& cb, const event_callback& handler ) : m_tcp_socket(context.get_wrapped_context(), zmq::socket_type::stream) , m_socket_id() , m_publisher(context.get_wrapped_context(), zmq::socket_type::pub) , m_controller(context.get_wrapped_context(), zmq::socket_type::rep) , m_controller_header(context.get_wrapped_context(), zmq::socket_type::rep) , m_dap_tcp_type(dap_config.m_dap_tcp_type) , m_dap_init_type(dap_config.m_dap_init_type) , m_user_name(dap_config.m_user_name) , m_session_id(dap_config.m_session_id) , m_event_callback(cb) , m_event_handler(handler) , p_auth(xeus::make_xauthentication(config.m_signature_scheme, config.m_key)) , m_parent_header("") , m_request_stop(false) { m_tcp_socket.set(zmq::sockopt::linger, socket_linger); m_publisher.set(zmq::sockopt::linger, socket_linger); m_controller.set(zmq::sockopt::linger, socket_linger); m_controller_header.set(zmq::sockopt::linger, socket_linger); } void xdap_tcp_client_impl::forward_event(nl::json message) { if (message["type"] == "event" && message["event"] == "stopped" && message["body"]["allThreadsStopped"]) { int seq = message["seq"].get() + 1; nl::json req = { {"seq", seq}, {"type", "request"}, {"command", "threads"} }; send_dap_request(std::move(req)); auto rep = wait_for_message([](const nl::json& msg) { return msg["command"] == "threads"; }); nl::json new_message = message; new_message["body"]["threadList"] = nl::json::array(); for (auto& th: rep["body"]["threads"]) { new_message["body"]["threadList"].push_back(th["id"]); } m_event_callback(new_message); } else { m_event_callback(message); } nl::json header = xeus::make_header("debug_event", m_user_name, m_session_id); nl::json parent_header = m_parent_header.empty() ? nl::json::object() : nl::json::parse(m_parent_header); xeus::xpub_message msg("debug_event", std::move(header), std::move(parent_header), nl::json::object(), std::move(message), xeus::buffer_sequence()); zmq::multipart_t wire_msg = xzmq_serializer::serialize_iopub(std::move(msg), *p_auth); //std::move(msg).serialize(wire_msg, *p_auth); wire_msg.send(m_publisher); } void xdap_tcp_client_impl::send_dap_request(nl::json message) { std::string content = message.dump(); size_t content_length = content.length(); std::string buffer = xdap_tcp_client::HEADER + std::to_string(content_length) + xdap_tcp_client::SEPARATOR + content; zmq::message_t raw_message(buffer.c_str(), buffer.length()); m_tcp_socket.send(get_tcp_id(), zmq::send_flags::sndmore); m_tcp_socket.send(raw_message, zmq::send_flags::none); } nl::json xdap_tcp_client_impl::wait_for_message(const message_condition& condition) { bool wait_cond = true; nl::json message; // Checks if the message is not already in the message queue auto iter = std::find_if(m_message_queue.cbegin(), m_message_queue.cend(), [&condition, &message](const std::string& raw_message) { message = nl::json::parse(raw_message); return condition(message); }); if (iter != m_message_queue.cend()) { wait_cond = false; m_message_queue.erase(iter); } // Waits for additional messages while (wait_cond) { handle_tcp_socket(m_stopped_queue); while (!m_stopped_queue.empty()) { const std::string& raw_message = m_stopped_queue.front(); nl::json tmp_message = nl::json::parse(raw_message); if (condition(tmp_message)) { wait_cond = false; message = tmp_message; } else { m_message_queue.push_back(raw_message); } m_stopped_queue.pop_front(); } } return message; } void xdap_tcp_client_impl::start_debugger(std::string tcp_end_point, std::string publisher_end_point, std::string controller_end_point, std::string controller_header_end_point) { m_publisher.connect(publisher_end_point); m_controller.connect(controller_end_point); m_controller_header.connect(controller_header_end_point); init_tcp_socket(tcp_end_point); // Tells the controller that the connection with // ptvsd has been established zmq::message_t req; (void)m_controller.recv(req); m_controller.send(zmq::message_t("ACK", 3), zmq::send_flags::none); zmq::pollitem_t items[] = { { m_controller_header, 0, ZMQ_POLLIN, 0 }, { m_controller, 0, ZMQ_POLLIN, 0 }, { m_tcp_socket, 0, ZMQ_POLLIN, 0 } }; m_request_stop = false; m_wait_attach = m_dap_init_type == dap_init_type::parallel; while(!m_request_stop) { zmq::poll(&items[0], 3, std::chrono::milliseconds(-1)); if(items[0].revents & ZMQ_POLLIN) { handle_header_socket(); } if(items[1].revents & ZMQ_POLLIN) { handle_control_socket(); } if(items[2].revents & ZMQ_POLLIN) { handle_tcp_socket(m_message_queue); } process_message_queue(); } m_request_stop = false; finalize_tcp_socket(tcp_end_point); m_controller.disconnect(controller_end_point); m_controller_header.disconnect(controller_header_end_point); m_publisher.disconnect(publisher_end_point); } zmq::message_t xdap_tcp_client_impl::get_tcp_id() const { return zmq::message_t(m_socket_id.data(), m_socket_id.size()); } void xdap_tcp_client_impl::init_tcp_socket(const std::string& tcp_end_point) { if (m_dap_tcp_type == dap_tcp_type::client) { m_tcp_socket.connect(tcp_end_point); size_t id_size = 256; std::string id = m_tcp_socket.get(zmq::sockopt::routing_id, id_size); m_socket_id = zmq::message_t(id); } else { m_tcp_socket.bind(tcp_end_point); (void)m_tcp_socket.recv(m_socket_id); zmq::message_t msg; (void)m_tcp_socket.recv(msg); } } void xdap_tcp_client_impl::finalize_tcp_socket(const std::string& tcp_end_point) { if (m_dap_tcp_type == dap_tcp_type::client) { m_tcp_socket.disconnect(tcp_end_point); } else { m_tcp_socket.unbind(tcp_end_point); } } void xdap_tcp_client_impl::handle_header_socket() { zmq::message_t message; (void)m_controller_header.recv(message); m_parent_header = std::string(message.data(), message.size()); m_controller_header.send(zmq::message_t("ACK", 3), zmq::send_flags::none); } void xdap_tcp_client_impl::handle_control_socket() { zmq::message_t message; (void)m_controller.recv(message); if (m_wait_attach) { std::string raw_message = std::string(message.data(), message.size()); auto pos = raw_message.find(xdap_tcp_client::SEPARATOR); std::string to_parse = raw_message.substr(pos + xdap_tcp_client::SEPARATOR_LENGTH); nl::json json_message = nl::json::parse(to_parse); // Sends a ZMQ header (required for stream socket) and forwards // the message m_tcp_socket.send(get_tcp_id(), zmq::send_flags::sndmore); m_tcp_socket.send(message, zmq::send_flags::none); if (json_message["command"] == "attach") { handle_init_sequence(); m_wait_attach = false; } } else { // Sends a ZMQ header (required for stream socket) and forwards // the message m_tcp_socket.send(get_tcp_id(), zmq::send_flags::sndmore); m_tcp_socket.send(message, zmq::send_flags::none); } } void xdap_tcp_client_impl::handle_tcp_socket(queue_type& message_queue) { using size_type = std::string::size_type; std::string buffer = ""; bool messages_received = false; size_type header_pos = std::string::npos; size_type separator_pos = std::string::npos; size_type msg_size = 0; size_type msg_pos = std::string::npos; size_type hint = 0; while(!messages_received) { while(header_pos == std::string::npos) { append_tcp_message(buffer); header_pos = buffer.find(xdap_tcp_client::HEADER, hint); } hint = header_pos + xdap_tcp_client::HEADER_LENGTH; separator_pos = buffer.find(xdap_tcp_client::SEPARATOR, hint); while(separator_pos == std::string::npos) { append_tcp_message(buffer); separator_pos = buffer.find(xdap_tcp_client::SEPARATOR, hint); } msg_size = std::stoull(buffer.substr(header_pos + xdap_tcp_client::HEADER_LENGTH, separator_pos)); msg_pos = separator_pos + xdap_tcp_client::SEPARATOR_LENGTH; // The end of the buffer does not contain a full message while(buffer.size() - msg_pos < msg_size) { append_tcp_message(buffer); } // The end of the buffer contains a full message if(buffer.size() - msg_pos == msg_size) { message_queue.push_back(buffer.substr(msg_pos)); messages_received = true; } else { // The end of the buffer contains a full message // and the beginning of a new one. We push the first // one in the queue, and loop again to get the next // one. message_queue.push_back(buffer.substr(msg_pos, msg_size)); hint = msg_pos + msg_size; header_pos = buffer.find(xdap_tcp_client::HEADER, hint); separator_pos = std::string::npos; } } } void xdap_tcp_client_impl::append_tcp_message(std::string& buffer) { // First message is a ZMQ header that we discard zmq::message_t header; (void)m_tcp_socket.recv(header); zmq::message_t content; (void)m_tcp_socket.recv(content); buffer += std::string(content.data(), content.size()); } void xdap_tcp_client_impl::process_message_queue() { while(!m_message_queue.empty()) { const std::string& raw_message = m_message_queue.front(); nl::json message = nl::json::parse(raw_message); // message is either an event or a response if(message["type"] == "event") { m_event_handler(std::move(message)); } else { if(message["command"] == "disconnect") { m_request_stop = true; } zmq::message_t reply(raw_message.c_str(), raw_message.size()); m_controller.send(reply, zmq::send_flags::none); } m_message_queue.pop_front(); } } void xdap_tcp_client_impl::handle_init_sequence() { // 1] Wait for initialized event nl::json initialized = wait_for_message([](const nl::json& message) { return message["type"] == "event" && message["event"] == "initialized"; }); // 2] Sends configuration done nl::json configuration_done = { {"type", "request"}, {"seq", initialized["seq"].get() + 1}, {"command", "configurationDone"}, }; send_dap_request(configuration_done); // 3] Waits for configurationDone response nl::json config_response = wait_for_message([](const nl::json& message) { return message["type"] == "response" && message["command"] == "configurationDone"; }); // 4] Waits for attach response nl::json attach_response = wait_for_message([](const nl::json& message) { return message["type"] == "response" && message["command"] == "attach"; }); // 5] Forwards initialized event and attach_response forward_event(std::move(initialized)); std::string raw_response = attach_response.dump(); zmq::message_t reply(raw_response.c_str(), raw_response.size()); m_controller.send(reply, zmq::send_flags::none); } } xeus-zmq-3.1.0/src/debugger/xdap_tcp_client_impl.hpp000066400000000000000000000062111464077067000225640ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_DAP_TCP_CLIENT_IMPL_HPP #define XEUS_DAP_TCP_CLIENT_IMPL_HPP #include #include #include "zmq.hpp" #include "nlohmann/json.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus/xeus_context.hpp" #include "xeus-zmq/xdap_tcp_client.hpp" #include "../common/xauthentication.hpp" namespace nl = nlohmann; namespace xeus { class xdap_tcp_client_impl { public: using event_callback = std::function; xdap_tcp_client_impl(xcontext& context, const xeus::xconfiguration& config, int socket_linger, const xdap_tcp_configuration& dap_config, const event_callback& cb, const event_callback& handler); void start_debugger(std::string tcp_end_point, std::string publisher_end_point, std::string controller_end_point, std::string controller_header_end_point); void forward_event(nl::json message); void send_dap_request(nl::json message); using message_condition = std::function; nl::json wait_for_message(const message_condition& condition); private: using queue_type = std::deque; zmq::message_t get_tcp_id() const; void init_tcp_socket(const std::string& tcp_end_point); void finalize_tcp_socket(const std::string& tcp_end_point); void handle_header_socket(); void handle_control_socket(); void handle_tcp_socket(queue_type& message_queue); void append_tcp_message(std::string& buffer); void process_message_queue(); void handle_init_sequence(); zmq::socket_t m_tcp_socket; zmq::message_t m_socket_id; zmq::socket_t m_publisher; zmq::socket_t m_controller; zmq::socket_t m_controller_header; dap_tcp_type m_dap_tcp_type; dap_init_type m_dap_init_type; std::string m_user_name; std::string m_session_id; event_callback m_event_callback; event_callback m_event_handler; using authentication_ptr = std::unique_ptr; authentication_ptr p_auth; // Saves parent header for future debug events std::string m_parent_header; bool m_request_stop; bool m_wait_attach; queue_type m_message_queue; queue_type m_stopped_queue; }; } #endif xeus-zmq-3.1.0/src/debugger/xdebugger_base.cpp000066400000000000000000000342041464077067000213470ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2018, Martin Renou, Johan Mabille, Sylvain Corlay, and * * Wolf Vollprecht * * Copyright (c) 2018, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include #include "xeus-zmq/xdap_tcp_client.hpp" #include "xeus-zmq/xdebugger_base.hpp" #include "xdebugger_middleware.hpp" using namespace std::placeholders; namespace xeus { xdebugger_info::xdebugger_info(std::size_t hash_seed, const std::string& tmp_file_prefix, const std::string& tmp_file_suffix, bool rich_rendering, std::vector exception_paths, bool copy_to_globals) : m_hash_seed(hash_seed) , m_tmp_file_prefix(tmp_file_prefix) , m_tmp_file_suffix(tmp_file_suffix) , m_rich_rendering(rich_rendering) , m_exception_paths(exception_paths) , m_copy_to_globals(copy_to_globals) { } xdebugger_base::~xdebugger_base() = default; xdebugger_base::xdebugger_base(xcontext& context) : p_middleware(new xdebugger_middleware(context)) , m_is_started(false) { register_request_handler("debugInfo", std::bind(&xdebugger_base::debug_info_request, this, _1), false); register_request_handler("dumpCell", std::bind(&xdebugger_base::dump_cell_request, this, _1), true); register_request_handler("setBreakpoints", std::bind(&xdebugger_base::set_breakpoints_request, this, _1), true); register_request_handler("source", std::bind(&xdebugger_base::source_request, this, _1), true); register_request_handler("stackTrace", std::bind(&xdebugger_base::stack_trace_request, this, _1), true); register_request_handler("variables", std::bind(&xdebugger_base::variables_request, this, _1), true); register_event_handler("continued", std::bind(&xdebugger_base::continued_event, this, _1)); register_event_handler("stopped", std::bind(&xdebugger_base::stopped_event, this, _1)); } bool xdebugger_base::is_started() const { return m_is_started; } std::function xdebugger_base::get_event_callback() { return std::bind(&xdebugger_base::handle_event, this, _1); } /********************* * Requests handling * *********************/ void xdebugger_base::register_request_handler(const std::string& command, const request_handler_t& handler, bool require_started) { request_handler_map_t& m = require_started ? m_started_handler : m_request_handler; m[command] = handler; } nl::json xdebugger_base::debug_info_request(const nl::json& message) { nl::json breakpoint_list = nl::json::array(); if(m_is_started) { for(auto it = m_breakpoint_list.cbegin(); it != m_breakpoint_list.cend(); ++it) { breakpoint_list.push_back({{"source", it->first}, {"breakpoints", it->second}}); } } xdebugger_info info = get_debugger_info(); std::lock_guard lock(m_stopped_mutex); nl::json reply = { {"type", "response"}, {"request_seq", message["seq"]}, {"success", true}, {"command", message["command"]}, {"body", { {"isStarted", m_is_started}, {"hashMethod", "Murmur2"}, {"hashSeed", info.m_hash_seed}, {"tmpFilePrefix", info.m_tmp_file_prefix}, {"tmpFileSuffix", info.m_tmp_file_suffix}, {"breakpoints", breakpoint_list}, {"stoppedThreads", m_stopped_threads}, {"richRendering", info.m_rich_rendering}, {"exceptionPaths", info.m_exception_paths}, {"copyToGlobals", info.m_copy_to_globals} }} }; return reply; } nl::json xdebugger_base::dump_cell_request(const nl::json& message) { std::string code; try { code = message["arguments"]["code"].get(); } catch(nl::json::type_error& e) { std::clog << e.what() << std::endl; } catch(...) { std::clog << "XDEBUGGER: Unknown issue" << std::endl; } std::string next_file_name = get_cell_temporary_file(code); std::clog << "XDEBUGGER: dumped " << next_file_name << std::endl; std::fstream fs(next_file_name, std::ios::in); if(!fs.is_open()) { fs.clear(); fs.open(next_file_name, std::ios::out); fs << code; } nl::json reply = { {"type", "response"}, {"request_seq", message["seq"]}, {"success", true}, {"command", message["command"]}, {"body", { {"sourcePath", next_file_name} }} }; return reply; } nl::json xdebugger_base::set_breakpoints_request(const nl::json& message) { std::string source = message["arguments"]["source"]["path"].get(); m_breakpoint_list.erase(source); nl::json bp_json = message["arguments"]["breakpoints"]; std::vector bp_list(bp_json.begin(), bp_json.end()); m_breakpoint_list.insert(std::make_pair(std::move(source), std::move(bp_list))); nl::json breakpoint_reply = forward_message(message); return breakpoint_reply; } nl::json xdebugger_base::source_request(const nl::json& message) { std::string sourcePath; try { sourcePath = message["arguments"]["source"]["path"].get(); } catch(nl::json::type_error& e) { std::clog << e.what() << std::endl; } catch(...) { std::clog << "XDEBUGGER: Unknown issue" << std::endl; } std::ifstream ifs(sourcePath, std::ios::in); if(!ifs.is_open()) { nl::json reply = { {"type", "response"}, {"request_seq", message["seq"]}, {"success", false}, {"command", message["command"]}, {"message", "source unavailable"}, {"body", {{}}} }; return reply; } std::string content((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); nl::json reply = { {"type", "response"}, {"request_seq", message["seq"]}, {"success", true}, {"command", message["command"]}, {"body", { {"content", content} }} }; return reply; } nl::json xdebugger_base::stack_trace_request(const nl::json& message) { nl::json reply = forward_message(message); size_t size = reply["body"]["stackFrames"].size(); for(size_t i = 0; i < size; ++i) { if(reply["body"]["stackFrames"][i]["source"]["path"] == "") { reply["body"]["stackFrames"].erase(i); break; } } #ifdef WIN32 size = reply["body"]["stackFrames"].size(); for(size_t i = 0; i < size; ++i) { std::string path = reply["body"]["stackFrames"][i]["source"]["path"]; std::replace(path.begin(), path.end(), '\\', '/'); reply["body"]["stackFrames"][i]["source"]["path"] = path; } #endif return reply; } nl::json xdebugger_base::variables_request(const nl::json& message) { return variables_request_impl(message); } nl::json xdebugger_base::forward_message(const nl::json& message) { std::string content = message.dump(); size_t content_length = content.length(); std::string buffer = xdap_tcp_client::HEADER + std::to_string(content_length) + xdap_tcp_client::SEPARATOR + content; return nl::json::parse(send_recv_request(buffer)); } /******************* * Events handling * *******************/ void xdebugger_base::register_event_handler(const std::string& event, const event_handler_t& handler) { m_event_handler[event] = handler; } void xdebugger_base::continued_event(const nl::json& message) { std::lock_guard lock(m_stopped_mutex); if (message["body"]["allThreadsContinued"]) { m_stopped_threads.clear(); } else { int id = message["body"]["threadId"]; m_stopped_threads.erase(id); } } void xdebugger_base::stopped_event(const nl::json& message) { std::lock_guard lock(m_stopped_mutex); if (message["body"]["allThreadsStopped"]) { for (auto& id: message["body"]["threadList"]) { m_stopped_threads.insert(id.get()); } } else { int id = message["body"]["threadId"]; m_stopped_threads.insert(id); } } const std::set& xdebugger_base::get_stopped_threads() const { return m_stopped_threads; } nl::json xdebugger_base::variables_request_impl(const nl::json& message) { nl::json reply = forward_message(message); auto start_it = message["arguments"].find("start"); auto count_it = message["arguments"].find("count"); auto end_it = message["arguments"].end(); if(start_it != end_it || count_it != end_it) { int start = start_it != end_it ? start_it->get() : 0; int count = count_it != end_it ? count_it->get() : 0; if(start != 0 || count != 0) { int end = count == 0 ? reply["body"]["variables"].size() : start + count; nl::json old_variables_list = reply["body"]["variables"]; reply["body"].erase("variables"); nl::json variables_list; for(int i = start; i < end; ++i) { variables_list.push_back(old_variables_list.at(i)); } reply["body"]["variables"] = variables_list; } } return reply; } /******************* * Middleware APIs * *******************/ void xdebugger_base::bind_sockets(const std::string& header_end_point, const std::string& request_end_point) { p_middleware->bind_sockets(header_end_point, request_end_point); } void xdebugger_base::unbind_sockets(const std::string& header_end_point, const std::string& request_end_point) { p_middleware->unbind_sockets(header_end_point, request_end_point); } std::string xdebugger_base::send_recv_header(const std::string& header) { return p_middleware->send_recv_header(header); } std::string xdebugger_base::send_recv_request(const std::string& request) { return p_middleware->send_recv_request(request); } /************************** * Private implementation * **************************/ void xdebugger_base::handle_event(const nl::json& message) { std::string event = message["event"]; auto it = m_event_handler.find(event); if (it != m_event_handler.end()) { (it->second)(message); } } nl::json xdebugger_base::process_request_impl(const nl::json& header, const nl::json& message) { nl::json reply = nl::json::object(); if(message["command"] == "initialize") { if(m_is_started) { std::clog << "XDEBUGGER: the debugger has already started" << std::endl; } else { m_is_started = start(); if (m_is_started) { std::clog << "XDEBUGGER: the debugger has started" << std::endl; } else { reply = { {"command", "initialize"}, {"request_seq", message["seq"]}, {"seq", 3}, {"success", false}, {"type", "response"} }; } } } auto it = m_request_handler.find(message["command"]); if (it != m_request_handler.end()) { reply = (it->second)(message); } else if (m_is_started) { std::string header_buffer = header.dump(); // client responds with ACK message send_recv_header(header_buffer); auto it = m_started_handler.find(message["command"]); if (it != m_started_handler.end()) { reply = (it->second)(message); } else { reply = forward_message(message); } } if (message["command"] == "disconnect") { stop(); m_breakpoint_list.clear(); m_stopped_threads.clear(); m_is_started = false; std::clog << "XDEBUGGER: the debugger has stopped" << std::endl; } return reply; } } xeus-zmq-3.1.0/src/debugger/xdebugger_middleware.cpp000066400000000000000000000046051464077067000225540ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2018, Martin Renou, Johan Mabille, Sylvain Corlay, and * * Wolf Vollprecht * * Copyright (c) 2018, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xeus-zmq/xmiddleware.hpp" #include "xdebugger_middleware.hpp" namespace xeus { xdebugger_middleware::xdebugger_middleware(xcontext& context) : m_header_socket(context.get_wrapped_context(), zmq::socket_type::req) , m_request_socket(context.get_wrapped_context(), zmq::socket_type::req) { m_header_socket.set(zmq::sockopt::linger, xeus::get_socket_linger()); m_request_socket.set(zmq::sockopt::linger, xeus::get_socket_linger()); } void xdebugger_middleware::bind_sockets(const std::string& header_end_point, const std::string& request_end_point) { m_header_socket.bind(header_end_point); m_request_socket.bind(request_end_point); } void xdebugger_middleware::unbind_sockets(const std::string& header_end_point, const std::string& request_end_point) { m_header_socket.unbind(header_end_point); m_request_socket.unbind(request_end_point); } std::string xdebugger_middleware::send_recv_header(const std::string& header) { return send_recv(header, m_header_socket); } std::string xdebugger_middleware::send_recv_request(const std::string& request) { return send_recv(request, m_request_socket); } std::string xdebugger_middleware::send_recv(const std::string& msg, zmq::socket_t& socket) { zmq::message_t raw_msg(msg.c_str(), msg.length()); socket.send(raw_msg, zmq::send_flags::none); zmq::message_t raw_reply; (void)socket.recv(raw_reply); return std::string(raw_reply.data(), raw_reply.size()); } } xeus-zmq-3.1.0/src/debugger/xdebugger_middleware.hpp000066400000000000000000000030211464077067000225500ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2018, Martin Renou, Johan Mabille, Sylvain Corlay, and * * Wolf Vollprecht * * Copyright (c) 2018, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_DEBUGGER_MIDDLEWARE_HPP #define XEUS_DEBUGGER_MIDDLEWARE_HPP #include #include "zmq.hpp" #include "xeus/xeus_context.hpp" namespace xeus { class xdebugger_middleware { public: explicit xdebugger_middleware(xcontext& context); void bind_sockets(const std::string& header_end_point, const std::string& request_end_point); void unbind_sockets(const std::string& header_end_point, const std::string& request_end_point); std::string send_recv_header(const std::string& header); std::string send_recv_request(const std::string& request); private: std::string send_recv(const std::string& msg, zmq::socket_t& socket); zmq::socket_t m_header_socket; zmq::socket_t m_request_socket; }; } #endif xeus-zmq-3.1.0/src/server/000077500000000000000000000000001464077067000154145ustar00rootroot00000000000000xeus-zmq-3.1.0/src/server/xcontrol.cpp000066400000000000000000000047301464077067000177740ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include #include #include "xcontrol.hpp" #include "xserver_zmq_split_impl.hpp" #include "../common/xmiddleware_impl.hpp" namespace xeus { xcontrol::xcontrol(zmq::context_t& context, const std::string& transport, const std::string& ip, const std::string& control_port, xserver_zmq_split_impl* server) : m_control(context, zmq::socket_type::router) , m_publisher_pub(context, zmq::socket_type::pub) , m_messenger(context) , p_server(server) { init_socket(m_control, transport, ip, control_port); m_publisher_pub.set(zmq::sockopt::linger, get_socket_linger()); m_publisher_pub.connect(get_publisher_end_point()); } std::string xcontrol::get_port() const { return get_socket_port(m_control); } fd_t xcontrol::get_fd() const { return m_control.get(zmq::sockopt::fd); } void xcontrol::connect_messenger() { m_messenger.connect(); } void xcontrol::stop_channels() { m_messenger.stop_channels(); } xcontrol_messenger& xcontrol::get_messenger() { return m_messenger; } std::optional xcontrol::read_control(int flags) { zmq::multipart_t wire_msg; if (wire_msg.recv(m_control, flags)) { try { return p_server->deserialize(wire_msg); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } } return std::nullopt; } void xcontrol::send_control(zmq::multipart_t& message) { message.send(m_control); } void xcontrol::publish(zmq::multipart_t& message) { message.send(m_publisher_pub); } } xeus-zmq-3.1.0/src/server/xcontrol.hpp000066400000000000000000000034141464077067000177770ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_CONTROL_HPP #define XEUS_CONTROL_HPP #include #include "zmq.hpp" #include "zmq_addon.hpp" #include "xzmq_messenger.hpp" #include "xeus/xmessage.hpp" #include "xeus-zmq/xmiddleware.hpp" namespace xeus { class xserver_zmq_split_impl; class xcontrol { public: using listener = std::function; xcontrol(zmq::context_t& context, const std::string& transport, const std::string& ip, const std::string& control_port, xserver_zmq_split_impl* server); std::string get_port() const; fd_t get_fd() const; void connect_messenger(); void stop_channels(); xcontrol_messenger& get_messenger(); std::optional read_control(int flags); void send_control(zmq::multipart_t& message); void publish(zmq::multipart_t& message); private: zmq::socket_t m_control; zmq::socket_t m_publisher_pub; // Internal sockets for controlling other threads xzmq_messenger m_messenger; xserver_zmq_split_impl* p_server; }; } #endif xeus-zmq-3.1.0/src/server/xcontrol_default_runner.cpp000066400000000000000000000021271464077067000230670ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xeus-zmq/xcontrol_default_runner.hpp" namespace xeus { void xcontrol_default_runner::run_impl() { m_request_stop = false; while (!m_request_stop) { auto msg = read_control(); if (msg.has_value()) { notify_control_listener(std::move(msg.value())); } } stop_channels(); } void xcontrol_default_runner::stop_impl() { m_request_stop = true; } } xeus-zmq-3.1.0/src/server/xcontrol_runner.cpp000066400000000000000000000026271464077067000213700ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xeus-zmq/xcontrol_runner.hpp" #include "xeus-zmq/xserver_zmq_split.hpp" namespace xeus { void xcontrol_runner::register_server(xserver_zmq_split& server) { p_server = &server; } void xcontrol_runner::run() { run_impl(); } void xcontrol_runner::stop() { stop_impl(); } fd_t xcontrol_runner::get_control_fd() const { return p_server->get_control_fd(); } std::optional xcontrol_runner::read_control(int flags) { return p_server->read_control(flags); } void xcontrol_runner::stop_channels() { p_server->stop_channels(); } void xcontrol_runner::notify_control_listener(xmessage message) { p_server->notify_control_listener(std::move(message)); } } xeus-zmq-3.1.0/src/server/xheartbeat.cpp000066400000000000000000000041361464077067000202530ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include #include "zmq_addon.hpp" #include "../common/xmiddleware_impl.hpp" #include "xheartbeat.hpp" namespace xeus { xheartbeat::xheartbeat(zmq::context_t& context, const std::string& transport, const std::string& ip, const std::string& port) : m_heartbeat(context, zmq::socket_type::router) , m_controller(context, zmq::socket_type::rep) { init_socket(m_heartbeat, transport, ip, port); init_socket(m_controller, get_controller_end_point("heartbeat")); } xheartbeat::~xheartbeat() { } std::string xheartbeat::get_port() const { return get_socket_port(m_heartbeat); } void xheartbeat::run() { zmq::pollitem_t items[] = { { m_heartbeat, 0, ZMQ_POLLIN, 0 }, { m_controller, 0, ZMQ_POLLIN, 0 } }; while (true) { zmq::poll(&items[0], 2, std::chrono::milliseconds(-1)); if (items[0].revents & ZMQ_POLLIN) { zmq::multipart_t wire_msg; wire_msg.recv(m_heartbeat); wire_msg.send(m_heartbeat); } if (items[1].revents & ZMQ_POLLIN) { // stop message zmq::multipart_t wire_msg; wire_msg.recv(m_controller); wire_msg.send(m_controller); break; } } } } xeus-zmq-3.1.0/src/server/xheartbeat.hpp000066400000000000000000000021601464077067000202530ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_HEARTBEAT_HPP #define XEUS_HEARTBEAT_HPP #include #include "zmq.hpp" namespace xeus { class xheartbeat { public: xheartbeat(zmq::context_t& context, const std::string& transport, const std::string& ip, const std::string& port); ~xheartbeat(); std::string get_port() const; void run(); private: zmq::socket_t m_heartbeat; zmq::socket_t m_controller; }; } #endif xeus-zmq-3.1.0/src/server/xpublisher.cpp000066400000000000000000000110061464077067000203030ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include "../common/xmiddleware_impl.hpp" #include "xpublisher.hpp" namespace xeus { xpublisher::xpublisher(zmq::context_t& context, std::function serialize_iopub_msg_cb, const std::string& transport, const std::string& ip, const std::string& port) : m_publisher(context, zmq::socket_type::xpub) , m_listener(context, zmq::socket_type::sub) , m_controller(context, zmq::socket_type::rep) , m_serialize_iopub_msg_cb(std::move(serialize_iopub_msg_cb)) { init_socket(m_publisher, transport, ip, port); // Set xpub_verbose option to 1 to pass all subscription messages (not only unique ones). m_publisher.set(zmq::sockopt::xpub_verbose, 1); m_listener.set(zmq::sockopt::subscribe, ""); m_listener.bind(get_publisher_end_point()); m_controller.set(zmq::sockopt::linger, get_socket_linger()); m_controller.bind(get_controller_end_point("publisher")); } xpublisher::~xpublisher() { } xpub_message xpublisher::create_xpub_message(const std::string& topic) { xmessage_base_data data; data.m_header = xeus::make_header("iopub_welcome", "", ""); data.m_content["subscription"] = topic; xpub_message p_msg("", std::move(data)); return p_msg; } std::string xpublisher::get_port() const { return get_socket_port(m_publisher); } void xpublisher::run() { zmq::pollitem_t items[] = { { m_listener, 0, ZMQ_POLLIN, 0 }, { m_controller, 0, ZMQ_POLLIN, 0 }, { m_publisher, 0, ZMQ_POLLIN, 0 } }; while (true) { zmq::poll(&items[0], 3, std::chrono::milliseconds(-1)); if (items[0].revents & ZMQ_POLLIN) { zmq::multipart_t wire_msg; wire_msg.recv(m_listener); wire_msg.send(m_publisher); } if (items[1].revents & ZMQ_POLLIN) { // stop message zmq::multipart_t wire_msg; wire_msg.recv(m_controller); wire_msg.send(m_controller); break; } if (items[2].revents & ZMQ_POLLIN) { // Received event: Single frame // Either `1{subscription-topic}` for subscription // or `0{subscription-topic}` for unsubscription zmq::multipart_t wire_msg; wire_msg.recv(m_publisher); // Received event should be a single frame if (wire_msg.size() != 1) { throw std::runtime_error("ERROR: Received message on XPUB is not a single frame"); } zmq::message_t frame = wire_msg.pop(); // Event is one byte 0 = unsub or 1 = sub, followed by topic uint8_t *event = (uint8_t *)frame.data(); // If subscription (unsubscription is ignored) if (event[0] == 1) { std::string topic((char *)(event + 1), frame.size() - 1); if (m_serialize_iopub_msg_cb) { // Construct the `iopub_welcome` message xpub_message p_msg = create_xpub_message(topic); zmq::multipart_t iopub_welcome_wire_msg = m_serialize_iopub_msg_cb(std::move(p_msg)); // Send the `iopub_welcome` message iopub_welcome_wire_msg.send(m_publisher); } else { throw std::runtime_error("ERROR: IOPUB serialization callback not set"); } } } } } } xeus-zmq-3.1.0/src/server/xpublisher.hpp000066400000000000000000000027221464077067000203150ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_PUBLISHER_HPP #define XEUS_PUBLISHER_HPP #include #include #include "zmq.hpp" #include "zmq_addon.hpp" #include "xeus/xmessage.hpp" namespace xeus { class xpublisher { public: xpublisher(zmq::context_t& context, std::function serialize_iopub_msg_cb, const std::string& transport, const std::string& ip, const std::string& port); ~xpublisher(); std::string get_port() const; void run(); private: xpub_message create_xpub_message(const std::string& topic); zmq::socket_t m_publisher; zmq::socket_t m_listener; zmq::socket_t m_controller; std::function m_serialize_iopub_msg_cb; }; } #endif xeus-zmq-3.1.0/src/server/xserver_control_main.cpp000066400000000000000000000050661464077067000223710ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xeus-zmq/xcontrol_default_runner.hpp" #include "xeus-zmq/xshell_default_runner.hpp" #include "xserver_control_main.hpp" namespace xeus { xserver_control_main::xserver_control_main(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh, control_runner_ptr control, shell_runner_ptr shell) : xserver_zmq_split( context, config, eh, std::move(control), std::move(shell) ) { } void xserver_control_main::start_impl(xpub_message message) { xserver_zmq_split::start_publisher_thread(); xserver_zmq_split::start_heartbeat_thread(); xserver_zmq_split::start_shell_thread(); xserver_zmq_split::publish(std::move(message), channel::CONTROL); xserver_zmq_split::run_control(); } std::unique_ptr make_xserver_control_main(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh) { return make_xserver_control ( context, config, eh, std::make_unique(), std::make_unique() ); } std::unique_ptr make_xserver_control(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh, std::unique_ptr control, std::unique_ptr shell) { return std::make_unique ( context, config, eh, std::move(control), std::move(shell) ); } } xeus-zmq-3.1.0/src/server/xserver_control_main.hpp000066400000000000000000000027711464077067000223760ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_SERVER_CONTROL_MAIN_HPP #define XEUS_SERVER_CONTROL_MAIN_HPP #include "xeus/xeus_context.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus-zmq/xeus-zmq.hpp" #include "xeus-zmq/xserver_zmq_split.hpp" namespace xeus { class XEUS_ZMQ_API xserver_control_main final : public xserver_zmq_split { public: using control_runner_ptr = xserver_zmq_split::control_runner_ptr; using shell_runner_ptr = xserver_zmq_split::shell_runner_ptr; xserver_control_main(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh, control_runner_ptr control, shell_runner_ptr shell); virtual ~xserver_control_main() = default; private: void start_impl(xpub_message message) override; }; } #endif xeus-zmq-3.1.0/src/server/xserver_shell_main.cpp000066400000000000000000000050061464077067000220120ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xeus-zmq/xcontrol_default_runner.hpp" #include "xeus-zmq/xshell_default_runner.hpp" #include "xserver_shell_main.hpp" namespace xeus { xserver_shell_main::xserver_shell_main(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh, control_runner_ptr control, shell_runner_ptr shell) : xserver_zmq_split( context, config, eh, std::move(control), std::move(shell) ) { } void xserver_shell_main::start_impl(xpub_message message) { xserver_zmq_split::start_publisher_thread(); xserver_zmq_split::start_heartbeat_thread(); xserver_zmq_split::start_control_thread(); xserver_zmq_split::publish(std::move(message), channel::SHELL); xserver_zmq_split::run_shell(); } std::unique_ptr make_xserver_shell_main(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh) { return make_xserver_shell ( context, config, eh, std::make_unique(), std::make_unique() ); } std::unique_ptr make_xserver_shell(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh, std::unique_ptr control, std::unique_ptr shell) { return std::make_unique ( context, config, eh, std::move(control), std::move(shell) ); } } xeus-zmq-3.1.0/src/server/xserver_shell_main.hpp000066400000000000000000000027471464077067000220300ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_SERVER_SHELL_MAIN_HPP #define XEUS_SERVER_SHELL_MAIN_HPP #include "xeus/xeus_context.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus-zmq/xeus-zmq.hpp" #include "xeus-zmq/xserver_zmq_split.hpp" namespace xeus { class XEUS_ZMQ_API xserver_shell_main final : public xserver_zmq_split { public: using control_runner_ptr = xserver_zmq_split::control_runner_ptr; using shell_runner_ptr = xserver_zmq_split::shell_runner_ptr; xserver_shell_main(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh, control_runner_ptr control, shell_runner_ptr shell); virtual ~xserver_shell_main() = default; private: void start_impl(xpub_message message) override; }; } #endif xeus-zmq-3.1.0/src/server/xserver_zmq.cpp000066400000000000000000000065021464077067000205100ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xeus-zmq/xserver_zmq.hpp" #include "xserver_zmq_impl.hpp" namespace xeus { xserver_zmq::xserver_zmq(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh) : p_impl(std::make_unique( context.get_wrapped_context(), config, eh, std::bind(&xserver_zmq::notify_internal_listener, this, std::placeholders::_1))) { } // Has to be in the cpp because incomplete // types are used in unique_ptr in the header xserver_zmq::~xserver_zmq() = default; //////////////////////////////// // API for inheriting classes // //////////////////////////////// void xserver_zmq::start_publisher_thread() { p_impl->start_publisher_thread(); } void xserver_zmq::start_heartbeat_thread() { p_impl->start_heartbeat_thread(); } void xserver_zmq::stop_channels() { p_impl->stop_channels(); } void xserver_zmq::set_request_stop(bool stop) { p_impl->set_request_stop(stop); } bool xserver_zmq::is_stopped() const { return p_impl->is_stopped(); } auto xserver_zmq::poll_channels(long timeout) -> std::optional { return p_impl->poll_channels(timeout); } void xserver_zmq::send_shell_message(xmessage msg) { p_impl->send_shell(std::move(msg)); } void xserver_zmq::send_control_message(xmessage msg) { p_impl->send_control(std::move(msg)); } /////////////////////////////////////////////// // Implementation of xserver virtual methods // /////////////////////////////////////////////// xcontrol_messenger& xserver_zmq::get_control_messenger_impl() { return p_impl->get_control_messenger(); } void xserver_zmq::send_shell_impl(xmessage msg) { send_shell_message(std::move(msg)); } void xserver_zmq::send_control_impl(xmessage msg) { send_control_message(std::move(msg)); } void xserver_zmq::send_stdin_impl(xmessage msg) { auto reply = p_impl->send_stdin(std::move(msg)); if (reply) { xserver::notify_stdin_listener(std::move(reply.value())); } } void xserver_zmq::publish_impl(xpub_message msg, channel c) { p_impl->publish(std::move(msg), c); } void xserver_zmq::abort_queue_impl(const listener& l, long polling_interval) { p_impl->abort_queue(l, polling_interval); } void xserver_zmq::update_config_impl(xconfiguration& config) const { p_impl->update_config(config); } } xeus-zmq-3.1.0/src/server/xserver_zmq_default.cpp000066400000000000000000000037231464077067000222160ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xserver_zmq_default.hpp" namespace xeus { xserver_zmq_default::xserver_zmq_default(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh) : xserver_zmq(context, config, eh) { } void xserver_zmq_default::start_impl(xpub_message msg) { start_publisher_thread(); start_heartbeat_thread(); publish(std::move(msg), channel::SHELL); while(!is_stopped()) { auto msg = poll_channels(-1); if (msg) { if (msg.value().second == channel::SHELL) { notify_shell_listener(std::move(msg.value().first)); } else { notify_control_listener(std::move(msg.value().first)); } } } stop_channels(); } void xserver_zmq_default::stop_impl() { set_request_stop(true); } std::unique_ptr make_xserver_default(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh) { return std::make_unique(context, config, eh); } } xeus-zmq-3.1.0/src/server/xserver_zmq_default.hpp000066400000000000000000000021751464077067000222230ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XSERVER_ZMQ_DEFAULT_HPP #define XSERVER_ZMQ_DEFAULT_HPP #include "xeus-zmq/xserver_zmq.hpp" namespace xeus { class xserver_zmq_default final : public xserver_zmq { public: xserver_zmq_default(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh); ~xserver_zmq_default() override = default; private: void start_impl(xpub_message msg) override; void stop_impl() override; }; } #endif xeus-zmq-3.1.0/src/server/xserver_zmq_impl.cpp000066400000000000000000000161101464077067000215250ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include "xserver_zmq_impl.hpp" #include "../common/xmiddleware_impl.hpp" #include "../common/xzmq_serializer.hpp" namespace xeus { xserver_zmq_impl::xserver_zmq_impl(zmq::context_t& context, const xconfiguration& config, nl::json::error_handler_t eh, internal_listener listener) : m_shell(context, zmq::socket_type::router) , m_controller(context, zmq::socket_type::router) , m_stdin(context, zmq::socket_type::router) , m_publisher_pub(context, zmq::socket_type::pub) , m_publisher_controller(context, zmq::socket_type::req) , m_heartbeat_controller(context, zmq::socket_type::req) , p_auth(make_xauthentication(config.m_signature_scheme, config.m_key)) , m_publisher(context, std::bind(&xserver_zmq_impl::serialize_iopub, this, std::placeholders::_1), config.m_transport, config.m_ip, config.m_iopub_port) , m_heartbeat(context, config.m_transport, config.m_ip, config.m_hb_port) , m_iopub_thread() , m_hb_thread() , m_messenger(std::move(listener)) , m_error_handler(eh) , m_request_stop(false) { init_socket(m_shell, config.m_transport, config.m_ip, config.m_shell_port); init_socket(m_controller, config.m_transport, config.m_ip, config.m_control_port); init_socket(m_stdin, config.m_transport, config.m_ip, config.m_stdin_port); m_publisher_pub.set(zmq::sockopt::linger, get_socket_linger()); m_publisher_pub.connect(get_publisher_end_point()); m_publisher_controller.set(zmq::sockopt::linger, get_socket_linger()); m_publisher_controller.connect(get_controller_end_point("publisher")); m_heartbeat_controller.set(zmq::sockopt::linger, get_socket_linger()); m_heartbeat_controller.connect(get_controller_end_point("heartbeat")); } void xserver_zmq_impl::start_publisher_thread() { m_iopub_thread = xthread(&xpublisher::run, &m_publisher); } void xserver_zmq_impl::start_heartbeat_thread() { m_hb_thread = xthread(&xheartbeat::run, &m_heartbeat); } void xserver_zmq_impl::stop_channels() { zmq::message_t stop_msg("stop", 4); zmq::message_t response; // Wait for publisher answer m_publisher_controller.send(stop_msg, zmq::send_flags::none); (void)m_publisher_controller.recv(response); // Wait for heartbeat answer m_heartbeat_controller.send(stop_msg, zmq::send_flags::none); (void)m_heartbeat_controller.recv(response); } void xserver_zmq_impl::set_request_stop(bool stop) { m_request_stop = stop; } bool xserver_zmq_impl::is_stopped() const { return m_request_stop; } auto xserver_zmq_impl::poll_channels(long timeout) -> std::optional { zmq::pollitem_t items[] = { { m_controller, 0, ZMQ_POLLIN, 0 }, { m_shell, 0, ZMQ_POLLIN, 0 } }; zmq::poll(&items[0], 2, std::chrono::milliseconds(timeout)); try { if (items[0].revents & ZMQ_POLLIN) { zmq::multipart_t wire_msg; wire_msg.recv(m_controller); xmessage msg = xzmq_serializer::deserialize(wire_msg, *p_auth); return { std::make_pair(std::move(msg), channel::CONTROL) }; } if (!m_request_stop && (items[1].revents & ZMQ_POLLIN)) { zmq::multipart_t wire_msg; wire_msg.recv(m_shell); xmessage msg = xzmq_serializer::deserialize(wire_msg, *p_auth); return { std::make_pair(std::move(msg), channel::SHELL) }; } } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return std::nullopt; } xcontrol_messenger& xserver_zmq_impl::get_control_messenger() { return m_messenger; } void xserver_zmq_impl::send_shell(xmessage message) { zmq::multipart_t wire_msg = xzmq_serializer::serialize(std::move(message), *p_auth, m_error_handler); wire_msg.send(m_shell); } void xserver_zmq_impl::send_control(xmessage message) { zmq::multipart_t wire_msg = xzmq_serializer::serialize(std::move(message), *p_auth, m_error_handler); wire_msg.send(m_controller); } std::optional xserver_zmq_impl::send_stdin(xmessage message) { zmq::multipart_t wire_msg = xzmq_serializer::serialize(std::move(message), *p_auth, m_error_handler); wire_msg.send(m_stdin); zmq::multipart_t wire_reply; // Block until a response to the input request is received. wire_reply.recv(m_stdin); try { return xzmq_serializer::deserialize(wire_reply, *p_auth); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return std::nullopt; } void xserver_zmq_impl::publish(xpub_message message, channel) { zmq::multipart_t wire_msg = xzmq_serializer::serialize_iopub(std::move(message), *p_auth, m_error_handler); wire_msg.send(m_publisher_pub); } void xserver_zmq_impl::abort_queue(const listener& l, long polling_interval) { while (true) { zmq::multipart_t wire_msg; bool msg = wire_msg.recv(m_shell, ZMQ_NOBLOCK); if (!msg) { return; } try { xmessage msg = xzmq_serializer::deserialize(wire_msg, *p_auth); l(std::move(msg)); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } std::this_thread::sleep_for(std::chrono::milliseconds(polling_interval)); } } void xserver_zmq_impl::update_config(xconfiguration& config) const { config.m_control_port = get_socket_port(m_controller); config.m_shell_port = get_socket_port(m_shell); config.m_stdin_port = get_socket_port(m_stdin); config.m_iopub_port = m_publisher.get_port(); config.m_hb_port = m_heartbeat.get_port(); } zmq::multipart_t xserver_zmq_impl::serialize_iopub(xpub_message&& msg) { return xzmq_serializer::serialize_iopub(std::move(msg), *p_auth, m_error_handler); } } xeus-zmq-3.1.0/src/server/xserver_zmq_impl.hpp000066400000000000000000000054141464077067000215370ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_SERVER_ZMQ_IMPL_HPP #define XEUS_SERVER_ZMQ_IMPL_HPP #include #include "zmq.hpp" #include "zmq_addon.hpp" #include "xeus/xeus_context.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus/xserver.hpp" #include "xeus-zmq/xeus-zmq.hpp" #include "xeus-zmq/xthread.hpp" #include "../common/xauthentication.hpp" #include "xpublisher.hpp" #include "xheartbeat.hpp" #include "xtrivial_messenger.hpp" namespace xeus { class xserver_zmq_impl { public: using listener = std::function; using internal_listener = xtrivial_messenger::listener; xserver_zmq_impl(zmq::context_t& context, const xconfiguration& config, nl::json::error_handler_t eh, internal_listener listener); void start_publisher_thread(); void start_heartbeat_thread(); void stop_channels(); void set_request_stop(bool stop); bool is_stopped() const; using message_channel = std::pair; std::optional poll_channels(long timeout); xcontrol_messenger& get_control_messenger(); void send_shell(xmessage message); void send_control(xmessage message); std::optional send_stdin(xmessage message); void publish(xpub_message message, channel c); void abort_queue(const listener& l, long polling_interval); void update_config(xconfiguration& config) const; zmq::multipart_t serialize_iopub(xpub_message&& msg); private: zmq::socket_t m_shell; zmq::socket_t m_controller; zmq::socket_t m_stdin; zmq::socket_t m_publisher_pub; zmq::socket_t m_publisher_controller; zmq::socket_t m_heartbeat_controller; using authentication_ptr = std::unique_ptr; authentication_ptr p_auth; xpublisher m_publisher; xheartbeat m_heartbeat; xthread m_iopub_thread; xthread m_hb_thread; xtrivial_messenger m_messenger; nl::json::error_handler_t m_error_handler; bool m_request_stop; }; } #endif xeus-zmq-3.1.0/src/server/xserver_zmq_split.cpp000066400000000000000000000113601464077067000217210ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xeus-zmq/xserver_zmq_split.hpp" #include "xserver_zmq_split_impl.hpp" namespace xeus { xserver_zmq_split::xserver_zmq_split(xcontext& context, const xconfiguration& config, nl::json::error_handler_t eh, control_runner_ptr control, shell_runner_ptr shell) : p_impl(new xserver_zmq_split_impl(context.get_wrapped_context(), config, eh)) , p_control_runner(std::move(control)) , p_shell_runner(std::move(shell)) , m_error_handler(eh) { p_control_runner->register_server(*this); p_shell_runner->register_server(*this); } xserver_zmq_split::~xserver_zmq_split() = default; fd_t xserver_zmq_split::get_control_fd() const { return p_impl->get_control_fd(); } std::optional xserver_zmq_split::read_control(int flags) { return p_impl->read_control(flags); } void xserver_zmq_split::send_control_message(xmessage msg) { p_impl->send_control(std::move(msg)); } void xserver_zmq_split::stop_channels() { p_impl->stop_channels(); } std::string xserver_zmq_split::notify_internal_listener(std::string message) { nl::json msg = nl::json::parse(std::move(message)); nl::json reply = xserver::notify_internal_listener(std::move(msg)); return reply.dump(-1, ' ', false, m_error_handler); } fd_t xserver_zmq_split::get_shell_fd() const { return p_impl->get_shell_fd(); } fd_t xserver_zmq_split::get_shell_controller_fd() const { return p_impl->get_shell_controller_fd(); } std::optional xserver_zmq_split::poll_shell_channels(long timeout) { return p_impl->poll_shell_channels(timeout); } std::optional xserver_zmq_split::read_shell(int flags) { return p_impl->read_shell(flags); } void xserver_zmq_split::send_shell_message(xmessage msg) { p_impl->send_shell(std::move(msg)); } std::optional xserver_zmq_split::read_shell_controller(int flags) { return p_impl->read_shell_controller(flags); } void xserver_zmq_split::send_shell_controller(std::string message) { p_impl->send_shell_controller(std::move(message)); } void xserver_zmq_split::start_publisher_thread() { p_impl->start_publisher_thread(); } void xserver_zmq_split::start_heartbeat_thread() { p_impl->start_heartbeat_thread(); } void xserver_zmq_split::start_control_thread() { m_control_thread = xthread(&xcontrol_runner::run, p_control_runner.get()); } void xserver_zmq_split::run_control() { p_control_runner->run(); } void xserver_zmq_split::start_shell_thread() { m_shell_thread = xthread(&xshell_runner::run, p_shell_runner.get()); } void xserver_zmq_split::run_shell() { p_shell_runner->run(); } xcontrol_messenger& xserver_zmq_split::get_control_messenger_impl() { return p_impl->get_control_messenger(); } void xserver_zmq_split::send_shell_impl(xmessage msg) { send_shell_message(std::move(msg)); } void xserver_zmq_split::send_control_impl(xmessage msg) { send_control_message(std::move(msg)); } void xserver_zmq_split::send_stdin_impl(xmessage msg) { auto rep = p_impl->send_stdin(std::move(msg)); if (rep) { notify_stdin_listener(std::move(rep.value())); } } void xserver_zmq_split::publish_impl(xpub_message msg, channel c) { p_impl->publish(std::move(msg), c); } void xserver_zmq_split::stop_impl() { p_control_runner->stop(); } void xserver_zmq_split::abort_queue_impl(const listener& l, long polling_interval) { p_impl->abort_queue(l, polling_interval); } void xserver_zmq_split::update_config_impl(xconfiguration& config) const { p_impl->update_config(config); } } xeus-zmq-3.1.0/src/server/xserver_zmq_split_impl.cpp000066400000000000000000000120061464077067000227400ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xserver_zmq_split_impl.hpp" #include "../common/xzmq_serializer.hpp" namespace xeus { xserver_zmq_split_impl::xserver_zmq_split_impl(zmq::context_t& context, const xconfiguration& config, nl::json::error_handler_t eh) : p_auth(make_xauthentication(config.m_signature_scheme, config.m_key)) , m_control(context, config.m_transport, config.m_ip ,config.m_control_port, this) , m_heartbeat(context, config.m_transport, config.m_ip, config.m_hb_port) , m_publisher(context, std::bind(&xserver_zmq_split_impl::serialize_iopub, this, std::placeholders::_1), config.m_transport, config.m_ip, config.m_iopub_port) , m_shell(context, config.m_transport, config.m_ip ,config.m_shell_port, config.m_stdin_port, this) , m_hb_thread() , m_iopub_thread() , m_error_handler(eh) { m_control.connect_messenger(); } void xserver_zmq_split_impl::start_heartbeat_thread() { m_hb_thread = xthread(&xheartbeat::run, &m_heartbeat); } void xserver_zmq_split_impl::start_publisher_thread() { m_iopub_thread = xthread(&xpublisher::run, &m_publisher); } void xserver_zmq_split_impl::stop_channels() { m_control.stop_channels(); } fd_t xserver_zmq_split_impl::get_shell_fd() const { return m_shell.get_shell_fd(); } fd_t xserver_zmq_split_impl::get_shell_controller_fd() const { return m_shell.get_controller_fd(); } fd_t xserver_zmq_split_impl::get_control_fd() const { return m_control.get_fd(); } std::optional xserver_zmq_split_impl::poll_shell_channels(long timeout) { return m_shell.poll_channels(timeout); } std::optional xserver_zmq_split_impl::read_shell(int flags) { return m_shell.read_shell(flags); } std::optional xserver_zmq_split_impl::read_shell_controller(int flags) { return m_shell.read_controller(flags); } std::optional xserver_zmq_split_impl::read_control(int flags) { return m_control.read_control(flags); } xcontrol_messenger& xserver_zmq_split_impl::get_control_messenger() { return m_control.get_messenger(); } void xserver_zmq_split_impl::send_shell(xmessage message) { zmq::multipart_t wire_msg = xzmq_serializer::serialize(std::move(message), *p_auth, m_error_handler); m_shell.send_shell(wire_msg); } void xserver_zmq_split_impl::send_shell_controller(std::string message) { m_shell.send_controller(std::move(message)); } void xserver_zmq_split_impl::send_control(xmessage message) { zmq::multipart_t wire_msg = xzmq_serializer::serialize(std::move(message), *p_auth, m_error_handler); m_control.send_control(wire_msg); } std::optional xserver_zmq_split_impl::send_stdin(xmessage message) { zmq::multipart_t wire_msg = xzmq_serializer::serialize(std::move(message), *p_auth, m_error_handler); return m_shell.send_stdin(wire_msg); } void xserver_zmq_split_impl::publish(xpub_message message, channel c) { zmq::multipart_t wire_msg = xzmq_serializer::serialize_iopub(std::move(message), *p_auth, m_error_handler); if (c == channel::SHELL) { m_shell.publish(wire_msg); } else { m_control.publish(wire_msg); } } void xserver_zmq_split_impl::abort_queue(const listener& l, long polling_interval) { m_shell.abort_queue(l, polling_interval); } void xserver_zmq_split_impl::update_config(xconfiguration& config) const { config.m_control_port = m_control.get_port(); config.m_shell_port = m_shell.get_shell_port(); config.m_stdin_port = m_shell.get_stdin_port(); config.m_iopub_port = m_publisher.get_port(); config.m_hb_port = m_heartbeat.get_port(); } xmessage xserver_zmq_split_impl::deserialize(zmq::multipart_t& wire_msg) const { return xzmq_serializer::deserialize(wire_msg, *p_auth); } zmq::multipart_t xserver_zmq_split_impl::serialize_iopub(xpub_message&& msg) { return xzmq_serializer::serialize_iopub(std::move(msg), *p_auth, m_error_handler); } } xeus-zmq-3.1.0/src/server/xserver_zmq_split_impl.hpp000066400000000000000000000052721464077067000227540ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_SERVER_ZMQ_SPLIT_IMPL_HPP #define XEUS_SERVER_ZMQ_SPLIT_IMPL_HPP #include #include "zmq.hpp" #include "zmq_addon.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus-zmq/xmiddleware.hpp" #include "xeus-zmq/xthread.hpp" #include "../common/xauthentication.hpp" #include "xcontrol.hpp" #include "xheartbeat.hpp" #include "xpublisher.hpp" #include "xshell.hpp" namespace xeus { class xserver_zmq_split_impl { public: using listener = std::function; xserver_zmq_split_impl(zmq::context_t& context, const xconfiguration& config, nl::json::error_handler_t eh); void start_heartbeat_thread(); void start_publisher_thread(); void stop_channels(); fd_t get_shell_fd() const; fd_t get_shell_controller_fd() const; fd_t get_control_fd() const; std::optional poll_shell_channels(long timeout); std::optional read_shell(int flags); std::optional read_shell_controller(int flags); std::optional read_control(int flags); xcontrol_messenger& get_control_messenger(); void send_shell(xmessage message); void send_shell_controller(std::string message); void send_control(xmessage message); std::optional send_stdin(xmessage message); void publish(xpub_message message, channel c); void abort_queue(const listener& l, long polling_interval); void update_config(xconfiguration& config) const; xmessage deserialize(zmq::multipart_t& wire_msg) const; zmq::multipart_t serialize_iopub(xpub_message&& msg); private: using authentication_ptr = std::unique_ptr; authentication_ptr p_auth; xcontrol m_control; xheartbeat m_heartbeat; xpublisher m_publisher; xshell m_shell; xthread m_hb_thread; xthread m_iopub_thread; nl::json::error_handler_t m_error_handler; }; } #endif xeus-zmq-3.1.0/src/server/xshell.cpp000066400000000000000000000112061464077067000174170ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include #include #include "xserver_zmq_split_impl.hpp" #include "xshell.hpp" #include "../common/xmiddleware_impl.hpp" namespace xeus { xshell::xshell(zmq::context_t& context, const std::string& transport, const std::string& ip, const std::string& shell_port, const std::string& stdin_port, xserver_zmq_split_impl* server) : m_shell(context, zmq::socket_type::router) , m_stdin(context, zmq::socket_type::router) , m_publisher_pub(context, zmq::socket_type::pub) , m_controller(context, zmq::socket_type::rep) , p_server(server) { init_socket(m_shell, transport, ip, shell_port); init_socket(m_stdin, transport, ip, stdin_port); m_publisher_pub.set(zmq::sockopt::linger, get_socket_linger()); m_publisher_pub.connect(get_publisher_end_point()); m_controller.set(zmq::sockopt::linger, get_socket_linger()); m_controller.bind(get_controller_end_point("shell")); } std::string xshell::get_shell_port() const { return get_socket_port(m_shell); } std::string xshell::get_stdin_port() const { return get_socket_port(m_stdin); } fd_t xshell::get_shell_fd() const { return m_shell.get(zmq::sockopt::fd); } fd_t xshell::get_controller_fd() const { return m_controller.get(zmq::sockopt::fd); } std::optional xshell::poll_channels(long timeout) { zmq::pollitem_t items[] = { { m_shell, 0, ZMQ_POLLIN, 0 }, { m_controller, 0, ZMQ_POLLIN, 0 } }; zmq::poll(&items[0], 2, std::chrono::milliseconds(timeout)); if (items[0].revents & ZMQ_POLLIN) { return channel::SHELL; } if (items[1].revents & ZMQ_POLLIN) { return channel::CONTROL; } return std::nullopt; } std::optional xshell::read_shell(int flags) { zmq::multipart_t wire_msg; if (wire_msg.recv(m_shell, flags)) { try { return p_server->deserialize(wire_msg); } catch(std::exception& e) { std::cerr << e.what() << std::endl; } } return std::nullopt; } std::optional xshell::read_controller(int flags) { zmq::multipart_t wire_msg; if (wire_msg.recv(m_controller, flags)) { return wire_msg.popstr(); } return std::nullopt; } void xshell::send_shell(zmq::multipart_t& message) { message.send(m_shell); } std::optional xshell::send_stdin(zmq::multipart_t& message) { message.send(m_stdin); zmq::multipart_t wire_msg; wire_msg.recv(m_stdin); try { return p_server->deserialize(wire_msg); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return std::nullopt; } void xshell::send_controller(std::string message) { zmq::multipart_t wire_msg(std::move(message)); wire_msg.send(m_controller); } void xshell::publish(zmq::multipart_t& message) { message.send(m_publisher_pub); } void xshell::abort_queue(const listener& l, long polling_interval) { while (true) { zmq::multipart_t wire_msg; bool received = wire_msg.recv(m_shell, ZMQ_NOBLOCK); if (!received) { return; } try { xmessage msg = p_server->deserialize(wire_msg); l(std::move(msg)); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } std::this_thread::sleep_for(std::chrono::milliseconds(polling_interval)); } } } xeus-zmq-3.1.0/src/server/xshell.hpp000066400000000000000000000040661464077067000174320ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_SHELL_HPP #define XEUS_SHELL_HPP #include #include #include "zmq.hpp" #include "zmq_addon.hpp" #include "xeus/xmessage.hpp" #include "xeus/xserver.hpp" #include "xeus-zmq/xmiddleware.hpp" namespace xeus { class xzmq_server_split_impl; class xshell { public: using listener = std::function; xshell(zmq::context_t& context, const std::string& transport, const std::string& ip, const std::string& shell_port, const std::string& stdin_port, xserver_zmq_split_impl* server); std::string get_shell_port() const; std::string get_stdin_port() const; fd_t get_shell_fd() const; fd_t get_controller_fd() const; std::optional poll_channels(long timeout); std::optional read_shell(int flags); std::optional read_controller(int flags); void send_shell(zmq::multipart_t& message); std::optional send_stdin(zmq::multipart_t& message); void send_controller(std::string message); void publish(zmq::multipart_t& message); void abort_queue(const listener& l, long polling_interval); private: zmq::socket_t m_shell; zmq::socket_t m_stdin; zmq::socket_t m_publisher_pub; zmq::socket_t m_controller; xserver_zmq_split_impl* p_server; }; } #endif xeus-zmq-3.1.0/src/server/xshell_default_runner.cpp000066400000000000000000000026401464077067000225160ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xeus-zmq/xshell_default_runner.hpp" namespace xeus { void xshell_default_runner::run_impl() { while (true) { auto chan = poll_channels(); if (auto msg = read_shell(chan)) { notify_shell_listener(std::move(msg.value())); } else if (auto msg = read_controller(chan)) { std::string val = std::move(msg.value()); if (val == "stop") { send_controller(std::move(val)); break; } else { std::string rep = notify_internal_listener(std::move(val)); send_controller(std::move(rep)); } } } } } xeus-zmq-3.1.0/src/server/xshell_runner.cpp000066400000000000000000000046411464077067000210150ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xeus-zmq/xshell_runner.hpp" #include "xeus-zmq/xserver_zmq_split.hpp" namespace xeus { void xshell_runner::register_server(xserver_zmq_split& server) { p_server = &server; } void xshell_runner::run() { run_impl(); } fd_t xshell_runner::get_shell_fd() const { return p_server->get_shell_fd(); } fd_t xshell_runner::get_shell_controller_fd() const { return p_server->get_shell_controller_fd(); } auto xshell_runner::poll_channels(long timeout) -> optional_channel { return p_server->poll_shell_channels(timeout); } std::optional xshell_runner::read_shell(int flags) { return p_server->read_shell(flags); } std::optional xshell_runner::read_shell(optional_channel chan, int flags) { if (chan.has_value() && chan.value() == channel::SHELL) { return read_shell(flags); } return std::nullopt; } std::optional xshell_runner::read_controller(int flags) { return p_server->read_shell_controller(flags); } std::optional xshell_runner::read_controller(optional_channel chan, int flags) { if (chan.has_value() && chan.value() == channel::CONTROL) { return read_controller(flags); } return std::nullopt; } void xshell_runner::send_controller(std::string message) { p_server->send_shell_controller(std::move(message)); } void xshell_runner::notify_shell_listener(xmessage message) { p_server->notify_shell_listener(std::move(message)); } std::string xshell_runner::notify_internal_listener(std::string message) { return p_server->notify_internal_listener(std::move(message)); } } xeus-zmq-3.1.0/src/server/xtrivial_messenger.cpp000066400000000000000000000016051464077067000220340ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xtrivial_messenger.hpp" namespace xeus { xtrivial_messenger::xtrivial_messenger(listener l) : m_listener(std::move(l)) { } nl::json xtrivial_messenger::send_to_shell_impl(const nl::json& message) { return m_listener(message); } } xeus-zmq-3.1.0/src/server/xtrivial_messenger.hpp000066400000000000000000000023211464077067000220350ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_TRIVIAL_MESSENGER_HPP #define XEUS_TRIVIAL_MESSENGER_HPP #include #include "nlohmann/json.hpp" #include "xeus/xcontrol_messenger.hpp" namespace nl = nlohmann; namespace xeus { class xserver_zmq_default; class xtrivial_messenger : public xcontrol_messenger { public: using listener = std::function; explicit xtrivial_messenger(listener l); virtual ~xtrivial_messenger() = default; private: nl::json send_to_shell_impl(const nl::json& message) override; listener m_listener; }; } #endif xeus-zmq-3.1.0/src/server/xzmq_messenger.cpp000066400000000000000000000047051464077067000211750ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "nlohmann/json.hpp" #include "xeus-zmq/xmiddleware.hpp" #include "xzmq_messenger.hpp" namespace nl = nlohmann; namespace xeus { xzmq_messenger::xzmq_messenger(zmq::context_t& context) : m_shell_controller(context, zmq::socket_type::req) , m_publisher_controller(context, zmq::socket_type::req) , m_heartbeat_controller(context, zmq::socket_type::req) { } xzmq_messenger::~xzmq_messenger() { } void xzmq_messenger::connect() { m_shell_controller.set(zmq::sockopt::linger, get_socket_linger()); m_shell_controller.connect(get_controller_end_point("shell")); m_publisher_controller.set(zmq::sockopt::linger, get_socket_linger()); m_publisher_controller.connect(get_controller_end_point("publisher")); m_heartbeat_controller.set(zmq::sockopt::linger, get_socket_linger()); m_heartbeat_controller.connect(get_controller_end_point("heartbeat")); } void xzmq_messenger::stop_channels() { zmq::message_t stop_msg("stop", 4); zmq::message_t response; // Wait for shell answer m_shell_controller.send(stop_msg, zmq::send_flags::none); (void)m_shell_controller.recv(response); // Wait for publisher answer m_publisher_controller.send(stop_msg, zmq::send_flags::none); (void)m_publisher_controller.recv(response); // Wait for heartbeat answer m_heartbeat_controller.send(stop_msg, zmq::send_flags::none); (void)m_heartbeat_controller.recv(response); } nl::json xzmq_messenger::send_to_shell_impl(const nl::json& message) { zmq::multipart_t wire_msg(message.dump()); wire_msg.send(m_shell_controller); zmq::multipart_t wire_reply; wire_reply.recv(m_shell_controller); return nl::json::parse(wire_reply.popstr()); } } xeus-zmq-3.1.0/src/server/xzmq_messenger.hpp000066400000000000000000000024601464077067000211760ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou * * Copyright (c) 2016, QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_ZMQ_MESSENGER_HPP #define XEUS_ZMQ_MESSENGER_HPP #include "zmq.hpp" #include "zmq_addon.hpp" #include "nlohmann/json.hpp" #include "xeus/xcontrol_messenger.hpp" #include "xeus-zmq/xeus-zmq.hpp" namespace nl = nlohmann; namespace xeus { class xzmq_messenger : public xcontrol_messenger { public: explicit xzmq_messenger(zmq::context_t& context); virtual ~xzmq_messenger(); void connect(); void stop_channels(); private: nl::json send_to_shell_impl(const nl::json& message) override; zmq::socket_t m_shell_controller; zmq::socket_t m_publisher_controller; zmq::socket_t m_heartbeat_controller; }; } #endif xeus-zmq-3.1.0/test/000077500000000000000000000000001464077067000142765ustar00rootroot00000000000000xeus-zmq-3.1.0/test/CMakeLists.txt000066400000000000000000000131641464077067000170430ustar00rootroot00000000000000############################################################################ # Copyright (c) 2016, Sylvain Corlay, Johan Mabille, Martin Renou # # Copyright (c) 2016, QuantStack # # # # Distributed under the terms of the BSD 3-Clause License. # # # # The full license is in the file LICENSE, distributed with this software. # ############################################################################ # Unit tests # ========== cmake_minimum_required(VERSION 3.1) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) project(xeus-zmq-test) enable_testing() find_package(xeus-zmq REQUIRED CONFIG) find_package(nlohmann_json QUIET CONFIG) set(XEUS_ZMQ_TEST_DIR ${CMAKE_CURRENT_LIST_DIR}) endif () message(STATUS "Forcing tests build type to Release") set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) include(CheckCXXCompilerFlag) string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) if(nlohmann_json_FOUND) add_definitions(-DHAVE_NLOHMANN_JSON) endif() if(CMAKE_CXX_COMPILER_ID MATCHES Clang OR CMAKE_CXX_COMPILER_ID MATCHES GNU OR CMAKE_CXX_COMPILER_ID MATCHES Intel) add_compile_options(-Wunused-parameter -Wextra -Wreorder -Wconversion -Wsign-conversion) CHECK_CXX_COMPILER_FLAG(-march=native HAS_MARCH_NATIVE) if (HAS_MARCH_NATIVE) add_compile_options(-march=native) endif() endif() if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) add_compile_options(/EHsc /MP /bigobj) set(CMAKE_EXE_LINKER_FLAGS /MANIFEST:NO) endif() find_package(doctest REQUIRED) find_package(Threads) find_program(PYTEST NAMES pytest-3 pytest py.test-3 py.test REQUIRED) if(nlohmann_json_FOUND) # Version up to 3.1.2 export the target `nlohmann_json` if(TARGET nlohmann_json) set(nlohmann_json_TARGET nlohmann_json) # Newer versions export the namespaced target `nlohmann_json::nlohmann_json` elseif(TARGET nlohmann_json::nlohmann_json) set(nlohmann_json_TARGET nlohmann_json::nlohmann_json) endif() endif() if (TARGET xeus-zmq) set(xeus-zmq_TARGET xeus-zmq) message("Found xeus-zmq shared library.") elseif (TARGET xeus-zmq-static) set(xeus-zmq_TARGET xeus-zmq-static) message("Found xeus-zmq static library.") endif () # Test_kernel tests # ================= set(TEST_KERNEL_SOURCES xmock_interpreter.cpp xmock_interpreter.hpp main.cpp) configure_file( "${XEUS_ZMQ_TEST_DIR}/test_kernel/kernel.json.in" "kernels/test_kernel/kernel.json" ) add_executable(test_kernel ${TEST_KERNEL_SOURCES}) target_link_libraries(test_kernel PRIVATE ${xeus-zmq_TARGET} Threads::Threads) target_compile_features(test_kernel PRIVATE cxx_std_17) set(CONNECTION_FILE ${CMAKE_CURRENT_SOURCE_DIR}/connection.json) configure_file( "${XEUS_ZMQ_TEST_DIR}/test_kernel.py" "${CMAKE_CURRENT_BINARY_DIR}/" COPYONLY) add_test(NAME test_kernel COMMAND ${PYTEST} test_kernel.py) set_tests_properties(test_kernel PROPERTIES ENVIRONMENT "JUPYTER_PATH=${CMAKE_CURRENT_BINARY_DIR}") # Test_kernel_control tests # ========================= set(TEST_KERNEL_SPLIT_SOURCES xmock_interpreter.cpp xmock_interpreter.hpp main_control.cpp) configure_file( "${XEUS_ZMQ_TEST_DIR}/test_kernel_control/kernel.json.in" "kernels/test_kernel_control/kernel.json" ) add_executable(test_kernel_control ${TEST_KERNEL_SPLIT_SOURCES}) target_link_libraries(test_kernel_control PRIVATE ${xeus-zmq_TARGET} Threads::Threads) target_compile_features(test_kernel_control PRIVATE cxx_std_17) set(CONNECTION_FILE ${CMAKE_CURRENT_SOURCE_DIR}/connection.json) configure_file( "${XEUS_ZMQ_TEST_DIR}/test_kernel_control.py" "${CMAKE_CURRENT_BINARY_DIR}/" COPYONLY) add_test(NAME test_kernel_control COMMAND ${PYTEST} test_kernel_control.py) set_tests_properties(test_kernel_control PROPERTIES ENVIRONMENT "JUPYTER_PATH=${CMAKE_CURRENT_BINARY_DIR}") # Test_kernel_shell tests # ======================= set(TEST_KERNEL_SPLIT_SOURCES xmock_interpreter.cpp xmock_interpreter.hpp main_shell.cpp) configure_file( "${XEUS_ZMQ_TEST_DIR}/test_kernel_shell/kernel.json.in" "kernels/test_kernel_shell/kernel.json" ) add_executable(test_kernel_shell ${TEST_KERNEL_SPLIT_SOURCES}) target_link_libraries(test_kernel_shell PRIVATE ${xeus-zmq_TARGET} Threads::Threads) target_compile_features(test_kernel_shell PRIVATE cxx_std_17) set(CONNECTION_FILE ${CMAKE_CURRENT_SOURCE_DIR}/connection.json) configure_file( "${XEUS_ZMQ_TEST_DIR}/test_kernel_shell.py" "${CMAKE_CURRENT_BINARY_DIR}/" COPYONLY) add_test(NAME test_kernel_shell COMMAND ${PYTEST} test_kernel_shell.py) set_tests_properties(test_kernel_shell PROPERTIES ENVIRONMENT "JUPYTER_PATH=${CMAKE_CURRENT_BINARY_DIR}") if (UNIX) # Test_kernel_ipc # =============== set(TEST_KERNEL_IPC_SOURCES xmock_interpreter.cpp xmock_interpreter.hpp main_ipc.cpp) add_executable(test_kernel_ipc ${TEST_KERNEL_IPC_SOURCES}) target_link_libraries(test_kernel_ipc PRIVATE ${xeus-zmq_TARGET} Threads::Threads) target_compile_features(test_kernel_ipc PRIVATE cxx_std_17) # Test_client_ipc # =============== set(TEST_CLIENT_IPC_SOURCES xipc_client.cpp xipc_client.hpp client_ipc.cpp) add_executable(test_client_ipc ${TEST_CLIENT_IPC_SOURCES}) target_link_libraries(test_client_ipc PRIVATE ${xeus-zmq_TARGET} Threads::Threads) target_compile_features(test_client_ipc PRIVATE cxx_std_17) endif (UNIX) xeus-zmq-3.1.0/test/client_ipc.cpp000066400000000000000000000037321464077067000171200ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille and Sylvain Corlay * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include "zmq_addon.hpp" #include "nlohmann/json.hpp" #include "xeus/xguid.hpp" #include "xeus/xmessage.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus-zmq/xzmq_context.hpp" #include "xipc_client.hpp" namespace nl = nlohmann; int main(int, char**) { auto context_ptr = xeus::make_zmq_context(); xeus::xconfiguration config; config.m_transport = "ipc"; config.m_ip = "localhost"; config.m_control_port = "control"; config.m_shell_port = "shell"; config.m_stdin_port = "stdin"; config.m_iopub_port = "iopub"; config.m_hb_port = "heartbeat"; config.m_signature_scheme = "none"; config.m_key = ""; xeus::xipc_client ipc_client(*context_ptr, config); xeus::xguid socket_id = xeus::new_xguid(); nl::json header = xeus::make_header("execute_request", "tester", "DAEDZFAEDE12"); std::string code = "std::cout << \"this is a test\" << std::endl;"; nl::json req = { { "code", code } }; xeus::xmessage msg( { socket_id}, header, code, nl::json::object(), nl::json::object(), xeus::buffer_sequence() ); ipc_client.send_on_shell(std::move(msg)); auto response = ipc_client.receive_on_shell(false); if (response.has_value()) { std::cout << response->content().dump(4) << std::endl; } else { std::cout << "No response received" << std::endl; } return 0; } xeus-zmq-3.1.0/test/main.cpp000066400000000000000000000026501464077067000157310ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille and Sylvain Corlay * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include #include "xeus/xkernel.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus-zmq/xzmq_context.hpp" #include "xeus-zmq/xserver_zmq.hpp" #include "xmock_interpreter.hpp" int main(int argc, char* argv[]) { std::string file_name = (argc == 1) ? "connection.json" : argv[2]; xeus::xconfiguration config = xeus::load_configuration(file_name); auto context = xeus::make_zmq_context(); using interpreter_ptr = std::unique_ptr; interpreter_ptr interpreter = interpreter_ptr(new xeus::xmock_interpreter()); xeus::xkernel kernel(config, xeus::get_user_name(), std::move(context), std::move(interpreter), xeus::make_xserver_default); std::cout << "starting kernel" << std::endl; kernel.start(); return 0; } xeus-zmq-3.1.0/test/main_control.cpp000066400000000000000000000032311464077067000174650ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille and Sylvain Corlay * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include #include "xeus/xkernel.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus-zmq/xzmq_context.hpp" #include "xeus-zmq/xserver_zmq_split.hpp" #include "xmock_interpreter.hpp" int main(int argc, char* argv[]) { std::string file_name = (argc == 1) ? "connection.json" : argv[2]; xeus::xconfiguration config = xeus::load_configuration(file_name); using history_manager_ptr = std::unique_ptr; history_manager_ptr hist = xeus::make_in_memory_history_manager(); auto context = xeus::make_zmq_context(); using interpreter_ptr = std::unique_ptr; interpreter_ptr interpreter = interpreter_ptr(new xeus::xmock_interpreter()); xeus::xkernel kernel(config, xeus::get_user_name(), std::move(context), std::move(interpreter), xeus::make_xserver_control_main, std::move(hist), nullptr); std::cout << "starting kernel" << std::endl; kernel.start(); return 0; } xeus-zmq-3.1.0/test/main_ipc.cpp000066400000000000000000000032641464077067000165660ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille and Sylvain Corlay * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include #include #include "xeus/xkernel.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus-zmq/xzmq_context.hpp" #include "xeus-zmq/xserver_zmq.hpp" #include "xmock_interpreter.hpp" int main(int /*argc*/, char* /*argv*/[]) { using namespace std::chrono_literals; xeus::xconfiguration config; config.m_transport = "ipc"; config.m_ip = "localhost"; config.m_control_port = "control"; config.m_shell_port = "shell"; config.m_stdin_port = "stdin"; config.m_iopub_port = "iopub"; config.m_hb_port = "heartbeat"; config.m_signature_scheme = "none"; config.m_key = ""; auto context = xeus::make_zmq_context(); using interpreter_ptr = std::unique_ptr; interpreter_ptr interpreter = interpreter_ptr(new xeus::xmock_interpreter()); xeus::xkernel kernel(config, xeus::get_user_name(), std::move(context), std::move(interpreter), xeus::make_xserver_default); std::cout << "starting kernel" << std::endl; kernel.start(); return 0; } xeus-zmq-3.1.0/test/main_shell.cpp000066400000000000000000000032271464077067000171210ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille and Sylvain Corlay * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include #include "xeus/xkernel.hpp" #include "xeus/xkernel_configuration.hpp" #include "xeus-zmq/xzmq_context.hpp" #include "xeus-zmq/xserver_zmq_split.hpp" #include "xmock_interpreter.hpp" int main(int argc, char* argv[]) { std::string file_name = (argc == 1) ? "connection.json" : argv[2]; xeus::xconfiguration config = xeus::load_configuration(file_name); using history_manager_ptr = std::unique_ptr; history_manager_ptr hist = xeus::make_in_memory_history_manager(); auto context = xeus::make_zmq_context(); using interpreter_ptr = std::unique_ptr; interpreter_ptr interpreter = interpreter_ptr(new xeus::xmock_interpreter()); xeus::xkernel kernel(config, xeus::get_user_name(), std::move(context), std::move(interpreter), xeus::make_xserver_shell_main, std::move(hist), nullptr); std::cout << "starting kernel" << std::endl; kernel.start(); return 0; } xeus-zmq-3.1.0/test/test_kernel.py000066400000000000000000000020751464077067000171730ustar00rootroot00000000000000import unittest import jupyter_kernel_test class XeusKernelTests(jupyter_kernel_test.KernelTests): kernel_name = "test_kernel" language_name = "cpp" code_hello_world = "hello, world" code_page_something = "?" code_execute_result = [ {'code': '6*7', 'result': '6*7'}, {'code': 'test', 'result': 'test'} ] completion_samples = [ {'text': 'a.', 'matches': ['a.test1', 'a.test2']} ] complete_code_samples = ["complete"] incomplete_code_samples = ["incomplete"] invalid_code_samples = ["invalid"] code_inspect_sample = "invalid" def test_xeus_stderr(self): reply, output_msgs = self.execute_helper(code='error') self.assertEqual(output_msgs[0]['msg_type'], 'stream') self.assertEqual(output_msgs[0]['content']['name'], 'stderr') self.assertEqual(output_msgs[0]['content']['text'], 'error') class XeusIopubWelcomeTests(jupyter_kernel_test.IopubWelcomeTests): kernel_name = "test_kernel" support_iopub_welcome = True if __name__ == '__main__': unittest.main() xeus-zmq-3.1.0/test/test_kernel/000077500000000000000000000000001464077067000166155ustar00rootroot00000000000000xeus-zmq-3.1.0/test/test_kernel/kernel.json.in000066400000000000000000000002541464077067000213760ustar00rootroot00000000000000{ "display_name": "test_kernel", "language" : "cpp", "argv": [ "@CMAKE_BINARY_DIR@/test/test_kernel", "-f", "{connection_file}" ] } xeus-zmq-3.1.0/test/test_kernel_control.py000066400000000000000000000021151464077067000207260ustar00rootroot00000000000000import unittest import jupyter_kernel_test class XeusKernelTests(jupyter_kernel_test.KernelTests): kernel_name = "test_kernel_control" language_name = "cpp" code_hello_world = "hello, world" code_page_something = "?" code_execute_result = [ {'code': '6*7', 'result': '6*7'}, {'code': 'test', 'result': 'test'} ] completion_samples = [ {'text': 'a.', 'matches': ['a.test1', 'a.test2']} ] complete_code_samples = ["complete"] incomplete_code_samples = ["incomplete"] invalid_code_samples = ["invalid"] code_inspect_sample = "invalid" def test_xeus_stderr(self): reply, output_msgs = self.execute_helper(code='error') self.assertEqual(output_msgs[0]['msg_type'], 'stream') self.assertEqual(output_msgs[0]['content']['name'], 'stderr') self.assertEqual(output_msgs[0]['content']['text'], 'error') class XeusIopubWelcomeTests(jupyter_kernel_test.IopubWelcomeTests): kernel_name = "test_kernel_control" support_iopub_welcome = True if __name__ == '__main__': unittest.main() xeus-zmq-3.1.0/test/test_kernel_control/000077500000000000000000000000001464077067000203555ustar00rootroot00000000000000xeus-zmq-3.1.0/test/test_kernel_control/kernel.json.in000066400000000000000000000002641464077067000231370ustar00rootroot00000000000000{ "display_name": "test_kernel", "language" : "cpp", "argv": [ "@CMAKE_BINARY_DIR@/test/test_kernel_control", "-f", "{connection_file}" ] } xeus-zmq-3.1.0/test/test_kernel_shell.py000066400000000000000000000021111464077067000203510ustar00rootroot00000000000000import unittest import jupyter_kernel_test class XeusKernelTests(jupyter_kernel_test.KernelTests): kernel_name = "test_kernel_shell" language_name = "cpp" code_hello_world = "hello, world" code_page_something = "?" code_execute_result = [ {'code': '6*7', 'result': '6*7'}, {'code': 'test', 'result': 'test'} ] completion_samples = [ {'text': 'a.', 'matches': ['a.test1', 'a.test2']} ] complete_code_samples = ["complete"] incomplete_code_samples = ["incomplete"] invalid_code_samples = ["invalid"] code_inspect_sample = "invalid" def test_xeus_stderr(self): reply, output_msgs = self.execute_helper(code='error') self.assertEqual(output_msgs[0]['msg_type'], 'stream') self.assertEqual(output_msgs[0]['content']['name'], 'stderr') self.assertEqual(output_msgs[0]['content']['text'], 'error') class XeusIopubWelcomeTests(jupyter_kernel_test.IopubWelcomeTests): kernel_name = "test_kernel_shell" support_iopub_welcome = True if __name__ == '__main__': unittest.main() xeus-zmq-3.1.0/test/test_kernel_shell/000077500000000000000000000000001464077067000200045ustar00rootroot00000000000000xeus-zmq-3.1.0/test/test_kernel_shell/kernel.json.in000066400000000000000000000002621464077067000225640ustar00rootroot00000000000000{ "display_name": "test_kernel", "language" : "cpp", "argv": [ "@CMAKE_BINARY_DIR@/test/test_kernel_shell", "-f", "{connection_file}" ] } xeus-zmq-3.1.0/test/xipc_client.cpp000066400000000000000000000017301464077067000173040ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille and Sylvain Corlay * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include "xipc_client.hpp" namespace xeus { xipc_client::xipc_client(xcontext& context, const xconfiguration& config) : p_client(make_xclient_zmq(context, config)) { } void xipc_client::send_on_shell(xmessage msg) { p_client->send_on_shell(std::move(msg)); } std::optional xipc_client::receive_on_shell(bool blocking) { return p_client->receive_on_shell(blocking); } } xeus-zmq-3.1.0/test/xipc_client.hpp000066400000000000000000000017431464077067000173150ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille and Sylvain Corlay * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_IPC_CLIENT_HPP #define XEUS_IPC_CLIENT_HPP #include "xeus-zmq/xclient_zmq.hpp" namespace xeus { class xipc_client { public: using client_ptr = std::unique_ptr; xipc_client(xcontext& context, const xconfiguration& config); void send_on_shell(xmessage msg); std::optional receive_on_shell(bool blocking = true); private: client_ptr p_client; }; } #endif xeus-zmq-3.1.0/test/xmock_interpreter.cpp000066400000000000000000000102141464077067000205440ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille and Sylvain Corlay * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include "nlohmann/json.hpp" #include "xmock_interpreter.hpp" #include "xeus/xhelper.hpp" #include "xeus/xguid.hpp" namespace nl = nlohmann; namespace xeus { void xmock_interpreter::configure_impl() { auto handle_comm_opened = [](xeus::xcomm&& comm, const xeus::xmessage&) { std::cout << "Comm opened for target: " << comm.target().name() << std::endl; }; comm_manager().register_comm_target("test_target", handle_comm_opened); using function_type = std::function; } void xmock_interpreter::execute_request_impl(send_reply_callback cb, int execution_counter, const std::string& code, execute_request_config /*config*/, nl::json /*user_expressions*/) { if (code.compare("hello, world") == 0) { publish_stream("stdout", code); } if (code.compare("error") == 0) { publish_stream("stderr", code); } if (code.compare("?") == 0) { std::string html_content = R"()"; auto payload = nl::json::array(); payload[0] = nl::json::object({ {"data", { {"text/plain", "https://xeus.readthedocs.io"}, {"text/html", html_content}} }, {"source", "page"}, {"start", 0} }); cb(xeus::create_successful_reply(payload)); } else { nl::json pub_data; pub_data["text/plain"] = code; publish_execution_result(execution_counter, std::move(pub_data), nl::json::object()); cb(xeus::create_successful_reply()); } } nl::json xmock_interpreter::complete_request_impl(const std::string& /* code */, int /* cursor_pos */) { return xeus::create_complete_reply({"a.test1", "a.test2"}, 2, 6); } nl::json xmock_interpreter::inspect_request_impl(const std::string& /* code */, int /* cursor_pos */, int /* detail_level */) { return xeus::create_inspect_reply(true, {{"text/plain", ""}}, {{"text/plain", ""}}); } nl::json xmock_interpreter::is_complete_request_impl(const std::string& code) { nl::json result = xeus::create_is_complete_reply(code); if (code.compare("incomplete") == 0) { result["indent"] = " "; } return result; } nl::json xmock_interpreter::kernel_info_request_impl() { return xeus::create_info_reply("", "cpp_test", "1.0.0", "cpp", "14.0.0", "text/x-c++src", ".cpp", "", "", "", "test_kernel"); } void xmock_interpreter::shutdown_request_impl() { } } xeus-zmq-3.1.0/test/xmock_interpreter.hpp000066400000000000000000000032401464077067000205520ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2016, Johan Mabille and Sylvain Corlay * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XEUS_MOCK_INTERPRETER_HPP #define XEUS_MOCK_INTERPRETER_HPP #include "xeus/xinterpreter.hpp" namespace xeus { class xmock_interpreter : public xinterpreter { public: xmock_interpreter() = default; virtual ~xmock_interpreter() = default; private: void configure_impl() override; void execute_request_impl(send_reply_callback cb, int execution_counter, const std::string& code, execute_request_config config, nl::json user_expressions) override; nl::json complete_request_impl(const std::string& code, int cursor_pos) override; nl::json inspect_request_impl(const std::string& code, int cursor_pos, int detail_level) override; nl::json is_complete_request_impl(const std::string& code) override; nl::json kernel_info_request_impl() override; void shutdown_request_impl() override; }; } #endif xeus-zmq-3.1.0/xeus-zmqConfig.cmake.in000066400000000000000000000041251464077067000176470ustar00rootroot00000000000000############################################################################ # Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou # # Copyright (c) 2016, QuantStack # # # # Distributed under the terms of the BSD 3-Clause License. # # # # The full license is in the file LICENSE, distributed with this software. # ############################################################################ # xeus cmake module # This module sets the following variables in your project:: # # xeus_FOUND - true if xeus found on the system # xeus_INCLUDE_DIRS - the directory containing xeus headers # xeus_LIBRARY - the library for dynamic linking # xeus_STATIC_LIBRARY - the library for static linking @PACKAGE_INIT@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR};${CMAKE_MODULE_PATH}") @XEUS_ZMQ_CONFIG_CODE@ include(CMakeFindDependencyMacro) find_dependency(nlohmann_json @nlohmann_json_VERSION@ EXACT) find_dependency(xeus @xeus_REQUIRED_VERSION@) find_dependency(OpenSSL) if(NOT TARGET xeus-zmq AND NOT TARGET xeus-zmq-static) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") if (TARGET xeus-zmq AND TARGET xeus-zmq-static) get_target_property(@PROJECT_NAME@_INCLUDE_DIR xeus-zmq INTERFACE_INCLUDE_DIRECTORIES) get_target_property(@PROJECT_NAME@_LIBRARY xeus-zmq LOCATION) get_target_property(@PROJECT_NAME@_STATIC_LIBRARY xeus-zmq-static LOCATION) elseif (TARGET xeus-zmq) get_target_property(@PROJECT_NAME@_INCLUDE_DIR xeus-zmq INTERFACE_INCLUDE_DIRECTORIES) get_target_property(@PROJECT_NAME@_LIBRARY xeus-zmq LOCATION) elseif (TARGET xeus-zmq-static) get_target_property(@PROJECT_NAME@_INCLUDE_DIR xeus-zmq-static INTERFACE_INCLUDE_DIRECTORIES) get_target_property(@PROJECT_NAME@_STATIC_LIBRARY xeus-zmq-static LOCATION) set(@PROJECT_NAME@_LIBRARY ${@PROJECT_NAME@_STATIC_LIBRARY}) endif () endif()