De-coupled JSON parsing from the Netstring class.

This commit is contained in:
Gunnar Beutner 2012-05-13 10:44:03 +02:00
parent 7b03f52e99
commit cdcac0d903
9 changed files with 125 additions and 110 deletions

View File

@ -57,6 +57,8 @@
#include <typeinfo>
#include <map>
#include <list>
#include <algorithm>
#include <functional>
#if defined(__APPLE__) && defined(__MACH__)
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"

View File

@ -17,8 +17,6 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include <functional>
#include <algorithm>
#include "i2-base.h"
using namespace icinga;

View File

@ -68,7 +68,7 @@ void EndpointManager::AddConnection(string node, string service)
void EndpointManager::RegisterServer(JsonRpcServer::Ptr server)
{
m_Servers.push_front(server);
m_Servers.push_back(server);
server->OnNewClient += bind_weak(&EndpointManager::NewClientHandler, shared_from_this());
}
@ -86,7 +86,9 @@ int EndpointManager::NewClientHandler(const NewClientEventArgs& ncea)
void EndpointManager::UnregisterServer(JsonRpcServer::Ptr server)
{
m_Servers.remove(server);
m_Servers.erase(
remove(m_Servers.begin(), m_Servers.end(), server),
m_Servers.end());
// TODO: unbind event
}
@ -96,7 +98,7 @@ void EndpointManager::RegisterEndpoint(Endpoint::Ptr endpoint)
throw InvalidArgumentException("Identity must be empty.");
endpoint->SetEndpointManager(static_pointer_cast<EndpointManager>(shared_from_this()));
m_Endpoints.push_front(endpoint);
m_Endpoints.push_back(endpoint);
NewEndpointEventArgs neea;
neea.Source = shared_from_this();
@ -106,7 +108,9 @@ void EndpointManager::RegisterEndpoint(Endpoint::Ptr endpoint)
void EndpointManager::UnregisterEndpoint(Endpoint::Ptr endpoint)
{
m_Endpoints.remove(endpoint);
m_Endpoints.erase(
remove(m_Endpoints.begin(), m_Endpoints.end(), endpoint),
m_Endpoints.end());
}
void EndpointManager::SendUnicastRequest(Endpoint::Ptr sender, Endpoint::Ptr recipient, const JsonRpcRequest& request, bool fromLocal)
@ -123,7 +127,7 @@ void EndpointManager::SendUnicastRequest(Endpoint::Ptr sender, Endpoint::Ptr rec
throw InvalidArgumentException("Missing 'method' parameter.");
if (recipient->IsMethodSink(method)) {
Application::Log(sender->GetAddress() + " -> " + recipient->GetAddress() + ": " + method);
//Application::Log(sender->GetAddress() + " -> " + recipient->GetAddress() + ": " + method);
recipient->ProcessRequest(sender, request);
}
}
@ -145,7 +149,7 @@ void EndpointManager::SendMulticastRequest(Endpoint::Ptr sender, const JsonRpcRe
if (!request.GetMethod(&method))
throw InvalidArgumentException("Message is missing the 'method' property.");
for (list<Endpoint::Ptr>::iterator i = m_Endpoints.begin(); i != m_Endpoints.end(); i++)
for (vector<Endpoint::Ptr>::iterator i = m_Endpoints.begin(); i != m_Endpoints.end(); i++)
{
SendUnicastRequest(sender, *i, request, fromLocal);
}
@ -156,7 +160,7 @@ void EndpointManager::ForEachEndpoint(function<int (const NewEndpointEventArgs&)
NewEndpointEventArgs neea;
neea.Source = shared_from_this();
list<Endpoint::Ptr>::iterator prev, i;
vector<Endpoint::Ptr>::iterator prev, i;
for (i = m_Endpoints.begin(); i != m_Endpoints.end(); ) {
prev = i;
i++;
@ -168,7 +172,7 @@ void EndpointManager::ForEachEndpoint(function<int (const NewEndpointEventArgs&)
Endpoint::Ptr EndpointManager::GetEndpointByIdentity(string identity) const
{
list<Endpoint::Ptr>::const_iterator i;
vector<Endpoint::Ptr>::const_iterator i;
for (i = m_Endpoints.begin(); i != m_Endpoints.end(); i++) {
if ((*i)->GetIdentity() == identity)
return *i;

View File

@ -33,8 +33,8 @@ class I2_ICINGA_API EndpointManager : public Object
string m_Identity;
shared_ptr<SSL_CTX> m_SSLContext;
list<JsonRpcServer::Ptr> m_Servers;
list<Endpoint::Ptr> m_Endpoints;
vector<JsonRpcServer::Ptr> m_Servers;
vector<Endpoint::Ptr> m_Endpoints;
void RegisterServer(JsonRpcServer::Ptr server);
void UnregisterServer(JsonRpcServer::Ptr server);

View File

@ -33,18 +33,21 @@ void JsonRpcClient::Start(void)
void JsonRpcClient::SendMessage(const Message& message)
{
Netstring::WriteMessageToFIFO(GetSendQueue(), message);
Netstring::WriteStringToFIFO(GetSendQueue(), message.ToJsonString());
}
int JsonRpcClient::DataAvailableHandler(const EventArgs&)
{
for (;;) {
try {
string jsonString;
Message message;
if (!Netstring::ReadMessageFromFIFO(GetRecvQueue(), &message))
if (!Netstring::ReadStringFromFIFO(GetRecvQueue(), &jsonString))
break;
message = Message(jsonString);
NewMessageEventArgs nea;
nea.Source = shared_from_this();
nea.Message = message;

View File

@ -18,6 +18,7 @@
******************************************************************************/
#include "i2-jsonrpc.h"
#include <cJSON.h>
using namespace icinga;
@ -26,6 +27,18 @@ Message::Message(void)
m_Dictionary = make_shared<Dictionary>();
}
Message::Message(string jsonString)
{
json_t *json = cJSON_Parse(jsonString.c_str());
if (!json)
throw InvalidArgumentException("Invalid JSON string");
m_Dictionary = GetDictionaryFromJson(json);
cJSON_Delete(json);
}
Message::Message(const Dictionary::Ptr& dictionary)
{
m_Dictionary = dictionary;
@ -36,6 +49,80 @@ Message::Message(const Message& message)
m_Dictionary = message.GetDictionary();
}
Dictionary::Ptr Message::GetDictionaryFromJson(json_t *json)
{
Dictionary::Ptr dictionary = make_shared<Dictionary>();
for (cJSON *i = json->child; i != NULL; i = i->next) {
switch (i->type) {
case cJSON_Number:
dictionary->SetProperty(i->string, i->valueint);
break;
case cJSON_String:
dictionary->SetProperty(i->string, i->valuestring);
break;
case cJSON_Object:
dictionary->SetProperty(i->string, GetDictionaryFromJson(i));
break;
default:
break;
}
}
return dictionary;
}
json_t *Message::GetJsonFromDictionary(const Dictionary::Ptr& dictionary)
{
cJSON *json;
string valueString;
Dictionary::Ptr valueDictionary;
json = cJSON_CreateObject();
for (DictionaryIterator i = dictionary->Begin(); i != dictionary->End(); i++) {
switch (i->second.GetType()) {
case VariantInteger:
cJSON_AddNumberToObject(json, i->first.c_str(), i->second.GetInteger());
break;
case VariantString:
valueString = i->second.GetString();
cJSON_AddStringToObject(json, i->first.c_str(), valueString.c_str());
break;
case VariantObject:
valueDictionary = dynamic_pointer_cast<Dictionary>(i->second.GetObject());
if (valueDictionary)
cJSON_AddItemToObject(json, i->first.c_str(), GetJsonFromDictionary(valueDictionary));
default:
break;
}
}
return json;
}
string Message::ToJsonString(void) const
{
json_t *json = GetJsonFromDictionary(m_Dictionary);
char *jsonString;
string result;
#ifdef _DEBUG
jsonString = cJSON_Print(json);
#else /* _DEBUG */
jsonString = cJSON_PrintUnformatted(json);
#endif /* _DEBUG */
cJSON_Delete(json);
result = jsonString;
free(jsonString);
return result;
}
Dictionary::Ptr Message::GetDictionary(void) const
{
return m_Dictionary;

View File

@ -20,19 +20,29 @@
#ifndef MESSAGE_H
#define MESSAGE_H
struct cJSON;
namespace icinga
{
typedef ::cJSON json_t;
class I2_JSONRPC_API Message
{
private:
Dictionary::Ptr m_Dictionary;
static Dictionary::Ptr GetDictionaryFromJson(json_t *json);
static json_t *GetJsonFromDictionary(const Dictionary::Ptr& dictionary);
public:
Message(void);
Message(string json);
Message(const Dictionary::Ptr& dictionary);
Message(const Message& message);
string ToJsonString(void) const;
Dictionary::Ptr GetDictionary(void) const;
bool GetPropertyString(string key, string *value) const;

View File

@ -17,67 +17,12 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include <cstdio>
#include "i2-jsonrpc.h"
#include <cJSON.h>
using namespace icinga;
Dictionary::Ptr Netstring::GetDictionaryFromJson(json_t *json)
{
Dictionary::Ptr dictionary = make_shared<Dictionary>();
for (cJSON *i = json->child; i != NULL; i = i->next) {
switch (i->type) {
case cJSON_Number:
dictionary->SetProperty(i->string, i->valueint);
break;
case cJSON_String:
dictionary->SetProperty(i->string, i->valuestring);
break;
case cJSON_Object:
dictionary->SetProperty(i->string, GetDictionaryFromJson(i));
break;
default:
break;
}
}
return dictionary;
}
json_t *Netstring::GetJsonFromDictionary(const Dictionary::Ptr& dictionary)
{
cJSON *json;
string valueString;
Dictionary::Ptr valueDictionary;
json = cJSON_CreateObject();
for (DictionaryIterator i = dictionary->Begin(); i != dictionary->End(); i++) {
switch (i->second.GetType()) {
case VariantInteger:
cJSON_AddNumberToObject(json, i->first.c_str(), i->second.GetInteger());
break;
case VariantString:
valueString = i->second.GetString();
cJSON_AddStringToObject(json, i->first.c_str(), valueString.c_str());
break;
case VariantObject:
valueDictionary = dynamic_pointer_cast<Dictionary>(i->second.GetObject());
if (valueDictionary)
cJSON_AddItemToObject(json, i->first.c_str(), GetJsonFromDictionary(valueDictionary));
default:
break;
}
}
return json;
}
/* based on https://github.com/PeterScott/netstring-c/blob/master/netstring.c */
bool Netstring::ReadMessageFromFIFO(FIFO::Ptr fifo, Message *message)
bool Netstring::ReadStringFromFIFO(FIFO::Ptr fifo, string *str)
{
size_t buffer_length = fifo->GetSize();
char *buffer = (char *)fifo->GetReadBuffer();
@ -113,45 +58,22 @@ bool Netstring::ReadMessageFromFIFO(FIFO::Ptr fifo, Message *message)
if (buffer[i + len] != ',')
throw InvalidArgumentException("Invalid Netstring (missing ,)");
/* nuke the comma delimiter */
buffer[i + len] = '\0';
cJSON *object = cJSON_Parse(&buffer[i]);
if (object == NULL) {
/* restore the comma */
buffer[i + len] = ',';
throw InvalidArgumentException("Invalid JSON string");
}
*str = string(&buffer[i], &buffer[i + len]);
/* remove the data from the fifo */
fifo->Read(NULL, i + len + 1);
*message = Message(GetDictionaryFromJson(object));
cJSON_Delete(object);
return true;
}
void Netstring::WriteMessageToFIFO(FIFO::Ptr fifo, const Message& message)
void Netstring::WriteStringToFIFO(FIFO::Ptr fifo, const string& str)
{
char *json;
cJSON *object = GetJsonFromDictionary(message.GetDictionary());
size_t len;
#ifdef _DEBUG
json = cJSON_Print(object);
#else /* _DEBUG */
json = cJSON_PrintUnformatted(object);
#endif /* _DEBUG */
cJSON_Delete(object);
len = strlen(json);
unsigned long len = str.size();
char strLength[50];
sprintf(strLength, "%lu:", (unsigned long)len);
fifo->Write(strLength, strlen(strLength));
fifo->Write(json, len);
free(json);
fifo->Write(str.c_str(), len);
fifo->Write(",", 1);
}

View File

@ -20,28 +20,17 @@
#ifndef NETSTRING_H
#define NETSTRING_H
struct cJSON;
namespace icinga
{
typedef ::cJSON json_t;
class I2_JSONRPC_API Netstring : public Object
{
private:
size_t m_Length;
void *m_Data;
static Dictionary::Ptr GetDictionaryFromJson(json_t *json);
static json_t *GetJsonFromDictionary(const Dictionary::Ptr& dictionary);
public:
typedef shared_ptr<Netstring> Ptr;
typedef weak_ptr<Netstring> WeakPtr;
static bool ReadMessageFromFIFO(FIFO::Ptr fifo, Message *message);
static void WriteMessageToFIFO(FIFO::Ptr fifo, const Message& message);
static bool ReadStringFromFIFO(FIFO::Ptr fifo, string *message);
static void WriteStringToFIFO(FIFO::Ptr fifo, const string& message);
};
}