diff --git a/server/jsonrpc.cpp b/server/jsonrpc.cpp new file mode 100644 index 00000000..8a18531a --- /dev/null +++ b/server/jsonrpc.cpp @@ -0,0 +1,161 @@ +/*** + This file is part of snapcast + Copyright (C) 2015 Johannes Pohl + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +***/ + +#include "jsonrpc.h" +#include "common/log.h" + + +using namespace std; + + + +JsonRequest::JsonRequest() : id(-1), method("") +{ +} + + +void JsonRequest::parse(const std::string& json) +{ + // 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 + { + try + { + json_ = Json::parse(json); + } + catch (const exception& e) + { + throw JsonRequestException(e.what(), -32700); + } + + id = json_["id"].get(); + string jsonrpc = json_["jsonrpc"].get(); + if (jsonrpc != "2.0") + throw JsonRequestException("invalid jsonrpc value: " + jsonrpc, -32600); + method = json_["method"].get(); + if (method.empty()) + throw JsonRequestException("method must not be empty", -32600); + if (id < 0) + throw JsonRequestException("id must be a positive integer", -32600); + + params.clear(); + try + { + if (json_["params"] != nullptr) + params = json_["params"].get>(); + } + catch (const exception& e) + { + throw JsonRequestException(e.what(), -32602); + } + } + catch (const JsonRequestException& e) + { + throw; + } + catch (const exception& e) + { + throw JsonRequestException(e.what(), -32603, id); + } +} + + +Json JsonRequest::getResponse(const Json& result) +{ + Json response = { + {"jsonrpc", "2.0"}, + {"id", id}, + {"result", result} + }; + + return response; +} + + +Json JsonRequest::getError(int code, const std::string& message) +{ + Json response = { + {"jsonrpc", "2.0"}, + {"error", { + {"code", code}, + {"message", message} + }}, + }; + + return response; + +} + + + +/* + + if ((method == "get") || (method == "set")) + { + vector params; + try + { + params = request["params"].get>(); + } + catch (const exception& e) + { + throw JsonRpcException(e.what(), -32602); + } + if (method == "get") + { + //{"jsonrpc": "2.0", "method": "get", "params": ["status"], "id": 2} + //{"jsonrpc": "2.0", "method": "get", "params": ["status", "server"], "id": 2} + //{"jsonrpc": "2.0", "method": "get", "params": ["status", "client"], "id": 2} + //{"jsonrpc": "2.0", "method": "get", "params": ["status", "client", "MAC"], "id": 2} + vector params = request["params"].get>(); + for (auto s: params) + logO << s << "\n"; + response["result"] = "???";//nullptr; + } + else if (method == "set") + { + //{"jsonrpc": "2.0", "method": "set", "params": ["volume", "0.9", "client", "MAC"], "id": 2} + //{"jsonrpc": "2.0", "method": "set", "params": ["active", "client", "MAC"], "id": 2} + response["result"] = "234";//nullptr; + } + } + else + throw JsonRpcException("method not found: \"" + method + "\"", -32601); + + connection->send(response.dump()); + +*/ + + + +/* + Json response = { + {"jsonrpc", "2.0"}, + {"id", id} + }; + +*/ + + diff --git a/server/jsonrpc.h b/server/jsonrpc.h new file mode 100644 index 00000000..7200e57f --- /dev/null +++ b/server/jsonrpc.h @@ -0,0 +1,129 @@ +/*** + This file is part of snapcast + Copyright (C) 2015 Johannes Pohl + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +***/ + +#ifndef JSON_RPC_H +#define JSON_RPC_H + +#include +#include +#include "json.hpp" +#include "common/snapException.h" + +using Json = nlohmann::json; + + + + +class JsonRequest +{ +public: + /// ctor. Encoded PCM data is passed to the PipeListener + JsonRequest(); + + void parse(const std::string& json); + int id; + std::string method; + std::vector params; + + Json getResponse(const Json& result); + Json getError(int code, const std::string& message); + +protected: + Json json_; + +}; + + + + +class JsonRequestException : public SnapException +{ + int errorCode_, id_; +public: + JsonRequestException(const char* text, int errorCode = 0, int id = -1) : SnapException(text), errorCode_(errorCode), id_(id) + { + } + + JsonRequestException(const std::string& text, int errorCode = 0, int id = -1) : SnapException(text), errorCode_(errorCode), id_(id) + { + } + + JsonRequestException(const JsonRequest& request, const std::string& text, int errorCode = 0) : SnapException(text), errorCode_(errorCode), id_(request.id) + { + } + + JsonRequestException(const JsonRequestException& e) : SnapException(e.what()), errorCode_(e.errorCode()), id_(e.id_) + { + } + + virtual int errorCode() const noexcept + { + return errorCode_; + } + + Json getResponse() const noexcept + { + int errorCode = errorCode_; + if (errorCode == 0) + errorCode = -32603; + + Json response = { + {"jsonrpc", "2.0"}, + {"error", { + {"code", errorCode}, + {"message", what()} + }}, + }; + if (id_ == -1) + response["id"] = nullptr; + else + response["id"] = id_; + + return response; + } +}; + + +class JsonMethodNotFoundException : public JsonRequestException +{ +public: + JsonMethodNotFoundException(const JsonRequest& request) : JsonRequestException(request, "method not found", -32601) + { + } + + JsonMethodNotFoundException(const JsonRequest& request, const std::string& message) : JsonRequestException(request, message, -32601) + { + } +}; + + + +class JsonInvalidParamsException : public JsonRequestException +{ +public: + JsonInvalidParamsException(const JsonRequest& request) : JsonRequestException(request, "invalid params", -32602) + { + } + + JsonInvalidParamsException(const JsonRequest& request, const std::string& message) : JsonRequestException(request, message, -32602) + { + } +}; + + +#endif