1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-02-23 21:27:14 +01:00
Sandu Liviu Catalin 4a6bfc086c Major plugin refactor and cleanup.
Switched to POCO library for unified platform/library interface.
Deprecated the external module API. It was creating more problems than solving.
Removed most built-in libraries in favor of system libraries for easier maintenance.
Cleaned and secured code with help from static analyzers.
2021-01-30 08:51:39 +02:00

240 lines
6.3 KiB
C++

//
// Client.h
//
// Library: Redis
// Package: Redis
// Module: Client
//
// Definition of the Client class.
//
// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Redis_Client_INCLUDED
#define Redis_Client_INCLUDED
#include "Poco/Redis/Redis.h"
#include "Poco/Redis/Array.h"
#include "Poco/Redis/Error.h"
#include "Poco/Redis/RedisStream.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Timespan.h"
namespace Poco {
namespace Redis {
class Redis_API Client
/// Represents a connection to a Redis server.
///
/// A command is always made from an Array and a reply can be a signed 64
/// bit integer, a simple string, a bulk string, an array or an error. The
/// first element of the command array is the Redis command. A simple string
/// is a string that cannot contain a CR or LF character. A bulk string is
/// implemented as an alias for Poco::Nullable<std::string>. This is
/// because a bulk string can represent a Null value.
///
/// BulkString bs = client.execute<BulkString>(...);
/// if ( bs.isNull() )
/// {
/// // We have a Null value
/// }
/// else
/// {
/// // We have a string value
/// }
///
/// To create Redis commands, the factory methods of the Command class can
/// be used or the Array class can be used directly.
///
/// Command llen = Command::llen("list");
///
/// is the same as:
///
/// Array command;
/// command.add("LLEN").add("list");
///
/// or:
///
/// Array command;
/// command << "LLEN" << "list";
///
/// or even:
///
/// Command command("LLEN");
/// command << "list";
{
public:
using Ptr = SharedPtr<Client>;
Client();
/// Creates an unconnected Client.
/// Use this when you want to connect later on.
Client(const std::string& hostAndPort);
/// Constructor which connects to the given Redis host/port.
/// The host and port must be separated with a colon.
Client(const std::string& host, int port);
/// Constructor which connects to the given Redis host/port.
Client(const Net::SocketAddress& addrs);
/// Constructor which connects to the given Redis host/port.
virtual ~Client();
/// Destroys the Client.
Net::SocketAddress address() const;
/// Returns the address of the Redis connection.
void connect(const std::string& hostAndPort);
/// Connects to the given Redis server. The host and port must be
/// separated with a colon.
void connect(const std::string& host, int port);
/// Connects to the given Redis server.
void connect(const Net::SocketAddress& addrs);
/// Connects to the given Redis server.
void connect(const std::string& hostAndPort, const Timespan& timeout);
/// Connects to the given Redis server. The host and port must be
/// separated with a colon.
void connect(const std::string& host, int port, const Timespan& timeout);
/// Connects to the given Redis server.
void connect(const Net::SocketAddress& addrs, const Timespan& timeout);
/// Connects to the given Redis server.
void disconnect();
/// Disconnects from the Redis server.
bool isConnected() const;
/// Returns true iff the Client is connected to a Redis server.
template<typename T>
T execute(const Array& command)
/// Sends the Redis Command to the server. It gets the reply
/// and tries to convert it to the given template type.
///
/// A specialization exists for type void, which doesn't read
/// the reply. If the server sends a reply, it is your
/// responsibility to read it. Use this for pipelining.
///
/// A Poco::BadCastException will be thrown when the reply couldn't be
/// converted. Supported types are Int64, std::string, BulkString,
/// Array and void. When the reply is an Error, it will throw
/// a RedisException.
{
T result = T();
writeCommand(command, true);
readReply(result);
return result;
}
void flush();
/// Flush the output buffer to Redis. Use this when commands
/// are stored in the buffer to send them all at once to Redis.
RedisType::Ptr sendCommand(const Array& command);
/// Sends a Redis command to the server and returns the reply.
/// Use this when the type of the reply isn't known.
RedisType::Ptr readReply();
/// Read a reply from the Redis server.
template<typename T>
void readReply(T& result)
/// Read a reply from the Redis server and tries to convert that reply
/// to the template type. When the reply is a Redis error, it will
/// throw a RedisException. A BadCastException will be thrown, when
/// the reply is not of the given type.
{
RedisType::Ptr redisResult = readReply();
if (redisResult->type() == RedisTypeTraits<Error>::TypeId)
{
Type<Error>* error = dynamic_cast<Type<Error>*>(redisResult.get());
throw RedisException(error->value().getMessage());
}
if (redisResult->type() == RedisTypeTraits<T>::TypeId)
{
Type<T>* type = dynamic_cast<Type<T>*>(redisResult.get());
if (type != NULL) result = type->value();
}
else throw BadCastException();
}
Array sendCommands(const std::vector<Array>& commands);
/// Sends all commands (pipelining) to the Redis server before
/// getting all replies.
void setReceiveTimeout(const Timespan& timeout);
/// Sets a receive timeout.
private:
Client(const Client&);
Client& operator = (const Client&);
void connect();
/// Connects to the Redis server
void connect(const Timespan& timeout);
/// Connects to the Redis server and sets a timeout.
void writeCommand(const Array& command, bool flush);
/// Sends a request to the Redis server. Use readReply to get the
/// answer. Can also be used for pipelining commands. Make sure you
/// call readReply as many times as you called writeCommand, even when
/// an error occurred on a command.
Net::SocketAddress _address;
Net::StreamSocket _socket;
RedisInputStream* _input;
RedisOutputStream* _output;
};
//
// inlines
//
inline Net::SocketAddress Client::address() const
{
return _address;
}
template<> inline
void Client::execute<void>(const Array& command)
{
writeCommand(command, false);
}
inline void Client::flush()
{
poco_assert(_output);
_output->flush();
}
inline void Client::setReceiveTimeout(const Timespan& timeout)
{
_socket.setReceiveTimeout(timeout);
}
} } // namespace Poco::Redis
#endif // Redis_Client_INCLUDED