diff --git a/server/json/jsonRequestId.h b/server/json/jsonRequestId.h
deleted file mode 100644
index 7f177b49..00000000
--- a/server/json/jsonRequestId.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/***
- This file is part of snapcast
- Copyright (C) 2014-2016 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_REQUEST_ID_H
-#define JSON_REQUEST_ID_H
-
-#include
-#include
-#include "externals/json.hpp"
-
-
-using Json = nlohmann::json;
-
-
-struct req_id
-{
- enum class value_t : uint8_t
- {
- null = 0,
- string,
- integer
- };
-
- req_id() : type(value_t::null), int_id(0), string_id("")
- {
- }
-
- req_id(int id) : type(value_t::integer), int_id(id), string_id("")
- {
- }
-
- req_id(const std::string& id) : type(value_t::string), int_id(0), string_id(id)
- {
- }
-
- req_id(const Json& json_id) : type(value_t::null)
- {
- if (json_id.is_null())
- {
- type = value_t::null;
- }
- else if (json_id.is_number_integer())
- {
- int_id = json_id.get();
- type = value_t::integer;
- }
- else if (json_id.is_string())
- {
- string_id = json_id.get();
- type = value_t::string;
- }
- else
- throw std::invalid_argument("id must be integer, string or null");
- }
-
- Json toJson() const
- {
- if (type == value_t::string)
- return string_id;
- else if (type == value_t::integer)
- return int_id;
- else
- return nullptr;
- }
-
- friend std::ostream& operator<< (std::ostream &out, const req_id &id)
- {
- out << id.toJson();
- return out;
- }
-
- value_t type;
- int int_id;
- std::string string_id;
-};
-
-
-#endif
-
diff --git a/server/json/jsonrpc.cpp b/server/json/jsonrpc.cpp
index b21e2d41..b5ac19f0 100644
--- a/server/json/jsonrpc.cpp
+++ b/server/json/jsonrpc.cpp
@@ -22,14 +22,15 @@
using namespace std;
+namespace jsonrpc
+{
-
-JsonRequest::JsonRequest() : id(), method("")
+Request::Request() : method(""), id()
{
}
-void JsonRequest::parse(const std::string& json)
+void Request::parse(const std::string& json)
{
// http://www.jsonrpc.org/specification
// code message meaning
@@ -47,32 +48,32 @@ void JsonRequest::parse(const std::string& json)
}
catch (const exception& e)
{
- throw JsonRequestException(e.what(), -32700);
+ throw RequestException(e.what(), -32700);
}
if (json_.count("id") == 0)
- throw JsonInvalidRequestException("id is missing");
+ throw InvalidRequestException("id is missing");
try
{
- id = req_id(json_["id"]);
+ id = Id(json_["id"]);
}
catch(const std::exception& e)
{
- throw JsonInvalidRequestException(e.what());
+ throw InvalidRequestException(e.what());
}
if (json_.count("jsonrpc") == 0)
- throw JsonInvalidRequestException("jsonrpc is missing", id);
+ throw InvalidRequestException("jsonrpc is missing", id);
string jsonrpc = json_["jsonrpc"].get();
if (jsonrpc != "2.0")
- throw JsonInvalidRequestException("invalid jsonrpc value: " + jsonrpc, id);
+ throw InvalidRequestException("invalid jsonrpc value: " + jsonrpc, id);
if (json_.count("method") == 0)
- throw JsonInvalidRequestException("method is missing", id);
+ throw InvalidRequestException("method is missing", id);
method = json_["method"].get();
if (method.empty())
- throw JsonInvalidRequestException("method must not be empty", id);
+ throw InvalidRequestException("method must not be empty", id);
params.clear();
try
@@ -86,25 +87,25 @@ void JsonRequest::parse(const std::string& json)
}
catch (const exception& e)
{
- throw JsonInvalidParamsException(e.what(), id);
+ throw InvalidParamsException(e.what(), id);
}
}
- catch (const JsonRequestException& e)
+ catch (const RequestException& e)
{
throw;
}
catch (const exception& e)
{
- throw JsonInternalErrorException(e.what(), id);
+ throw InternalErrorException(e.what(), id);
}
}
-Json JsonRequest::getResponse(const Json& result)
+Json Request::getResponse(const Json& result)
{
Json response = {
{"jsonrpc", "2.0"},
- {"id", id.toJson()},
+ {"id", id.to_json()},
{"result", result}
};
@@ -112,7 +113,7 @@ Json JsonRequest::getResponse(const Json& result)
}
-Json JsonRequest::getError(int code, const std::string& message)
+Json Request::getError(int code, const std::string& message)
{
Json response = {
{"jsonrpc", "2.0"},
@@ -127,16 +128,16 @@ Json JsonRequest::getError(int code, const std::string& message)
}
-bool JsonRequest::hasParam(const std::string& key)
+bool Request::hasParam(const std::string& key)
{
return (params.find(key) != params.end());
}
-Json JsonRequest::getParam(const std::string& key)
+Json Request::getParam(const std::string& key)
{
if (!hasParam(key))
- throw JsonInvalidParamsException(id);
+ throw InvalidParamsException(id);
return params[key];
}
@@ -146,12 +147,12 @@ Json JsonRequest::getParam(const std::string& key)
bool JsonRequest::isParam(size_t idx, const std::string& param)
{
if (idx >= params.size())
- throw JsonInvalidParamsException(*this);
+ throw InvalidParamsException(*this);
return (params[idx] == param);
}
*/
-Json JsonNotification::getJson(const std::string& method, Json data)
+Json Notification::getJson(const std::string& method, const Json& data)
{
Json notification = {
{"jsonrpc", "2.0"},
@@ -162,3 +163,6 @@ Json JsonNotification::getJson(const std::string& method, Json data)
return notification;
}
+}
+
+
diff --git a/server/json/jsonrpc.h b/server/json/jsonrpc.h
index d27df1a8..a83d4332 100644
--- a/server/json/jsonrpc.h
+++ b/server/json/jsonrpc.h
@@ -22,28 +22,251 @@
#include
#include
#include "externals/json.hpp"
-#include "jsonrpcException.h"
-#include "jsonRequestId.h"
+#include "common/snapException.h"
using Json = nlohmann::json;
+namespace jsonrpc
+{
+class Entity
+{
+public:
+ Entity()
+ {
+ }
+
+ virtual ~Entity()
+ {
+ }
+
+ virtual Json to_json() const = 0;
+};
+
+
+
+struct Id
+{
+ enum class value_t : uint8_t
+ {
+ null = 0,
+ string,
+ integer
+ };
+
+ Id() : type(value_t::null), int_id(0), string_id("")
+ {
+ }
+
+ Id(int id) : type(value_t::integer), int_id(id), string_id("")
+ {
+ }
+
+ Id(const std::string& id) : type(value_t::string), int_id(0), string_id(id)
+ {
+ }
+
+ Id(const Json& json_id) : type(value_t::null)
+ {
+ if (json_id.is_null())
+ {
+ type = value_t::null;
+ }
+ else if (json_id.is_number_integer())
+ {
+ int_id = json_id.get();
+ type = value_t::integer;
+ }
+ else if (json_id.is_string())
+ {
+ string_id = json_id.get();
+ type = value_t::string;
+ }
+ else
+ throw std::invalid_argument("id must be integer, string or null");
+ }
+
+ Json to_json() const
+ {
+ if (type == value_t::string)
+ return string_id;
+ else if (type == value_t::integer)
+ return int_id;
+ else
+ return nullptr;
+ }
+
+ 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 Error : public Entity
+{
+public:
+ Error(int code, const std::string& message, const Json& data = nullptr) : Entity(), code(code), message(message), data(data)
+ {
+ }
+
+ Error(const std::string& message, const Json& data = nullptr) : Error(-32603, message, data)
+ {
+ }
+
+ virtual Json to_json() const
+ {
+ Json j = {
+ {"code", code},
+ {"message", message},
+ };
+
+ if (!data.is_null())
+ j["data"] = data;
+ return j;
+ }
+
+ int code;
+ std::string message;
+ Json data;
+};
+
+
+class RequestException : public SnapException
+{
+ Error error_;
+ Id id_;
+public:
+ RequestException(const char* text, int errorCode = 0, const Id& requestId = Id()) : SnapException(text), error_(text, errorCode), id_(requestId)
+ {
+ }
+
+ RequestException(const std::string& text, int errorCode = 0, const Id& requestId = Id()) : SnapException(text), error_(text, errorCode), id_(requestId)
+ {
+ }
+
+ RequestException(const RequestException& e) : SnapException(e.what()), error_(error()), id_(e.id_)
+ {
+ }
+
+ virtual Error error() const noexcept
+ {
+ return error_;
+ }
+
+ Json getResponse() const noexcept
+ {
+ Json response = {
+ {"jsonrpc", "2.0"},
+ {"error", error_.to_json()},
+ {"id", id_.to_json()}
+ };
+
+ return response;
+ }
+};
+
+
+// -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 InvalidRequestException : public RequestException
+{
+public:
+ InvalidRequestException(const Id& requestId = Id()) : RequestException("invalid request", -32600, requestId)
+ {
+ }
+
+ InvalidRequestException(const std::string& message, const Id& requestId = Id()) : RequestException(message, -32600, requestId)
+ {
+ }
+};
+
+
+
+class MethodNotFoundException : public RequestException
+{
+public:
+ MethodNotFoundException(const Id& requestId = Id()) : RequestException("method not found", -32601, requestId)
+ {
+ }
+
+ MethodNotFoundException(const std::string& message, const Id& requestId = Id()) : RequestException(message, -32601, requestId)
+ {
+ }
+};
+
+
+
+class InvalidParamsException : public RequestException
+{
+public:
+ InvalidParamsException(const Id& requestId = Id()) : RequestException("invalid params", -32602, requestId)
+ {
+ }
+
+ InvalidParamsException(const std::string& message, const Id& requestId = Id()) : RequestException(message, -32602, requestId)
+ {
+ }
+};
+
+
+class InternalErrorException : public RequestException
+{
+public:
+ InternalErrorException(const Id& requestId = Id()) : RequestException("internal error", -32603, requestId)
+ {
+ }
+
+ InternalErrorException(const std::string& message, const Id& requestId = Id()) : RequestException(message, -32603, requestId)
+ {
+ }
+};
+
+
+
+
+/*
+class Response
+{
+public:
+ Response();
+
+ void parse(const std::string& json);
+ std::string result;
+ Error error;
+ Id id;
+
+
+protected:
+ Json json_;
+
+};
+*/
/// JSON-RPC 2.0 request
/**
* Simple jsonrpc 2.0 parser with getters
* Currently no named parameters are supported, but only array parameters
*/
-class JsonRequest
+class Request
{
public:
- JsonRequest();
+ Request();
void parse(const std::string& json);
- req_id id;
std::string method;
std::map params;
+ Id id;
Json getResponse(const Json& result);
Json getError(int code, const std::string& message);
@@ -56,9 +279,9 @@ public:
{
T value = getParam(key).get();
if (value < lowerRange)
- throw JsonInvalidParamsException(key + " out of range", id);
+ throw InvalidParamsException(key + " out of range", id);
else if (value > upperRange)
- throw JsonInvalidParamsException(key + " out of range", id);
+ throw InvalidParamsException(key + " out of range", id);
return value;
}
@@ -71,14 +294,23 @@ protected:
-class JsonNotification
+class Notification
{
public:
- static Json getJson(const std::string& method, Json data);
+ static Json getJson(const std::string& method, const Json& data);
};
+class Batch
+{
+
+};
+
+
+}
+
+
diff --git a/server/json/jsonrpcException.h b/server/json/jsonrpcException.h
deleted file mode 100644
index 3d26d0be..00000000
--- a/server/json/jsonrpcException.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/***
- This file is part of snapcast
- Copyright (C) 2014-2016 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_EXCEPTION_H
-#define JSON_RPC_EXCEPTION_H
-
-#include
-#include "externals/json.hpp"
-#include "common/snapException.h"
-#include "jsonRequestId.h"
-
-
-using Json = nlohmann::json;
-
-
-
-class JsonRequestException : public SnapException
-{
- int errorCode_;
- req_id id_;
-public:
- JsonRequestException(const char* text, int errorCode = 0, const req_id& requestId = req_id()) : SnapException(text), errorCode_(errorCode), id_(requestId)
- {
- }
-
- JsonRequestException(const std::string& text, int errorCode = 0, const req_id& requestId = req_id()) : SnapException(text), errorCode_(errorCode), id_(requestId)
- {
- }
-
-// 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()}
- }},
- {"id", id_.toJson()}
- };
-
- return response;
- }
-};
-
-
-// -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 JsonInvalidRequestException : public JsonRequestException
-{
-public:
- JsonInvalidRequestException(const req_id& requestId = req_id()) : JsonRequestException("invalid request", -32600, requestId)
- {
- }
-
- JsonInvalidRequestException(const std::string& message, const req_id& requestId = req_id()) : JsonRequestException(message, -32600, requestId)
- {
- }
-};
-
-
-
-class JsonMethodNotFoundException : public JsonRequestException
-{
-public:
- JsonMethodNotFoundException(const req_id& requestId = req_id()) : JsonRequestException("method not found", -32601, requestId)
- {
- }
-
- JsonMethodNotFoundException(const std::string& message, const req_id& requestId = req_id()) : JsonRequestException(message, -32601, requestId)
- {
- }
-};
-
-
-
-class JsonInvalidParamsException : public JsonRequestException
-{
-public:
- JsonInvalidParamsException(const req_id& requestId = req_id()) : JsonRequestException("invalid params", -32602, requestId)
- {
- }
-
- JsonInvalidParamsException(const std::string& message, const req_id& requestId = req_id()) : JsonRequestException(message, -32602, requestId)
- {
- }
-};
-
-
-class JsonInternalErrorException : public JsonRequestException
-{
-public:
- JsonInternalErrorException(const req_id& requestId = req_id()) : JsonRequestException("internal error", -32603, requestId)
- {
- }
-
- JsonInternalErrorException(const std::string& message, const req_id& requestId = req_id()) : JsonRequestException(message, -32603, requestId)
- {
- }
-};
-
-
-#endif
-
diff --git a/server/streamServer.cpp b/server/streamServer.cpp
index 9513d2b3..d61e479a 100644
--- a/server/streamServer.cpp
+++ b/server/streamServer.cpp
@@ -43,7 +43,7 @@ void StreamServer::onStateChanged(const PcmStream* pcmStream, const ReaderState&
{
logO << "onStateChanged (" << pcmStream->getName() << "): " << state << "\n";
// logO << pcmStream->toJson().dump(4);
- json notification = JsonNotification::getJson("Stream.OnUpdate", pcmStream->toJson());
+ json notification = jsonrpc::Notification::getJson("Stream.OnUpdate", pcmStream->toJson());
controlServer_->send(notification.dump(), NULL);
}
@@ -99,7 +99,7 @@ void StreamServer::onDisconnect(StreamSession* streamSession)
Config::instance().save();
if (controlServer_ != nullptr)
{
- json notification = JsonNotification::getJson("Client.OnDisconnect", clientInfo->toJson());
+ json notification = jsonrpc::Notification::getJson("Client.OnDisconnect", clientInfo->toJson());
controlServer_->send(notification.dump());
}
}
@@ -108,7 +108,7 @@ void StreamServer::onDisconnect(StreamSession* streamSession)
void StreamServer::onMessageReceived(ControlSession* controlSession, const std::string& message)
{
- JsonRequest request;
+ jsonrpc::Request request;
try
{
request.parse(message);
@@ -120,7 +120,7 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
{
ClientInfoPtr clientInfo = Config::instance().getClientInfo(request.getParam("client").get());
if (clientInfo == nullptr)
- throw JsonInternalErrorException("Client not found", request.id);
+ throw jsonrpc::InternalErrorException("Client not found", request.id);
if (request.method == "Client.GetStatus")
{
@@ -139,7 +139,7 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
clientInfo->config.name = request.getParam("name").get();
}
else
- throw JsonMethodNotFoundException(request.id);
+ throw jsonrpc::MethodNotFoundException(request.id);
if (request.method.find("Client.Set") == 0)
@@ -160,7 +160,7 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
}
/// Notify others
- json notification = JsonNotification::getJson("Client.OnUpdate", clientInfo->toJson());
+ json notification = jsonrpc::Notification::getJson("Client.OnUpdate", clientInfo->toJson());
logO << "Notification: " << notification.dump() << "\n";
controlServer_->send(notification.dump(), controlSession);
}
@@ -169,7 +169,7 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
{
GroupPtr group = Config::instance().getGroup(request.getParam("group").get());
if (group == nullptr)
- throw JsonInternalErrorException("Group not found", request.id);
+ throw jsonrpc::InternalErrorException("Group not found", request.id);
if (request.method == "Group.GetStatus")
{
@@ -180,7 +180,7 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
string streamId = request.getParam("id").get();
PcmStreamPtr stream = streamManager_->getStream(streamId);
if (stream == nullptr)
- throw JsonInternalErrorException("Stream not found", request.id);
+ throw jsonrpc::InternalErrorException("Stream not found", request.id);
group->streamId = streamId;
@@ -199,7 +199,7 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
}
/// Notify others
- json notification = JsonNotification::getJson("Group.OnUpdate", group->toJson());
+ json notification = jsonrpc::Notification::getJson("Group.OnUpdate", group->toJson());
logO << "Notification: " << notification.dump() << "\n";
controlServer_->send(notification.dump(), controlSession);
}
@@ -258,12 +258,12 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
result = {{"method", "Server.OnUpdate"}, {"params", serverJson}};
/// Notify others: since at least two groups are affected, send a complete server update
- json notification = JsonNotification::getJson("Server.OnUpdate", serverJson);
+ json notification = jsonrpc::Notification::getJson("Server.OnUpdate", serverJson);
logO << "Notification: " << notification.dump() << "\n";
controlServer_->send(notification.dump(), controlSession);
}
else
- throw JsonMethodNotFoundException(request.id);
+ throw jsonrpc::MethodNotFoundException(request.id);
}
else if (request.method.find("Server.") == 0)
{
@@ -275,7 +275,7 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
{
ClientInfoPtr clientInfo = Config::instance().getClientInfo(request.getParam("client").get());
if (clientInfo == nullptr)
- throw JsonInternalErrorException("Client not found", request.id);
+ throw jsonrpc::InternalErrorException("Client not found", request.id);
Config::instance().remove(clientInfo);
@@ -283,29 +283,29 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
result = {{"method", "Server.OnUpdate"}, {"params", serverJson}};
/// Notify others
- json notification = JsonNotification::getJson("Server.OnUpdate", serverJson);
+ json notification = jsonrpc::Notification::getJson("Server.OnUpdate", serverJson);
logO << "Notification: " << notification.dump() << "\n";
controlServer_->send(notification.dump(), controlSession);
}
else
- throw JsonMethodNotFoundException(request.id);
+ throw jsonrpc::MethodNotFoundException(request.id);
}
else
- throw JsonMethodNotFoundException(request.id);
+ throw jsonrpc::MethodNotFoundException(request.id);
Config::instance().save();
string responseJson = request.getResponse(result).dump();
logO << "Response: " << responseJson << "\n";
controlSession->send(responseJson);
}
- catch (const JsonRequestException& e)
+ catch (const jsonrpc::RequestException& e)
{
// logE << "JsonRequestException: " << e.getResponse().dump() << ", message: " << message << "\n";
controlSession->send(e.getResponse().dump());
}
catch (const exception& e)
{
- JsonInternalErrorException jsonException(e.what(), request.id);
+ jsonrpc::InternalErrorException jsonException(e.what(), request.id);
controlSession->send(jsonException.getResponse().dump());
}
}
@@ -392,12 +392,12 @@ void StreamServer::onMessageReceived(StreamSession* connection, const msg::BaseM
if (newGroup)
{
json serverJson = Config::instance().getServerStatus(streamManager_->toJson());
- json notification = JsonNotification::getJson("Server.OnUpdate", serverJson);
+ json notification = jsonrpc::Notification::getJson("Server.OnUpdate", serverJson);
controlServer_->send(notification.dump());
}
else
{
- json notification = JsonNotification::getJson("Client.OnConnect", client->toJson());
+ json notification = jsonrpc::Notification::getJson("Client.OnConnect", client->toJson());
//logO << notification.dump(4) << "\n";
controlServer_->send(notification.dump());
}