Committing more work ...

This commit is contained in:
fbraem
2015-10-22 18:54:44 +02:00
parent 9acd00e25a
commit 8f950a903a
20 changed files with 492 additions and 178 deletions

View File

@@ -19,6 +19,8 @@
#define Redis_Array_INCLUDED
#include <vector>
#include <sstream>
#include "Poco/Redis/Redis.h"
#include "Poco/Redis/Type.h"
#include "Poco/Redis/Exception.h"
@@ -43,9 +45,13 @@ public:
void add();
void add(AbstractType::Ptr value);
void add(RedisType::Ptr value);
std::vector<RedisType::Ptr>::const_iterator begin() const;
void clear();
std::vector<RedisType::Ptr>::const_iterator end() const;
std::string toString() const;
@@ -53,22 +59,32 @@ public:
private:
std::vector<AbstractType::Ptr> _elements;
std::vector<RedisType::Ptr> _elements;
friend class Connection;
};
inline std::vector<RedisType::Ptr>::const_iterator Array::begin() const
{
return _elements.begin();
}
inline void Array::clear()
{
_elements.clear();
}
inline std::vector<RedisType::Ptr>::const_iterator Array::end() const
{
return _elements.end();
}
inline size_t Array::size() const
{
return _elements.size();
}
inline void Array::add(AbstractType::Ptr value)
inline void Array::add(RedisType::Ptr value)
{
_elements.push_back(value);
}
@@ -76,7 +92,9 @@ inline void Array::add(AbstractType::Ptr value)
template<>
struct ElementTraits<Array>
{
enum { TypeId = AbstractType::REDIS_ARRAY };
enum { TypeId = RedisType::REDIS_ARRAY };
static const char marker = '*';
static std::string typeName()
{
@@ -85,39 +103,45 @@ struct ElementTraits<Array>
static std::string toString(const Array& value)
{
return value.toString();
std::stringstream result;
result << marker << value.size() << LineEnding::NEWLINE_CRLF;
for(std::vector<RedisType::Ptr>::const_iterator it = value.begin(); it != value.end(); ++it)
{
result << (*it)->toString();
}
return result.str();
}
};
template<> inline
void Type<Array>::read(RedisSocket& socket)
{
std::string line;
socket.readLine(line);
Int64 length = NumberParser::parse64(line);
for(int i = 0; i < length; ++i)
{
char elementType = socket.get();
AbstractType::Ptr t;
RedisType::Ptr element;
switch(elementType)
{
case ':': // Integer
t = new Type<Int64>();
case ElementTraits<Int64>::marker :
element = new Type<Int64>();
break;
case '+' : // Simple String
t = new Type<std::string>();
case ElementTraits<std::string>::marker :
element = new Type<std::string>();
break;
case '$' : // Bulk String
t = new Type<BulkString>();
case ElementTraits<BulkString>::marker :
element = new Type<BulkString>();
break;
}
if ( t.isNull() ) throw RedisException("Wrong answer received from Redis server");
if ( element.isNull() ) throw RedisException("Wrong answer received from Redis server");
t->read(socket);
_value.add(t);
element->read(socket);
_value.add(element);
}
}

View File

@@ -1,13 +1,13 @@
//
// Connection.h
// Client.h
//
// $Id$
//
// Library: Redis
// Package: Redis
// Module: Connection
// Module: Client
//
// Definition of the Connection class.
// Definition of the Client class.
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
@@ -25,33 +25,34 @@
#include "Poco/Redis/Redis.h"
#include "Poco/Redis/Array.h"
#include "Poco/Redis/Error.h"
#include "Poco/Redis/RedisSocket.h"
namespace Poco {
namespace Redis {
class Redis_API Connection
class Redis_API Client
/// Represents a connection to a Redis server
{
public:
typedef Poco::SharedPtr<Connection> Ptr;
typedef Poco::SharedPtr<Client> Ptr;
Connection();
Client();
/// Default constructor. Use this when you want to
/// connect later on.
Connection(const std::string& hostAndPort);
Client(const std::string& hostAndPort);
/// Constructor which connects to the given Redis host/port.
/// The host and port must be separated with a colon.
Connection(const std::string& host, int port);
Client(const std::string& host, int port);
/// Constructor which connects to the given Redis host/port.
Connection(const Net::SocketAddress& addrs);
Client(const Net::SocketAddress& addrs);
/// Constructor which connects to the given Redis host/port.
virtual ~Connection();
virtual ~Client();
/// Destructor
Net::SocketAddress address() const;
@@ -70,111 +71,47 @@ public:
void disconnect();
/// Disconnects from the Redis server
void sendCommand(const Array& command);
/// Sends a request to the Redis server
RedisType::Ptr sendCommand(const Array& command);
template<typename T>
void sendCommand(const Array& command, T& result)
void sendCommand(const Array& command, T& result)
{
Type<T> resultType;
sendCommand(command);
char type = _socket.get();
switch(type)
{
case ':':
{
if ( resultType.getType() == AbstractType::REDIS_INTEGER )
{
resultType.read(_socket);
}
else
{
std::string message;
message.append("Expected ");
message.append(ElementTraits<T>::typeName());
message.append(", got an Integer");
throw InvalidArgumentException(message);
}
break;
}
case '+': // Simple String
{
if ( resultType.getType() == AbstractType::REDIS_SIMPLE_STRING )
{
resultType.read(_socket);
}
else
{
std::string message;
message.append("Expected ");
message.append(ElementTraits<T>::typeName());
message.append(", got a Simple String");
throw InvalidArgumentException(message);
}
break;
}
case '-' : // Error
{
std::string error;
_socket.readLine(error);
throw RedisException(error);
}
case '$' : // Bulk String
{
if ( resultType.getType() == AbstractType::REDIS_BULK_STRING )
{
resultType.read(_socket);
}
else
{
std::string message;
message.append("Expected ");
message.append(ElementTraits<T>::typeName());
message.append(", got a Bulk String");
throw InvalidArgumentException(message);
}
break;
}
case '*' : //Array
{
if ( resultType.getType() == AbstractType::REDIS_ARRAY )
{
resultType.read(_socket);
}
else
{
std::string message;
message.append("Expected ");
message.append(ElementTraits<T>::typeName());
message.append(", got an Array");
throw InvalidArgumentException(message);
}
throw InvalidArgumentException("Expected integer, got an array");
}
default:
throw IOException("Invalid Redis type returned");
}
result = resultType.value();
readReply(result);
}
RedisType::Ptr readReply();
template<typename T>
void readReply(T& result)
{
RedisType::Ptr redisResult = readReply();
if ( redisResult->type() == ElementTraits<T>::TypeId )
result = ((Type<T>*) redisResult.get())->value();
else throw BadCastException();
}
void sendCommands(const std::vector<Array>& commands, std::vector<RedisType::Ptr>& results);
void writeCommand(const Array& command);
/// Sends a request to the Redis server
private:
Connection(const Connection&);
Connection& operator = (const Connection&);
Client(const Client&);
Client& operator = (const Client&);
Net::SocketAddress _address;
RedisSocket _socket;
void connect();
/// Connects to the Redis server
static RedisType::Ptr createRedisType(char marker);
};
inline Net::SocketAddress Connection::address() const
inline Net::SocketAddress Client::address() const
{
return _address;
}

View File

@@ -0,0 +1,83 @@
//
// Error.h
//
// $Id$
//
// Library: Redis
// Package: Redis
// Module: Error
//
// Definition of the Error class.
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Redis_Error_INCLUDED
#define Redis_Error_INCLUDED
#include "Poco/Redis/Type.h"
#include "Poco/Redis/RedisSocket.h"
namespace Poco {
namespace Redis {
class Redis_API Error
{
public:
Error();
Error(const std::string& message);
virtual ~Error();
std::string getMessage() const;
void setMessage(const std::string& message);
private:
std::string _message;
};
inline std::string Error::getMessage() const
{
return _message;
}
inline void Error::setMessage(const std::string& message)
{
_message = message;
}
template<>
struct ElementTraits<Error>
{
enum { TypeId = RedisType::REDIS_ERROR };
static const char marker = '-';
static std::string typeName()
{
return "Error";
}
static std::string toString(const Error& value)
{
return marker + value.getMessage() + "\r\n";
}
};
template<> inline
void Type<Error>::read(RedisSocket& socket)
{
std::string s;
socket.readLine(s);
_value = s;
}
}} // Namespace Poco::Redis
#endif // Redis_Error_INCLUDED

View File

@@ -18,6 +18,7 @@
#ifndef Redis_Type_INCLUDED
#define Redis_Type_INCLUDED
#include "Poco/LineEndingConverter.h"
#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"
#include "Poco/SharedPtr.h"
@@ -30,16 +31,16 @@ namespace Poco {
namespace Redis {
class Redis_API AbstractType
class Redis_API RedisType
{
public:
typedef SharedPtr<AbstractType> Ptr;
typedef SharedPtr<RedisType> Ptr;
AbstractType();
virtual ~AbstractType();
RedisType();
virtual ~RedisType();
virtual int getType() const = 0;
virtual int type() const = 0;
virtual void read(RedisSocket& socket) = 0;
@@ -49,7 +50,8 @@ public:
REDIS_INTEGER,
REDIS_SIMPLE_STRING,
REDIS_BULK_STRING,
REDIS_ARRAY
REDIS_ARRAY,
REDIS_ERROR
};
private:
@@ -65,7 +67,9 @@ struct ElementTraits
template<>
struct ElementTraits<Poco::Int64>
{
enum { TypeId = AbstractType::REDIS_INTEGER };
enum { TypeId = RedisType::REDIS_INTEGER };
static const char marker = ':';
static std::string typeName()
{
@@ -74,7 +78,7 @@ struct ElementTraits<Poco::Int64>
static std::string toString(const Poco::Int64& value)
{
return ":" + NumberFormatter::format(value) + "\r\n";
return marker + NumberFormatter::format(value) + "\r\n";
}
};
@@ -82,16 +86,18 @@ struct ElementTraits<Poco::Int64>
template<>
struct ElementTraits<std::string>
{
enum { TypeId = AbstractType::REDIS_SIMPLE_STRING };
enum { TypeId = RedisType::REDIS_SIMPLE_STRING };
static std::string typeName()
{
return "Simple String";
}
static const char marker = '+';
static std::string toString(const std::string& value)
{
return "+" + value + "\r\n";
return marker + value + LineEnding::NEWLINE_CRLF;
}
};
@@ -102,28 +108,31 @@ typedef Optional<std::string> BulkString;
template<>
struct ElementTraits<BulkString>
{
enum { TypeId = AbstractType::REDIS_BULK_STRING };
enum { TypeId = RedisType::REDIS_BULK_STRING };
static std::string typeName()
{
return "Bulk String";
}
static const char marker = '$';
static std::string toString(const BulkString& value)
{
if ( value.isSpecified() ) {
if ( value.isSpecified() )
{
std::string s = value.value();
return "$" + NumberFormatter::format(s.length()) + "\r\n" + s + "\r\n";
return marker + NumberFormatter::format(s.length()) + LineEnding::NEWLINE_CRLF + s + LineEnding::NEWLINE_CRLF;
}
return "$-1\r\n";
return marker + std::string("-1") + LineEnding::NEWLINE_CRLF;
}
};
template<typename T>
class Redis_API Type : public AbstractType
class Redis_API Type : public RedisType
{
public:
public:
Type()
{
@@ -141,16 +150,15 @@ class Redis_API Type : public AbstractType
{
}
int getType() const
int type() const
{
return ElementTraits<T>::TypeId;
}
void read(RedisSocket& socket)
{
}
virtual void read(RedisSocket& socket);
virtual std::string toString() const {
virtual std::string toString() const
{
return ElementTraits<T>::toString(_value);
}
@@ -175,9 +183,8 @@ void Type<Int64>::read(RedisSocket& socket)
template<> inline
void Type<std::string>::read(RedisSocket& socket)
{
std::string s;
socket.readLine(s);
_value = s;
_value.clear();
socket.readLine(_value);
}
template<> inline
@@ -187,16 +194,15 @@ void Type<BulkString>::read(RedisSocket& socket)
std::string line;
socket.readLine(line);
int length = NumberParser::parse64(line);
if ( length >= 0 )
{
std::string s;
socket.read(length, s);
_value.assign(s);
socket.readLine(line);
}
else // -1
{
socket.readLine(line);
}
}