├── .clang-format ├── .editorconfig ├── .gitignore ├── .gitmodules ├── .lgtm.yml ├── .pre-commit-config.yaml ├── .pyup.yaml ├── .travis.yml ├── AUTHORS.txt ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── apps ├── CMakeLists.txt ├── httpRequest.cpp ├── jsonrpcRequest.cpp └── server.cpp ├── doc └── Changelog.md ├── js ├── .npmignore ├── CHANGELOG.md ├── README.md ├── jest.config.js ├── package.json ├── rollup.config.js ├── src │ ├── client.spec.ts │ ├── client.ts │ ├── constants.ts │ ├── error.spec.ts │ ├── error.ts │ ├── index.ts │ ├── notification.spec.ts │ ├── notification.ts │ ├── request.spec.ts │ ├── request.ts │ ├── response.spec.ts │ ├── response.ts │ ├── testing.ts │ ├── types.ts │ ├── utils.spec.ts │ └── utils.ts ├── test │ └── setup.js ├── tsconfig.cjs.json ├── tsconfig.es2015.json ├── tsconfig.es5.json ├── tsconfig.json ├── tsconfig.spec.json ├── tsconfig.types.json ├── tslint.json └── yarn.lock ├── python ├── .gitignore ├── MANIFEST.in ├── Makefile ├── README.md ├── doc │ ├── Makefile │ └── source │ │ ├── api.rst │ │ ├── conf.py │ │ └── index.rst ├── pylintrc ├── requirements.txt ├── requirements_dev.txt ├── requirements_rtd.txt ├── rockets │ ├── __init__.py │ ├── async_client.py │ ├── client.py │ ├── notification.py │ ├── request.py │ ├── request_error.py │ ├── request_progress.py │ ├── request_task.py │ ├── response.py │ ├── utils.py │ └── version.py ├── setup.cfg ├── setup.py ├── tests │ ├── __init__.py │ ├── test_batch.py │ ├── test_connect.py │ ├── test_notebook.py │ ├── test_notify.py │ ├── test_observable.py │ ├── test_request.py │ └── test_request_id.py └── tox.ini ├── rockets ├── CMakeLists.txt ├── clientContext.cpp ├── clientContext.h ├── debug.h ├── helpers.h ├── http │ ├── channel.cpp │ ├── channel.h │ ├── client.cpp │ ├── client.h │ ├── connection.cpp │ ├── connection.h │ ├── connectionHandler.cpp │ ├── connectionHandler.h │ ├── cors.h │ ├── filter.h │ ├── helpers.h │ ├── registry.cpp │ ├── registry.h │ ├── request.h │ ├── requestHandler.cpp │ ├── requestHandler.h │ ├── response.h │ ├── types.h │ ├── utils.cpp │ └── utils.h ├── json.hpp ├── jsonrpc │ ├── asyncReceiver.cpp │ ├── asyncReceiver.h │ ├── asyncReceiverImpl.h │ ├── cancellableReceiver.cpp │ ├── cancellableReceiver.h │ ├── cancellableReceiverImpl.h │ ├── client.h │ ├── clientRequest.cpp │ ├── clientRequest.h │ ├── errorCodes.h │ ├── helpers.cpp │ ├── helpers.h │ ├── http.cpp │ ├── http.h │ ├── notifier.cpp │ ├── notifier.h │ ├── receiver.cpp │ ├── receiver.h │ ├── receiverImpl.h │ ├── requestProcessor.cpp │ ├── requestProcessor.h │ ├── requester.cpp │ ├── requester.h │ ├── response.h │ ├── responseError.h │ ├── server.h │ ├── types.h │ └── utils.h ├── log.cpp ├── pollDescriptors.cpp ├── pollDescriptors.h ├── proxyConnectionError.h ├── qt │ ├── readWriteSocketNotifier.h │ └── socketProcessor.h ├── server.cpp ├── server.h ├── serverContext.cpp ├── serverContext.h ├── serviceThreadPool.cpp ├── serviceThreadPool.h ├── socketBasedInterface.h ├── socketListener.h ├── types.h ├── unavailablePortError.h ├── utils.cpp ├── utils.h ├── wrappers.h └── ws │ ├── channel.cpp │ ├── channel.h │ ├── client.cpp │ ├── client.h │ ├── connection.cpp │ ├── connection.h │ ├── messageHandler.cpp │ ├── messageHandler.h │ └── types.h ├── scripts ├── build_lib.sh ├── check_version.py ├── install_requirements.sh └── set_npm_package_version.sh └── tests ├── CMakeLists.txt ├── http.cpp ├── jsonRpc.cpp ├── jsonRpcAsync.cpp ├── jsonRpcCancellable.cpp ├── jsonRpcClientServer.cpp ├── jsonRpcHttp.cpp ├── json_utils.h └── websockets.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: -4 3 | AlignConsecutiveAssignments: false 4 | AlignConsecutiveDeclarations: false 5 | AlignEscapedNewlinesLeft: true 6 | AlignOperands: true 7 | AlignTrailingComments: true 8 | AllowAllParametersOfDeclarationOnNextLine: true 9 | AllowShortFunctionsOnASingleLine: Inline 10 | AllowShortIfStatementsOnASingleLine: false 11 | AllowShortLoopsOnASingleLine: false 12 | AlwaysBreakBeforeMultilineStrings: true 13 | AlwaysBreakTemplateDeclarations: true 14 | BinPackParameters: true 15 | BreakBeforeBinaryOperators: false 16 | BreakBeforeBraces: Allman # brace on new line 17 | BreakBeforeTernaryOperators: true 18 | BreakConstructorInitializersBeforeComma: true 19 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 20 | ConstructorInitializerIndentWidth: 4 21 | ContinuationIndentWidth: 4 22 | Cpp11BracedListStyle: true 23 | DerivePointerBinding: true 24 | ExperimentalAutoDetectBinPacking: false 25 | #FixNamespaceComments: false # uncomment since clang-format 5.0 26 | IndentCaseLabels: false 27 | IndentFunctionDeclarationAfterType: true 28 | IndentWidth: 4 29 | KeepEmptyLinesAtTheStartOfBlocks: false 30 | Language: Cpp 31 | MaxEmptyLinesToKeep: 1 32 | NamespaceIndentation: None 33 | PenaltyBreakBeforeFirstCallParameter: 100 34 | PenaltyBreakComment: 60 35 | PenaltyBreakFirstLessLess: 120 36 | PenaltyBreakString: 1000 37 | PenaltyExcessCharacter: 1000000 38 | PenaltyReturnTypeOnItsOwnLine: 200 39 | PointerBindsToType: true 40 | SortIncludes: true 41 | SpaceAfterControlStatementKeyword: true 42 | SpaceBeforeAssignmentOperators: true 43 | SpaceBeforeParens: ControlStatements 44 | SpaceInEmptyParentheses: false 45 | SpacesBeforeTrailingComments: 1 46 | SpacesInAngles: false # '< ' style 47 | SpacesInCStyleCastParentheses: false 48 | SpacesInParentheses: false # '(' style 49 | Standard: Cpp11 50 | TabWidth: 4 51 | UseTab: Never 52 | ... 53 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs 2 | # http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*{.yml}] 14 | indent_size = 2 15 | 16 | [*.md] 17 | trim_trailing_whitespace = false 18 | max_line_length = off 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .envrc 3 | *~ 4 | *.autosave 5 | CMakeLists.txt.user* 6 | build/ 7 | 8 | node_modules 9 | coverage 10 | docs 11 | dist 12 | out-tsc 13 | tmp 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "CMake/common"] 2 | path = CMake/common 3 | url = https://github.com/Eyescale/CMake 4 | -------------------------------------------------------------------------------- /.lgtm.yml: -------------------------------------------------------------------------------- 1 | extraction: 2 | cpp: 3 | prepare: 4 | packages: 5 | - libwebsockets-dev 6 | - libuv1-dev 7 | python: 8 | python_setup: 9 | version: 3 10 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/asottile/reorder_python_imports 3 | rev: v1.3.4 4 | hooks: 5 | - id: reorder-python-imports 6 | - repo: https://github.com/ambv/black 7 | rev: 18.9b0 8 | hooks: 9 | - id: black 10 | - repo: git://github.com/tribal-tec/pre-commit-clang-format 11 | rev: 5d64714207462c7ab063560e3f61ca00adfe5e06 12 | hooks: 13 | - id: clang-format 14 | -------------------------------------------------------------------------------- /.pyup.yaml: -------------------------------------------------------------------------------- 1 | # autogenerated pyup.io config file 2 | # see https://pyup.io/docs/configuration/ for all available options 3 | 4 | update: false 5 | -------------------------------------------------------------------------------- /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | Raphael Dumusc 2 | Andrei-Roland Groza 3 | Daniel Nachbaur 4 | 5 | Jonas Karlsson (contributor) 6 | Judit Planas Carbonell (contributor) 7 | Pawel Jozef Podhajski (contributor) 8 | Nadir Roman Guerrero (contributor) 9 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017-2019, EPFL/Blue Brain Project 2 | # Raphael.Dumusc@epfl.ch 3 | # 4 | # This file is part of Rockets 5 | # 6 | # This library is free software; you can redistribute it and/or modify it under 7 | # the terms of the GNU Lesser General Public License version 3.0 as published 8 | # by the Free Software Foundation. 9 | # 10 | # This library is distributed in the hope that it will be useful, but WITHOUT 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | # details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with this library; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | cmake_minimum_required(VERSION 3.1 FATAL_ERROR) 20 | project(Rockets VERSION 1.0.0) 21 | set(Rockets_VERSION_ABI 1) 22 | 23 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake/common) 24 | if(NOT EXISTS ${CMAKE_SOURCE_DIR}/CMake/common/Common.cmake) 25 | message(FATAL_ERROR "CMake/common missing, run: git submodule update --init") 26 | endif() 27 | 28 | set(ROCKETS_DEB_DEPENDS libboost-test-dev libwebsockets-dev libuv1-dev) 29 | set(ROCKETS_PORT_DEPENDS libwebsockets) 30 | 31 | # disable noisy warnings from ChoosePython 32 | set(CHOOSE_PYTHON_DONE ON) 33 | include(FindBoostConfig) 34 | 35 | include(Common) 36 | 37 | set(ROCKETS_DESCRIPTION "Rockets - REST and websockets C++ library") 38 | set(ROCKETS_MAINTAINER "Blue Brain Project ") 39 | set(ROCKETS_LICENSE LGPL) 40 | 41 | common_find_package(Boost SYSTEM COMPONENTS unit_test_framework) 42 | if(APPLE) 43 | common_find_package(OpenSSL REQUIRED) # libwebsockets depends on that 44 | endif() 45 | common_find_package(Libwebsockets SYSTEM) 46 | if(NOT Libwebsockets_FOUND) # Ubuntu package only has libwebsockets.pc 47 | common_find_package_disable(Libwebsockets) 48 | common_find_package(libwebsockets SYSTEM REQUIRED) 49 | set(Libwebsockets_VERSION ${libwebsockets_VERSION}) 50 | endif() 51 | common_find_package_post() 52 | 53 | # Prefer pthread and add '-pthread' to import target 54 | set(CMAKE_THREAD_PREFER_PTHREAD TRUE) 55 | set(THREADS_PREFER_PTHREAD_FLAG ON) 56 | find_package(Threads REQUIRED) 57 | set(ROCKETS_DEPENDENT_LIBRARIES Threads) 58 | 59 | option(ROCKETS_BUILD_APPLICATIONS "Build example applications" ON) 60 | 61 | if(ROCKETS_BUILD_APPLICATIONS) 62 | add_subdirectory(apps) 63 | endif() 64 | add_subdirectory(rockets) 65 | add_subdirectory(tests) 66 | 67 | set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md") 68 | set(ROCKETS_PACKAGE_DEB_DEPENDS libwebsockets-dev) 69 | include(CommonCPack) 70 | 71 | set(COMMON_PROJECT_DOMAIN ch.epfl.bluebrain) 72 | set(DOXYGEN_MAINPAGE_MD README.md) 73 | set(DOXYGEN_EXTRA_INPUT ${PROJECT_SOURCE_DIR}/README.md) 74 | include(DoxygenRule) 75 | -------------------------------------------------------------------------------- /apps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | # Raphael.Dumusc@epfl.ch 3 | # 4 | # This file is part of Rockets 5 | # 6 | # This library is free software; you can redistribute it and/or modify it under 7 | # the terms of the GNU Lesser General Public License version 3.0 as published 8 | # by the Free Software Foundation. 9 | # 10 | # This library is distributed in the hope that it will be useful, but WITHOUT 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | # details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with this library; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | if(NOT ${Libwebsockets_VERSION} VERSION_LESS 2.0.0) 20 | set(ROCKETS-HTTP-REQUEST_SOURCES httpRequest.cpp) 21 | set(ROCKETS-HTTP-REQUEST_LINK_LIBRARIES Rockets) 22 | common_application(rockets-http-request) 23 | 24 | set(ROCKETS-JSONRPC-REQUEST_SOURCES jsonrpcRequest.cpp) 25 | set(ROCKETS-JSONRPC-REQUEST_LINK_LIBRARIES Rockets) 26 | common_application(rockets-jsonrpc-request) 27 | endif() 28 | 29 | set(ROCKETS-SERVER_SOURCES server.cpp) 30 | set(ROCKETS-SERVER_LINK_LIBRARIES Rockets) 31 | common_application(rockets-server) 32 | -------------------------------------------------------------------------------- /apps/httpRequest.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * - Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * - Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * - Neither the name of Blue Brain Project / EPFL nor the names of its 15 | * contributors may be used to endorse or promote products derived from this 16 | * software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | using namespace rockets; 38 | 39 | void print_usage() 40 | { 41 | std::cout << "Usage: rockets-http-request url [body]" << std::endl; 42 | } 43 | 44 | int main(int argc, char** argv) 45 | { 46 | for (int i = 1; i < argc; ++i) 47 | { 48 | if (std::string(argv[i]) == "--help") 49 | { 50 | print_usage(); 51 | return EXIT_SUCCESS; 52 | } 53 | } 54 | 55 | if (argc < 2) 56 | { 57 | print_usage(); 58 | return EXIT_FAILURE; 59 | } 60 | 61 | const auto uri = std::string(argv[1]); 62 | const auto body = argc == 3 ? std::string(argv[2]) : std::string(); 63 | const auto method = body.empty() ? http::Method::GET : http::Method::POST; 64 | 65 | http::Client client; 66 | try 67 | { 68 | auto res = client.request(uri, method, body); 69 | while (!is_ready(res)) 70 | client.process(250); 71 | 72 | const auto response = res.get(); 73 | if (response.code != http::Code::OK) 74 | std::cout << "Code " << (int)response.code << ":" << std::endl; 75 | if (!response.body.empty()) 76 | std::cout << response.body << std::endl; 77 | return EXIT_SUCCESS; 78 | } 79 | catch (const std::runtime_error& e) 80 | { 81 | std::cerr << "Error: " << e.what() << std::endl; 82 | return EXIT_FAILURE; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /doc/Changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog {#Changelog} 2 | 3 | ## [1.0.0](https://github.com/BlueBrain/Rockets/tree/1.0.0) (2019-01-07) 4 | 5 | - First release 6 | -------------------------------------------------------------------------------- /js/.npmignore: -------------------------------------------------------------------------------- 1 | coverage 2 | node_modules 3 | out-tsc 4 | test 5 | *.spec.ts 6 | jest.config.js 7 | rollup.config.js 8 | tsconfig.cjs.json 9 | tsconfig.es5.json 10 | tsconfig.es2015.json 11 | tsconfig.json 12 | tsconfig.spec.json 13 | tsconfig.types.json 14 | tslint.json 15 | yarn.lock 16 | -------------------------------------------------------------------------------- /js/CHANGELOG.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/Rockets/b99f8062af25bed3bd15c753cda7a31d5110fc38/js/CHANGELOG.md -------------------------------------------------------------------------------- /js/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | setupFiles: [ 3 | './test/setup.js' 4 | ], 5 | globals: { 6 | 'ts-jest': { 7 | tsConfig: './tsconfig.spec.json', 8 | diagnostics: true 9 | } 10 | }, 11 | transform: { 12 | '^.+\\.tsx?$': 'ts-jest' 13 | }, 14 | testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$', 15 | coveragePathIgnorePatterns: [ 16 | '/dist/', 17 | '/node_modules/', 18 | '/out-tsc/', 19 | '/test/' 20 | ], 21 | moduleFileExtensions: [ 22 | 'ts', 23 | 'tsx', 24 | 'js', 25 | 'jsx', 26 | 'json', 27 | 'node' 28 | ] 29 | }; 30 | -------------------------------------------------------------------------------- /js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rockets-client", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/es5/index.js", 7 | "es2015": "./dist/es2015/index.js", 8 | "typings": "./dist/index.d.ts", 9 | "keywords": [ 10 | "rockets", 11 | "websocket", 12 | "json-rpc", 13 | "client" 14 | ], 15 | "homepage": "https://github.com/BlueBrain/Rockets", 16 | "license": "LGPL-3.0+", 17 | "author": { 18 | "name": "Roland Groza", 19 | "email": "roland.groza@epfl.ch" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/BlueBrain/Rockets" 24 | }, 25 | "scripts": { 26 | "prebuild": "yarn run clean", 27 | "build": "npm-run-all -s compile build:umd", 28 | "build:umd": "rollup -c ./rollup.config.js", 29 | "compile": "npm-run-all -p compile:es2015 compile:es5 compile:cjs compile:types", 30 | "compile:es2015": "tsc -p ./tsconfig.es2015.json", 31 | "compile:es5": "tsc -p ./tsconfig.es5.json", 32 | "compile:cjs": "tsc -p ./tsconfig.cjs.json", 33 | "compile:types": "tsc -p ./tsconfig.types.json", 34 | "clean": "rm -rf dist/*", 35 | "docs": "typedoc --out docs/ ./ --mode file --exclude *.spec.ts --excludeExternals --excludePrivate", 36 | "lint": "tslint -c tslint.json -p ./tsconfig.spec.json -t stylish", 37 | "lint:fix": "yarn run lint -- --fix", 38 | "pretest:cov": "yarn run lint", 39 | "test:cov": "jest --coverage", 40 | "test": "jest --watch", 41 | "release": "standard-version" 42 | }, 43 | "standard-version": { 44 | "message": "chore(js): Release v%s :tada:", 45 | "scripts": { 46 | "prerelease": "$(yarn bin)/npm-run-all -p test:cov build" 47 | }, 48 | "skip": { 49 | "changelog": true, 50 | "tag": true 51 | } 52 | }, 53 | "dependencies": { 54 | "crypto-uid": "^0.3.0", 55 | "lodash": "^4.17.10", 56 | "tslib": "^1.9.0" 57 | }, 58 | "peerDependencies": { 59 | "rxjs": ">= 6.2" 60 | }, 61 | "devDependencies": { 62 | "@babel/core": "^7.0.0", 63 | "@babel/preset-env": "^7.0.0", 64 | "@trust/webcrypto": "^0.9.2", 65 | "@types/jest": "^23.3.1", 66 | "@types/lodash": "^4.14.116", 67 | "@types/node": "^9.4.5", 68 | "babel-core": "^7.0.0-0", 69 | "babel-plugin-lodash": "^3.3.4", 70 | "babel-jest": "^23.4.0", 71 | "camelcase": "^4.1.0", 72 | "jest": "^23.5.0", 73 | "mock-socket": "^8.0.1", 74 | "npm-run-all": "^4.1.3", 75 | "rollup": "^0.65.0", 76 | "rollup-plugin-babel": "latest", 77 | "rollup-plugin-commonjs": "^9.1.6", 78 | "rollup-plugin-node-resolve": "^3.3.0", 79 | "rollup-plugin-sourcemaps": "^0.4.2", 80 | "rollup-plugin-uglify": "^4.0.0", 81 | "rxjs": "^6.2.1", 82 | "standard-version": "^4.4.0", 83 | "ts-jest": "^23.1.4", 84 | "tslint": "^5.9.1", 85 | "typedoc": "^0.11.1", 86 | "typescript": "2.8.3" 87 | }, 88 | "engines": { 89 | "node": ">= 7.9" 90 | }, 91 | "resolutions": { 92 | "**/event-stream": "^4.0.1" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /js/rollup.config.js: -------------------------------------------------------------------------------- 1 | const camelCase = require('camelcase'); 2 | const babel = require('rollup-plugin-babel'); 3 | const commonjs = require('rollup-plugin-commonjs'); 4 | const resolve = require('rollup-plugin-node-resolve'); 5 | const sourcemaps = require('rollup-plugin-sourcemaps'); 6 | const {uglify} = require('rollup-plugin-uglify'); 7 | 8 | const pckg = require('./package.json'); 9 | const name = pckg.name; 10 | const input = pckg.module; 11 | 12 | const plugins = [ 13 | resolve(), 14 | commonjs(), 15 | // Transform Lodash imports from: 16 | // import {isString} from 'lodash'; 17 | // to: 18 | // import isString from 'lodash'; 19 | // https://github.com/rollup/rollup/issues/691#issue-158687701 20 | babel({ 21 | babelrc: false, 22 | presets: [['@babel/preset-env', { 23 | // Disable modules transform 24 | // https://github.com/rollup/rollup-plugin-babel#modules 25 | modules: false 26 | }]], 27 | plugins: [ 28 | "lodash" 29 | ] 30 | }), 31 | sourcemaps() 32 | ]; 33 | 34 | const output = { 35 | format: 'umd', 36 | name: camelCase(name), 37 | // The key is library name and the value is the name of the global variable name on the window object. 38 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#globals for more. 39 | globals: { 40 | // RxJS 41 | // https://github.com/ReactiveX/rxjs#cdn 42 | 'rxjs': 'rxjs', 43 | 'rxjs/operators': 'rxjs.operators', 44 | 'rxjs/webSocket': 'rxjs.webSocket' 45 | }, 46 | sourcemap: true 47 | }; 48 | 49 | // List of dependencies 50 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#external for more. 51 | const external = [ 52 | // RxJS 53 | 'rxjs', 54 | 'rxjs/operators', 55 | 'rxjs/webSocket' 56 | ]; 57 | 58 | export default [{ 59 | input, 60 | plugins, 61 | external, 62 | output: { 63 | ...output, 64 | file: distPath(`${name}.umd.js`) 65 | } 66 | }, 67 | { 68 | input, 69 | plugins: [ 70 | ...plugins, 71 | uglify() 72 | ], 73 | external, 74 | output: { 75 | ...output, 76 | file: distPath(`${name}.umd.min.js`) 77 | } 78 | }]; 79 | 80 | function distPath(file) { 81 | return `./dist/bundles/${file}`; 82 | } 83 | -------------------------------------------------------------------------------- /js/src/constants.ts: -------------------------------------------------------------------------------- 1 | // https://www.jsonrpc.org/specification#compatibility 2 | export const JSON_RPC_VERSION = '2.0'; 3 | export type JSON_RPC_VERSION_TYPE = typeof JSON_RPC_VERSION; 4 | 5 | // http://www.jsonrpc.org/specification#error_object 6 | // http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php 7 | export const PARSE_ERROR = -32700; 8 | export const INVALID_REQUEST = -32600; 9 | export const METHOD_NOT_FOUND = -32601; 10 | export const INVALID_PARAMS = -32602; 11 | export const INTERNAL_ERROR = -32603; 12 | 13 | // Rockets error codes 14 | export const INVALID_JSON_RESPONSE = -31001; 15 | export const REQUEST_ABORTED = -31002; 16 | export const HTTP_ERROR = -31003; 17 | 18 | // Rockets server notifications 19 | export const CANCEL = 'cancel'; 20 | export const PROGRESS = 'progress'; 21 | 22 | // Request events 23 | export const PROGRESS_EVENT = 'progress'; 24 | export type PROGRESS_EVENT_TYPE = typeof PROGRESS_EVENT; 25 | 26 | // Custom error codes 27 | export const SOCKET_CLOSED = -30100; 28 | export const SOCKET_PIPE_BROKEN = -30101; 29 | 30 | // UID 31 | export const UID_BYTE_LENGTH = 6; 32 | 33 | // Networking 34 | export const HTTP = 'http'; 35 | export const HTTPS = 'https'; 36 | export const WS = 'ws'; 37 | export const WSS = 'wss'; 38 | export type ProtocolType = typeof HTTP 39 | | typeof HTTPS 40 | | typeof WS 41 | | typeof WSS; 42 | -------------------------------------------------------------------------------- /js/src/error.spec.ts: -------------------------------------------------------------------------------- 1 | import {JsonRpcError} from './error'; 2 | 3 | describe('JsonRpcError', () => { 4 | it('should be an instance of Error', () => { 5 | expect(new JsonRpcError({ 6 | code: 0, 7 | message: 'Oops' 8 | })).toBeInstanceOf(Error); 9 | }); 10 | 11 | it('should be an instance of itself', () => { 12 | expect(new JsonRpcError({ 13 | code: 0, 14 | message: 'Oops' 15 | })).toBeInstanceOf(JsonRpcError); 16 | }); 17 | 18 | it('should have the JSON RPC error object props', () => { 19 | const data = {ping: true}; 20 | const err = new JsonRpcError({ 21 | data, 22 | code: 0, 23 | message: 'Oops' 24 | }); 25 | expect(err.code).toBe(0); 26 | expect(err.message).toBe('Oops'); 27 | expect(err.data).toEqual(data); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /js/src/error.ts: -------------------------------------------------------------------------------- 1 | import {JsonRpcErrorObject} from './types'; 2 | 3 | export class JsonRpcError extends Error implements JsonRpcErrorObject { 4 | code: number; 5 | data?: T; 6 | constructor({code, message, data}: JsonRpcErrorObject) { 7 | super(message); 8 | // https://bit.ly/2j94DZX 9 | Object.setPrototypeOf(this, JsonRpcError.prototype); 10 | this.code = code; 11 | this.data = data; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /js/src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | HTTP_ERROR, 3 | INTERNAL_ERROR, 4 | INVALID_JSON_RESPONSE, 5 | INVALID_PARAMS, 6 | INVALID_REQUEST, 7 | JSON_RPC_VERSION, 8 | METHOD_NOT_FOUND, 9 | PARSE_ERROR, 10 | PROGRESS_EVENT, 11 | REQUEST_ABORTED, 12 | SOCKET_CLOSED, 13 | SOCKET_PIPE_BROKEN 14 | } from './constants'; 15 | 16 | export {JsonRpcError} from './error'; 17 | export {Notification} from './notification'; 18 | export {Request} from './request'; 19 | export {Response} from './response'; 20 | 21 | export { 22 | BatchResponse, 23 | BatchTask, 24 | Client, 25 | ClientOptions, 26 | RequestTask, 27 | TaskEvent 28 | } from './client'; 29 | 30 | export { 31 | isJsonRpcNotification, 32 | isJsonRpcRequest 33 | } from './utils'; 34 | 35 | export { 36 | JsonRpcNotification, 37 | JsonRpcRequest, 38 | JsonRpcResponse, 39 | Progress 40 | } from './types'; 41 | -------------------------------------------------------------------------------- /js/src/notification.ts: -------------------------------------------------------------------------------- 1 | import { 2 | JSON_RPC_VERSION, 3 | JSON_RPC_VERSION_TYPE 4 | } from './constants'; 5 | import {JsonRpcNotification} from './types'; 6 | import {setParams} from './utils'; 7 | 8 | export class Notification implements JsonRpcNotification, Iterable { 9 | static fromJson(json: JsonRpcNotification) { 10 | return new this(json.method, json.params); 11 | } 12 | 13 | readonly jsonrpc: JSON_RPC_VERSION_TYPE = JSON_RPC_VERSION; 14 | readonly params?: T; 15 | 16 | constructor( 17 | readonly method: string, 18 | params?: T 19 | ) { 20 | setParams(this, params); 21 | } 22 | 23 | isOfType(method: string) { 24 | return this.method === method; 25 | } 26 | 27 | /** 28 | * Make the class iterable 29 | * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators 30 | */ 31 | *[Symbol.iterator]() { 32 | for (const key in this) { 33 | if (this.hasOwnProperty(key)) { 34 | yield [key, this[key]]; 35 | } 36 | } 37 | } 38 | 39 | /** 40 | * Custom JSON serializer 41 | * @see https://mzl.la/2hgTyXG 42 | */ 43 | toJSON(): JsonRpcNotification { 44 | const json: any = { 45 | ...this as object 46 | }; 47 | return json; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /js/src/request.ts: -------------------------------------------------------------------------------- 1 | import uid from 'crypto-uid'; 2 | import { 3 | JSON_RPC_VERSION, 4 | JSON_RPC_VERSION_TYPE, 5 | UID_BYTE_LENGTH 6 | } from './constants'; 7 | import {JsonRpcIdType, JsonRpcRequest} from './types'; 8 | import {setParams} from './utils'; 9 | 10 | export class Request implements JsonRpcRequest, Iterable { 11 | readonly jsonrpc: JSON_RPC_VERSION_TYPE = JSON_RPC_VERSION; 12 | readonly id: JsonRpcIdType = uid(UID_BYTE_LENGTH); 13 | readonly params?: T; 14 | 15 | constructor( 16 | readonly method: string, 17 | params?: T 18 | ) { 19 | setParams(this, params); 20 | } 21 | 22 | /** 23 | * Make the class iterable 24 | * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators 25 | */ 26 | *[Symbol.iterator]() { 27 | for (const key in this) { 28 | if (this.hasOwnProperty(key)) { 29 | yield [key, this[key]]; 30 | } 31 | } 32 | } 33 | 34 | /** 35 | * Custom JSON serializer 36 | * @see https://mzl.la/2hgTyXG 37 | */ 38 | toJSON(): JsonRpcRequest { 39 | const json: any = { 40 | ...this as object 41 | }; 42 | return json; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /js/src/response.ts: -------------------------------------------------------------------------------- 1 | import { 2 | JSON_RPC_VERSION, 3 | JSON_RPC_VERSION_TYPE 4 | } from './constants'; 5 | import {JsonRpcError} from './error'; 6 | import { 7 | JsonRpcIdType, 8 | JsonRpcResponse, 9 | JsonRpcVersion 10 | } from './types'; 11 | 12 | export class Response implements JsonRpcVersion, Iterable { 13 | readonly id: JsonRpcIdType | null; 14 | readonly jsonrpc: JSON_RPC_VERSION_TYPE = JSON_RPC_VERSION; 15 | 16 | // @ts-ignore 17 | private response: JsonRpcResponse; 18 | 19 | constructor(response: JsonRpcResponse) { 20 | this.id = response.id; 21 | Object.defineProperty(this, 'response', { 22 | enumerable: false, 23 | value: response 24 | }); 25 | } 26 | 27 | async json(): Promise { 28 | const {error, result} = this.response; 29 | if (!result) { 30 | throw new JsonRpcError(error!); 31 | } 32 | return result; 33 | } 34 | 35 | /** 36 | * Make the class iterable 37 | * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators 38 | */ 39 | *[Symbol.iterator]() { 40 | for (const key in this) { 41 | if (this.hasOwnProperty(key)) { 42 | yield [key, this[key]]; 43 | } 44 | } 45 | } 46 | 47 | /** 48 | * Custom JSON serializer 49 | * @see https://mzl.la/2hgTyXG 50 | */ 51 | toJSON(): Pick { 52 | const json: any = { 53 | ...this as object 54 | }; 55 | return json; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /js/src/testing.ts: -------------------------------------------------------------------------------- 1 | import uid from 'crypto-uid'; 2 | import { 3 | JSON_RPC_VERSION, 4 | UID_BYTE_LENGTH 5 | } from './constants'; 6 | import { 7 | JsonRpcNotification, 8 | JsonRpcResponse 9 | } from './types'; 10 | 11 | export function createJsonRpcResponse(result: T): JsonRpcResponse { 12 | const id = uid(UID_BYTE_LENGTH); 13 | return { 14 | id, 15 | result, 16 | jsonrpc: JSON_RPC_VERSION 17 | }; 18 | } 19 | 20 | export function createJsonRpcNotification(method: string, params?: T): JsonRpcNotification { 21 | return { 22 | method, 23 | params, 24 | jsonrpc: JSON_RPC_VERSION 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /js/src/types.ts: -------------------------------------------------------------------------------- 1 | import {JSON_RPC_VERSION_TYPE} from './constants'; 2 | 3 | // http://www.jsonrpc.org/specification#notification 4 | export type JsonRpcNotification = CommonProps 5 | & JsonRpcVersion; 6 | 7 | // http://www.jsonrpc.org/specification#request_object 8 | export interface JsonRpcRequest extends CommonProps, JsonRpcVersion { 9 | id: JsonRpcIdType; 10 | } 11 | 12 | // http://www.jsonrpc.org/specification#response_object 13 | export interface JsonRpcResponse extends JsonRpcVersion { 14 | id: JsonRpcIdType | null; 15 | error?: JsonRpcErrorObject; 16 | result?: T; 17 | } 18 | 19 | // http://www.jsonrpc.org/specification#error_object 20 | export interface JsonRpcErrorObject { 21 | code: number; 22 | message: string; 23 | data?: T; 24 | } 25 | 26 | export type JsonRpcIdType = string | number; 27 | 28 | export interface JsonRpcVersion { 29 | jsonrpc: JSON_RPC_VERSION_TYPE; 30 | } 31 | 32 | export interface CommonProps { 33 | method: string; 34 | params?: T; 35 | } 36 | 37 | export interface Progress { 38 | amount: number; 39 | operation?: string; 40 | } 41 | -------------------------------------------------------------------------------- /js/src/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import uid from 'crypto-uid'; 2 | import { 3 | JSON_RPC_VERSION, 4 | UID_BYTE_LENGTH 5 | } from './constants'; 6 | import {createJsonRpcNotification} from './testing'; 7 | import { 8 | isJsonRpcErrorObject, 9 | isJsonRpcNotification, 10 | isJsonRpcRequest 11 | } from './utils'; 12 | 13 | 14 | describe('isJsonRpcErrorObject()', () => { 15 | it('should return true if a value is a RocketsError', () => { 16 | const error = {code: 1, message: 'Oops'}; 17 | expect(isJsonRpcErrorObject(error)).toBe(true); 18 | }); 19 | 20 | it('should return false otherwise', () => { 21 | expect(isJsonRpcErrorObject({code: 1})).toBe(false); 22 | expect(isJsonRpcErrorObject({message: 'Oops'})).toBe(false); 23 | expect(isJsonRpcErrorObject({})).toBe(false); 24 | expect(isJsonRpcErrorObject(null)).toBe(false); 25 | }); 26 | }); 27 | 28 | describe('isJsonRpcNotification()', () => { 29 | it('should return true if a value is a JsonRpcNotification', () => { 30 | const value = createJsonRpcNotification('test'); 31 | expect(isJsonRpcNotification(value)).toBe(true); 32 | }); 33 | 34 | it('should not be true for a request', () => { 35 | const request = createJsonRpcRequest('test'); 36 | expect(isJsonRpcNotification(request)).toBe(false); 37 | }); 38 | 39 | it('should return false otherwise', () => { 40 | expect(isJsonRpcNotification({jsonrpc: JSON_RPC_VERSION})).toBe(false); 41 | expect(isJsonRpcNotification({ 42 | jsonrpc: '1.0', 43 | method: 'test' 44 | })).toBe(false); 45 | expect(isJsonRpcNotification({method: 'test'})).toBe(false); 46 | expect(isJsonRpcNotification({})).toBe(false); 47 | expect(isJsonRpcNotification(null)).toBe(false); 48 | }); 49 | }); 50 | 51 | describe('isJsonRpcRequest()', () => { 52 | it('should return true if a value is a JsonRpcRequest', () => { 53 | const request = createJsonRpcRequest('test'); 54 | expect(isJsonRpcRequest(request)).toBe(true); 55 | }); 56 | 57 | it('should not be true for a notification', () => { 58 | const notification = createJsonRpcNotification('test'); 59 | expect(isJsonRpcRequest(notification)).toBe(false); 60 | }); 61 | 62 | it('should return false otherwise', () => { 63 | expect(isJsonRpcRequest({jsonrpc: JSON_RPC_VERSION})).toBe(false); 64 | expect(isJsonRpcRequest({ 65 | jsonrpc: '1.0', 66 | method: 'test', 67 | id: 2 68 | })).toBe(false); 69 | expect(isJsonRpcRequest({ 70 | jsonrpc: JSON_RPC_VERSION, 71 | method: 'test' 72 | })).toBe(false); 73 | expect(isJsonRpcRequest(null)).toBe(false); 74 | expect(isJsonRpcRequest([])).toBe(false); 75 | expect(isJsonRpcRequest({})).toBe(false); 76 | expect(isJsonRpcRequest(true)).toBe(false); 77 | expect(isJsonRpcRequest(1)).toBe(false); 78 | }); 79 | }); 80 | 81 | 82 | function createJsonRpcRequest(method: string, params?: T) { 83 | const id = uid(UID_BYTE_LENGTH); 84 | return { 85 | method, 86 | id, 87 | params, 88 | jsonrpc: JSON_RPC_VERSION 89 | }; 90 | } 91 | -------------------------------------------------------------------------------- /js/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | isNumber, 3 | isObject, 4 | isString 5 | } from 'lodash'; 6 | import {JSON_RPC_VERSION} from './constants'; 7 | import {Notification} from './notification'; 8 | import {Request} from './request'; 9 | import { 10 | JsonRpcErrorObject, 11 | JsonRpcNotification, 12 | JsonRpcRequest 13 | } from './types'; 14 | 15 | /** 16 | * Check if value is a RPC notification 17 | * @param value 18 | */ 19 | export function isJsonRpcNotification(value: any): value is JsonRpcNotification { 20 | return isObject(value) 21 | && value.jsonrpc === JSON_RPC_VERSION 22 | && isString(value.method) 23 | && !value.hasOwnProperty('id'); 24 | } 25 | 26 | /** 27 | * Check if value is an RPC request 28 | * @param value 29 | */ 30 | export function isJsonRpcRequest(value: any): value is JsonRpcRequest { 31 | return isObject(value) 32 | && value.jsonrpc === JSON_RPC_VERSION 33 | && isString(value.method) 34 | && (isString(value.id) || isNumber(value.id)); 35 | } 36 | 37 | /** 38 | * Check if value is an RPC error 39 | * @param value 40 | */ 41 | export function isJsonRpcErrorObject(value: any): value is JsonRpcErrorObject { 42 | return isObject(value) 43 | && isNumber(value.code) 44 | && isString(value.message); 45 | } 46 | 47 | /** 48 | * @param obj 49 | * @param params 50 | * @private 51 | */ 52 | export function setParams( 53 | obj: Request | Notification, 54 | params: T 55 | ): void { 56 | if (isObject(params) || Array.isArray(params)) { 57 | Object.assign(obj, {params}); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /js/test/setup.js: -------------------------------------------------------------------------------- 1 | // Crypto 2 | // https://developer.mozilla.org/en-US/docs/Web/API/Crypto 3 | const crypto = require('@trust/webcrypto'); 4 | global.crypto = crypto; 5 | 6 | // Mock WebSocket 7 | const {WebSocket} = require('mock-socket'); 8 | global.WebSocket = WebSocket; 9 | -------------------------------------------------------------------------------- /js/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "target": "es5", 6 | "outDir": "./dist" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /js/tsconfig.es2015.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2015", 5 | "moduleResolution": "node", 6 | "target": "es2015", 7 | "outDir": "./dist/es2015", 8 | "importHelpers": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /js/tsconfig.es5.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2015", 5 | "moduleResolution": "node", 6 | "target": "es5", 7 | "outDir": "./dist/es5", 8 | "importHelpers": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": "./src", 4 | "baseUrl": "./src", 5 | "noEmit": false, 6 | "allowSyntheticDefaultImports": true, // Lodash 7 | "downlevelIteration": true, 8 | "sourceMap": true, 9 | "noImplicitReturns": true, 10 | "noImplicitThis": true, 11 | "noImplicitAny": true, 12 | "noUnusedLocals": true, 13 | "strict": true, 14 | "skipLibCheck": true, 15 | "typeRoots": [ 16 | "node_modules/@types" 17 | ], 18 | "lib": [ 19 | "es2016", 20 | "dom" 21 | ] 22 | }, 23 | "files": [ 24 | "./src/index.ts" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /js/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "target": "es2015" 6 | }, 7 | "include": [ 8 | "src/**/*.ts" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /js/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "emitDeclarationOnly": true, 6 | "declarationDir": "./dist", 7 | "moduleResolution": "node", 8 | "module": "es2015", 9 | "target": "esnext" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /js/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint:latest" 4 | ], 5 | "rules": { 6 | // TS Lint 7 | // https://palantir.github.io/tslint 8 | "no-implicit-dependencies": { 9 | "options": [ 10 | "dev" 11 | ] 12 | }, 13 | "no-submodule-imports": { 14 | "options": [ 15 | "lodash", 16 | "rxjs" 17 | ] 18 | }, 19 | "arrow-parens": { 20 | "options": [ 21 | "ban-single-arg-parens" 22 | ] 23 | }, 24 | "no-consecutive-blank-lines": { 25 | "options": 2 26 | }, 27 | "interface-name": false, 28 | "no-shadowed-variable": false, 29 | "max-line-length": { 30 | "options": [ 31 | 180 32 | ] 33 | }, 34 | "member-access": { 35 | "options": [ 36 | "no-public" 37 | ] 38 | }, 39 | "object-literal-sort-keys": false, 40 | "ordered-imports": true, 41 | "prefer-function-over-method": { 42 | "options": [ 43 | "allow-public" 44 | ] 45 | }, 46 | "prefer-method-signature": true, 47 | "trailing-comma": { 48 | "options": { 49 | "multiline": "never", 50 | "singleline": "never" 51 | } 52 | }, 53 | "quotemark": { 54 | "options": [ 55 | "avoid-escape", 56 | "avoid-template", 57 | "jsx-double", 58 | "single" 59 | ] 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /python/.gitignore: -------------------------------------------------------------------------------- 1 | .coverage 2 | .idea/ 3 | rockets.egg-info/ 4 | .installed 5 | pycodestyle.txt 6 | pydocstyle.txt 7 | pylint.txt 8 | *.pyc 9 | dist/ 10 | .tox/ 11 | venv/ 12 | doc/source/.ipynb_checkpoints/ 13 | -------------------------------------------------------------------------------- /python/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include requirements*.txt 2 | -------------------------------------------------------------------------------- /python/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Blue Brain Project 2 | # Daniel Nachbaur 3 | # 4 | # This file is part of Rockets 5 | # 6 | # This library is free software; you can redistribute it and/or modify it under 7 | # the terms of the GNU Lesser General Public License version 3.0 as published 8 | # by the Free Software Foundation. 9 | # 10 | # This library is distributed in the hope that it will be useful, but WITHOUT 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | # details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with this library; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | # All rights reserved. Do not distribute without further notice. 19 | 20 | ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) 21 | 22 | #see if we're in a virtualenv, and use that, otherwise use the default 23 | ifdef VIRTUAL_ENV 24 | VENV=$(VIRTUAL_ENV) 25 | else 26 | VENV:=venv 27 | endif 28 | VENV_BIN:=$(VENV)/bin 29 | 30 | # simulate running in headless mode 31 | unexport DISPLAY 32 | 33 | # Test coverage pass threshold (percent) 34 | MIN_COV?=100 35 | VENV_INSTALLED=.installed 36 | PIP_INSTALL_OPTIONS=--ignore-installed 37 | 38 | FIND_LINT_PY=`find rockets -name "*.py" -not -path "*/*test*"` 39 | LINT_PYFILES := $(shell find $(FIND_LINT_PY)) 40 | 41 | $(VENV): 42 | virtualenv --system-site-packages $(VENV) 43 | 44 | $(VENV_INSTALLED): $(VENV) 45 | $(VENV_BIN)/pip install --upgrade pip 46 | $(VENV_BIN)/pip install $(PIP_INSTALL_OPTIONS) -r requirements_dev.txt 47 | $(VENV_BIN)/pip install -e . 48 | touch $@ 49 | 50 | run_pycodestyle: $(VENV_INSTALLED) 51 | $(VENV_BIN)/pycodestyle $(LINT_PYFILES) > pycodestyle.txt 52 | 53 | run_pydocstyle: $(VENV_INSTALLED) 54 | $(VENV_BIN)/pydocstyle $(LINT_PYFILES) > pydocstyle.txt 55 | 56 | run_pylint: $(VENV_INSTALLED) 57 | $(VENV_BIN)/pylint --rcfile=pylintrc $(LINT_PYFILES) > pylint.txt 58 | 59 | run_tests: $(VENV_INSTALLED) 60 | $(VENV_BIN)/nosetests -v --with-coverage --cover-min-percentage=$(MIN_COV) --cover-erase --cover-package rockets 61 | 62 | run_tests_xunit: $(VENV_INSTALLED) 63 | @mkdir -p $(ROOT_DIR)/test-reports 64 | $(VENV_BIN)/nosetests rockets --with-coverage --cover-min-percentage=$(MIN_COV) --cover-inclusive --cover-erase --cover-package=rockets --with-xunit --xunit-file=test-reports/nosetests_rockets.xml 65 | 66 | lint: run_pycodestyle run_pydocstyle run_pylint 67 | 68 | test: lint run_tests 69 | 70 | doc: $(VENV_INSTALLED) 71 | make SPHINXBUILD=$(VENV_BIN)/sphinx-build -C doc html 72 | 73 | doc_pdf: $(VENV_INSTALLED) 74 | make SPHINXBUILD=$(VENV_BIN)/sphinx-build -C doc latexpdf 75 | 76 | clean_test_venv: 77 | @rm -rf $(VENV_INSTALLED) 78 | @rm -rf $(ROOT_DIR)/test-reports 79 | 80 | clean_doc: 81 | @test -x $(VENV_BIN)/sphinx-build && make SPHINXBUILD=$(VENV_BIN)/sphinx-build -C doc clean || true 82 | @rm -rf $(ROOT_DIR)/doc/build 83 | 84 | clean: clean_doc clean_test_venv 85 | @rm -f pycodestyle.txt 86 | @rm -f pydocstyle.txt 87 | @rm -f pylint.txt 88 | @rm -rf rockets/rockets.egg-info 89 | @rm -f .coverage 90 | @rm -rf test-reports 91 | @rm -rf dist 92 | @rm -f $(VENV_INSTALLED) 93 | 94 | .PHONY: run_pycodestyle test clean_test_venv clean doc 95 | -------------------------------------------------------------------------------- /python/doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = Rockets 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /python/doc/source/api.rst: -------------------------------------------------------------------------------- 1 | Rockets Python API 2 | ================== 3 | 4 | .. toctree:: 5 | :maxdepth: 3 6 | 7 | .. automodule:: rockets 8 | :members: 9 | -------------------------------------------------------------------------------- /python/doc/source/index.rst: -------------------------------------------------------------------------------- 1 | .. Rockets documentation master file, created by 2 | sphinx-quickstart on Mon Jul 23 16:11:34 2018. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Rockets python client 7 | ===================== 8 | 9 | A small client for Rockets using JSON-RPC as communication contract over a WebSocket. 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | api 15 | 16 | 17 | Indices and tables 18 | ================== 19 | 20 | * :ref:`genindex` 21 | * :ref:`modindex` 22 | * :ref:`search` 23 | -------------------------------------------------------------------------------- /python/pylintrc: -------------------------------------------------------------------------------- 1 | ## look at http://docutils.sourceforge.net/sandbox/py-rest-doc/utils/pylintrc 2 | # for some of the options that are available 3 | 4 | [MASTER] 5 | load-plugins=pylint.extensions.docparams,pylint.extensions.docstyle 6 | 7 | [MESSAGES CONTROL] 8 | #C0330 - disabled as there are currently some false positives: https://github.com/PyCQA/pylint/issues/289 9 | #C0103 - Invalid name "%s" (should match %s) - matches too many things, like variables w/ single char names 10 | #C0199 - First line empty in function docstring 11 | #C0325 - superfluous-parens 12 | #R0903 - Too Few public methods 13 | disable=C0330,C0103,C0199,C0325,R0903 14 | 15 | [FORMAT] 16 | # Maximum number of characters on a single line. 17 | max-line-length=100 18 | 19 | [DESIGN] 20 | # Maximum number of arguments for function / method 21 | max-args=8 22 | # Argument names that match this expression will be ignored. Default to name 23 | # with leading underscore 24 | ignored-argument-names=_.* 25 | # Maximum number of locals for function / method body 26 | max-locals=15 27 | # Maximum number of return / yield for function / method body 28 | max-returns=6 29 | # Maximum number of branch for function / method body 30 | max-branchs=12 31 | # Maximum number of statements in function / method body 32 | max-statements=50 33 | # Maximum number of parents for a class (see R0901). 34 | max-parents=7 35 | # Maximum number of attributes for a class (see R0902). 36 | max-attributes=40 37 | # Minimum number of public methods for a class (see R0903). 38 | min-public-methods=2 39 | # Maximum number of public methods for a class (see R0904). 40 | max-public-methods=60 41 | # checks for similarities and duplicated code. This computation may be 42 | # memory / CPU intensive, so you should disable it if you experiments some 43 | # problems. 44 | 45 | [SIMILARITIES] 46 | # Minimum lines number of a similarity. 47 | min-similarity-lines=25 48 | # Ignore comments when computing similarities. 49 | ignore-comments=yes 50 | # Ignore docstrings when computing similarities. 51 | ignore-docstrings=yes 52 | -------------------------------------------------------------------------------- /python/requirements.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Blue Brain Project 2 | # Daniel Nachbaur 3 | # 4 | # This file is part of Rockets 5 | # 6 | # This library is free software; you can redistribute it and/or modify it under 7 | # the terms of the GNU Lesser General Public License version 3.0 as published 8 | # by the Free Software Foundation. 9 | # 10 | # This library is distributed in the hope that it will be useful, but WITHOUT 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | # details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with this library; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | # All rights reserved. Do not distribute without further notice. 19 | 20 | json-rpc~=1.11.1 21 | rx~=1.6.1 22 | websockets~=7.0 23 | -------------------------------------------------------------------------------- /python/requirements_dev.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Blue Brain Project 2 | # Daniel Nachbaur 3 | # 4 | # This file is part of Rockets 5 | # 6 | # This library is free software; you can redistribute it and/or modify it under 7 | # the terms of the GNU Lesser General Public License version 3.0 as published 8 | # by the Free Software Foundation. 9 | # 10 | # This library is distributed in the hope that it will be useful, but WITHOUT 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | # details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with this library; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | # All rights reserved. Do not distribute without further notice. 19 | 20 | pylint~=2.2.2 21 | pycodestyle~=2.4.0 22 | pydocstyle~=3.0.0 23 | nose~=1.3.7 24 | coverage~=4.5.2 25 | nosexcover~=1.0.11 26 | tox~=3.6.1 27 | Sphinx~=1.8.3 28 | sphinx_rtd_theme~=0.4.2 29 | pandoc~=1.0.2 30 | jsonrpcserver~=3.5.6 31 | -------------------------------------------------------------------------------- /python/requirements_rtd.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Blue Brain Project 2 | # Daniel Nachbaur 3 | # 4 | # This file is part of Rockets 5 | # 6 | # This library is free software; you can redistribute it and/or modify it under 7 | # the terms of the GNU Lesser General Public License version 3.0 as published 8 | # by the Free Software Foundation. 9 | # 10 | # This library is distributed in the hope that it will be useful, but WITHOUT 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | # details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with this library; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | # All rights reserved. Do not distribute without further notice. 19 | 20 | json-rpc~=1.11.1 21 | nbsphinx~=0.4.1 22 | rx~=1.6.1 23 | websockets~=7.0 -------------------------------------------------------------------------------- /python/rockets/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Copyright (c) 2018, Blue Brain Project 4 | # Daniel Nachbaur 5 | # 6 | # This file is part of Rockets 7 | # 8 | # This library is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU Lesser General Public License version 3.0 as published 10 | # by the Free Software Foundation. 11 | # 12 | # This library is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 | # details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with this library; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # All rights reserved. Do not distribute without further notice. 21 | """A small client for Rockets using JSON-RPC as communication contract over a WebSocket.""" 22 | from .async_client import AsyncClient 23 | from .client import Client 24 | from .notification import Notification 25 | from .request import Request 26 | from .request_error import RequestError 27 | from .request_progress import RequestProgress 28 | from .request_task import RequestTask 29 | from .response import Response 30 | from .version import VERSION as __version__ 31 | 32 | __all__ = [ 33 | "AsyncClient", 34 | "Client", 35 | "Notification", 36 | "Request", 37 | "RequestError", 38 | "RequestProgress", 39 | "RequestTask", 40 | "Response", 41 | ] 42 | -------------------------------------------------------------------------------- /python/rockets/notification.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2018, Blue Brain Project 5 | # Daniel Nachbaur 6 | # 7 | # This file is part of Rockets 8 | # 9 | # This library is free software; you can redistribute it and/or modify it under 10 | # the terms of the GNU Lesser General Public License version 3.0 as published 11 | # by the Free Software Foundation. 12 | # 13 | # This library is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 16 | # details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with this library; if not, write to the Free Software Foundation, Inc., 20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | # All rights reserved. Do not distribute without further notice. 22 | 23 | """A JSON-RPC 2.0 notification""" 24 | 25 | from jsonrpc.jsonrpc2 import JSONRPC20Request 26 | 27 | 28 | class Notification(JSONRPC20Request): 29 | """A JSON-RPC 2.0 notification""" 30 | 31 | def __init__(self, method, params=None): 32 | super().__init__(method=method, params=params, is_notification=True) 33 | -------------------------------------------------------------------------------- /python/rockets/request.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Copyright (c) 2018, Blue Brain Project 4 | # Daniel Nachbaur 5 | # 6 | # This file is part of Rockets 7 | # 8 | # This library is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU Lesser General Public License version 3.0 as published 10 | # by the Free Software Foundation. 11 | # 12 | # This library is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 | # details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with this library; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # All rights reserved. Do not distribute without further notice. 21 | """A JSON-RPC 2.0 request""" 22 | from jsonrpc.jsonrpc2 import JSONRPC20Request 23 | 24 | from .utils import random_string 25 | 26 | 27 | class Request(JSONRPC20Request): 28 | """A JSON-RPC 2.0 request""" 29 | 30 | _id_generator = random_string() 31 | 32 | def __init__(self, method, params=None): 33 | super().__init__( 34 | method=method, 35 | params=params, 36 | _id=next(Request._id_generator), 37 | is_notification=False, 38 | ) 39 | 40 | def request_id(self): 41 | """Return the request ID""" 42 | return super()._id 43 | -------------------------------------------------------------------------------- /python/rockets/request_error.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Copyright (c) 2018, Blue Brain Project 4 | # Daniel Nachbaur 5 | # 6 | # This file is part of Rockets 7 | # 8 | # This library is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU Lesser General Public License version 3.0 as published 10 | # by the Free Software Foundation. 11 | # 12 | # This library is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 | # details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with this library; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # All rights reserved. Do not distribute without further notice. 21 | """Reports the error code and message of a request that has failed.""" 22 | 23 | 24 | class RequestError(Exception): 25 | """Reports the error code and message of a request that has failed.""" 26 | 27 | def __init__(self, code, message, data=None): 28 | super(RequestError, self).__init__(message) 29 | 30 | self.code = code 31 | self.message = message 32 | self.data = data 33 | 34 | 35 | SOCKET_CLOSED_ERROR = RequestError(-30100, "Socket connection closed") 36 | INVALID_REQUEST = RequestError(-32600, "Invalid Request") 37 | -------------------------------------------------------------------------------- /python/rockets/request_progress.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2018, Blue Brain Project 5 | # Daniel Nachbaur 6 | # 7 | # This file is part of Rockets 8 | # 9 | # This library is free software; you can redistribute it and/or modify it under 10 | # the terms of the GNU Lesser General Public License version 3.0 as published 11 | # by the Free Software Foundation. 12 | # 13 | # This library is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 16 | # details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with this library; if not, write to the Free Software Foundation, Inc., 20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | # All rights reserved. Do not distribute without further notice. 22 | 23 | """Reports the operation and amount of a request.""" 24 | 25 | 26 | class RequestProgress: 27 | """Reports the operation and amount of a request.""" 28 | 29 | def __init__(self, operation, amount): 30 | self.operation = operation 31 | self.amount = amount 32 | 33 | def __str__(self): 34 | """ 35 | Print progress as string 36 | 37 | :return: tuple(operation,amount) 38 | :rtype: str 39 | """ 40 | return str((self.operation, self.amount)) 41 | -------------------------------------------------------------------------------- /python/rockets/request_task.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2018, Blue Brain Project 5 | # Daniel Nachbaur 6 | # 7 | # This file is part of Rockets 8 | # 9 | # This library is free software; you can redistribute it and/or modify it under 10 | # the terms of the GNU Lesser General Public License version 3.0 as published 11 | # by the Free Software Foundation. 12 | # 13 | # This library is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 16 | # details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with this library; if not, write to the Free Software Foundation, Inc., 20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | # All rights reserved. Do not distribute without further notice. 22 | 23 | """Extend asyncio.Task to add callbacks for progress reporting while the request is not done.""" 24 | 25 | import asyncio 26 | 27 | 28 | class RequestTask(asyncio.Task): 29 | """Extend asyncio.Task to add callbacks for progress reporting while the request is not done.""" 30 | 31 | def __init__(self, coro, *, loop=None): 32 | super().__init__(coro=coro, loop=loop) 33 | self._progress_callbacks = [] 34 | 35 | def add_progress_callback(self, fn): 36 | """ 37 | Add a callback to be run everytime a progress update arrives. 38 | 39 | The callback is called with a single argument - the :class:`RequestProgress` object. 40 | """ 41 | self._progress_callbacks.append(fn) 42 | 43 | def _call_progress_callbacks(self, value): 44 | """Internal: Calls registered progress callbacks.""" 45 | for callback in self._progress_callbacks: 46 | callback(value) 47 | -------------------------------------------------------------------------------- /python/rockets/response.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Copyright (c) 2018, Blue Brain Project 4 | # Daniel Nachbaur 5 | # 6 | # This file is part of Rockets 7 | # 8 | # This library is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU Lesser General Public License version 3.0 as published 10 | # by the Free Software Foundation. 11 | # 12 | # This library is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 | # details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with this library; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # All rights reserved. Do not distribute without further notice. 21 | """A JSON-RPC 2.0 notification""" 22 | from jsonrpc.jsonrpc2 import JSONRPC20Response 23 | 24 | 25 | class Response(JSONRPC20Response): 26 | """A JSON-RPC 2.0 response""" 27 | 28 | @classmethod 29 | def from_json(cls, json_str): 30 | """Create Response from JSON string""" 31 | data = cls.deserialize(json_str) 32 | return cls.from_data(data) 33 | 34 | @classmethod 35 | def from_data(cls, data): 36 | """Create Response from dict""" 37 | data["_id"] = data["id"] 38 | response = Response(**data) 39 | return response 40 | -------------------------------------------------------------------------------- /python/rockets/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Copyright (c) 2018, Blue Brain Project 4 | # Daniel Nachbaur 5 | # 6 | # This file is part of Rockets 7 | # 8 | # This library is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU Lesser General Public License version 3.0 as published 10 | # by the Free Software Foundation. 11 | # 12 | # This library is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 | # details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with this library; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # All rights reserved. Do not distribute without further notice. 21 | """Utils for the client""" 22 | from random import choice 23 | from string import ascii_lowercase 24 | from string import digits 25 | 26 | HTTP = "http://" 27 | HTTPS = "https://" 28 | WS = "ws://" 29 | WSS = "wss://" 30 | 31 | 32 | def set_ws_protocol(url): 33 | """ 34 | Set the WebSocket protocol according to the resource url. 35 | 36 | :param str url: Url to be checked 37 | :return: Url preprend with ws for http, wss for https for ws if no protocol was found 38 | :rtype: str 39 | """ 40 | if url.startswith(WS) or url.startswith(WSS): 41 | return url 42 | if url.startswith(HTTP): 43 | return url.replace(HTTP, WS, 1) 44 | if url.startswith(HTTPS): 45 | return url.replace(HTTPS, WSS, 1) 46 | return WS + url 47 | 48 | 49 | def copydoc(fromfunc, sep="\n"): 50 | """ 51 | Copy the docstring of `fromfunc` 52 | 53 | :return: Decorator to use on any func to copy the docstring from `fromfunc` 54 | :rtype: obj 55 | """ 56 | 57 | def _decorator(func): 58 | sourcedoc = fromfunc.__doc__ 59 | if func.__doc__: # pragma: no cover 60 | func.__doc__ = sep.join([sourcedoc, func.__doc__]) 61 | else: 62 | func.__doc__ = sourcedoc 63 | return func 64 | 65 | return _decorator 66 | 67 | 68 | def random_string(length=8, chars=digits + ascii_lowercase): 69 | """ 70 | A random string. 71 | 72 | Not unique, but has around 1 in a million chance of collision (with the default 8 73 | character length). e.g. 'fubui5e6' 74 | 75 | :param int length: Length of the random string. 76 | :param str chars: The characters to randomly choose from. 77 | :return: random string 78 | :rtype: str 79 | """ 80 | while True: 81 | yield "".join([choice(chars) for _ in range(length)]) 82 | 83 | 84 | def is_json_rpc_response(value): 85 | """Check if the given value is valid JSON-RPC response.""" 86 | return isinstance(value, dict) and "id" in value 87 | 88 | 89 | def is_json_rpc_notification(value): 90 | """Check if the given value is valid JSON-RPC notification.""" 91 | return isinstance(value, dict) and "method" in value and "id" not in value 92 | 93 | 94 | def is_progress_notification(value): 95 | """Check if the given value is valid Rockets progress notification.""" 96 | return ( 97 | isinstance(value, dict) 98 | and "method" in value 99 | and value["method"] == "progress" 100 | and "params" in value 101 | and "id" in value["params"] 102 | ) 103 | -------------------------------------------------------------------------------- /python/rockets/version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Copyright (c) 2018, Blue Brain Project 4 | # Daniel Nachbaur 5 | # 6 | # This file is part of Rockets 7 | # 8 | # This library is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU Lesser General Public License version 3.0 as published 10 | # by the Free Software Foundation. 11 | # 12 | # This library is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 | # details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with this library; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # All rights reserved. Do not distribute without further notice. 21 | """The version of the rockets package""" 22 | from pkg_resources import DistributionNotFound 23 | from pkg_resources import get_distribution 24 | 25 | try: 26 | VERSION = get_distribution("rockets").version 27 | except DistributionNotFound: # pragma: no cover 28 | VERSION = "rockets-local" 29 | -------------------------------------------------------------------------------- /python/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | version = 1.0.3 3 | name = rockets 4 | summary = Rockets python client 5 | url = https://github.com/BlueBrain/Rockets 6 | author = Daniel Nachbaur 7 | author-email = bbp-open-source@googlegroups.com 8 | license = LGPLv3 9 | classifier = 10 | Development Status :: 5 - Production/Stable 11 | License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) 12 | Operating System :: OS Independent 13 | Programming Language :: Python :: 3.5 14 | Programming Language :: Python :: 3.6 15 | Programming Language :: Python :: 3.7 16 | Topic :: Software Development :: Libraries 17 | Topic :: Software Development :: Libraries :: Python Modules 18 | keywords = rockets, websocket, json-rpc, bbp, BlueBrain 19 | 20 | [pycodestyle] 21 | max-line-length = 100 22 | 23 | [pydocstyle] 24 | ignore = D107,D202,D203,D212,D400,D401 25 | 26 | [coverage:report] 27 | show_missing = True 28 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2018, Blue Brain Project 5 | # Daniel Nachbaur 6 | # Pawel Podhajski 7 | # 8 | # This file is part of Rockets 9 | # 10 | # This library is free software; you can redistribute it and/or modify it under 11 | # the terms of the GNU Lesser General Public License version 3.0 as published 12 | # by the Free Software Foundation. 13 | # 14 | # This library is distributed in the hope that it will be useful, but WITHOUT 15 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 16 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 17 | # details. 18 | # 19 | # You should have received a copy of the GNU Lesser General Public License 20 | # along with this library; if not, write to the Free Software Foundation, Inc., 21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | # All rights reserved. Do not distribute without further notice. 23 | 24 | """setup.py""" 25 | import os 26 | from setuptools import setup 27 | import pathlib 28 | import pkg_resources 29 | 30 | BASEDIR = os.path.dirname(os.path.abspath(__file__)) 31 | 32 | 33 | def parse_reqs(reqs_file): 34 | ''' parse the requirements ''' 35 | install_reqs = list() 36 | with pathlib.Path(reqs_file).open() as requirements_txt: 37 | install_reqs = [str(requirement) 38 | for requirement 39 | in pkg_resources.parse_requirements(requirements_txt)] 40 | return install_reqs 41 | 42 | 43 | REQS = parse_reqs(os.path.join(BASEDIR, "requirements.txt")) 44 | 45 | # read the contents of README.md 46 | this_directory = os.path.abspath(os.path.dirname(__file__)) 47 | with open(os.path.join(this_directory, 'README.md')) as f: 48 | long_description = f.read() 49 | 50 | setup( 51 | packages=['rockets'], 52 | install_requires=REQS, 53 | long_description=long_description, 54 | long_description_content_type='text/markdown' 55 | ) 56 | -------------------------------------------------------------------------------- /python/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Blue Brain Project 2 | # Daniel Nachbaur 3 | # 4 | # This file is part of Rockets 5 | # 6 | # This library is free software; you can redistribute it and/or modify it under 7 | # the terms of the GNU Lesser General Public License version 3.0 as published 8 | # by the Free Software Foundation. 9 | # 10 | # This library is distributed in the hope that it will be useful, but WITHOUT 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | # details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with this library; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | # All rights reserved. Do not distribute without further notice. 19 | -------------------------------------------------------------------------------- /python/tests/test_connect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Copyright (c) 2018, Blue Brain Project 4 | # Daniel Nachbaur 5 | # 6 | # This file is part of Rockets 7 | # 8 | # This library is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU Lesser General Public License version 3.0 as published 10 | # by the Free Software Foundation. 11 | # 12 | # This library is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 | # details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with this library; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # All rights reserved. Do not distribute without further notice. 21 | import asyncio 22 | 23 | import websockets 24 | from nose.tools import assert_equal 25 | from nose.tools import assert_false 26 | from nose.tools import assert_true 27 | 28 | import rockets 29 | 30 | 31 | async def server_handle(websocket, path): 32 | await websocket.recv() 33 | 34 | 35 | server_url = None 36 | 37 | 38 | def setup(): 39 | start_server = websockets.serve(server_handle, "localhost") 40 | server = asyncio.get_event_loop().run_until_complete(start_server) 41 | global server_url 42 | server_url = "localhost:" + str(server.sockets[0].getsockname()[1]) 43 | 44 | 45 | def test_connect_ws(): 46 | client = rockets.Client("ws://" + server_url) 47 | assert_equal(client.url, "ws://" + server_url) 48 | assert_false(client.connected()) 49 | 50 | 51 | def test_connect_wss(): 52 | client = rockets.Client("wss://" + server_url) 53 | assert_equal(client.url, "wss://" + server_url) 54 | assert_false(client.connected()) 55 | 56 | 57 | def test_connect_http(): 58 | client = rockets.Client("http://" + server_url) 59 | assert_equal(client.url, "ws://" + server_url) 60 | assert_false(client.connected()) 61 | 62 | 63 | def test_connect_https(): 64 | client = rockets.Client("https://" + server_url) 65 | assert_equal(client.url, "wss://" + server_url) 66 | assert_false(client.connected()) 67 | 68 | 69 | def test_connect(): 70 | client = rockets.Client(server_url) 71 | assert_equal(client.url, "ws://" + server_url) 72 | assert_false(client.connected()) 73 | 74 | 75 | def test_reconnect(): 76 | client = rockets.Client(server_url) 77 | client.connect() 78 | assert_true(client.connected()) 79 | client.disconnect() 80 | assert_false(client.connected()) 81 | client.connect() 82 | assert_true(client.connected()) 83 | 84 | 85 | def test_double_disconnect(): 86 | client = rockets.Client(server_url) 87 | client.connect() 88 | assert_true(client.connected()) 89 | client.disconnect() 90 | assert_false(client.connected()) 91 | client.disconnect() 92 | assert_false(client.connected()) 93 | 94 | 95 | if __name__ == "__main__": 96 | import nose 97 | 98 | nose.run(defaultTest=__name__) 99 | -------------------------------------------------------------------------------- /python/tests/test_notify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Copyright (c) 2018, Blue Brain Project 4 | # Daniel Nachbaur 5 | # 6 | # This file is part of Rockets 7 | # 8 | # This library is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU Lesser General Public License version 3.0 as published 10 | # by the Free Software Foundation. 11 | # 12 | # This library is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 | # details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with this library; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # All rights reserved. Do not distribute without further notice. 21 | import asyncio 22 | 23 | import websockets 24 | from jsonrpcserver.aio import methods 25 | from nose.tools import assert_equal 26 | from nose.tools import assert_false 27 | from nose.tools import assert_true 28 | 29 | import rockets 30 | 31 | 32 | got_hello = asyncio.Future() 33 | echo_param = asyncio.Future() 34 | 35 | 36 | @methods.add 37 | async def hello(): 38 | global got_hello 39 | got_hello.set_result(True) 40 | 41 | 42 | @methods.add 43 | async def echo(name): 44 | global echo_param 45 | echo_param.set_result(name) 46 | 47 | 48 | async def server_handle(websocket, path): 49 | request = await websocket.recv() 50 | await methods.dispatch(request) 51 | 52 | 53 | server_url = None 54 | 55 | 56 | def setup(): 57 | start_server = websockets.serve(server_handle, "localhost") 58 | server = asyncio.get_event_loop().run_until_complete(start_server) 59 | global server_url 60 | server_url = "localhost:" + str(server.sockets[0].getsockname()[1]) 61 | 62 | 63 | def test_no_param(): 64 | client = rockets.Client(server_url) 65 | client.notify("hello") 66 | asyncio.get_event_loop().run_until_complete(got_hello) 67 | assert_true(got_hello.result()) 68 | 69 | 70 | def test_param(): 71 | client = rockets.Client(server_url) 72 | client.notify("echo", {"name": "world"}) 73 | asyncio.get_event_loop().run_until_complete(echo_param) 74 | assert_equal(echo_param.result(), "world") 75 | 76 | 77 | def test_method_not_found(): 78 | client = rockets.Client(server_url) 79 | client.notify("pong") 80 | # no effect on the client side 81 | 82 | 83 | if __name__ == "__main__": 84 | import nose 85 | 86 | nose.run(defaultTest=__name__) 87 | -------------------------------------------------------------------------------- /python/tests/test_request_id.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Copyright (c) 2018, Blue Brain Project 4 | # Daniel Nachbaur 5 | # 6 | # This file is part of Rockets 7 | # 8 | # This library is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU Lesser General Public License version 3.0 as published 10 | # by the Free Software Foundation. 11 | # 12 | # This library is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 | # details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with this library; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # All rights reserved. Do not distribute without further notice. 21 | from nose.tools import assert_equal 22 | from nose.tools import assert_not_equal 23 | 24 | from rockets import Request 25 | 26 | 27 | def test_request_id_length(): 28 | request = Request("foo") 29 | assert_equal(len(request.request_id()), 8) 30 | 31 | 32 | def test_request_ids_different(): 33 | request_a = Request("foo") 34 | request_b = Request("bar") 35 | assert_not_equal(request_a.request_id(), request_b.request_id()) 36 | 37 | 38 | if __name__ == "__main__": 39 | import nose 40 | 41 | nose.run(defaultTest=__name__) 42 | -------------------------------------------------------------------------------- /python/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py35,py36,py37 3 | 4 | [testenv] 5 | whitelist_externals = make 6 | commands = 7 | make clean 8 | make run_tests 9 | -------------------------------------------------------------------------------- /rockets/clientContext.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_CLIENTCONTEXT_H 21 | #define ROCKETS_CLIENTCONTEXT_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #if LWS_LIBRARY_VERSION_NUMBER >= 2000000 35 | #define CLIENT_USE_EXPLICIT_VHOST 1 36 | #endif 37 | 38 | namespace rockets 39 | { 40 | /** 41 | * Common context for http and websockets clients. 42 | */ 43 | class ClientContext 44 | { 45 | public: 46 | ClientContext(lws_callback_function* callback, void* user); 47 | 48 | lws* startHttpRequest(http::Method method, const std::string& uri); 49 | 50 | std::unique_ptr connect(const std::string& uri, 51 | const std::string& protocol); 52 | 53 | void service(int timeout_ms); 54 | void service(PollDescriptors& pollDescriptors, SocketDescriptor fd, 55 | int events); 56 | 57 | private: 58 | lws_context_creation_info info; 59 | std::string wsProtocolName{"default"}; 60 | std::vector protocols; 61 | LwsContextPtr context; 62 | #if CLIENT_USE_EXPLICIT_VHOST 63 | lws_vhost* vhost = nullptr; 64 | #endif 65 | 66 | lws_client_connect_info makeConnectInfo(const Uri& uri) const; 67 | void createContext(); 68 | void createVhost(); 69 | void disableProxy(); 70 | }; 71 | } 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /rockets/helpers.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_HELPERS_H 21 | #define ROCKETS_HELPERS_H 22 | 23 | #include 24 | 25 | namespace rockets 26 | { 27 | /** @return true if the future is ready, i.e. a get() will not block. */ 28 | template 29 | bool is_ready(const std::future& f) 30 | { 31 | return f.valid() && 32 | f.wait_for(std::chrono::seconds(0)) == std::future_status::ready; 33 | } 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /rockets/http/channel.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_HTTP_CHANNEL_H 21 | #define ROCKETS_HTTP_CHANNEL_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | namespace rockets 31 | { 32 | namespace http 33 | { 34 | /** 35 | * An HTTP communication channel. 36 | * 37 | * Provides low-level HTTP read/write methods for the Client and Server over a 38 | * given libwebsockets connection. 39 | */ 40 | class Channel 41 | { 42 | public: 43 | explicit Channel(lws* wsi); 44 | Channel() = default; 45 | 46 | /* Client + Server */ 47 | size_t readContentLength() const; 48 | 49 | /* Server */ 50 | std::string readHost() const; 51 | Method readMethod() const; 52 | std::string readOrigin() const; 53 | std::map readQueryParameters() const; 54 | CorsRequestHeaders readCorsRequestHeaders() const; 55 | void requestCallback(); 56 | int writeResponseHeaders(const CorsResponseHeaders& corsHeaders, 57 | const Response& response); 58 | int writeResponseBody(const Response& response); 59 | 60 | /* Client */ 61 | int writeRequestHeader(const std::string& body, unsigned char** buffer, 62 | size_t bufferSize); 63 | #if LWS_LIBRARY_VERSION_NUMBER >= 2001000 64 | int writeRequestBody(const std::string& body); 65 | Code readResponseCode() const; 66 | #endif 67 | Response::Headers readResponseHeaders() const; 68 | 69 | private: 70 | lws* wsi = nullptr; 71 | 72 | std::string _readHeader(lws_token_indexes token) const; 73 | void _writeResponseBody(const std::string& message); 74 | bool _write(const std::string& message, lws_write_protocol protocol); 75 | }; 76 | } // namespace http 77 | } // namespace rockets 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /rockets/http/client.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_HTTP_CLIENT_H 21 | #define ROCKETS_HTTP_CLIENT_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | namespace rockets 28 | { 29 | namespace http 30 | { 31 | /** 32 | * Client for making asynchronous HTTP requests. 33 | * 34 | * Example usage: @include apps/httpRequest.cpp 35 | */ 36 | class Client : public SocketBasedInterface 37 | { 38 | public: 39 | /** @name Setup */ 40 | //@{ 41 | /** Construct a new client. */ 42 | ROCKETS_API Client(); 43 | 44 | /** Close the client. */ 45 | ROCKETS_API ~Client(); 46 | //@} 47 | 48 | /** 49 | * Make an http request. 50 | * 51 | * @param uri to address the request. 52 | * @param method http method to use. 53 | * @param body optional payload to send. 54 | * @throw std::invalid_argument if the uri is too long (>4000 char) or 55 | * some parameter is invalid or not supported. 56 | * @return future http response - can be a std::runtime_error if the 57 | * request fails. 58 | */ 59 | ROCKETS_API std::future request( 60 | const std::string& uri, http::Method method = http::Method::GET, 61 | std::string body = std::string()); 62 | 63 | /** 64 | * Make an http request. 65 | * 66 | * @param uri to address the request. 67 | * @param method http method to use. 68 | * @param body optional payload to send. 69 | * @param callback for the http response. 70 | * @param errorCallback used to report request failure (optional). 71 | * @throw std::invalid_argument if the uri is too long (>4000 char) or 72 | * some parameter is invalid or not supported. 73 | */ 74 | ROCKETS_API void request( 75 | const std::string& uri, http::Method method, std::string body, 76 | std::function callback, 77 | std::function errorCallback = {}); 78 | 79 | class Impl; // must be public for static_cast from C callback 80 | private: 81 | std::unique_ptr _impl; 82 | 83 | void _setSocketListener(SocketListener* listener) final; 84 | void _processSocket(SocketDescriptor fd, int events) final; 85 | void _process(int timeout_ms) final; 86 | }; 87 | } 88 | } 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /rockets/http/connection.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_HTTP_CONNECTION_H 21 | #define ROCKETS_HTTP_CONNECTION_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | namespace rockets 31 | { 32 | namespace http 33 | { 34 | /** 35 | * Incoming HTTP connection from a remote client on the Server. 36 | */ 37 | class Connection 38 | { 39 | public: 40 | Connection(lws* wsi, const char* path); 41 | 42 | // request 43 | 44 | std::string getPathWithoutLeadingSlash() const; 45 | Method getMethod() const; 46 | 47 | bool canHaveHttpBody() const; 48 | void appendBody(const char* in, const size_t len); 49 | 50 | bool isCorsPreflightRequest() const; 51 | 52 | const Request& getRequest() const { return request; } 53 | void overwriteRequestPath(std::string path); 54 | 55 | // response 56 | 57 | void setResponse(std::future&& futureResponse); 58 | void setCorsResponseHeaders(CorsResponseHeaders&& headers); 59 | 60 | bool isResponseSet() const; 61 | bool isResponseReady() const; 62 | 63 | void requestWriteCallback(); 64 | 65 | int writeResponseHeaders(); 66 | int writeResponseBody(); 67 | 68 | bool wereResponseHeadersSent() const; 69 | 70 | private: 71 | Channel channel; 72 | Request request; 73 | size_t contentLength = 0; 74 | CorsRequestHeaders corsHeaders; 75 | 76 | CorsResponseHeaders corsResponseHeaders; 77 | std::future delayedResponse; 78 | bool delayedResponseSet = false; 79 | bool responseFinalized = false; 80 | Response response; 81 | 82 | bool responseHeadersSent = false; 83 | bool responseBodySent = false; 84 | 85 | bool _canHaveHttpBody(Method m) const; 86 | bool _hasCorsPreflightHeaders() const; 87 | CorsResponseHeaders _getCorsResponseHeaders() const; 88 | void _finalizeResponse(); 89 | }; 90 | } 91 | } 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /rockets/http/connectionHandler.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_HTTP_CONNECTION_HANDLER_H 21 | #define ROCKETS_HTTP_CONNECTION_HANDLER_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace rockets 29 | { 30 | namespace http 31 | { 32 | /** 33 | * Handle HTTP connection requests from clients. 34 | * 35 | * This class processes incoming HTTP payload until requests are complete, 36 | * then responds to them by calling an appropriate handler from the Registry, 37 | * or an error code otherwise. 38 | * 39 | * It also answers CORS preflight requests directly. 40 | * 41 | * Incoming connections can optionally be filtered out by setting a Filter. 42 | */ 43 | class ConnectionHandler 44 | { 45 | public: 46 | ConnectionHandler(const Registry& registry); 47 | void setFilter(const Filter* filter); 48 | 49 | void handleNewRequest(Connection& connection) const; 50 | void handleData(Connection& connection, const char* data, 51 | size_t size) const; 52 | void prepareResponse(Connection& connection) const; 53 | int writeResponse(Connection& connection) const; 54 | 55 | private: 56 | const http::Filter* _filter = nullptr; 57 | const Registry& _registry; 58 | 59 | void _prepareCorsPreflightResponse(Connection& connection) const; 60 | std::future _generateResponse(Connection& connection) const; 61 | std::future _callHandler(const Connection& connection, 62 | const std::string& endpoint) const; 63 | CorsResponseHeaders _makeCorsPreflighResponseHeaders( 64 | const std::string& path) const; 65 | }; 66 | } 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /rockets/http/cors.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_HTTP_CORS_H 21 | #define ROCKETS_HTTP_CORS_H 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | namespace rockets 29 | { 30 | namespace http 31 | { 32 | struct CorsRequestHeaders 33 | { 34 | std::string origin; 35 | std::string accessControlRequestHeaders; 36 | Method accessControlRequestMethod = Method::ALL; 37 | }; 38 | 39 | enum class CorsResponseHeader 40 | { 41 | access_control_allow_headers, 42 | access_control_allow_methods, 43 | access_control_allow_origin 44 | }; 45 | using CorsResponseHeaders = std::map; 46 | } 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /rockets/http/filter.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_HTTP_FILTER_H 21 | #define ROCKETS_HTTP_FILTER_H 22 | 23 | #include 24 | #include 25 | 26 | namespace rockets 27 | { 28 | namespace http 29 | { 30 | /** 31 | * Filter for http requests. 32 | */ 33 | class Filter 34 | { 35 | public: 36 | /** @return true if the request must be filtered. */ 37 | ROCKETS_API virtual bool filter(const Request& request) const = 0; 38 | 39 | /** @return response to a request that must be blocked. */ 40 | ROCKETS_API virtual Response getResponse(const Request& request) const = 0; 41 | 42 | protected: 43 | ROCKETS_API virtual ~Filter() = default; 44 | }; 45 | } 46 | } 47 | #endif 48 | -------------------------------------------------------------------------------- /rockets/http/helpers.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_HTTP_HELPERS_H 21 | #define ROCKETS_HTTP_HELPERS_H 22 | 23 | #include 24 | 25 | #include 26 | 27 | namespace rockets 28 | { 29 | namespace http 30 | { 31 | /** 32 | * @return ready future wrapping an HTTP Response constructed with 33 | * the values passed. 34 | */ 35 | template 36 | std::future make_ready_response(Args&&... args) 37 | { 38 | std::promise promise; 39 | promise.set_value(Response(std::forward(args)...)); 40 | return promise.get_future(); 41 | } 42 | } 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /rockets/http/registry.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * Stefan.Eilemann@epfl.ch 4 | * Daniel.Nachbaur@epfl.ch 5 | * 6 | * This file is part of Rockets 7 | * 8 | * This library is free software; you can redistribute it and/or modify it under 9 | * the terms of the GNU Lesser General Public License version 3.0 as published 10 | * by the Free Software Foundation. 11 | * 12 | * This library is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this library; if not, write to the Free Software Foundation, Inc., 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | */ 21 | 22 | #ifndef ROCKETS_HTTP_REGISTRY_H 23 | #define ROCKETS_HTTP_REGISTRY_H 24 | 25 | #include "types.h" 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace rockets 32 | { 33 | namespace http 34 | { 35 | /** 36 | * Registry for HTTP endpoints. 37 | */ 38 | class Registry 39 | { 40 | public: 41 | bool add(Method method, const std::string& endpoint, RESTFunc func); 42 | bool remove(const std::string& endpoint); 43 | 44 | bool contains(Method method, const std::string& endpoint) const; 45 | RESTFunc getFunction(Method method, const std::string& endpoint) const; 46 | 47 | std::string getAllowedMethods(const std::string& endpoint) const; 48 | 49 | struct SearchResult 50 | { 51 | bool found; 52 | std::string endpoint; 53 | }; 54 | SearchResult findEndpoint(Method method, const std::string& path) const; 55 | 56 | std::string toJson() const; 57 | 58 | private: 59 | // key stores endpoints of Serializable objects lower-case, hyphenated, 60 | // with '/' separators 61 | // must be an ordered map in order to iterate from the most specific path 62 | using FuncMap = std::map>; 63 | std::array _methods; 64 | 65 | FuncMap::const_iterator _find(const Registry::FuncMap& FuncMap, 66 | const std::string& path) const; 67 | }; 68 | } 69 | } 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /rockets/http/request.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * Stefan.Eilemann@epfl.ch 4 | * 5 | * This file is part of Rockets 6 | * 7 | * This library is free software; you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License version 3.0 as published 9 | * by the Free Software Foundation. 10 | * 11 | * This library is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | */ 20 | 21 | #ifndef ROCKETS_HTTP_REQUEST_H 22 | #define ROCKETS_HTTP_REQUEST_H 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | namespace rockets 30 | { 31 | namespace http 32 | { 33 | /** 34 | * HTTP Request with method, path and body. 35 | * 36 | * The path provides the url part after the registered endpoint if it is 37 | * terminated with a slash. 38 | * Registered endpoint || HTTP request || path 39 | * "api/windows/" || "api/windows/jf321f" || "jf321f". 40 | * "api/windows/" || "api/windows/" || "" 41 | * 42 | * If an endpoint is not terminated with a slash, then only exactly matching 43 | * HTTP request will be processed. 44 | * Registered endpoint || HTTP request || path 45 | * "api/objects" || "api/objects" || "" 46 | * "api/objects" || "api/objects/abc" || ** ENDPOINT NOT FOUND: 404 ** 47 | * 48 | * The query is the url part after "?". 49 | * Registered endpoint || HTTP request || query || path 50 | * "api/objects" || "api/objects?size=4" || "size=4" || "" 51 | * "api/windows/" || "api/windows/jf321f?size=4" || "size=4" || "jf321" 52 | * 53 | * The body is the HTTP request payload. 54 | */ 55 | struct Request 56 | { 57 | Method method; 58 | std::string path; 59 | std::string origin; 60 | std::string host; 61 | std::map query; 62 | std::string body; 63 | }; 64 | } // namespace http 65 | } // namespace rockets 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /rockets/http/requestHandler.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "requestHandler.h" 21 | 22 | namespace rockets 23 | { 24 | namespace http 25 | { 26 | RequestHandler::RequestHandler(Channel&& channel_, std::string body_, 27 | std::function callback_, 28 | std::function errorCallback_) 29 | : channel{std::move(channel_)} 30 | , body{std::move(body_)} 31 | , callback{std::move(callback_)} 32 | , errorCallback{std::move(errorCallback_)} 33 | { 34 | } 35 | 36 | int RequestHandler::writeHeaders(unsigned char** buffer, const size_t size) 37 | { 38 | return channel.writeRequestHeader(body, buffer, size); 39 | } 40 | 41 | #if LWS_LIBRARY_VERSION_NUMBER >= 2001000 42 | int RequestHandler::writeBody() 43 | { 44 | return channel.writeRequestBody(body); 45 | } 46 | #endif 47 | 48 | void RequestHandler::readResponseHeaders() 49 | { 50 | #if LWS_LIBRARY_VERSION_NUMBER >= 2001000 51 | response.code = channel.readResponseCode(); 52 | #endif 53 | response.headers = channel.readResponseHeaders(); 54 | responseLength = channel.readContentLength(); 55 | } 56 | 57 | void RequestHandler::appendToResponseBody(const char* data, const size_t size) 58 | { 59 | response.body.append(data, size); 60 | } 61 | 62 | void RequestHandler::finish() 63 | { 64 | if (callback) 65 | callback(std::move(response)); 66 | } 67 | 68 | void RequestHandler::abort(std::string&& errorMessage) 69 | { 70 | if (errorCallback) 71 | errorCallback(std::move(errorMessage)); 72 | } 73 | 74 | bool RequestHandler::hasResponseBody() const 75 | { 76 | return responseLength > 0; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /rockets/http/requestHandler.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_HTTP_REQUEST_HANDLER_H 21 | #define ROCKETS_HTTP_REQUEST_HANDLER_H 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | 30 | namespace rockets 31 | { 32 | namespace http 33 | { 34 | /** 35 | * HTTP request handler. 36 | */ 37 | class RequestHandler 38 | { 39 | public: 40 | RequestHandler(Channel&& channel, std::string body, 41 | std::function callback, 42 | std::function errorCallback); 43 | 44 | int writeHeaders(unsigned char** buffer, const size_t size); 45 | #if LWS_LIBRARY_VERSION_NUMBER >= 2001000 46 | int writeBody(); 47 | #endif 48 | 49 | void readResponseHeaders(); 50 | bool hasResponseBody() const; 51 | void appendToResponseBody(const char* data, const size_t size); 52 | 53 | void finish(); 54 | void abort(std::string&& errorMessage); 55 | 56 | private: 57 | Channel channel; 58 | std::string body; 59 | std::function callback; 60 | std::function errorCallback; 61 | Response response; 62 | size_t responseLength = 0; 63 | }; 64 | } 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /rockets/http/response.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * Pawel.Podhajski@epfl.ch 4 | * 5 | * This file is part of Rockets 6 | * 7 | * This library is free software; you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License version 3.0 as published 9 | * by the Free Software Foundation. 10 | * 11 | * This library is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | */ 20 | 21 | #ifndef ROCKETS_HTTP_RESPONSE_H 22 | #define ROCKETS_HTTP_RESPONSE_H 23 | 24 | #include 25 | 26 | #include // member 27 | #include // member 28 | 29 | namespace rockets 30 | { 31 | namespace http 32 | { 33 | /** 34 | * Response to an HTTP Request. 35 | */ 36 | struct Response 37 | { 38 | /** HTTP return code. */ 39 | Code code; 40 | 41 | /** Payload to return in a format specified in CONTENT_TYPE header. */ 42 | std::string body; 43 | 44 | /** HTTP message headers. */ 45 | using Headers = std::map; 46 | Headers headers; 47 | 48 | /** Construct a Response with a given return code and payload. */ 49 | Response(const Code code_ = Code::OK, std::string body_ = std::string()) 50 | : code{code_} 51 | , body{std::move(body_)} 52 | { 53 | } 54 | 55 | /** Construct a Response with a given code, payload and content type. */ 56 | Response(const Code code_, std::string body_, 57 | const std::string& contentType) 58 | : code{code_} 59 | , body{std::move(body_)} 60 | , headers{{Header::CONTENT_TYPE, contentType}} 61 | { 62 | } 63 | 64 | /** Construct a Response with a given code, payload and map of headers. */ 65 | Response(const Code code_, std::string body_, 66 | std::map headers_) 67 | : code{code_} 68 | , body{std::move(body_)} 69 | , headers{{std::move(headers_)}} 70 | { 71 | } 72 | }; 73 | } 74 | } 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /rockets/http/types.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * Stefan.Eilemann@epfl.ch 4 | * 5 | * This file is part of Rockets 6 | * 7 | * This library is free software; you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License version 3.0 as published 9 | * by the Free Software Foundation. 10 | * 11 | * This library is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | */ 20 | 21 | #ifndef ROCKETS_HTTP_TYPES_H 22 | #define ROCKETS_HTTP_TYPES_H 23 | 24 | #include 25 | #include 26 | 27 | namespace rockets 28 | { 29 | namespace http 30 | { 31 | struct Request; 32 | struct Response; 33 | class Client; 34 | 35 | /** HTTP method used in a Request. */ 36 | enum class Method 37 | { 38 | GET, 39 | POST, 40 | PUT, 41 | PATCH, 42 | DELETE, 43 | OPTIONS, 44 | ALL //!< @internal, must be last 45 | }; 46 | 47 | /** HTTP headers which can be used in a Response. */ 48 | enum class Header 49 | { 50 | ALLOW, 51 | CONTENT_TYPE, 52 | LAST_MODIFIED, 53 | LOCATION, 54 | RETRY_AFTER 55 | }; 56 | 57 | /** HTTP codes to be used in a Response. */ 58 | enum Code 59 | { 60 | OK = 200, 61 | CREATED = 201, 62 | ACCEPTED = 202, 63 | NO_CONTENT = 204, 64 | PARTIAL_CONTENT = 206, 65 | MULTIPLE_CHOICES = 300, 66 | MOVED_PERMANENTLY = 301, 67 | MOVED_TEMPORARILY = 302, 68 | NOT_MODIFIED = 304, 69 | BAD_REQUEST = 400, 70 | UNAUTHORIZED = 401, 71 | FORBIDDEN = 403, 72 | NOT_FOUND = 404, 73 | NOT_SUPPORTED = 405, 74 | NOT_ACCEPTABLE = 406, 75 | REQUEST_TIMEOUT = 408, 76 | PRECONDITION_FAILED = 412, 77 | UNSATISFIABLE_RANGE = 416, 78 | INTERNAL_SERVER_ERROR = 500, 79 | NOT_IMPLEMENTED = 501, 80 | BAD_GATEWAY = 502, 81 | SERVICE_UNAVAILABLE = 503, 82 | SPACE_UNAVAILABLE = 507 83 | }; 84 | 85 | /** HTTP REST callback with Request parameter returning a Response future. */ 86 | using RESTFunc = std::function(const Request&)>; 87 | } 88 | } 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /rockets/http/utils.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "utils.h" 21 | 22 | #include 23 | 24 | namespace rockets 25 | { 26 | namespace http 27 | { 28 | std::string to_string(const CorsResponseHeader header) 29 | { 30 | switch (header) 31 | { 32 | case CorsResponseHeader::access_control_allow_headers: 33 | return "access-control-allow-headers"; 34 | case CorsResponseHeader::access_control_allow_methods: 35 | return "access-control-allow-methods"; 36 | case CorsResponseHeader::access_control_allow_origin: 37 | return "access-control-allow-origin"; 38 | default: 39 | throw std::logic_error("no such header"); 40 | } 41 | } 42 | 43 | const char* to_cstring(const Method method) 44 | { 45 | switch (method) 46 | { 47 | case Method::GET: 48 | return "GET"; 49 | case Method::POST: 50 | return "POST"; 51 | case Method::PUT: 52 | return "PUT"; 53 | case Method::PATCH: 54 | return "PATCH"; 55 | case Method::DELETE: 56 | return "DELETE"; 57 | case Method::OPTIONS: 58 | return "OPTIONS"; 59 | default: 60 | throw std::logic_error("unsupported http method"); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /rockets/http/utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_HTTP_UTILS_H 21 | #define ROCKETS_HTTP_UTILS_H 22 | 23 | #include "cors.h" 24 | 25 | namespace rockets 26 | { 27 | namespace http 28 | { 29 | std::string to_string(const CorsResponseHeader header); 30 | const char* to_cstring(const Method method); 31 | } 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /rockets/jsonrpc/asyncReceiver.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "asyncReceiver.h" 21 | #include "asyncReceiverImpl.h" 22 | #include "utils.h" 23 | 24 | namespace rockets 25 | { 26 | namespace jsonrpc 27 | { 28 | AsyncReceiver::AsyncReceiver() 29 | : Receiver(std::make_unique()) 30 | { 31 | } 32 | 33 | AsyncReceiver::AsyncReceiver(std::unique_ptr impl) 34 | : Receiver(std::move(impl)) 35 | { 36 | } 37 | 38 | void AsyncReceiver::bindAsync(const std::string& method, 39 | DelayedResponseCallback action) 40 | { 41 | static_cast(_impl.get()) 42 | ->registerMethod(method, 43 | [action](Request request, AsyncResponse response) { 44 | action(request, response); 45 | }); 46 | } 47 | 48 | std::future AsyncReceiver::processAsync(const Request& request) 49 | { 50 | auto promise = std::make_shared>(); 51 | auto future = promise->get_future(); 52 | auto callback = [promise](std::string response) { 53 | promise->set_value(std::move(response)); 54 | }; 55 | process(request, callback); 56 | return future; 57 | } 58 | 59 | void AsyncReceiver::process(const Request& request, 60 | AsyncStringResponse callback) 61 | { 62 | _impl->process(request, callback); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /rockets/jsonrpc/asyncReceiver.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_JSONRPC_ASYNC_RECEIVER_H 21 | #define ROCKETS_JSONRPC_ASYNC_RECEIVER_H 22 | 23 | #include 24 | 25 | #include 26 | 27 | namespace rockets 28 | { 29 | namespace jsonrpc 30 | { 31 | /** 32 | * Extends the synchronous receiver by providing asynchronous processing of 33 | * requests. 34 | */ 35 | class AsyncReceiver : public Receiver 36 | { 37 | public: 38 | /** Constructor. */ 39 | AsyncReceiver(); 40 | 41 | /** 42 | * Bind a method to an async response callback. 43 | * 44 | * @param method to register. 45 | * @param action to perform that will notify the caller upon completion. 46 | * @throw std::invalid_argument if the method name starts with "rpc." 47 | */ 48 | void bindAsync(const std::string& method, DelayedResponseCallback action); 49 | 50 | /** 51 | * Bind a method to an async response callback with templated parameters. 52 | * 53 | * The parameters object must be deserializable by a free function: 54 | * from_json(Params& object, const std::string& json). 55 | * 56 | * @param method to register. 57 | * @param action to perform that will notify the caller upon completion. 58 | * @throw std::invalid_argument if the method name starts with "rpc." 59 | */ 60 | template 61 | void bindAsync(const std::string& method, 62 | std::function action) 63 | { 64 | bindAsync(method, 65 | [action](const Request& request, AsyncResponse callback) { 66 | Params params; 67 | if (from_json(params, request.message)) 68 | action(std::move(params), callback); 69 | else 70 | callback(Response::invalidParams()); 71 | }); 72 | } 73 | 74 | /** 75 | * Process a JSON-RPC request asynchronously. 76 | * 77 | * @param request Request object with message in JSON-RPC 2.0 format. 78 | * @return future json response string in JSON-RPC 2.0 format. 79 | */ 80 | std::future processAsync(const Request& request); 81 | 82 | /** 83 | * Process a JSON-RPC request asynchronously. 84 | * 85 | * @param request Request object with message in JSON-RPC 2.0 format. 86 | * @param callback that return a json response string in JSON-RPC 2.0 87 | * format upon request completion. 88 | */ 89 | void process(const Request& request, AsyncStringResponse callback); 90 | 91 | protected: 92 | AsyncReceiver(std::unique_ptr impl); 93 | }; 94 | } 95 | } 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /rockets/jsonrpc/asyncReceiverImpl.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "receiverImpl.h" 23 | #include "utils.h" 24 | 25 | namespace rockets 26 | { 27 | namespace jsonrpc 28 | { 29 | class AsyncReceiverImpl : public ReceiverImpl 30 | { 31 | public: 32 | void registerMethod(const std::string& method, 33 | DelayedResponseCallback action) 34 | { 35 | verifyValidMethodName(method); 36 | _methods[method] = action; 37 | } 38 | 39 | bool isRegisteredMethodName(const std::string& method) const override 40 | { 41 | return _methods.find(method) != _methods.end() || 42 | ReceiverImpl::isRegisteredMethodName(method); 43 | } 44 | 45 | void process(const json& requestID, const std::string& method, 46 | const Request& request, JsonResponseCallback respond) override 47 | { 48 | if (_methods.find(method) == _methods.end()) 49 | { 50 | ReceiverImpl::process(requestID, method, request, respond); 51 | return; 52 | } 53 | 54 | const auto& func = _methods[method]; 55 | func(request, [respond, requestID](const Response& rep) { 56 | // No reply for valid "notifications" (requests without an "id") 57 | if (requestID.is_null()) 58 | respond(json()); 59 | else 60 | respond(makeResponse(rep, requestID)); 61 | }); 62 | } 63 | 64 | private: 65 | std::map _methods; 66 | }; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /rockets/jsonrpc/cancellableReceiver.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Daniel.Nachbaur@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "cancellableReceiver.h" 21 | #include "cancellableReceiverImpl.h" 22 | #include "helpers.h" 23 | #include "utils.h" 24 | 25 | namespace rockets 26 | { 27 | namespace jsonrpc 28 | { 29 | CancellableReceiver::CancellableReceiver(SendTextCallback sendTextCb) 30 | : AsyncReceiver{std::make_unique(sendTextCb)} 31 | { 32 | } 33 | 34 | void CancellableReceiver::bindAsync(const std::string& method, 35 | CancellableResponseCallback action) 36 | { 37 | static_cast(_impl.get()) 38 | ->registerMethod(method, 39 | [action](Request request, AsyncResponse response, 40 | ProgressUpdateCallback progress) { 41 | return action(request, response, progress); 42 | }); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /rockets/jsonrpc/client.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_JSONRPC_CLIENT_H 21 | #define ROCKETS_JSONRPC_CLIENT_H 22 | 23 | #include 24 | #include 25 | 26 | namespace rockets 27 | { 28 | namespace jsonrpc 29 | { 30 | /** 31 | * JSON-RPC client. 32 | * 33 | * The client can be used over any communication channel that provides the 34 | * following methods: 35 | * 36 | * - void sendText(std::string message); 37 | * Used to send notifications and requests to the server. 38 | * 39 | * - void handleText(ws::MessageCallback callback); 40 | * Used to register a callback for processing the responses from the server 41 | * when they arrive (non-blocking requests) as well as receiving 42 | * notifications. 43 | */ 44 | template 45 | class Client : public Requester, public Receiver 46 | { 47 | public: 48 | Client(Communicator& comm) 49 | : communicator{comm} 50 | { 51 | communicator.handleText( 52 | [ this, thisStatus = 53 | std::weak_ptr{status} ](const Request& request_) { 54 | // Prevent access to *this* by a callback after the Client has 55 | // been destroyed (in non-multithreaded contexts). 56 | if (!thisStatus.expired()) 57 | { 58 | if (!processResponse(request_.message)) 59 | _processNotification(request_); 60 | } 61 | return std::string(); 62 | }); 63 | } 64 | 65 | private: 66 | /** Notifier::_send */ 67 | void _send(std::string json) final 68 | { 69 | communicator.sendText(std::move(json)); 70 | } 71 | 72 | void _processNotification(const Request& request_) { process(request_); } 73 | Communicator& communicator; 74 | std::shared_ptr status = std::make_shared(true); 75 | }; 76 | } 77 | } 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /rockets/jsonrpc/clientRequest.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Daniel.Nachbaur@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "clientRequest.h" 21 | 22 | #include "../json.hpp" 23 | using namespace rockets_nlohmann; 24 | 25 | namespace rockets 26 | { 27 | namespace jsonrpc 28 | { 29 | std::string _getCancelJson(size_t id) 30 | { 31 | json cancel{{"id", id}}; 32 | return cancel.dump(4); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /rockets/jsonrpc/clientRequest.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Daniel.Nachbaur@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_JSONRPC_CLIENT_REQUEST_H 21 | #define ROCKETS_JSONRPC_CLIENT_REQUEST_H 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | namespace rockets 29 | { 30 | namespace jsonrpc 31 | { 32 | std::string _getCancelJson(size_t id); 33 | 34 | /** 35 | * A request object containing the future result and a handle to the request 36 | * made by Requester to cancel the request, if supported by the receiver. 37 | */ 38 | template 39 | class ClientRequest 40 | { 41 | public: 42 | /** @return true if the result is ready and get() won't block. */ 43 | bool is_ready() const { return rockets::is_ready(_future); } 44 | /** @return the result of the request, may wait if not ready yet. */ 45 | ResponseT get() { return _future.get(); } 46 | /** 47 | * Issue a cancel of the request. Depending on the receiver type and the 48 | * internal cancel handling, is_ready() might change. 49 | */ 50 | void cancel() { _notify("cancel", _getCancelJson(_id)); } 51 | private: 52 | friend class Requester; 53 | 54 | using NotifyFunc = std::function; 55 | ClientRequest(const size_t id, std::future&& future, 56 | NotifyFunc func) 57 | : _id(id) 58 | , _future(std::move(future)) 59 | , _notify(func) 60 | { 61 | } 62 | 63 | const size_t _id; 64 | std::future _future; 65 | NotifyFunc _notify; 66 | }; 67 | } 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /rockets/jsonrpc/errorCodes.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_JSONRPC_ERROR_CODES_H 21 | #define ROCKETS_JSONRPC_ERROR_CODES_H 22 | 23 | #include 24 | 25 | namespace rockets 26 | { 27 | namespace jsonrpc 28 | { 29 | /** 30 | * Error codes that can occur when making a request. 31 | */ 32 | enum ErrorCode : int16_t 33 | { 34 | // JSON-RPC 2.0 specification; server errors [-32768 to -32000] 35 | parse_error = -32700, 36 | invalid_request = -32600, 37 | method_not_found = -32601, 38 | invalid_params = -32602, 39 | internal_error = -32603, 40 | // Rockets client errors 41 | invalid_json_response = -31001, 42 | request_aborted = -31002, 43 | http_error = -31003 44 | }; 45 | } 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /rockets/jsonrpc/helpers.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "helpers.h" 21 | 22 | #include "../json.hpp" 23 | 24 | using namespace rockets_nlohmann; 25 | 26 | namespace rockets 27 | { 28 | namespace jsonrpc 29 | { 30 | std::string makeNotification(const std::string& method) 31 | { 32 | return json{{"jsonrpc", "2.0"}, {"method", method}}.dump(4); 33 | } 34 | 35 | std::string makeNotification(const std::string& method, 36 | const std::string& params) 37 | { 38 | return json{{"jsonrpc", "2.0"}, 39 | {"method", method}, 40 | {"params", json::parse(params)}} 41 | .dump(4); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /rockets/jsonrpc/helpers.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_JSONRPC_HELPERS_H 21 | #define ROCKETS_JSONRPC_HELPERS_H 22 | 23 | #include 24 | 25 | namespace rockets 26 | { 27 | namespace jsonrpc 28 | { 29 | /** @return a JSON RPC notification for the given method. */ 30 | std::string makeNotification(const std::string& method); 31 | 32 | /** @return a JSON RPC notification for the given method and params. */ 33 | std::string makeNotification(const std::string& method, 34 | const std::string& params); 35 | 36 | /** 37 | * @return a JSON RPC notification for the given method and templated 38 | * params. 39 | */ 40 | template 41 | std::string makeNotification(const std::string& method, const Params& params) 42 | { 43 | return makeNotification(method, to_json(params)); 44 | } 45 | } 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /rockets/jsonrpc/http.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "http.h" 21 | 22 | #include "../json.hpp" 23 | #include "errorCodes.h" 24 | 25 | using namespace rockets_nlohmann; 26 | 27 | namespace rockets 28 | { 29 | namespace jsonrpc 30 | { 31 | namespace 32 | { 33 | std::string makeJsonHttpError(const std::string& errorMsg, const json& id) 34 | { 35 | return json{{"jsonrpc", "2.0"}, 36 | {"error", 37 | json{{"message", errorMsg}, {"code", ErrorCode::http_error}}}, 38 | {"id", id}} 39 | .dump(4); 40 | } 41 | } 42 | 43 | void HttpCommunicator::sendText(std::string message) 44 | { 45 | const auto id = json::parse(message)["id"]; 46 | 47 | // Copying the callback in the lambda instead of *this* prevents potential 48 | // invalid memory access if the Communicator is destroyed before the 49 | // http::Client (which aborts pending requests, calling the error callback). 50 | const auto& cb = callback; 51 | client.request(url, http::Method::POST, std::move(message), 52 | [cb](http::Response&& response) { 53 | if (cb) 54 | cb(ws::Request{std::move(response.body)}); 55 | }, 56 | [cb, id](std::string errorMsg) { 57 | if (cb) 58 | cb(ws::Request{makeJsonHttpError(errorMsg, id)}); 59 | }); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /rockets/jsonrpc/http.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_JSONRPC_HTTP_H 21 | #define ROCKETS_JSONRPC_HTTP_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace rockets 29 | { 30 | namespace jsonrpc 31 | { 32 | /** 33 | * Connect HTTP POST requests to a JSON-RPC receiver. 34 | * 35 | * @param server HTTP server that will be receiving POST requests. 36 | * @param endpoint the endpoint at which JSON-RPC requests will arrive. 37 | * @param receiver the JSON-RPC request processor. 38 | */ 39 | template 40 | void connect(rockets::Server& server, const std::string& endpoint, 41 | ReceiverT& receiver) 42 | { 43 | auto processJsonRpc = [&receiver](const http::Request& request) { 44 | // Package json-rpc response in http::Response when ready 45 | auto promise = std::make_shared>(); 46 | auto callback = [promise](const std::string& body) { 47 | if (body.empty()) 48 | promise->set_value(http::Response{http::Code::OK}); 49 | else 50 | promise->set_value( 51 | http::Response{http::Code::OK, body, "application/json"}); 52 | }; 53 | receiver.process(request.body, callback); 54 | return promise->get_future(); 55 | }; 56 | server.handle(http::Method::POST, endpoint, processJsonRpc); 57 | } 58 | 59 | /** 60 | * Adapter for jsonrpc::Client to make JSON-RPC requests over an http::Client. 61 | * 62 | * Example usage: 63 | * http::Client httpClient; 64 | * HttpCommunicator communicator{httpClient, "localhost:8888/jsonrpc"}; 65 | * Client client{communicator}; 66 | * auto response = client.request(...); 67 | */ 68 | class HttpCommunicator 69 | { 70 | public: 71 | /** 72 | * Create a communicator for making requests to a specified url. 73 | * @param client_ an http client for performing the requests. 74 | * @param url_ the full path to the remote JSON-RPC HTTP endpoint. 75 | */ 76 | HttpCommunicator(http::Client& client_, const std::string& url_) 77 | : client{client_} 78 | , url{url_} 79 | { 80 | } 81 | 82 | private: 83 | http::Client& client; 84 | std::string url; 85 | ws::MessageCallback callback; 86 | 87 | friend class rockets::jsonrpc::Client; 88 | 89 | void sendText(std::string message); 90 | void handleText(ws::MessageCallback callback_) { callback = callback_; } 91 | }; 92 | } 93 | } 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /rockets/jsonrpc/notifier.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "notifier.h" 21 | 22 | #include "helpers.h" 23 | 24 | namespace rockets 25 | { 26 | namespace jsonrpc 27 | { 28 | void Notifier::notify(const std::string& method, const std::string& params) 29 | { 30 | _send(params.empty() ? makeNotification(method) 31 | : makeNotification(method, params)); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rockets/jsonrpc/notifier.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_JSONRPC_NOTIFIER_H 21 | #define ROCKETS_JSONRPC_NOTIFIER_H 22 | 23 | #include 24 | 25 | namespace rockets 26 | { 27 | namespace jsonrpc 28 | { 29 | /** 30 | * Emitter of JSON-RPC notifications (requests without an id and no response). 31 | */ 32 | class Notifier 33 | { 34 | public: 35 | virtual ~Notifier() = default; 36 | 37 | /** 38 | * Emit a notification. 39 | * 40 | * @param method to call. 41 | * @param params for the notification. 42 | */ 43 | void notify(const std::string& method, const std::string& params); 44 | 45 | /** 46 | * Emit a notification using a JSON-serializable object. 47 | * 48 | * @param method to call. 49 | * @param params object to send. 50 | */ 51 | template 52 | void notify(const std::string& method, const Params& params) 53 | { 54 | notify(method, to_json(params)); 55 | } 56 | 57 | protected: 58 | virtual void _send(std::string json) = 0; 59 | }; 60 | } 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /rockets/jsonrpc/receiver.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "receiver.h" 21 | #include "receiverImpl.h" 22 | #include "utils.h" 23 | 24 | namespace rockets 25 | { 26 | namespace jsonrpc 27 | { 28 | Receiver::Receiver() 29 | : _impl{std::make_unique()} 30 | { 31 | } 32 | 33 | Receiver::~Receiver() 34 | { 35 | } 36 | 37 | Receiver::Receiver(std::unique_ptr impl) 38 | : _impl(std::move(impl)) 39 | { 40 | } 41 | 42 | void Receiver::connect(const std::string& method, VoidCallback action) 43 | { 44 | bind(method, [action](const Request&) { 45 | action(); 46 | return Response{"\"OK\""}; 47 | }); 48 | } 49 | 50 | void Receiver::connect(const std::string& method, NotifyCallback action) 51 | { 52 | bind(method, [action](const Request& request) { 53 | action(request); 54 | return Response{"\"OK\""}; 55 | }); 56 | } 57 | 58 | void Receiver::bind(const std::string& method, ResponseCallback action) 59 | { 60 | static_cast(_impl.get())->registerMethod(method, action); 61 | } 62 | 63 | std::string Receiver::process(const Request& request) 64 | { 65 | std::string result; 66 | _impl->process(request, [&result](std::string result_) { 67 | result = std::move(result_); 68 | }); 69 | return result; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /rockets/jsonrpc/receiverImpl.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "requestProcessor.h" 23 | #include "utils.h" 24 | 25 | namespace rockets 26 | { 27 | namespace jsonrpc 28 | { 29 | class ReceiverImpl : public RequestProcessor 30 | { 31 | public: 32 | void registerMethod(const std::string& method, ResponseCallback action) 33 | { 34 | verifyValidMethodName(method); 35 | _methods[method] = action; 36 | } 37 | 38 | bool isRegisteredMethodName(const std::string& method) const override 39 | { 40 | return _methods.find(method) != _methods.end(); 41 | } 42 | 43 | void process(const json& requestID, const std::string& method, 44 | const Request& request, JsonResponseCallback respond) override 45 | { 46 | auto response = _methods[method](request); 47 | if (requestID.is_null()) 48 | respond(json()); 49 | else 50 | respond(makeResponse(response, requestID)); 51 | } 52 | 53 | private: 54 | std::map _methods; 55 | }; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /rockets/jsonrpc/requestProcessor.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_JSONRPC_REQUEST_PROCESSOR_H 21 | #define ROCKETS_JSONRPC_REQUEST_PROCESSOR_H 22 | 23 | #include 24 | 25 | #include "../json.hpp" 26 | 27 | namespace rockets 28 | { 29 | namespace jsonrpc 30 | { 31 | /** 32 | * JSON-RPC 2.0 request processor. 33 | * 34 | * See specification: http://www.jsonrpc.org/specification 35 | * 36 | * This class is designed to be used internally by the Receiver or AsyncReceiver 37 | * to handle processing of JSON-RPC messages, by using a JSON library which is 38 | * not meant to be exposed to the public interface. 39 | */ 40 | class RequestProcessor 41 | { 42 | public: 43 | virtual ~RequestProcessor() = default; 44 | 45 | /** 46 | * Process a JSON-RPC request asynchronously. 47 | * 48 | * @param request Request object with message in JSON-RPC 2.0 format. 49 | * @param callback that return a json response string in JSON-RPC 2.0 50 | * format upon request completion. 51 | */ 52 | void process(const Request& request, AsyncStringResponse callback); 53 | 54 | /** Check if given method name is valid, throws otherwise. */ 55 | virtual void verifyValidMethodName(const std::string& method) const; 56 | 57 | protected: 58 | using json = rockets_nlohmann::json; 59 | using JsonResponseCallback = std::function; 60 | 61 | private: 62 | /** 63 | * Implements the processing of a valid JSON-RPC request. The minimum this 64 | * processing needs to do is to respond() the result of the request. 65 | * 66 | * @param requestID 'id' field of the JSON-RPC request 67 | * @param method 'method' field of the JSON-RPC request 68 | * @param request 'params' field of the JSON-RPC request and the client ID 69 | * @param respond callback for responding JSON result of request processing 70 | */ 71 | virtual void process(const json& requestID, const std::string& method, 72 | const Request& request, 73 | JsonResponseCallback respond) = 0; 74 | 75 | /** 76 | * @return true if the given method name is valid to continue calling 77 | * _process(), false otherwise 78 | */ 79 | virtual bool isRegisteredMethodName(const std::string&) const = 0; 80 | 81 | std::string _processBatchBlocking(const json& array, uintptr_t clientID); 82 | 83 | json _processValidBatchBlocking(const json& array, 84 | const uintptr_t clientID); 85 | json _processCommandBlocking(const json& request, const uintptr_t clientID); 86 | void _processCommand(const json& request, const uintptr_t clientID, 87 | JsonResponseCallback respond); 88 | }; 89 | } 90 | } 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /rockets/jsonrpc/response.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Daniel.Nachbaur@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_JSONRPC_RESPONSE_H 21 | #define ROCKETS_JSONRPC_RESPONSE_H 22 | 23 | #include 24 | 25 | #include 26 | 27 | namespace rockets 28 | { 29 | namespace jsonrpc 30 | { 31 | /** 32 | * Response to a well-formed RPC request. 33 | */ 34 | struct Response 35 | { 36 | std::string result; // JSON encoded 37 | 38 | struct Error 39 | { 40 | std::string message; // short text description of the error 41 | int code = 0; 42 | std::string data{}; 43 | } error; 44 | 45 | /** 46 | * Construct a successful response. 47 | * @param res The result of the request in JSON format. 48 | */ 49 | Response(std::string&& res) 50 | : result{std::move(res)} 51 | { 52 | } 53 | 54 | /** 55 | * Construct an error response. 56 | * @param err The error that occured during the request. 57 | */ 58 | Response(Error&& err) 59 | : error(std::move(err)) 60 | { 61 | } 62 | 63 | bool isError() const { return error.code != 0; } 64 | static Response invalidParams() 65 | { 66 | return Response{Error{"Invalid params", ErrorCode::invalid_params}}; 67 | } 68 | }; 69 | } 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /rockets/jsonrpc/responseError.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018, EPFL/Blue Brain Project 2 | * Daniel.Nachbaur@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_RESPONSEERROR_H 21 | #define ROCKETS_RESPONSEERROR_H 22 | 23 | #include 24 | #include 25 | 26 | namespace rockets 27 | { 28 | namespace jsonrpc 29 | { 30 | class response_error : public std::runtime_error 31 | { 32 | public: 33 | response_error(const std::string& what, const int code_) 34 | : std::runtime_error(what) 35 | , code(code_) 36 | { 37 | } 38 | 39 | explicit response_error(const Response::Error& error) 40 | : std::runtime_error(error.message) 41 | , code(error.code) 42 | , data(error.data) 43 | { 44 | } 45 | 46 | const int code; 47 | const std::string data; 48 | }; 49 | } 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /rockets/jsonrpc/server.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_JSONRPC_SERVER_H 21 | #define ROCKETS_JSONRPC_SERVER_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | namespace rockets 28 | { 29 | namespace jsonrpc 30 | { 31 | /** 32 | * JSON-RPC server. 33 | * 34 | * The server can be used over any communication channel that provides the 35 | * following methods: 36 | * 37 | * - void broadcastText(std::string message); 38 | * Used for sending notifications to connected clients. 39 | * 40 | * - void handleText(ws::MessageCallback callback); 41 | * Used to register a callback for processing the requests and notifications 42 | * coming from the client(s). 43 | */ 44 | template 45 | class Server : public Notifier, public CancellableReceiver 46 | { 47 | public: 48 | Server(CommunicatorT& server) 49 | : CancellableReceiver([&server](std::string json, uintptr_t client) { 50 | server.sendText(std::move(json), client); 51 | }) 52 | , communicator{server} 53 | { 54 | communicator.handleText( 55 | [this](ws::Request request, ws::ResponseCallback callback) { 56 | process(std::move(request), callback); 57 | }); 58 | } 59 | 60 | private: 61 | /** Notifier::_send */ 62 | void _send(std::string json) final 63 | { 64 | communicator.broadcastText(std::move(json)); 65 | } 66 | 67 | CommunicatorT& communicator; 68 | }; 69 | } 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /rockets/jsonrpc/types.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_JSONRPC_TYPES_H 21 | #define ROCKETS_JSONRPC_TYPES_H 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | namespace rockets 30 | { 31 | namespace jsonrpc 32 | { 33 | using ws::Request; 34 | 35 | class RequestProcessor; 36 | 37 | /** @name Asynchronous response to a request. */ 38 | //@{ 39 | using AsyncResponse = std::function; 40 | using AsyncStringResponse = std::function; 41 | //@} 42 | 43 | /** @name Callbacks that can be registered. */ 44 | //@{ 45 | using VoidCallback = std::function; 46 | using NotifyCallback = std::function; 47 | using ResponseCallback = std::function; 48 | using CancelRequestCallback = std::function; 49 | using ProgressUpdateCallback = std::function; 50 | using DelayedResponseCallback = std::function; 51 | using CancellableResponseCallback = 52 | std::function; 54 | //@} 55 | 56 | using SendTextCallback = std::function; 57 | } 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /rockets/jsonrpc/utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_JSONRPC_UTILS_H 21 | #define ROCKETS_JSONRPC_UTILS_H 22 | 23 | #include 24 | 25 | #include "../json.hpp" 26 | 27 | namespace rockets 28 | { 29 | namespace jsonrpc 30 | { 31 | const std::string jsonResponseParseError = 32 | "Server response is not a valid json string"; 33 | 34 | const Response::Error internalError{"Internal error", 35 | ErrorCode::internal_error}; 36 | 37 | using json = rockets_nlohmann::json; 38 | 39 | inline json makeErrorResponse(const json& error, const json& id) 40 | { 41 | return json{{"jsonrpc", "2.0"}, {"error", error}, {"id", id}}; 42 | } 43 | 44 | inline json makeErrorResponse(const Response::Error& error, 45 | const json& id = json()) 46 | { 47 | json jsonError{{"code", error.code}, {"message", error.message}}; 48 | if (!error.data.empty()) 49 | jsonError["data"] = json::parse(error.data); 50 | return makeErrorResponse(jsonError, id); 51 | } 52 | 53 | inline json makeErrorResponse(const Response::Error& error, const json& id, 54 | const json& data) 55 | { 56 | return makeErrorResponse(json{{"code", error.code}, 57 | {"message", error.message}, 58 | {"data", data}}, 59 | id); 60 | } 61 | 62 | inline json makeResponse(const json& result, const json& id) 63 | { 64 | return json{{"jsonrpc", "2.0"}, {"result", result}, {"id", id}}; 65 | } 66 | 67 | inline json makeResponse(const std::string& resultJson, const json& id) 68 | { 69 | try 70 | { 71 | return makeResponse(json::parse(resultJson), id); 72 | } 73 | catch (const json::parse_error&) 74 | { 75 | return makeErrorResponse(internalError, id, jsonResponseParseError); 76 | } 77 | } 78 | 79 | inline json makeResponse(const Response& rep, const json& id) 80 | { 81 | return rep.isError() ? makeErrorResponse(rep.error, id) 82 | : makeResponse(rep.result, id); 83 | } 84 | 85 | inline bool begins_with(const std::string& string, const std::string& other) 86 | { 87 | return string.compare(0, other.length(), other) == 0; 88 | } 89 | } 90 | } 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /rockets/log.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "proxyConnectionError.h" 21 | #include "unavailablePortError.h" 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | namespace rockets 29 | { 30 | namespace 31 | { 32 | const std::string proxyError = "ERROR proxy: HTTP/1.1 503 \n"; 33 | #if LWS_LIBRARY_VERSION_NUMBER >= 3000000 34 | const char portError[] = "ERROR on binding fd "; 35 | #endif 36 | 37 | void handleErrorMessage(int, const char* message) 38 | { 39 | #if PROXY_CONNECTION_ERROR_THROWS 40 | if (message == proxyError) 41 | throw proxy_connection_error(message); 42 | #endif 43 | 44 | #if LWS_LIBRARY_VERSION_NUMBER >= 3000000 45 | // Occurs during lws_create_vhost() if the chosen port is unavailable. 46 | // The returned vhost is valid(!) so the error can only be caught here. 47 | if (strncmp(message, portError, sizeof(portError) - 1) == 0) 48 | throw unavailable_port_error(message); 49 | #endif 50 | 51 | #ifdef NDEBUG 52 | (void)message; 53 | #else 54 | std::cerr << "rockets: lws_err: " << message; // ends with \n 55 | #endif 56 | } 57 | struct LogInitializer 58 | { 59 | LogInitializer() { lws_set_log_level(LLL_ERR, handleErrorMessage); } 60 | }; 61 | static LogInitializer silencer; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /rockets/pollDescriptors.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "pollDescriptors.h" 21 | 22 | #include "socketListener.h" 23 | 24 | namespace rockets 25 | { 26 | void PollDescriptors::add(const lws_pollargs* pa) 27 | { 28 | const auto fd = pa->fd; 29 | if (pollDescriptors.count(fd)) 30 | return; 31 | 32 | pollDescriptors[fd].fd = fd; 33 | pollDescriptors[fd].events = pa->events; 34 | pollDescriptors[fd].revents = pa->prev_events; 35 | if (_listener) 36 | _listener->onNewSocket(fd, pa->events); 37 | } 38 | 39 | void PollDescriptors::update(const lws_pollargs* pa) 40 | { 41 | const auto fd = pa->fd; 42 | if (!pollDescriptors.count(fd)) 43 | return; 44 | 45 | pollDescriptors[fd].events = pa->events; 46 | pollDescriptors[fd].revents = pa->prev_events; 47 | if (_listener) 48 | _listener->onUpdateSocket(fd, pa->events); 49 | } 50 | 51 | void PollDescriptors::remove(const lws_pollargs* pa) 52 | { 53 | const auto fd = pa->fd; 54 | if (!pollDescriptors.count(fd)) 55 | return; 56 | 57 | if (_listener) 58 | _listener->onDeleteSocket(fd); 59 | pollDescriptors.erase(fd); 60 | } 61 | 62 | void PollDescriptors::setListener(SocketListener* listener) 63 | { 64 | _listener = listener; 65 | if (_listener) 66 | { 67 | for (const auto& fd : pollDescriptors) 68 | _listener->onNewSocket(fd.first, fd.second.events); 69 | } 70 | } 71 | 72 | void PollDescriptors::service(lws_context* context, const int fd, 73 | const int events) 74 | { 75 | const auto socket = pollDescriptors.find(fd); 76 | if (socket == pollDescriptors.end()) 77 | return; 78 | 79 | socket->second.revents = events; 80 | lws_service_fd(context, &socket->second); 81 | 82 | #if LWS_LIBRARY_VERSION_NUMBER >= 2001000 83 | // if needed, force-service wsis that may not have read all input 84 | while (!lws_service_adjust_timeout(context, 1, 0)) 85 | lws_service_tsi(context, -1, 0); 86 | #endif 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /rockets/pollDescriptors.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_POLLDESCRIPTORS_H 21 | #define ROCKETS_POLLDESCRIPTORS_H 22 | 23 | #include "types.h" 24 | 25 | #include 26 | #include 27 | 28 | namespace rockets 29 | { 30 | /** 31 | * Poll descriptors for integration of server and client in external poll array. 32 | */ 33 | class PollDescriptors 34 | { 35 | public: 36 | void add(const lws_pollargs* pa); 37 | void update(const lws_pollargs* pa); 38 | void remove(const lws_pollargs* pa); 39 | 40 | void setListener(SocketListener* listener); 41 | 42 | void service(lws_context* context, lws_sockfd_type fd, int events); 43 | 44 | private: 45 | std::map pollDescriptors; 46 | SocketListener* _listener = nullptr; 47 | }; 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /rockets/proxyConnectionError.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_PROXYCONNECTIONERROR_H 21 | #define ROCKETS_PROXYCONNECTIONERROR_H 22 | 23 | #include 24 | 25 | #include 26 | 27 | // WAR: older versions of libwebsockets did not call 28 | // LWS_CALLBACK_CLIENT_CONNECTION_ERROR on proxy connection error. 29 | // To avoid that the client waits endlessly for the connection future to be 30 | // ready, a proxy_connection_error is thrown from the log handler. 31 | 32 | #define PROXY_CONNECTION_ERROR_THROWS (LWS_LIBRARY_VERSION_NUMBER < 2004000) 33 | 34 | namespace rockets 35 | { 36 | class proxy_connection_error : public std::runtime_error 37 | { 38 | using runtime_error::runtime_error; 39 | }; 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /rockets/qt/readWriteSocketNotifier.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_QT_READWRITESOCKETNOTIFIER_H 21 | #define ROCKETS_QT_READWRITESOCKETNOTIFIER_H 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | namespace rockets 31 | { 32 | namespace qt 33 | { 34 | /** 35 | * Notifier to monitor read+write activity on a socket as part of a QEventLoop. 36 | */ 37 | class ReadWriteSocketNotifier 38 | { 39 | public: 40 | ReadWriteSocketNotifier(const SocketDescriptor fd) 41 | : read{new QSocketNotifier{fd, QSocketNotifier::Read}} 42 | , write{new QSocketNotifier{fd, QSocketNotifier::Write}} 43 | { 44 | } 45 | 46 | ~ReadWriteSocketNotifier() 47 | { 48 | read->setEnabled(false); 49 | read->deleteLater(); 50 | write->setEnabled(false); 51 | write->deleteLater(); 52 | } 53 | 54 | void enable(const int mode) 55 | { 56 | read->setEnabled(mode & POLLIN); 57 | write->setEnabled(mode & POLLOUT); 58 | } 59 | 60 | void onReadReady(std::function callback) 61 | { 62 | QObject::connect(read, &QSocketNotifier::activated, callback); 63 | } 64 | 65 | void onWriteReady(std::function callback) 66 | { 67 | QObject::connect(write, &QSocketNotifier::activated, callback); 68 | } 69 | 70 | private: 71 | QSocketNotifier* read = nullptr; 72 | QSocketNotifier* write = nullptr; 73 | }; 74 | } 75 | } 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /rockets/qt/socketProcessor.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_QT_SOCKETPROCESSOR_H 21 | #define ROCKETS_QT_SOCKETPROCESSOR_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | namespace rockets 30 | { 31 | namespace qt 32 | { 33 | /** 34 | * Helper class to process any SocketBasedInterface as part of a QEventLoop. 35 | */ 36 | class SocketProcessor : public SocketListener 37 | { 38 | public: 39 | SocketProcessor(SocketBasedInterface& interface) 40 | : iface{interface} 41 | { 42 | } 43 | 44 | void onNewSocket(const SocketDescriptor fd, const int mode) final 45 | { 46 | notifiers.emplace(fd, fd); 47 | auto& notifier = notifiers.at(fd); 48 | notifier.enable(mode); 49 | notifier.onReadReady([this, fd] { iface.processSocket(fd, POLLIN); }); 50 | notifier.onWriteReady([this, fd] { iface.processSocket(fd, POLLOUT); }); 51 | } 52 | 53 | void onUpdateSocket(const SocketDescriptor fd, const int mode) final 54 | { 55 | notifiers.at(fd).enable(mode); 56 | } 57 | 58 | void onDeleteSocket(const SocketDescriptor fd) final 59 | { 60 | notifiers.erase(fd); 61 | } 62 | 63 | private: 64 | SocketBasedInterface& iface; 65 | std::map notifiers; 66 | }; 67 | } 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /rockets/serverContext.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_SERVERCONTEXT_H 21 | #define ROCKETS_SERVERCONTEXT_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | namespace rockets 35 | { 36 | /** 37 | * Server context for http and websockets protocols. 38 | */ 39 | class ServerContext 40 | { 41 | public: 42 | ServerContext(const std::string& uri, const std::string& name, 43 | const unsigned int threadCount, 44 | lws_callback_function* callback, 45 | lws_callback_function* wsCallback, void* user, 46 | void* uvLoop = nullptr); 47 | 48 | std::string getHostname() const; 49 | uint16_t getPort() const; 50 | int getThreadCount() const; 51 | 52 | void requestBroadcast(); 53 | 54 | bool service(int tsi, int timeout_ms); 55 | void service(int timeout_ms); 56 | void service(PollDescriptors& pollDescriptors, SocketDescriptor fd, 57 | int events); 58 | void cancelService(); 59 | 60 | private: 61 | std::string interface; 62 | lws_context_creation_info info; 63 | std::vector protocols; 64 | std::string wsProtocolName; 65 | LwsContextPtr context; 66 | 67 | void fillContextInfo(const std::string& uri, 68 | const unsigned int threadCount); 69 | void createWebsocketsProtocol(lws_callback_function* wsCallback, 70 | void* user); 71 | }; 72 | } 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /rockets/serviceThreadPool.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "serviceThreadPool.h" 21 | 22 | #ifdef __linux__ 23 | #include 24 | #endif 25 | 26 | namespace 27 | { 28 | const auto serviceTimeoutMs = 50; 29 | 30 | void setThreadName(const std::string& name) 31 | { 32 | #ifdef __APPLE__ 33 | pthread_setname_np(name.c_str()); 34 | #elif defined(__linux__) 35 | prctl(PR_SET_NAME, name.c_str(), 0, 0, 0); 36 | #endif 37 | } 38 | } 39 | 40 | namespace rockets 41 | { 42 | ServiceThreadPool::ServiceThreadPool(ServerContext& context_) 43 | : context(context_) 44 | , broadcastRequested{new std::atomic_bool[context.getThreadCount()]} 45 | { 46 | start(); 47 | } 48 | 49 | ServiceThreadPool::~ServiceThreadPool() 50 | { 51 | stop(); 52 | } 53 | 54 | size_t ServiceThreadPool::getSize() const 55 | { 56 | return serviceThreads.size(); 57 | } 58 | 59 | void ServiceThreadPool::requestBroadcast() 60 | { 61 | for (size_t tsi = 0; tsi < getSize(); ++tsi) 62 | broadcastRequested[tsi] = true; 63 | } 64 | 65 | void ServiceThreadPool::handleBroadcastRequest(const int tsi) 66 | { 67 | if (broadcastRequested[tsi]) 68 | { 69 | context.requestBroadcast(); 70 | broadcastRequested[tsi] = false; 71 | } 72 | } 73 | 74 | void ServiceThreadPool::start() 75 | { 76 | for (int tsi = 0; tsi < context.getThreadCount(); ++tsi) 77 | { 78 | const auto name = "rockets_" + std::to_string(tsi); 79 | serviceThreads.emplace_back(std::thread([this, tsi, name]() { 80 | setThreadName(name); 81 | while (context.service(tsi, serviceTimeoutMs) && !exitService) 82 | handleBroadcastRequest(tsi); 83 | })); 84 | } 85 | } 86 | 87 | void ServiceThreadPool::stop() 88 | { 89 | exitService = true; 90 | context.cancelService(); 91 | for (auto& thread : serviceThreads) 92 | thread.join(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /rockets/serviceThreadPool.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_SERVICETHREADPOOL_H 21 | #define ROCKETS_SERVICETHREADPOOL_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | namespace rockets 30 | { 31 | /** 32 | * Service thread pool for the server. 33 | */ 34 | class ServiceThreadPool 35 | { 36 | public: 37 | ServiceThreadPool(ServerContext& context); 38 | ~ServiceThreadPool(); 39 | 40 | size_t getSize() const; 41 | void requestBroadcast(); 42 | 43 | private: 44 | ServerContext& context; 45 | std::vector serviceThreads; 46 | std::unique_ptr broadcastRequested; 47 | std::atomic_bool exitService{false}; 48 | 49 | void handleBroadcastRequest(int tsi); 50 | 51 | void start(); 52 | void stop(); 53 | }; 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /rockets/socketBasedInterface.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_SOCKETBASEDINTERFACE_H 21 | #define ROCKETS_SOCKETBASEDINTERFACE_H 22 | 23 | #include 24 | #include 25 | 26 | namespace rockets 27 | { 28 | /** 29 | * Base class for all socket-based interfaces (clients and server). 30 | */ 31 | class SocketBasedInterface 32 | { 33 | public: 34 | ROCKETS_API virtual ~SocketBasedInterface() = default; 35 | 36 | /** 37 | * Set a listener for integrating the server in an external poll array. 38 | * 39 | * @param listener to set, nullptr to remove. 40 | * @sa processSocket 41 | */ 42 | ROCKETS_API void setSocketListener(SocketListener* listener) 43 | { 44 | _setSocketListener(listener); 45 | } 46 | 47 | /** 48 | * Process pending data on a given socket. 49 | * 50 | * @param fd socket with data to process. 51 | * @param events to process, must be POLLIN | POLLOUT according to return 52 | * value of poll() operation for the fd. 53 | * @sa setSocketListener 54 | */ 55 | ROCKETS_API void processSocket(const SocketDescriptor fd, const int events) 56 | { 57 | _processSocket(fd, events); 58 | } 59 | 60 | /** 61 | * Process all sockets using the internal poll array. 62 | * 63 | * @param timeout_ms maximum time allowed before returning. 64 | */ 65 | ROCKETS_API void process(int timeout_ms) { _process(timeout_ms); } 66 | private: 67 | virtual void _setSocketListener(SocketListener* listener) = 0; 68 | virtual void _processSocket(SocketDescriptor fd, int events) = 0; 69 | virtual void _process(int timeout_ms) = 0; 70 | }; 71 | } 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /rockets/socketListener.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_SOCKETLISTENER_H 21 | #define ROCKETS_SOCKETLISTENER_H 22 | 23 | #include 24 | #include 25 | 26 | namespace rockets 27 | { 28 | /** 29 | * File descriptor listener for integration in external poll array. 30 | */ 31 | class SocketListener 32 | { 33 | public: 34 | ROCKETS_API virtual ~SocketListener() {} 35 | /** 36 | * Called when a new socket opens for a client connection. 37 | * 38 | * Call process(fd) when new data is available on the socket. 39 | * 40 | * @param fd socket descriptor for polling the connection. 41 | * @param events to poll() for, can be POLLIN | POLLOUT. 42 | * @sa onDeleteSocket 43 | */ 44 | virtual void onNewSocket(SocketDescriptor fd, int events) = 0; 45 | 46 | /** 47 | * Called when the events to poll for have changed for a socket. 48 | * 49 | * @param fd socket descriptor for which to update polling events. 50 | * @param events to poll() for, can be POLLIN | POLLOUT. 51 | */ 52 | virtual void onUpdateSocket(SocketDescriptor fd, int events) = 0; 53 | 54 | /** 55 | * Called when a client connection closes. 56 | * 57 | * @param fd socket descriptor to deregister. 58 | * @sa onNewSocket 59 | */ 60 | virtual void onDeleteSocket(SocketDescriptor fd) = 0; 61 | }; 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /rockets/types.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_TYPES_H 21 | #define ROCKETS_TYPES_H 22 | 23 | #include 24 | #include 25 | 26 | namespace rockets 27 | { 28 | class Server; 29 | class SocketListener; 30 | 31 | #ifdef WIN32 32 | typedef SOCKET SocketDescriptor; 33 | #else 34 | typedef int SocketDescriptor; 35 | #endif 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /rockets/unavailablePortError.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_UNAVAILABLEPORTERROR_H 21 | #define ROCKETS_UNAVAILABLEPORTERROR_H 22 | 23 | #include 24 | 25 | namespace rockets 26 | { 27 | class unavailable_port_error : public std::runtime_error 28 | { 29 | using runtime_error::runtime_error; 30 | }; 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /rockets/utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_UTILS_H 21 | #define ROCKETS_UTILS_H 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | namespace rockets 29 | { 30 | struct Uri 31 | { 32 | std::string protocol; 33 | std::string host; 34 | uint16_t port; 35 | std::string path; 36 | }; 37 | Uri parse(const std::string& uri); 38 | 39 | lws_protocols make_protocol(const char* name, lws_callback_function* callback, 40 | void* user); 41 | lws_protocols null_protocol(); 42 | 43 | std::string getIP(const std::string& iface); 44 | std::string getInterface(const std::string& hostnameOrIP); 45 | 46 | std::string getHostname(); 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /rockets/wrappers.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_WRAPPERS_H 21 | #define ROCKETS_WRAPPERS_H 22 | 23 | #include 24 | 25 | #include 26 | 27 | namespace rockets 28 | { 29 | struct LwsContextDeleter 30 | { 31 | void operator()(lws_context* context) { lws_context_destroy(context); } 32 | }; 33 | using LwsContextPtr = std::unique_ptr; 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /rockets/ws/channel.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "channel.h" 21 | 22 | namespace rockets 23 | { 24 | namespace ws 25 | { 26 | namespace 27 | { 28 | lws_write_protocol _getProtocol(const Format format) 29 | { 30 | return format == Format::text ? LWS_WRITE_TEXT : LWS_WRITE_BINARY; 31 | } 32 | } 33 | 34 | Channel::Channel(lws* wsi_) 35 | : wsi{wsi_} 36 | { 37 | } 38 | 39 | Format Channel::getCurrentMessageFormat() const 40 | { 41 | return lws_frame_is_binary(wsi) ? Format::binary : Format::text; 42 | } 43 | 44 | void Channel::requestWrite() 45 | { 46 | lws_callback_on_writable(wsi); 47 | } 48 | 49 | bool Channel::canWrite() const 50 | { 51 | return !lws_send_pipe_choked(wsi); 52 | } 53 | 54 | bool Channel::currentMessageHasMore() const 55 | { 56 | return !lws_is_final_fragment(wsi); 57 | } 58 | 59 | size_t Channel::getCurrentMessageRemainingSize() const 60 | { 61 | return lws_remaining_packet_payload(wsi); 62 | } 63 | 64 | void Channel::write(std::string&& message, const Format format) 65 | { 66 | const auto size = message.size(); 67 | message.insert(0, LWS_PRE, '0'); 68 | auto data = (unsigned char*)(&message.data()[LWS_PRE]); 69 | const auto protocol = _getProtocol(format); 70 | lws_write(wsi, data, size, protocol); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /rockets/ws/channel.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_WS_CHANNEL_H 21 | #define ROCKETS_WS_CHANNEL_H 22 | 23 | #include 24 | 25 | #include 26 | 27 | namespace rockets 28 | { 29 | namespace ws 30 | { 31 | /** 32 | * A WebSocket communication channel. 33 | * 34 | * Wraps libwebsockets read/write methods for use on both Client and Server. 35 | */ 36 | class Channel 37 | { 38 | public: 39 | explicit Channel(lws* wsi); 40 | 41 | Format getCurrentMessageFormat() const; 42 | bool currentMessageHasMore() const; 43 | size_t getCurrentMessageRemainingSize() const; 44 | 45 | void requestWrite(); 46 | bool canWrite() const; 47 | void write(std::string&& message, Format format); 48 | 49 | private: 50 | lws* wsi = nullptr; 51 | }; 52 | } 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /rockets/ws/client.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_WS_CLIENT_H 21 | #define ROCKETS_WS_CLIENT_H 22 | 23 | #include 24 | #include 25 | 26 | namespace rockets 27 | { 28 | namespace ws 29 | { 30 | /** 31 | * Websocket client. 32 | */ 33 | class Client : public SocketBasedInterface 34 | { 35 | public: 36 | /** @name Setup */ 37 | //@{ 38 | /** Construct a new client. */ 39 | ROCKETS_API Client(); 40 | 41 | /** Close the client. */ 42 | ROCKETS_API ~Client(); 43 | 44 | /** 45 | * Connect to a websockets server. 46 | * 47 | * @param uri "hostname:port" to connect to. 48 | * @param protocol to use. 49 | * @return future that becomes ready when the connection is established - 50 | * can be a std::runtime_error if the connection fails. 51 | */ 52 | ROCKETS_API std::future connect(const std::string& uri, 53 | const std::string& protocol); 54 | //@} 55 | 56 | /** Send a text message to the websocket server. */ 57 | ROCKETS_API void sendText(std::string message); 58 | 59 | /** Send a binary message to the websocket server. */ 60 | ROCKETS_API void sendBinary(const char* data, size_t size); 61 | 62 | /** Set a callback for handling text messages from the server. */ 63 | ROCKETS_API void handleText(MessageCallback callback); 64 | 65 | /** Set a callback for handling binray messages from the server. */ 66 | ROCKETS_API void handleBinary(MessageCallback callback); 67 | 68 | class Impl; // must be public for static_cast from C callback 69 | private: 70 | std::unique_ptr _impl; 71 | 72 | void _setSocketListener(SocketListener* listener) final; 73 | void _processSocket(SocketDescriptor fd, int events) final; 74 | void _process(int timeout_ms) final; 75 | }; 76 | } 77 | } 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /rockets/ws/connection.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "connection.h" 21 | 22 | #include "channel.h" 23 | 24 | namespace rockets 25 | { 26 | namespace ws 27 | { 28 | Connection::Connection(std::unique_ptr channel_) 29 | : channel{std::move(channel_)} 30 | { 31 | } 32 | 33 | void Connection::sendText(std::string message) 34 | { 35 | enqueueText(std::move(message)); 36 | channel->requestWrite(); 37 | } 38 | 39 | void Connection::sendBinary(std::string message) 40 | { 41 | enqueueBinary(std::move(message)); 42 | channel->requestWrite(); 43 | } 44 | 45 | void Connection::writeMessages() 46 | { 47 | while (hasMessage() && channel->canWrite()) 48 | writeOneMessage(); 49 | 50 | if (hasMessage()) 51 | channel->requestWrite(); 52 | } 53 | 54 | void Connection::enqueueText(std::string message) 55 | { 56 | out.emplace_back(std::move(message), Format::text); 57 | } 58 | 59 | void Connection::enqueueBinary(std::string message) 60 | { 61 | out.emplace_back(std::move(message), Format::binary); 62 | } 63 | 64 | const Channel& Connection::getChannel() const 65 | { 66 | return *channel; 67 | } 68 | 69 | bool Connection::hasMessage() const 70 | { 71 | return !out.empty(); 72 | } 73 | 74 | void Connection::writeOneMessage() 75 | { 76 | auto& message = out.at(0); 77 | channel->write(std::move(message.first), message.second); 78 | out.pop_front(); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /rockets/ws/connection.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_WS_CONNECTION_H 21 | #define ROCKETS_WS_CONNECTION_H 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | namespace rockets 29 | { 30 | namespace ws 31 | { 32 | class Channel; 33 | 34 | /** 35 | * A WebSocket connection. 36 | */ 37 | class Connection 38 | { 39 | public: 40 | explicit Connection(std::unique_ptr channel); 41 | 42 | /** Send a text message (will be queued for later processing). */ 43 | void sendText(std::string message); 44 | 45 | /** Send a binary message (will be queued for later processing). */ 46 | void sendBinary(std::string message); 47 | 48 | /** Write all pending messages. */ 49 | void writeMessages(); 50 | 51 | /** Enqueue a text message. */ 52 | void enqueueText(std::string message); 53 | 54 | /** Enqueue a binary message. */ 55 | void enqueueBinary(std::string message); 56 | 57 | /** @internal*. */ 58 | const Channel& getChannel() const; 59 | 60 | private: 61 | std::unique_ptr channel; 62 | std::deque> out; 63 | 64 | bool hasMessage() const; 65 | void writeOneMessage(); 66 | }; 67 | } 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /rockets/ws/messageHandler.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_WS_MESSAGEHANDLER_H 21 | #define ROCKETS_WS_MESSAGEHANDLER_H 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | namespace rockets 29 | { 30 | namespace ws 31 | { 32 | using Connections = std::map; 33 | 34 | /** 35 | * Handle message callbacks for text/binary messages. 36 | */ 37 | class MessageHandler 38 | { 39 | public: 40 | MessageHandler() = default; 41 | MessageHandler(const Connections& connections); 42 | 43 | /** 44 | * Handle a new connection. 45 | * 46 | * @param connection the connection to use for reply. 47 | */ 48 | void handleOpenConnection(ConnectionPtr connection); 49 | 50 | /** 51 | * Handle close of a connection. 52 | * 53 | * @param connection the connection to use for reply. 54 | */ 55 | void handleCloseConnection(ConnectionPtr connection); 56 | 57 | /** 58 | * Handle an incomming message for the given connection. 59 | * 60 | * @param connection the connection to use for reply. 61 | * @param data the incoming data pointer. 62 | * @param len the length of the data. 63 | */ 64 | void handleMessage(ConnectionPtr connection, const char* data, size_t len); 65 | 66 | /** The callback for incoming connections. */ 67 | ConnectionCallback callbackOpen; 68 | 69 | /** The callback for closing connections. */ 70 | ConnectionCallback callbackClose; 71 | 72 | /** The callback for messages in text format. */ 73 | MessageCallback callbackText; 74 | 75 | /** The callback for messages in text format with async response. */ 76 | MessageCallbackAsync callbackTextAsync; 77 | 78 | /** The callback for messages in binary format. */ 79 | MessageCallback callbackBinary; 80 | 81 | private: 82 | void _sendResponseToRecipient(const Response& response, 83 | ConnectionPtr connection); 84 | 85 | static Connections _emptyConnections; 86 | const Connections& _connections{_emptyConnections}; 87 | std::string _buffer; 88 | }; 89 | } 90 | } 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /rockets/ws/types.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef ROCKETS_WS_TYPES_H 21 | #define ROCKETS_WS_TYPES_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace rockets 29 | { 30 | namespace ws 31 | { 32 | class Connection; 33 | using ConnectionPtr = std::shared_ptr; 34 | 35 | /** 36 | * The possible websocket message formats. 37 | */ 38 | enum class Format 39 | { 40 | text, 41 | binary, 42 | unspecified 43 | }; 44 | 45 | /** 46 | * The different types of recipients for a response. 47 | */ 48 | enum class Recipient 49 | { 50 | sender, 51 | others, 52 | all 53 | }; 54 | 55 | /** 56 | * A request from a client during handleText()/handleBinary(). 57 | */ 58 | struct Request 59 | { 60 | Request(const std::string& message_, const uintptr_t clientID_ = 0) 61 | : message(message_) 62 | , clientID(clientID_) 63 | { 64 | } 65 | 66 | Request(std::string&& message_, const uintptr_t clientID_ = 0) 67 | : message(std::move(message_)) 68 | , clientID(clientID_) 69 | { 70 | } 71 | 72 | std::string message; 73 | const uintptr_t clientID; 74 | }; 75 | 76 | /** 77 | * A response to an incoming request. 78 | */ 79 | struct Response 80 | { 81 | Response() = default; 82 | 83 | Response(const char* message_) 84 | : message(message_) 85 | { 86 | } 87 | 88 | Response(const std::string& message_, 89 | const Recipient recipient_ = Recipient::sender, 90 | const Format format_ = Format::unspecified) 91 | : message(message_) 92 | , recipient(recipient_) 93 | , format(format_) 94 | { 95 | } 96 | 97 | std::string message; 98 | Recipient recipient = Recipient::sender; 99 | Format format = Format::unspecified; // derive from request format 100 | }; 101 | 102 | /** Callback for asynchronously responding to a message. */ 103 | using ResponseCallback = std::function; 104 | 105 | /** WebSocket callback for handling requests of text / binary messages. */ 106 | using MessageCallback = std::function; 107 | 108 | /** Callback for handling request with delayed response. */ 109 | using MessageCallbackAsync = std::function; 110 | 111 | /** Websocket callback for handling connection (open/close) messages. */ 112 | using ConnectionCallback = std::function(uintptr_t)>; 113 | } 114 | } 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /scripts/build_lib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | export PKG_CONFIG_PATH=$(brew --prefix openssl)/lib/pkgconfig 5 | 6 | mkdir $BUILD_TYPE 7 | cd $BUILD_TYPE 8 | 9 | cmake -GNinja \ 10 | -DCMAKE_INSTALL_PREFIX=$PWD/install \ 11 | -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ 12 | .. 13 | 14 | ninja all && \ 15 | ninja $PROJECT_NAME-tests && \ 16 | ninja install 17 | -------------------------------------------------------------------------------- /scripts/check_version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import configparser 3 | import json 4 | import sys 5 | import urllib.request 6 | 7 | config = configparser.ConfigParser() 8 | config.read("setup.cfg") 9 | to_check = config["metadata"]["version"] 10 | url = "https://pypi.python.org/pypi/rockets/json" 11 | with urllib.request.urlopen(url) as response: 12 | data = json.loads(response.read().decode("utf-8")) 13 | versions = data["releases"].keys() 14 | if to_check not in versions: 15 | print(to_check) 16 | -------------------------------------------------------------------------------- /scripts/install_requirements.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | brew update 5 | brew outdated cmake || brew upgrade cmake 6 | brew install ninja libwebsockets openssl 7 | -------------------------------------------------------------------------------- /scripts/set_npm_package_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | REMOTE_VERSION=$(npm show rockets-client version) 5 | R_VER=${REMOTE_VERSION// /} 6 | # https://gist.github.com/DarrenN/8c6a5b969481725a4413 7 | LOCAL_VERSION=$(node -p "require('./js/package.json').version") 8 | L_VER=${LOCAL_VERSION// /} 9 | 10 | echo "Remote version: ${R_VER}" 11 | echo "Local version: ${L_VER}" 12 | 13 | if [ "${R_VER}" != "${L_VER}" ]; then 14 | export ROCKETS_CLIENT_VERSION=${L_VER} 15 | echo "Set version: ${L_VER}" 16 | fi 17 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | # Raphael.Dumusc@epfl.ch 3 | # 4 | # This file is part of Rockets 5 | # 6 | # This library is free software; you can redistribute it and/or modify it under 7 | # the terms of the GNU Lesser General Public License version 3.0 as published 8 | # by the Free Software Foundation. 9 | # 10 | # This library is distributed in the hope that it will be useful, but WITHOUT 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | # details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with this library; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | if(NOT BOOST_FOUND) 20 | return() 21 | endif() 22 | 23 | if(${Libwebsockets_VERSION} VERSION_LESS 2.1.0) 24 | set(EXCLUDE_FROM_TESTS jsonRpcHttp.cpp) 25 | endif() 26 | 27 | set(TEST_LIBRARIES ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} Rockets) 28 | 29 | list(APPEND LCOV_EXCLUDE '${PROJECT_SOURCE_DIR}/rockets/json.hpp') 30 | include(CommonCTest) 31 | -------------------------------------------------------------------------------- /tests/json_utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018, EPFL/Blue Brain Project 2 | * Raphael.Dumusc@epfl.ch 3 | * 4 | * This file is part of Rockets 5 | * 6 | * This library is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU Lesser General Public License version 3.0 as published 8 | * by the Free Software Foundation. 9 | * 10 | * This library is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include 21 | 22 | /** Format a JSON string exactly as Rockets does it for string comparison. */ 23 | template 24 | std::string json_reformat(T&& json) 25 | { 26 | return rockets_nlohmann::json::parse(std::forward(json)).dump(4); 27 | } 28 | --------------------------------------------------------------------------------