From e7e529c818d6e5ee8095d3dd196b547d51514aa7 Mon Sep 17 00:00:00 2001 From: badaix Date: Sun, 1 Jul 2018 20:51:18 +0200 Subject: [PATCH] update jsonrpc++ to v1.2.0 --- server/CMakeLists.txt | 1 - server/Makefile | 2 +- server/controlServer.cpp | 2 +- server/jsonrp.cpp | 1017 ------------------------- server/jsonrp.hpp | 457 ------------ server/jsonrpcpp.hpp | 1510 ++++++++++++++++++++++++++++++++++++++ server/streamServer.cpp | 82 +-- server/streamServer.h | 2 +- 8 files changed, 1554 insertions(+), 1519 deletions(-) delete mode 100644 server/jsonrp.cpp delete mode 100644 server/jsonrp.hpp create mode 100644 server/jsonrpcpp.hpp diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index e527a68a..48b15654 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -2,7 +2,6 @@ set(SERVER_SOURCES config.cpp controlServer.cpp controlSession.cpp - jsonrp.cpp snapServer.cpp streamServer.cpp streamSession.cpp diff --git a/server/Makefile b/server/Makefile index f5b70041..48b79a7f 100644 --- a/server/Makefile +++ b/server/Makefile @@ -36,7 +36,7 @@ DEBUG=-O3 CXXFLAGS += $(ADD_CFLAGS) -std=c++0x -Wall -Wno-unused-function $(DEBUG) -DHAS_FLAC -DHAS_OGG -DHAS_VORBIS -DHAS_VORBIS_ENC -DASIO_STANDALONE -DVERSION=\"$(VERSION)\" -I. -I.. -isystem ../externals/asio/asio/include -I../externals/popl/include -I../externals/aixlog/include -I../externals -I../common LDFLAGS = $(ADD_LDFLAGS) -lvorbis -lvorbisenc -logg -lFLAC -OBJ = snapServer.o config.o controlServer.o controlSession.o jsonrp.o streamServer.o streamSession.o streamreader/streamUri.o streamreader/base64.o streamreader/streamManager.o streamreader/pcmStream.o streamreader/pipeStream.o streamreader/fileStream.o streamreader/processStream.o streamreader/airplayStream.o streamreader/spotifyStream.o streamreader/watchdog.o encoder/encoderFactory.o encoder/flacEncoder.o encoder/pcmEncoder.o encoder/oggEncoder.o ../common/sampleFormat.o +OBJ = snapServer.o config.o controlServer.o controlSession.o streamServer.o streamSession.o streamreader/streamUri.o streamreader/base64.o streamreader/streamManager.o streamreader/pcmStream.o streamreader/pipeStream.o streamreader/fileStream.o streamreader/processStream.o streamreader/airplayStream.o streamreader/spotifyStream.o streamreader/watchdog.o encoder/encoderFactory.o encoder/flacEncoder.o encoder/pcmEncoder.o encoder/oggEncoder.o ../common/sampleFormat.o ifneq (,$(TARGET)) CXXFLAGS += -D$(TARGET) diff --git a/server/controlServer.cpp b/server/controlServer.cpp index 0bae102f..0fa28a1b 100644 --- a/server/controlServer.cpp +++ b/server/controlServer.cpp @@ -16,7 +16,7 @@ along with this program. If not, see . ***/ -#include "jsonrp.hpp" +#include "jsonrpcpp.hpp" #include "controlServer.h" #include "message/time.h" #include "aixlog.hpp" diff --git a/server/jsonrp.cpp b/server/jsonrp.cpp deleted file mode 100644 index 29b6938c..00000000 --- a/server/jsonrp.cpp +++ /dev/null @@ -1,1017 +0,0 @@ -/*** - This file is part of jsonrpc++ - Copyright (C) 2017 Johannes Pohl - - This software may be modified and distributed under the terms - of the MIT license. See the LICENSE file for details. -***/ - -#include "jsonrp.hpp" - - -using namespace std; - -namespace jsonrpcpp -{ - - -/////////////////////////// Entity implementation ///////////////////////////// - -Entity::Entity(entity_t type) : entity(type) -{ -} - - -Entity::~Entity() -{ -} - - -bool Entity::is_exception() -{ - return (entity == entity_t::exception); -} - - -bool Entity::is_id() -{ - return (entity == entity_t::id); -} - - -bool Entity::is_error() -{ - return (entity == entity_t::error); -} - - -bool Entity::is_response() -{ - return (entity == entity_t::response); -} - - -bool Entity::is_request() -{ - return (entity == entity_t::request); -} - - -bool Entity::is_notification() -{ - return (entity == entity_t::notification); -} - - -bool Entity::is_batch() -{ - return (entity == entity_t::batch); -} - - -void Entity::parse(const char* json_str) -{ - // http://www.jsonrpc.org/specification - // code message meaning - // -32700 Parse error Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text. - // -32600 Invalid Request The JSON sent is not a valid Request object. - // -32601 Method not found The method does not exist / is not available. - // -32602 Invalid params Invalid method parameter(s). - // -32603 Internal error Internal JSON-RPC error. - // -32000 to -32099 Server error Reserved for implementation-defined server-errors. - try - { - parse_json(Json::parse(json_str)); - } - catch (const RpcException& e) - { - throw; - } - catch (const exception& e) - { - throw ParseErrorException(e.what()); - } -} - - -void Entity::parse(const std::string& json_str) -{ - parse(json_str.c_str()); -} - - -std::string Entity::type_str() const -{ - switch (entity) - { - case entity_t::unknown: - return "unknown"; - case entity_t::id: - return "id"; - case entity_t::exception: - return "exception"; - case entity_t::error: - return "error"; - case entity_t::response: - return "response"; - case entity_t::request: - return "request"; - case entity_t::notification: - return "notification"; - case entity_t::batch: - return "batch"; - default: - return "unknown"; - } -} - - - - - -/////////////////////////// NullableEntity implementation ///////////////////// - -NullableEntity::NullableEntity(entity_t type) : Entity(type), isNull(false) -{ -} - - -NullableEntity::NullableEntity(entity_t type, std::nullptr_t) : Entity(type), isNull(true) -{ -} - - -NullableEntity::~NullableEntity() -{ -}; - - - - - -/////////////////////////// Id implementation ///////////////////////////////// - -Id::Id() : Entity(entity_t::id), type(value_t::null), int_id(0), string_id("") -{ -} - - -Id::Id(int id) : Entity(entity_t::id), type(value_t::integer), int_id(id), string_id("") -{ -} - - -Id::Id(const char* id) : Entity(entity_t::id), type(value_t::string), int_id(0), string_id(id) -{ -} - - -Id::Id(const std::string& id) : Id(id.c_str()) -{ -} - - -Id::Id(const Json& json_id) : Entity(entity_t::id), type(value_t::null) -{ - parse_json(json_id); -} - - -void Id::parse_json(const Json& json) -{ - if (json.is_null()) - { - type = value_t::null; - } - else if (json.is_number_integer()) - { - int_id = json.get(); - type = value_t::integer; - } - else if (json.is_string()) - { - string_id = json.get(); - type = value_t::string; - } - else - throw std::invalid_argument("id must be integer, string or null"); -} - - -Json Id::to_json() const -{ - if (type == value_t::null) - return nullptr; - else if (type == value_t::string) - return string_id; - else if (type == value_t::integer) - return int_id; - - return nullptr; -} - - - - - -//////////////////////// Error implementation ///////////////////////////////// - -Parameter::Parameter(std::nullptr_t) : NullableEntity(entity_t::id, nullptr), type(value_t::null) -{ -} - - -Parameter::Parameter(const Json& json) : NullableEntity(entity_t::id), type(value_t::null) -{ - if (json != nullptr) - parse_json(json); -} - - -Parameter::Parameter(const std::string& key1, const Json& value1, - const std::string& key2, const Json& value2, - const std::string& key3, const Json& value3, - const std::string& key4, const Json& value4) : NullableEntity(entity_t::id), type(value_t::map) -{ - param_map[key1] = value1; - if (!key2.empty()) - param_map[key2] = value2; - if (!key3.empty()) - param_map[key3] = value3; - if (!key4.empty()) - param_map[key4] = value4; -} - - -void Parameter::parse_json(const Json& json) -{ - if (json.is_array()) - { - param_array = json.get>(); - param_map.clear(); - type = value_t::array; - } - else - { - param_map = json.get>(); - param_array.clear(); - type = value_t::map; - } -} - - -Json Parameter::to_json() const -{ - if (type == value_t::array) - return param_array; - else if (type == value_t::map) - return param_map; - else - return nullptr; -} - - -bool Parameter::is_array() const -{ - return type == value_t::array; -} - - -bool Parameter::is_map() const -{ - return type == value_t::map; -} - - -bool Parameter::is_null() const -{ - return isNull; -} - - -bool Parameter::has(const std::string& key) const -{ - if (type != value_t::map) - return false; - return (param_map.find(key) != param_map.end()); -} - - -Json Parameter::get(const std::string& key) const -{ - return param_map.at(key); -} - - -bool Parameter::has(size_t idx) const -{ - if (type != value_t::array) - return false; - return (param_array.size() > idx); -} - - -Json Parameter::get(size_t idx) const -{ - return param_array.at(idx); -} - - - - - -//////////////////////// Error implementation ///////////////////////////////// - -Error::Error(const Json& json) : Error("Internal error", -32603, nullptr) -{ - if (json != nullptr) - parse_json(json); -} - - -Error::Error(std::nullptr_t) : NullableEntity(entity_t::error, nullptr), code(0), message(""), data(nullptr) -{ -} - - -Error::Error(const std::string& message, int code, const Json& data) : NullableEntity(entity_t::error), code(code), message(message), data(data) -{ -} - - -void Error::parse_json(const Json& json) -{ - try - { - if (json.count("code") == 0) - throw RpcException("code is missing"); - code = json["code"]; - if (json.count("message") == 0) - throw RpcException("message is missing"); - message = json["message"]; - if (json.count("data")) - data = json["data"]; - else - data = nullptr; - } - catch (const RpcException& e) - { - throw; - } - catch (const exception& e) - { - throw RpcException(e.what()); - } -} - - -Json Error::to_json() const -{ - Json j = { - {"code", code}, - {"message", message}, - }; - - if (!data.is_null()) - j["data"] = data; - return j; -} - - - - - -////////////////////// Request implementation ///////////////////////////////// - -Request::Request(const Json& json) : Entity(entity_t::request), method(""), id() -{ - if (json != nullptr) - parse_json(json); -} - - -Request::Request(const Id& id, const std::string& method, const Parameter& params) : Entity(entity_t::request), method(method), params(params), id(id) -{ -} - - -void Request::parse_json(const Json& json) -{ - try - { - if (json.count("id") == 0) - throw InvalidRequestException("id is missing"); - - try - { - id = Id(json["id"]); - } - catch(const std::exception& e) - { - throw InvalidRequestException(e.what()); - } - - if (json.count("jsonrpc") == 0) - throw InvalidRequestException("jsonrpc is missing", id); - string jsonrpc = json["jsonrpc"].get(); - if (jsonrpc != "2.0") - throw InvalidRequestException("invalid jsonrpc value: " + jsonrpc, id); - - if (json.count("method") == 0) - throw InvalidRequestException("method is missing", id); - if (!json["method"].is_string()) - throw InvalidRequestException("method must be a string value", id); - method = json["method"]; - if (method.empty()) - throw InvalidRequestException("method must not be empty", id); - - if (json.count("params")) - params.parse_json(json["params"]); - else - params = nullptr; - } - catch (const RequestException& e) - { - throw; - } - catch (const exception& e) - { - throw InternalErrorException(e.what(), id); - } -} - - -Json Request::to_json() const -{ - Json json = { - {"jsonrpc", "2.0"}, - {"method", method}, - {"id", id.to_json()} - }; - - if (params) - json["params"] = params.to_json(); - - return json; -} - - - -RpcException::RpcException(const char* text) -{ - text_ = new char[std::strlen(text) + 1]; - std::strcpy(text_, text); -} - -RpcException::RpcException(const std::string& text) : RpcException(text.c_str()) -{ -} - -RpcException::RpcException(const RpcException& e) : RpcException(e.what()) -{ -} - -RpcException::~RpcException() throw() -{ - delete[] text_; -} - -const char* RpcException::what() const noexcept -{ - return text_; -} - - - - -ParseErrorException::ParseErrorException(const Error& error) : RpcException(error.message), Entity(entity_t::exception), error(error) -{ -} - -ParseErrorException::ParseErrorException(const ParseErrorException& e) : RpcException(e.what()), Entity(entity_t::exception), error(e.error) -{ -} - -ParseErrorException::ParseErrorException(const std::string& data) : ParseErrorException(Error("Parse error", -32700, data)) -{ -} - -Json ParseErrorException::to_json() const -{ - Json response = { - {"jsonrpc", "2.0"}, - {"error", error.to_json()}, - {"id", nullptr} - }; - - return response; -} - -void ParseErrorException::parse_json(const Json& json) -{ -} - - - - -RequestException::RequestException(const Error& error, const Id& requestId) : RpcException(error.message), Entity(entity_t::exception), error(error), id(requestId) -{ -} - -RequestException::RequestException(const RequestException& e) : RpcException(e.what()), Entity(entity_t::exception), error(e.error), id(e.id) -{ -} - -Json RequestException::to_json() const -{ - Json response = { - {"jsonrpc", "2.0"}, - {"error", error.to_json()}, - {"id", id.to_json()} - }; - - return response; -} - -void RequestException::parse_json(const Json& json) -{ -} - - - - - -InvalidRequestException::InvalidRequestException(const Id& requestId) : RequestException(Error("Invalid request", -32600), requestId) -{ -} - -InvalidRequestException::InvalidRequestException(const Request& request) : InvalidRequestException(request.id) -{ -} - -InvalidRequestException::InvalidRequestException(const char* data, const Id& requestId) : RequestException(Error("Invalid request", -32600, data), requestId) -{ -} - -InvalidRequestException::InvalidRequestException(const std::string& data, const Id& requestId) : InvalidRequestException(data.c_str(), requestId) -{ -} - - - -MethodNotFoundException::MethodNotFoundException(const Id& requestId) : RequestException(Error("Method not found", -32601), requestId) -{ -} - -MethodNotFoundException::MethodNotFoundException(const Request& request) : MethodNotFoundException(request.id) -{ -} - -MethodNotFoundException::MethodNotFoundException(const char* data, const Id& requestId) : RequestException(Error("Method not found", -32601, data), requestId) -{ -} - -MethodNotFoundException::MethodNotFoundException(const std::string& data, const Id& requestId) : MethodNotFoundException(data.c_str(), requestId) -{ -} - - - -InvalidParamsException::InvalidParamsException(const Id& requestId) : RequestException(Error("Invalid params", -32602), requestId) -{ -} - -InvalidParamsException::InvalidParamsException(const Request& request) : InvalidParamsException(request.id) -{ -} - -InvalidParamsException::InvalidParamsException(const char* data, const Id& requestId) : RequestException(Error("Invalid params", -32602, data), requestId) -{ -} - -InvalidParamsException::InvalidParamsException(const std::string& data, const Id& requestId) : InvalidParamsException(data.c_str(), requestId) -{ -} - - - -InternalErrorException::InternalErrorException(const Id& requestId) : RequestException(Error("Internal error", -32603), requestId) -{ -} - -InternalErrorException::InternalErrorException(const Request& request) : InternalErrorException(request.id) -{ -} - -InternalErrorException::InternalErrorException(const char* data, const Id& requestId) : RequestException(Error("Internal error", -32603, data), requestId) -{ -} - -InternalErrorException::InternalErrorException(const std::string& data, const Id& requestId) : InternalErrorException(data.c_str(), requestId) -{ -} - - - -///////////////////// Response implementation ///////////////////////////////// - -Response::Response(const Json& json) : Entity(entity_t::response) -{ - if (json != nullptr) - parse_json(json); -} - - -Response::Response(const Id& id, const Json& result) : Entity(entity_t::response), id(id), result(result), error(nullptr) -{ -} - - -Response::Response(const Id& id, const Error& error) : Entity(entity_t::response), id(id), result(), error(error) -{ -} - - -Response::Response(const Request& request, const Json& result) : Response(request.id, result) -{ -} - - -Response::Response(const Request& request, const Error& error) : Response(request.id, error) -{ -} - - -Response::Response(const RequestException& exception) : Response(exception.id, exception.error) -{ -} - - -void Response::parse_json(const Json& json) -{ - try - { - error = nullptr; - result = nullptr; - if (json.count("jsonrpc") == 0) - throw RpcException("jsonrpc is missing"); - string jsonrpc = json["jsonrpc"].get(); - if (jsonrpc != "2.0") - throw RpcException("invalid jsonrpc value: " + jsonrpc); - if (json.count("id") == 0) - throw RpcException("id is missing"); - id = Id(json["id"]); - if (json.count("result")) - result = json["result"]; - else if (json.count("error")) - error.parse_json(json["error"]); - else - throw RpcException("response must contain result or error"); - } - catch (const RpcException& e) - { - throw; - } - catch (const exception& e) - { - throw RpcException(e.what()); - } -} - - -Json Response::to_json() const -{ - Json j = { - {"jsonrpc", "2.0"}, - {"id", id.to_json()}, - }; - - if (error) - j["error"] = error.to_json(); - else - j["result"] = result; - - return j; -} - - - - - -///////////////// Notification implementation ///////////////////////////////// - -Notification::Notification(const Json& json) : Entity(entity_t::notification) -{ - if (json != nullptr) - parse_json(json); -} - - -Notification::Notification(const char* method, const Parameter& params) : Entity(entity_t::notification), method(method), params(params) -{ -} - - -Notification::Notification(const std::string& method, const Parameter& params) : Notification(method.c_str(), params) -{ -} - - -void Notification::parse_json(const Json& json) -{ - try - { - if (json.count("jsonrpc") == 0) - throw RpcException("jsonrpc is missing"); - string jsonrpc = json["jsonrpc"].get(); - if (jsonrpc != "2.0") - throw RpcException("invalid jsonrpc value: " + jsonrpc); - - if (json.count("method") == 0) - throw RpcException("method is missing"); - if (!json["method"].is_string()) - throw RpcException("method must be a string value"); - method = json["method"]; - if (method.empty()) - throw RpcException("method must not be empty"); - - if (json.count("params")) - params.parse_json(json["params"]); - else - params = nullptr; - } - catch (const RpcException& e) - { - throw; - } - catch (const exception& e) - { - throw RpcException(e.what()); - } -} - - -Json Notification::to_json() const -{ - Json json = { - {"jsonrpc", "2.0"}, - {"method", method}, - }; - - if (params) - json["params"] = params.to_json(); - - return json; -} - - - - - -//////////////////////// Batch implementation ///////////////////////////////// - -Batch::Batch(const Json& json) : Entity(entity_t::batch) -{ - if (json != nullptr) - parse_json(json); -} - - -void Batch::parse_json(const Json& json) -{ -// cout << "Batch::parse: " << json.dump() << "\n"; - entities.clear(); - for (auto it = json.begin(); it != json.end(); ++it) - { -// cout << "x: " << it->dump() << "\n"; - entity_ptr entity(nullptr); - try - { - entity = Parser::do_parse_json(*it); - if (!entity) - entity = make_shared("Invalid Request", -32600); - } - catch(const RequestException& e) - { - entity = make_shared(e); - } - catch(const std::exception& e) - { - entity = make_shared(e.what(), -32600); - } - entities.push_back(entity); - } - if (entities.empty()) - throw InvalidRequestException(); -} - - -Json Batch::to_json() const -{ - Json result; - for (const auto& j: entities) - result.push_back(j->to_json()); - return result; -} - - -/*void Batch::add(const entity_ptr entity) -{ - entities.push_back(entity); -} -*/ - - - - -//////////////////////// Parser implementation //////////////////////////////// - -Parser::Parser() -{ - -} - - -Parser::~Parser() -{ - -} - - -void Parser::register_notification_callback(const std::string& notification, notification_callback callback) -{ - if (callback) - notification_callbacks_[notification] = callback; -} - - -void Parser::register_request_callback(const std::string& request, request_callback callback) -{ - if (callback) - request_callbacks_[request] = callback; -} - - -entity_ptr Parser::parse(const std::string& json_str) -{ - //std::cout << "parse: " << json_str << "\n"; - entity_ptr entity = do_parse(json_str); - if (entity && entity->is_notification()) - { - notification_ptr notification = dynamic_pointer_cast(entity); - if (notification_callbacks_.find(notification->method) != notification_callbacks_.end()) - { - notification_callback callback = notification_callbacks_[notification->method]; - if (callback) - callback(notification->params); - } - } - else if (entity && entity->is_request()) - { - request_ptr request = dynamic_pointer_cast(entity); - if (request_callbacks_.find(request->method) != request_callbacks_.end()) - { - request_callback callback = request_callbacks_[request->method]; - if (callback) - { - jsonrpcpp::response_ptr response = callback(request->id, request->params); - if (response) - return response; - } - } - } - return entity; -} - - -entity_ptr Parser::parse_json(const Json& json) -{ - return do_parse_json(json); -} - - -entity_ptr Parser::do_parse(const std::string& json_str) -{ - try - { - return do_parse_json(Json::parse(json_str)); - } - catch (const RpcException& e) - { - throw; - } - catch (const exception& e) - { - throw ParseErrorException(e.what()); - } - - return nullptr; -} - - -entity_ptr Parser::do_parse_json(const Json& json) -{ - try - { - if (is_request(json)) - return make_shared(json); - else if (is_notification(json)) - return make_shared(json); - else if (is_response(json)) - return make_shared(json); - else if (is_batch(json)) - return make_shared(json); - } - catch (const RpcException& e) - { - throw; - } - catch (const exception& e) - { - throw RpcException(e.what()); - } - - return nullptr; -} - - -bool Parser::is_request(const std::string& json_str) -{ - try - { - return is_request(Json::parse(json_str)); - } - catch (const exception& e) - { - return false; - } -} - - -bool Parser::is_request(const Json& json) -{ - return (json.count("method") && json.count("id")); -} - - -bool Parser::is_notification(const std::string& json_str) -{ - try - { - return is_notification(Json::parse(json_str)); - } - catch (const exception& e) - { - return false; - } -} - - -bool Parser:: is_notification(const Json& json) -{ - return (json.count("method") && (json.count("id") == 0)); -} - - -bool Parser::is_response(const std::string& json_str) -{ - try - { - return is_response(Json::parse(json_str)); - } - catch (const exception& e) - { - return false; - } -} - - -bool Parser::is_response(const Json& json) -{ - return (json.count("result") && json.count("id")); -} - - -bool Parser::is_batch(const std::string& json_str) -{ - try - { - return is_batch(Json::parse(json_str)); - } - catch (const exception& e) - { - return false; - } -} - - -bool Parser::is_batch(const Json& json) -{ - return (json.is_array()); -} - - - -} - - diff --git a/server/jsonrp.hpp b/server/jsonrp.hpp deleted file mode 100644 index adc80245..00000000 --- a/server/jsonrp.hpp +++ /dev/null @@ -1,457 +0,0 @@ -/*** - __ ____ __ __ _ ____ ____ ___ _ _ - _( )/ ___) / \ ( ( \( _ \( _ \ / __)( ) ( ) - / \) \\___ \( O )/ / ) / ) __/( (__(_ _)(_ _) - \____/(____/ \__/ \_)__)(__\_)(__) \___)(_) (_) - version 1.1.0 - https://github.com/badaix/jsonrpcpp - - This file is part of jsonrpc++ - Copyright (C) 2017 Johannes Pohl - - This software may be modified and distributed under the terms - of the MIT license. See the LICENSE file for details. -***/ - -/// http://patorjk.com/software/taag/#p=display&f=Graceful&t=JSONRPC%2B%2B - -#ifndef JSON_RPC_H -#define JSON_RPC_H - -#include -#include -#include -#include -#include "common/json.hpp" - - -using Json = nlohmann::json; - -namespace jsonrpcpp -{ - - -class Entity; -class Request; -class Notification; -class Parameter; -class Response; -class Error; -class Batch; - - -typedef std::shared_ptr entity_ptr; -typedef std::shared_ptr request_ptr; -typedef std::shared_ptr notification_ptr; -typedef std::shared_ptr parameter_ptr; -typedef std::shared_ptr response_ptr; -typedef std::shared_ptr error_ptr; -typedef std::shared_ptr batch_ptr; - - - -class Entity -{ -public: - enum class entity_t : uint8_t - { - unknown, - exception, - id, - error, - response, - request, - notification, - batch - }; - - Entity(entity_t type); - virtual ~Entity(); - - bool is_exception(); - bool is_id(); - bool is_error(); - bool is_response(); - bool is_request(); - bool is_notification(); - bool is_batch(); - - virtual std::string type_str() const; - - virtual Json to_json() const = 0; - virtual void parse_json(const Json& json) = 0; - - virtual void parse(const std::string& json_str); - virtual void parse(const char* json_str); - -protected: - entity_t entity; -}; - - - - - -class NullableEntity : public Entity -{ -public: - NullableEntity(entity_t type); - NullableEntity(entity_t type, std::nullptr_t); - virtual ~NullableEntity(); - virtual explicit operator bool() const - { - return !isNull; - } - -protected: - bool isNull; -}; - - - - - -class Id : public Entity -{ -public: - enum class value_t : uint8_t - { - null, - string, - integer - }; - - Id(); - Id(int id); - Id(const char* id); - Id(const std::string& id); - Id(const Json& json_id); - - virtual Json to_json() const; - virtual void parse_json(const Json& json); - - friend std::ostream& operator<< (std::ostream &out, const Id &id) - { - out << id.to_json(); - return out; - } - - value_t type; - int int_id; - std::string string_id; -}; - - - - - -class Parameter : public NullableEntity -{ -public: - enum class value_t : uint8_t - { - null, - array, - map - }; - - Parameter(std::nullptr_t); - Parameter(const Json& json = nullptr); - Parameter(const std::string& key1, const Json& value1, - const std::string& key2 = "", const Json& value2 = nullptr, - const std::string& key3 = "", const Json& value3 = nullptr, - const std::string& key4 = "", const Json& value4 = nullptr); - - virtual Json to_json() const; - virtual void parse_json(const Json& json); - - bool is_array() const; - bool is_map() const; - bool is_null() const; - - Json get(const std::string& key) const; - Json get(size_t idx) const; - bool has(const std::string& key) const; - bool has(size_t idx) const; - - template - T get(const std::string& key) const - { - return get(key).get(); - } - - template - T get(size_t idx) const - { - return get(idx).get(); - } - - template - T get(const std::string& key, const T& default_value) const - { - if (!has(key)) - return default_value; - else - return get(key); - } - - template - T get(size_t idx, const T& default_value) const - { - if (!has(idx)) - return default_value; - else - return get(idx); - } - - value_t type; - std::vector param_array; - std::map param_map; -}; - - - - - -class Error : public NullableEntity -{ -public: - Error(const Json& json = nullptr); - Error(std::nullptr_t); - Error(const std::string& message, int code, const Json& data = nullptr); - - virtual Json to_json() const; - virtual void parse_json(const Json& json); - - int code; - std::string message; - Json data; -}; - - - -/// JSON-RPC 2.0 request -/** - * Simple jsonrpc 2.0 parser with getters - * Currently no named parameters are supported, but only array parameters - */ -class Request : public Entity -{ -public: - Request(const Json& json = nullptr); - Request(const Id& id, const std::string& method, const Parameter& params = nullptr); - - virtual Json to_json() const; - virtual void parse_json(const Json& json); - - std::string method; - Parameter params; - Id id; -}; - - - - - -class RpcException : public std::exception -{ - char* text_; -public: - RpcException(const char* text); - RpcException(const std::string& text); - RpcException(const RpcException& e); - - virtual ~RpcException() throw(); - virtual const char* what() const noexcept; -}; - - - - - -class ParseErrorException : public RpcException, public Entity -{ -public: - Error error; - - ParseErrorException(const Error& error); - ParseErrorException(const ParseErrorException& e); - ParseErrorException(const std::string& data); - virtual Json to_json() const; - -protected: - virtual void parse_json(const Json& json); -}; - - - -// -32600 Invalid Request The JSON sent is not a valid Request object. -// -32601 Method not found The method does not exist / is not available. -// -32602 Invalid params Invalid method parameter(s). -// -32603 Internal error Internal JSON-RPC error. - -class RequestException : public RpcException, public Entity -{ -public: - Error error; - Id id; - - RequestException(const Error& error, const Id& requestId = Id()); - RequestException(const RequestException& e); - virtual Json to_json() const; - -protected: - virtual void parse_json(const Json& json); -}; - - - -class InvalidRequestException : public RequestException -{ -public: - InvalidRequestException(const Id& requestId = Id()); - InvalidRequestException(const Request& request); - InvalidRequestException(const char* data, const Id& requestId = Id()); - InvalidRequestException(const std::string& data, const Id& requestId = Id()); -}; - - - -class MethodNotFoundException : public RequestException -{ -public: - MethodNotFoundException(const Id& requestId = Id()); - MethodNotFoundException(const Request& request); - MethodNotFoundException(const char* data, const Id& requestId = Id()); - MethodNotFoundException(const std::string& data, const Id& requestId = Id()); -}; - - - -class InvalidParamsException : public RequestException -{ -public: - InvalidParamsException(const Id& requestId = Id()); - InvalidParamsException(const Request& request); - InvalidParamsException(const char* data, const Id& requestId = Id()); - InvalidParamsException(const std::string& data, const Id& requestId = Id()); -}; - - - -class InternalErrorException : public RequestException -{ -public: - InternalErrorException(const Id& requestId = Id()); - InternalErrorException(const Request& request); - InternalErrorException(const char* data, const Id& requestId = Id()); - InternalErrorException(const std::string& data, const Id& requestId = Id()); -}; - - - - - -class Response : public Entity -{ -public: - Id id; - Json result; - Error error; - - Response(const Json& json = nullptr); - Response(const Id& id, const Json& result); - Response(const Id& id, const Error& error); - Response(const Request& request, const Json& result); - Response(const Request& request, const Error& error); - Response(const RequestException& exception); - - virtual Json to_json() const; - virtual void parse_json(const Json& json); -}; - - - - - -class Notification : public Entity -{ -public: - std::string method; - Parameter params; - Notification(const Json& json = nullptr); - Notification(const char* method, const Parameter& params = nullptr); - Notification(const std::string& method, const Parameter& params); - - virtual Json to_json() const; - virtual void parse_json(const Json& json); -}; - - - - -typedef std::function notification_callback; -typedef std::function request_callback; - - -class Parser -{ -public: - Parser(); - virtual ~Parser(); - - entity_ptr parse(const std::string& json_str); - entity_ptr parse_json(const Json& json); - - void register_notification_callback(const std::string& notification, notification_callback callback); - void register_request_callback(const std::string& request, request_callback callback); - - static entity_ptr do_parse(const std::string& json_str); - static entity_ptr do_parse_json(const Json& json); - static bool is_request(const std::string& json_str); - static bool is_request(const Json& json); - static bool is_notification(const std::string& json_str); - static bool is_notification(const Json& json); - static bool is_response(const std::string& json_str); - static bool is_response(const Json& json); - static bool is_batch(const std::string& json_str); - static bool is_batch(const Json& json); - -private: - std::map notification_callbacks_; - std::map request_callbacks_; -}; - - - - - -class Batch : public Entity -{ -public: - std::vector entities; - - Batch(const Json& json = nullptr); - - virtual Json to_json() const; - virtual void parse_json(const Json& json); - - template - void add(const T& entity) - { - entities.push_back(std::make_shared(entity)); - } - - void add_ptr(const entity_ptr& entity) - { - entities.push_back(entity); - } -}; - - - -} //namespace jsonrpc - - - -#endif diff --git a/server/jsonrpcpp.hpp b/server/jsonrpcpp.hpp new file mode 100644 index 00000000..230ad50b --- /dev/null +++ b/server/jsonrpcpp.hpp @@ -0,0 +1,1510 @@ +/*** + __ ____ __ __ _ ____ ____ ___ _ _ + _( )/ ___) / \ ( ( \( _ \( _ \ / __)( ) ( ) + / \) \\___ \( O )/ / ) / ) __/( (__(_ _)(_ _) + \____/(____/ \__/ \_)__)(__\_)(__) \___)(_) (_) + version 1.2.0 + https://github.com/badaix/jsonrpcpp + + This file is part of jsonrpc++ + Copyright (C) 2017-2018 Johannes Pohl + + This software may be modified and distributed under the terms + of the MIT license. See the LICENSE file for details. +***/ + +/// http://patorjk.com/software/taag/#p=display&f=Graceful&t=JSONRPC%2B%2B + +/// checked with clang-tidy: +/// run-clang-tidy-3.8.py -header-filter='jsonrpcpp.hpp' -checks='*,-misc-definitions-in-headers,-google-readability-braces-around-statements,-readability-braces-around-statements,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-google-build-using-namespace,-google-build-using-namespace,-modernize-pass-by-value,-google-explicit-constructor' + +#ifndef JSON_RPC_H +#define JSON_RPC_H + +#include +#include +#include +#include "json.hpp" +#include + + +using Json = nlohmann::json; + +namespace jsonrpcpp +{ + + +class Entity; +class Request; +class Notification; +class Parameter; +class Response; +class Error; +class Batch; + + +typedef std::shared_ptr entity_ptr; +typedef std::shared_ptr request_ptr; +typedef std::shared_ptr notification_ptr; +typedef std::shared_ptr parameter_ptr; +typedef std::shared_ptr response_ptr; +typedef std::shared_ptr error_ptr; +typedef std::shared_ptr batch_ptr; + + + +class Entity +{ +public: + enum class entity_t : uint8_t + { + unknown, + exception, + id, + error, + response, + request, + notification, + batch + }; + + Entity(entity_t type); + virtual ~Entity() = default; + + bool is_exception(); + bool is_id(); + bool is_error(); + bool is_response(); + bool is_request(); + bool is_notification(); + bool is_batch(); + + virtual std::string type_str() const; + + virtual Json to_json() const = 0; + virtual void parse_json(const Json& json) = 0; + + virtual void parse(const std::string& json_str); + virtual void parse(const char* json_str); + +protected: + entity_t entity; +}; + + + + + +class NullableEntity : public Entity +{ +public: + NullableEntity(entity_t type); + NullableEntity(entity_t type, std::nullptr_t); + ~NullableEntity() override = default; +#ifdef _MSC_VER + virtual operator bool() const +#else + virtual explicit operator bool() const +#endif + { + return !isNull; + } + +protected: + bool isNull; +}; + + + + + +class Id : public Entity +{ +public: + enum class value_t : uint8_t + { + null, + string, + integer + }; + + Id(); + Id(int id); + Id(const char* id); + Id(const std::string& id); + Id(const Json& json_id); + + Json to_json() const override; + void parse_json(const Json& json) override; + + friend std::ostream& operator<< (std::ostream &out, const Id &id) + { + out << id.to_json(); + return out; + } + + value_t type() const + { + return type_; + } + + int int_id() const + { + return int_id_; + } + + std::string string_id() const + { + return string_id_; + } + +protected: + value_t type_; + int int_id_; + std::string string_id_; +}; + + + + + +class Parameter : public NullableEntity +{ +public: + enum class value_t : uint8_t + { + null, + array, + map + }; + + Parameter(std::nullptr_t); + Parameter(const Json& json = nullptr); + Parameter(const std::string& key1, const Json& value1, + const std::string& key2 = "", const Json& value2 = nullptr, + const std::string& key3 = "", const Json& value3 = nullptr, + const std::string& key4 = "", const Json& value4 = nullptr); + + Json to_json() const override; + void parse_json(const Json& json) override; + + bool is_array() const; + bool is_map() const; + bool is_null() const; + + Json get(const std::string& key) const; + Json get(size_t idx) const; + bool has(const std::string& key) const; + bool has(size_t idx) const; + + template + T get(const std::string& key) const + { + return get(key).get(); + } + + template + T get(size_t idx) const + { + return get(idx).get(); + } + + template + T get(const std::string& key, const T& default_value) const + { + if (!has(key)) + return default_value; + return get(key); + } + + template + T get(size_t idx, const T& default_value) const + { + if (!has(idx)) + return default_value; + return get(idx); + } + + value_t type; + std::vector param_array; + std::map param_map; +}; + + + + + +class Error : public NullableEntity +{ +public: + Error(const Json& json = nullptr); + Error(std::nullptr_t); + Error(const std::string& message, int code, const Json& data = nullptr); + + Json to_json() const override; + void parse_json(const Json& json) override; + + int code() const + { + return code_; + } + + std::string message() const + { + return message_; + } + + Json data() const + { + return data_; + } + +protected: + int code_; + std::string message_; + Json data_; +}; + + + +/// JSON-RPC 2.0 request +/** + * Simple jsonrpc 2.0 parser with getters + * Currently no named parameters are supported, but only array parameters + */ +class Request : public Entity +{ +public: + Request(const Json& json = nullptr); + Request(const Id& id, const std::string& method, const Parameter& params = nullptr); + + Json to_json() const override; + void parse_json(const Json& json) override; + + std::string method() const + { + return method_; + } + + Parameter params() const + { + return params_; + } + + Id id() const + { + return id_; + } + +protected: + std::string method_; + Parameter params_; + Id id_; +}; + + + + + +class RpcException : public std::exception +{ +public: + RpcException(const char* text); + RpcException(const std::string& text); + + ~RpcException() override = default; + const char* what() const noexcept override; + +protected: + std::runtime_error m_; +}; + + + +class RpcEntityException : public RpcException, public Entity +{ +public: + RpcEntityException(const Error& error); + RpcEntityException(const std::string& text); + Json to_json() const override = 0; + + Error error() const + { + return error_; + } + +protected: + void parse_json(const Json& json) override; + Error error_; +}; + + + +class ParseErrorException : public RpcEntityException +{ +public: + ParseErrorException(const Error& error); + ParseErrorException(const std::string& data); + Json to_json() const override; +}; + + + +// -32600 Invalid Request The JSON sent is not a valid Request object. +// -32601 Method not found The method does not exist / is not available. +// -32602 Invalid params Invalid method parameter(s). +// -32603 Internal error Internal JSON-RPC error. + +class RequestException : public RpcEntityException +{ +public: + RequestException(const Error& error, const Id& requestId = Id()); + RequestException(const RequestException& e) = default; + Json to_json() const override; + + Id id() const + { + return id_; + } + +protected: + Id id_; +}; + + + +class InvalidRequestException : public RequestException +{ +public: + InvalidRequestException(const Id& requestId = Id()); + InvalidRequestException(const Request& request); + InvalidRequestException(const char* data, const Id& requestId = Id()); + InvalidRequestException(const std::string& data, const Id& requestId = Id()); +}; + + + +class MethodNotFoundException : public RequestException +{ +public: + MethodNotFoundException(const Id& requestId = Id()); + MethodNotFoundException(const Request& request); + MethodNotFoundException(const char* data, const Id& requestId = Id()); + MethodNotFoundException(const std::string& data, const Id& requestId = Id()); +}; + + + +class InvalidParamsException : public RequestException +{ +public: + InvalidParamsException(const Id& requestId = Id()); + InvalidParamsException(const Request& request); + InvalidParamsException(const char* data, const Id& requestId = Id()); + InvalidParamsException(const std::string& data, const Id& requestId = Id()); +}; + + + +class InternalErrorException : public RequestException +{ +public: + InternalErrorException(const Id& requestId = Id()); + InternalErrorException(const Request& request); + InternalErrorException(const char* data, const Id& requestId = Id()); + InternalErrorException(const std::string& data, const Id& requestId = Id()); +}; + + + + + +class Response : public Entity +{ +public: + Response(const Json& json = nullptr); + Response(const Id& id, const Json& result); + Response(const Id& id, const Error& error); + Response(const Request& request, const Json& result); + Response(const Request& request, const Error& error); + Response(const RequestException& exception); + + Json to_json() const override; + void parse_json(const Json& json) override; + + Id id() const + { + return id_; + } + + Json result() const + { + return result_; + } + + Error error() const + { + return error_; + } + +protected: + Id id_; + Json result_; + Error error_; +}; + + + + + +class Notification : public Entity +{ +public: + Notification(const Json& json = nullptr); + Notification(const char* method, const Parameter& params = nullptr); + Notification(const std::string& method, const Parameter& params); + + Json to_json() const override; + void parse_json(const Json& json) override; + + std::string method() const + { + return method_; + } + + Parameter params() const + { + return params_; + } + +protected: + std::string method_; + Parameter params_; +}; + + + + +typedef std::function notification_callback; +typedef std::function request_callback; + + +class Parser +{ +public: + Parser() = default; + virtual ~Parser() = default; + + entity_ptr parse(const std::string& json_str); + entity_ptr parse_json(const Json& json); + + void register_notification_callback(const std::string& notification, notification_callback callback); + void register_request_callback(const std::string& request, request_callback callback); + + static entity_ptr do_parse(const std::string& json_str); + static entity_ptr do_parse_json(const Json& json); + static bool is_request(const std::string& json_str); + static bool is_request(const Json& json); + static bool is_notification(const std::string& json_str); + static bool is_notification(const Json& json); + static bool is_response(const std::string& json_str); + static bool is_response(const Json& json); + static bool is_batch(const std::string& json_str); + static bool is_batch(const Json& json); + +private: + std::map notification_callbacks_; + std::map request_callbacks_; +}; + + + + + +class Batch : public Entity +{ +public: + std::vector entities; + + Batch(const Json& json = nullptr); + + Json to_json() const override; + void parse_json(const Json& json) override; + + template + void add(const T& entity) + { + entities.push_back(std::make_shared(entity)); + } + + void add_ptr(const entity_ptr& entity) + { + entities.push_back(entity); + } +}; + + + + +/////////////////////////// Entity implementation ///////////////////////////// + +inline Entity::Entity(entity_t type) : entity(type) +{ +} + + +inline bool Entity::is_exception() +{ + return (entity == entity_t::exception); +} + + +inline bool Entity::is_id() +{ + return (entity == entity_t::id); +} + + +inline bool Entity::is_error() +{ + return (entity == entity_t::error); +} + + +inline bool Entity::is_response() +{ + return (entity == entity_t::response); +} + + +inline bool Entity::is_request() +{ + return (entity == entity_t::request); +} + + +inline bool Entity::is_notification() +{ + return (entity == entity_t::notification); +} + + +inline bool Entity::is_batch() +{ + return (entity == entity_t::batch); +} + + +inline void Entity::parse(const char* json_str) +{ + // http://www.jsonrpc.org/specification + // code message meaning + // -32700 Parse error Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text. + // -32600 Invalid Request The JSON sent is not a valid Request object. + // -32601 Method not found The method does not exist / is not available. + // -32602 Invalid params Invalid method parameter(s). + // -32603 Internal error Internal JSON-RPC error. + // -32000 to -32099 Server error Reserved for implementation-defined server-errors. + try + { + parse_json(Json::parse(json_str)); + } + catch (const RpcException& e) + { + throw; + } + catch (const std::exception& e) + { + throw ParseErrorException(e.what()); + } +} + + +inline void Entity::parse(const std::string& json_str) +{ + parse(json_str.c_str()); +} + + +inline std::string Entity::type_str() const +{ + switch (entity) + { + case entity_t::unknown: + return "unknown"; + case entity_t::id: + return "id"; + case entity_t::exception: + return "exception"; + case entity_t::error: + return "error"; + case entity_t::response: + return "response"; + case entity_t::request: + return "request"; + case entity_t::notification: + return "notification"; + case entity_t::batch: + return "batch"; + default: + return "unknown"; + } +} + + + + + +/////////////////////////// NullableEntity implementation ///////////////////// + +inline NullableEntity::NullableEntity(entity_t type) : Entity(type), isNull(false) +{ +} + + +inline NullableEntity::NullableEntity(entity_t type, std::nullptr_t) : Entity(type), isNull(true) +{ +} + + + + + +/////////////////////////// Id implementation ///////////////////////////////// + +inline Id::Id() : Entity(entity_t::id), type_(value_t::null), int_id_(0), string_id_("") +{ +} + + +inline Id::Id(int id) : Entity(entity_t::id), type_(value_t::integer), int_id_(id), string_id_("") +{ +} + + +inline Id::Id(const char* id) : Entity(entity_t::id), type_(value_t::string), int_id_(0), string_id_(id) +{ +} + + +inline Id::Id(const std::string& id) : Id(id.c_str()) +{ +} + + +inline Id::Id(const Json& json_id) : Entity(entity_t::id), type_(value_t::null) +{ + Id::parse_json(json_id); +} + + +inline void Id::parse_json(const Json& json) +{ + if (json.is_null()) + { + type_ = value_t::null; + } + else if (json.is_number_integer()) + { + int_id_ = json.get(); + type_ = value_t::integer; + } + else if (json.is_string()) + { + string_id_ = json.get(); + type_ = value_t::string; + } + else + throw std::invalid_argument("id must be integer, string or null"); +} + + +inline Json Id::to_json() const +{ + if (type_ == value_t::null) + return nullptr; + if (type_ == value_t::string) + return string_id_; + if (type_ == value_t::integer) + return int_id_; + + return nullptr; +} + + + + + +//////////////////////// Error implementation ///////////////////////////////// + +inline Parameter::Parameter(std::nullptr_t) : NullableEntity(entity_t::id, nullptr), type(value_t::null) +{ +} + + +inline Parameter::Parameter(const Json& json) : NullableEntity(entity_t::id), type(value_t::null) +{ + if (json != nullptr) + Parameter::parse_json(json); +} + + +inline Parameter::Parameter(const std::string& key1, const Json& value1, + const std::string& key2, const Json& value2, + const std::string& key3, const Json& value3, + const std::string& key4, const Json& value4) : NullableEntity(entity_t::id), type(value_t::map) +{ + param_map[key1] = value1; + if (!key2.empty()) + param_map[key2] = value2; + if (!key3.empty()) + param_map[key3] = value3; + if (!key4.empty()) + param_map[key4] = value4; +} + + +inline void Parameter::parse_json(const Json& json) +{ + if (json.is_array()) + { + param_array = json.get>(); + param_map.clear(); + type = value_t::array; + } + else + { + param_map = json.get>(); + param_array.clear(); + type = value_t::map; + } +} + + +inline Json Parameter::to_json() const +{ + if (type == value_t::array) + return param_array; + if (type == value_t::map) + return param_map; + + return nullptr; +} + + +inline bool Parameter::is_array() const +{ + return type == value_t::array; +} + + +inline bool Parameter::is_map() const +{ + return type == value_t::map; +} + + +inline bool Parameter::is_null() const +{ + return isNull; +} + + +inline bool Parameter::has(const std::string& key) const +{ + if (type != value_t::map) + return false; + return (param_map.find(key) != param_map.end()); +} + + +inline Json Parameter::get(const std::string& key) const +{ + return param_map.at(key); +} + + +inline bool Parameter::has(size_t idx) const +{ + if (type != value_t::array) + return false; + return (param_array.size() > idx); +} + + +inline Json Parameter::get(size_t idx) const +{ + return param_array.at(idx); +} + + + + + +//////////////////////// Error implementation ///////////////////////////////// + +inline Error::Error(const Json& json) : Error("Internal error", -32603, nullptr) +{ + if (json != nullptr) + Error::parse_json(json); +} + + +inline Error::Error(std::nullptr_t) : NullableEntity(entity_t::error, nullptr), code_(0), message_(""), data_(nullptr) +{ +} + + +inline Error::Error(const std::string& message, int code, const Json& data) : NullableEntity(entity_t::error), code_(code), message_(message), data_(data) +{ +} + + +inline void Error::parse_json(const Json& json) +{ + try + { + if (json.count("code") == 0) + throw RpcException("code is missing"); + code_ = json["code"]; + if (json.count("message") == 0) + throw RpcException("message is missing"); + message_ = json["message"]; + if (json.count("data") != 0u) + data_ = json["data"]; + else + data_ = nullptr; + } + catch (const RpcException& e) + { + throw; + } + catch (const std::exception& e) + { + throw RpcException(e.what()); + } +} + + +inline Json Error::to_json() const +{ + Json j = { + {"code", code_}, + {"message", message_}, + }; + + if (!data_.is_null()) + j["data"] = data_; + return j; +} + + + + + +////////////////////// Request implementation ///////////////////////////////// + +inline Request::Request(const Json& json) : Entity(entity_t::request), method_(""), id_() +{ + if (json != nullptr) + Request::parse_json(json); +} + + +inline Request::Request(const Id& id, const std::string& method, const Parameter& params) : Entity(entity_t::request), method_(method), params_(params), id_(id) +{ +} + + +inline void Request::parse_json(const Json& json) +{ + try + { + if (json.count("id") == 0) + throw InvalidRequestException("id is missing"); + + try + { + id_ = Id(json["id"]); + } + catch(const std::exception& e) + { + throw InvalidRequestException(e.what()); + } + + if (json.count("jsonrpc") == 0) + throw InvalidRequestException("jsonrpc is missing", id_); + std::string jsonrpc = json["jsonrpc"].get(); + if (jsonrpc != "2.0") + throw InvalidRequestException("invalid jsonrpc value: " + jsonrpc, id_); + + if (json.count("method") == 0) + throw InvalidRequestException("method is missing", id_); + if (!json["method"].is_string()) + throw InvalidRequestException("method must be a string value", id_); + method_ = json["method"]; + if (method_.empty()) + throw InvalidRequestException("method must not be empty", id_); + + if (json.count("params") != 0u) + params_.parse_json(json["params"]); + else + params_ = nullptr; + } + catch (const RequestException& e) + { + throw; + } + catch (const std::exception& e) + { + throw InternalErrorException(e.what(), id_); + } +} + + +inline Json Request::to_json() const +{ + Json json = { + {"jsonrpc", "2.0"}, + {"method", method_}, + {"id", id_.to_json()} + }; + + if (params_) + json["params"] = params_.to_json(); + + return json; +} + + + +inline RpcException::RpcException(const char* text) : m_(text) +{ +} + +inline RpcException::RpcException(const std::string& text) : RpcException(text.c_str()) +{ +} + +inline const char* RpcException::what() const noexcept +{ + return m_.what(); +} + + + + +inline RpcEntityException::RpcEntityException(const Error& error) : RpcException(error.message()), Entity(entity_t::exception), error_(error) +{ +} + +inline void RpcEntityException::parse_json(const Json& /*json*/) +{ +} + + + +inline ParseErrorException::ParseErrorException(const Error& error) : RpcEntityException(error) +{ +} + +inline ParseErrorException::ParseErrorException(const std::string& data) : ParseErrorException(Error("Parse error", -32700, data)) +{ +} + +inline Json ParseErrorException::to_json() const +{ + Json response = { + {"jsonrpc", "2.0"}, + {"error", error_.to_json()}, + {"id", nullptr} + }; + + return response; +} + + + + +inline RequestException::RequestException(const Error& error, const Id& requestId) : RpcEntityException(error), id_(requestId) +{ +} + +inline Json RequestException::to_json() const +{ + Json response = { + {"jsonrpc", "2.0"}, + {"error", error_.to_json()}, + {"id", id_.to_json()} + }; + + return response; +} + + + + + +inline InvalidRequestException::InvalidRequestException(const Id& requestId) : RequestException(Error("Invalid request", -32600), requestId) +{ +} + +inline InvalidRequestException::InvalidRequestException(const Request& request) : InvalidRequestException(request.id()) +{ +} + +inline InvalidRequestException::InvalidRequestException(const char* data, const Id& requestId) : RequestException(Error("Invalid request", -32600, data), requestId) +{ +} + +inline InvalidRequestException::InvalidRequestException(const std::string& data, const Id& requestId) : InvalidRequestException(data.c_str(), requestId) +{ +} + + + +inline MethodNotFoundException::MethodNotFoundException(const Id& requestId) : RequestException(Error("Method not found", -32601), requestId) +{ +} + +inline MethodNotFoundException::MethodNotFoundException(const Request& request) : MethodNotFoundException(request.id()) +{ +} + +inline MethodNotFoundException::MethodNotFoundException(const char* data, const Id& requestId) : RequestException(Error("Method not found", -32601, data), requestId) +{ +} + +inline MethodNotFoundException::MethodNotFoundException(const std::string& data, const Id& requestId) : MethodNotFoundException(data.c_str(), requestId) +{ +} + + + +inline InvalidParamsException::InvalidParamsException(const Id& requestId) : RequestException(Error("Invalid params", -32602), requestId) +{ +} + +inline InvalidParamsException::InvalidParamsException(const Request& request) : InvalidParamsException(request.id()) +{ +} + +inline InvalidParamsException::InvalidParamsException(const char* data, const Id& requestId) : RequestException(Error("Invalid params", -32602, data), requestId) +{ +} + +inline InvalidParamsException::InvalidParamsException(const std::string& data, const Id& requestId) : InvalidParamsException(data.c_str(), requestId) +{ +} + + + +inline InternalErrorException::InternalErrorException(const Id& requestId) : RequestException(Error("Internal error", -32603), requestId) +{ +} + +inline InternalErrorException::InternalErrorException(const Request& request) : InternalErrorException(request.id()) +{ +} + +inline InternalErrorException::InternalErrorException(const char* data, const Id& requestId) : RequestException(Error("Internal error", -32603, data), requestId) +{ +} + +inline InternalErrorException::InternalErrorException(const std::string& data, const Id& requestId) : InternalErrorException(data.c_str(), requestId) +{ +} + + + +///////////////////// Response implementation ///////////////////////////////// + +inline Response::Response(const Json& json) : Entity(entity_t::response) +{ + if (json != nullptr) + Response::parse_json(json); +} + + +inline Response::Response(const Id& id, const Json& result) : Entity(entity_t::response), id_(id), result_(result), error_(nullptr) +{ +} + + +inline Response::Response(const Id& id, const Error& error) : Entity(entity_t::response), id_(id), result_(), error_(error) +{ +} + + +inline Response::Response(const Request& request, const Json& result) : Response(request.id(), result) +{ +} + + +inline Response::Response(const Request& request, const Error& error) : Response(request.id(), error) +{ +} + + +inline Response::Response(const RequestException& exception) : Response(exception.id(), exception.error()) +{ +} + + +inline void Response::parse_json(const Json& json) +{ + try + { + error_ = nullptr; + result_ = nullptr; + if (json.count("jsonrpc") == 0) + throw RpcException("jsonrpc is missing"); + std::string jsonrpc = json["jsonrpc"].get(); + if (jsonrpc != "2.0") + throw RpcException("invalid jsonrpc value: " + jsonrpc); + if (json.count("id") == 0) + throw RpcException("id is missing"); + id_ = Id(json["id"]); + if (json.count("result") != 0u) + result_ = json["result"]; + else if (json.count("error") != 0u) + error_.parse_json(json["error"]); + else + throw RpcException("response must contain result or error"); + } + catch (const RpcException& e) + { + throw; + } + catch (const std::exception& e) + { + throw RpcException(e.what()); + } +} + + +inline Json Response::to_json() const +{ + Json j = { + {"jsonrpc", "2.0"}, + {"id", id_.to_json()}, + }; + + if (error_) + j["error"] = error_.to_json(); + else + j["result"] = result_; + + return j; +} + + + + + +///////////////// Notification implementation ///////////////////////////////// + +inline Notification::Notification(const Json& json) : Entity(entity_t::notification) +{ + if (json != nullptr) + Notification::parse_json(json); +} + + +inline Notification::Notification(const char* method, const Parameter& params) : Entity(entity_t::notification), method_(method), params_(params) +{ +} + + +inline Notification::Notification(const std::string& method, const Parameter& params) : Notification(method.c_str(), params) +{ +} + + +inline void Notification::parse_json(const Json& json) +{ + try + { + if (json.count("jsonrpc") == 0) + throw RpcException("jsonrpc is missing"); + std::string jsonrpc = json["jsonrpc"].get(); + if (jsonrpc != "2.0") + throw RpcException("invalid jsonrpc value: " + jsonrpc); + + if (json.count("method") == 0) + throw RpcException("method is missing"); + if (!json["method"].is_string()) + throw RpcException("method must be a string value"); + method_ = json["method"]; + if (method_.empty()) + throw RpcException("method must not be empty"); + + if (json.count("params") != 0u) + params_.parse_json(json["params"]); + else + params_ = nullptr; + } + catch (const RpcException& e) + { + throw; + } + catch (const std::exception& e) + { + throw RpcException(e.what()); + } +} + + +inline Json Notification::to_json() const +{ + Json json = { + {"jsonrpc", "2.0"}, + {"method", method_}, + }; + + if (params_) + json["params"] = params_.to_json(); + + return json; +} + + + + + +//////////////////////// Batch implementation ///////////////////////////////// + +inline Batch::Batch(const Json& json) : Entity(entity_t::batch) +{ + if (json != nullptr) + Batch::parse_json(json); +} + + +inline void Batch::parse_json(const Json& json) +{ +// cout << "Batch::parse: " << json.dump() << "\n"; + entities.clear(); + for (const auto& it: json) + { +// cout << "x: " << it->dump() << "\n"; + entity_ptr entity(nullptr); + try + { + entity = Parser::do_parse_json(it); + if (!entity) + entity = std::make_shared("Invalid Request", -32600); + } + catch(const RequestException& e) + { + entity = std::make_shared(e); + } + catch(const std::exception& e) + { + entity = std::make_shared(e.what(), -32600); + } + entities.push_back(entity); + } + if (entities.empty()) + throw InvalidRequestException(); +} + + +inline Json Batch::to_json() const +{ + Json result; + for (const auto& j: entities) + result.push_back(j->to_json()); + return result; +} + + +/*void Batch::add(const entity_ptr entity) +{ + entities.push_back(entity); +} +*/ + + + + +//////////////////////// Parser implementation //////////////////////////////// + +inline void Parser::register_notification_callback(const std::string& notification, notification_callback callback) +{ + if (callback) + notification_callbacks_[notification] = callback; +} + + +inline void Parser::register_request_callback(const std::string& request, request_callback callback) +{ + if (callback) + request_callbacks_[request] = callback; +} + + +inline entity_ptr Parser::parse(const std::string& json_str) +{ + //std::cout << "parse: " << json_str << "\n"; + entity_ptr entity = do_parse(json_str); + if (entity && entity->is_notification()) + { + notification_ptr notification = std::dynamic_pointer_cast(entity); + if (notification_callbacks_.find(notification->method()) != notification_callbacks_.end()) + { + notification_callback callback = notification_callbacks_[notification->method()]; + if (callback) + callback(notification->params()); + } + } + else if (entity && entity->is_request()) + { + request_ptr request = std::dynamic_pointer_cast(entity); + if (request_callbacks_.find(request->method()) != request_callbacks_.end()) + { + request_callback callback = request_callbacks_[request->method()]; + if (callback) + { + jsonrpcpp::response_ptr response = callback(request->id(), request->params()); + if (response) + return response; + } + } + } + return entity; +} + + +inline entity_ptr Parser::parse_json(const Json& json) +{ + return do_parse_json(json); +} + + +inline entity_ptr Parser::do_parse(const std::string& json_str) +{ + try + { + return do_parse_json(Json::parse(json_str)); + } + catch (const RpcException& e) + { + throw; + } + catch (const std::exception& e) + { + throw ParseErrorException(e.what()); + } + + return nullptr; +} + + +inline entity_ptr Parser::do_parse_json(const Json& json) +{ + try + { + if (is_request(json)) + return std::make_shared(json); + if (is_notification(json)) + return std::make_shared(json); + if (is_response(json)) + return std::make_shared(json); + if (is_batch(json)) + return std::make_shared(json); + } + catch (const RpcException& e) + { + throw; + } + catch (const std::exception& e) + { + throw RpcException(e.what()); + } + + return nullptr; +} + + +inline bool Parser::is_request(const std::string& json_str) +{ + try + { + return is_request(Json::parse(json_str)); + } + catch (const std::exception& e) + { + return false; + } +} + + +inline bool Parser::is_request(const Json& json) +{ + return ((json.count("method") != 0u) && (json.count("id") != 0u)); +} + + +inline bool Parser::is_notification(const std::string& json_str) +{ + try + { + return is_notification(Json::parse(json_str)); + } + catch (const std::exception& e) + { + return false; + } +} + + +inline bool Parser:: is_notification(const Json& json) +{ + return ((json.count("method") != 0u) && (json.count("id") == 0)); +} + + +inline bool Parser::is_response(const std::string& json_str) +{ + try + { + return is_response(Json::parse(json_str)); + } + catch (const std::exception& e) + { + return false; + } +} + + +inline bool Parser::is_response(const Json& json) +{ + return ((json.count("result") != 0u) && (json.count("id") != 0u)); +} + + +inline bool Parser::is_batch(const std::string& json_str) +{ + try + { + return is_batch(Json::parse(json_str)); + } + catch (const std::exception& e) + { + return false; + } +} + + +inline bool Parser::is_batch(const Json& json) +{ + return (json.is_array()); +} + + +} // namespace jsonrpcpp + + + +#endif diff --git a/server/streamServer.cpp b/server/streamServer.cpp index 104cc7c8..662aec09 100644 --- a/server/streamServer.cpp +++ b/server/streamServer.cpp @@ -151,36 +151,36 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp { try { - ////LOG(INFO) << "StreamServer::ProcessRequest method: " << request->method << ", " << "id: " << request->id << "\n"; + ////LOG(INFO) << "StreamServer::ProcessRequest method: " << request->method << ", " << "id: " << request->id() << "\n"; Json result; - if (request->method.find("Client.") == 0) + if (request->method().find("Client.") == 0) { - ClientInfoPtr clientInfo = Config::instance().getClientInfo(request->params.get("id")); + ClientInfoPtr clientInfo = Config::instance().getClientInfo(request->params().get("id")); if (clientInfo == nullptr) - throw jsonrpcpp::InternalErrorException("Client not found", request->id); + throw jsonrpcpp::InternalErrorException("Client not found", request->id()); - if (request->method == "Client.GetStatus") + if (request->method() == "Client.GetStatus") { /// Request: {"id":8,"jsonrpc":"2.0","method":"Client.GetStatus","params":{"id":"00:21:6a:7d:74:fc"}} /// Response: {"id":8,"jsonrpc":"2.0","result":{"client":{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":74}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488026416,"usec":135973},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}}} result["client"] = clientInfo->toJson(); } - else if (request->method == "Client.SetVolume") + else if (request->method() == "Client.SetVolume") { /// Request: {"id":8,"jsonrpc":"2.0","method":"Client.SetVolume","params":{"id":"00:21:6a:7d:74:fc","volume":{"muted":false,"percent":74}}} /// Response: {"id":8,"jsonrpc":"2.0","result":{"volume":{"muted":false,"percent":74}}} /// Notification: {"jsonrpc":"2.0","method":"Client.OnVolumeChanged","params":{"id":"00:21:6a:7d:74:fc","volume":{"muted":false,"percent":74}}} - clientInfo->config.volume.fromJson(request->params.get("volume")); + clientInfo->config.volume.fromJson(request->params().get("volume")); result["volume"] = clientInfo->config.volume.toJson(); notification.reset(new jsonrpcpp::Notification("Client.OnVolumeChanged", jsonrpcpp::Parameter("id", clientInfo->id, "volume", clientInfo->config.volume.toJson()))); } - else if (request->method == "Client.SetLatency") + else if (request->method() == "Client.SetLatency") { /// Request: {"id":7,"jsonrpc":"2.0","method":"Client.SetLatency","params":{"id":"00:21:6a:7d:74:fc#2","latency":10}} /// Response: {"id":7,"jsonrpc":"2.0","result":{"latency":10}} /// Notification: {"jsonrpc":"2.0","method":"Client.OnLatencyChanged","params":{"id":"00:21:6a:7d:74:fc#2","latency":10}} - int latency = request->params.get("latency"); + int latency = request->params().get("latency"); if (latency < -10000) latency = -10000; else if (latency > settings_.bufferMs) @@ -189,20 +189,20 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp result["latency"] = clientInfo->config.latency; notification.reset(new jsonrpcpp::Notification("Client.OnLatencyChanged", jsonrpcpp::Parameter("id", clientInfo->id, "latency", clientInfo->config.latency))); } - else if (request->method == "Client.SetName") + else if (request->method() == "Client.SetName") { /// Request: {"id":6,"jsonrpc":"2.0","method":"Client.SetName","params":{"id":"00:21:6a:7d:74:fc#2","name":"Laptop"}} /// Response: {"id":6,"jsonrpc":"2.0","result":{"name":"Laptop"}} /// Notification: {"jsonrpc":"2.0","method":"Client.OnNameChanged","params":{"id":"00:21:6a:7d:74:fc#2","name":"Laptop"}} - clientInfo->config.name = request->params.get("name"); + clientInfo->config.name = request->params().get("name"); result["name"] = clientInfo->config.name; notification.reset(new jsonrpcpp::Notification("Client.OnNameChanged", jsonrpcpp::Parameter("id", clientInfo->id, "name", clientInfo->config.name))); } else - throw jsonrpcpp::MethodNotFoundException(request->id); + throw jsonrpcpp::MethodNotFoundException(request->id()); - if (request->method.find("Client.Set") == 0) + if (request->method().find("Client.Set") == 0) { /// Update client session_ptr session = getStreamSession(clientInfo->id); @@ -218,24 +218,24 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp } } } - else if (request->method.find("Group.") == 0) + else if (request->method().find("Group.") == 0) { - GroupPtr group = Config::instance().getGroup(request->params.get("id")); + GroupPtr group = Config::instance().getGroup(request->params().get("id")); if (group == nullptr) - throw jsonrpcpp::InternalErrorException("Group not found", request->id); + throw jsonrpcpp::InternalErrorException("Group not found", request->id()); - if (request->method == "Group.GetStatus") + if (request->method() == "Group.GetStatus") { /// Request: {"id":5,"jsonrpc":"2.0","method":"Group.GetStatus","params":{"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1"}} /// Response: {"id":5,"jsonrpc":"2.0","result":{"group":{"clients":[{"config":{"instance":2,"latency":10,"name":"Laptop","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488026485,"usec":644997},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":74}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488026481,"usec":223747},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":true,"name":"","stream_id":"stream 1"}}} result["group"] = group->toJson(); } - else if (request->method == "Group.SetMute") + else if (request->method() == "Group.SetMute") { /// Request: {"id":5,"jsonrpc":"2.0","method":"Group.SetMute","params":{"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","mute":true}} /// Response: {"id":5,"jsonrpc":"2.0","result":{"mute":true}} /// Notification: {"jsonrpc":"2.0","method":"Group.OnMute","params":{"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","mute":true}} - bool muted = request->params.get("mute"); + bool muted = request->params().get("mute"); group->muted = muted; /// Update clients @@ -257,15 +257,15 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp result["mute"] = group->muted; notification.reset(new jsonrpcpp::Notification("Group.OnMute", jsonrpcpp::Parameter("id", group->id, "mute", group->muted))); } - else if (request->method == "Group.SetStream") + else if (request->method() == "Group.SetStream") { /// Request: {"id":4,"jsonrpc":"2.0","method":"Group.SetStream","params":{"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","stream_id":"stream 1"}} /// Response: {"id":4,"jsonrpc":"2.0","result":{"stream_id":"stream 1"}} /// Notification: {"jsonrpc":"2.0","method":"Group.OnStreamChanged","params":{"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","stream_id":"stream 1"}} - string streamId = request->params.get("stream_id"); + string streamId = request->params().get("stream_id"); PcmStreamPtr stream = streamManager_->getStream(streamId); if (stream == nullptr) - throw jsonrpcpp::InternalErrorException("Stream not found", request->id); + throw jsonrpcpp::InternalErrorException("Stream not found", request->id()); group->streamId = streamId; @@ -285,12 +285,12 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp result["stream_id"] = group->streamId; notification.reset(new jsonrpcpp::Notification("Group.OnStreamChanged", jsonrpcpp::Parameter("id", group->id, "stream_id", group->streamId))); } - else if (request->method == "Group.SetClients") + else if (request->method() == "Group.SetClients") { /// Request: {"id":3,"jsonrpc":"2.0","method":"Group.SetClients","params":{"clients":["00:21:6a:7d:74:fc#2","00:21:6a:7d:74:fc"],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1"}} /// Response: {"id":3,"jsonrpc":"2.0","result":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025901,"usec":864472},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":100}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025905,"usec":45238},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}} /// Notification: {"jsonrpc":"2.0","method":"Server.OnUpdate","params":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025901,"usec":864472},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":100}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025905,"usec":45238},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}} - vector clients = request->params.get("clients"); + vector clients = request->params().get("clients"); /// Remove clients from group for (auto iter = group->clients.begin(); iter != group->clients.end();) { @@ -344,11 +344,11 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp notification.reset(new jsonrpcpp::Notification("Server.OnUpdate", jsonrpcpp::Parameter("server", server))); } else - throw jsonrpcpp::MethodNotFoundException(request->id); + throw jsonrpcpp::MethodNotFoundException(request->id()); } - else if (request->method.find("Server.") == 0) + else if (request->method().find("Server.") == 0) { - if (request->method.find("Server.GetRPCVersion") == 0) + if (request->method().find("Server.GetRPCVersion") == 0) { /// Request: {"id":8,"jsonrpc":"2.0","method":"Server.GetRPCVersion"} /// Response: {"id":8,"jsonrpc":"2.0","result":{"major":2,"minor":0,"patch":0}} @@ -359,20 +359,20 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp // : bugfix release result["patch"] = 0; } - else if (request->method == "Server.GetStatus") + else if (request->method() == "Server.GetStatus") { /// Request: {"id":1,"jsonrpc":"2.0","method":"Server.GetStatus"} /// Response: {"id":1,"jsonrpc":"2.0","result":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025696,"usec":578142},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":81}},"connected":true,"host":{"arch":"x86_64","ip":"192.168.0.54","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025696,"usec":611255},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}} result["server"] = Config::instance().getServerStatus(streamManager_->toJson()); } - else if (request->method == "Server.DeleteClient") + else if (request->method() == "Server.DeleteClient") { /// Request: {"id":2,"jsonrpc":"2.0","method":"Server.DeleteClient","params":{"id":"00:21:6a:7d:74:fc"}} /// Response: {"id":2,"jsonrpc":"2.0","result":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025751,"usec":654777},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}} /// Notification: {"jsonrpc":"2.0","method":"Server.OnUpdate","params":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025751,"usec":654777},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}} - ClientInfoPtr clientInfo = Config::instance().getClientInfo(request->params.get("id")); + ClientInfoPtr clientInfo = Config::instance().getClientInfo(request->params().get("id")); if (clientInfo == nullptr) - throw jsonrpcpp::InternalErrorException("Client not found", request->id); + throw jsonrpcpp::InternalErrorException("Client not found", request->id()); Config::instance().remove(clientInfo); @@ -383,11 +383,11 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp notification.reset(new jsonrpcpp::Notification("Server.OnUpdate", jsonrpcpp::Parameter("server", server))); } else - throw jsonrpcpp::MethodNotFoundException(request->id); + throw jsonrpcpp::MethodNotFoundException(request->id()); } - else if (request->method.find("Stream.") == 0) + else if (request->method().find("Stream.") == 0) { - if (request->method.find("Stream.SetMeta") == 0) + if (request->method().find("Stream.SetMeta") == 0) { /// Request: {"id":4,"jsonrpc":"2.0","method":"Stream.SetMeta","params":{"id":"Spotify", /// "meta": {"album": "some album", "artist": "some artist", "track": "some track"...}}} @@ -395,25 +395,25 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp /// Response: {"id":4,"jsonrpc":"2.0","result":{"stream_id":"Spotify"}} /// Call onMetaChanged(const PcmStream* pcmStream) for updates and notifications - LOG(INFO) << "Stream.SetMeta(" << request->params.get("id") << ")" << request->params.get("meta") <<"\n"; + LOG(INFO) << "Stream.SetMeta(" << request->params().get("id") << ")" << request->params().get("meta") <<"\n"; // Find stream - string streamId = request->params.get("id"); + string streamId = request->params().get("id"); PcmStreamPtr stream = streamManager_->getStream(streamId); if (stream == nullptr) - throw jsonrpcpp::InternalErrorException("Stream not found", request->id); + throw jsonrpcpp::InternalErrorException("Stream not found", request->id()); // Set metadata from request - stream->setMeta(request->params.get("meta")); + stream->setMeta(request->params().get("meta")); // Setup response result["id"] = streamId; } else - throw jsonrpcpp::MethodNotFoundException(request->id); + throw jsonrpcpp::MethodNotFoundException(request->id()); } else - throw jsonrpcpp::MethodNotFoundException(request->id); + throw jsonrpcpp::MethodNotFoundException(request->id()); Config::instance().save(); response.reset(new jsonrpcpp::Response(*request, result)); @@ -426,7 +426,7 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp catch (const exception& e) { LOG(ERROR) << "StreamServer::onMessageReceived exception: " << e.what() << ", message: " << request->to_json().dump() << "\n"; - response.reset(new jsonrpcpp::InternalErrorException(e.what(), request->id)); + response.reset(new jsonrpcpp::InternalErrorException(e.what(), request->id())); } } diff --git a/server/streamServer.h b/server/streamServer.h index bbc40a38..ede20ea0 100644 --- a/server/streamServer.h +++ b/server/streamServer.h @@ -27,7 +27,7 @@ #include #include -#include "jsonrp.hpp" +#include "jsonrpcpp.hpp" #include "streamSession.h" #include "streamreader/streamManager.h" #include "common/queue.h"