Integrated new Lexer and Parser class into Client class.

This commit is contained in:
Nathan Osman 2013-07-15 22:19:40 -07:00
parent ac876e196e
commit 12df269ae0
4 changed files with 42 additions and 130 deletions

View File

@ -41,16 +41,17 @@ namespace QRedis
Q_SIGNALS: Q_SIGNALS:
/** /**
* @brief Emitted when a bulk reply is received * @brief Emitted when a status reply is received
* @param value the value as a byte array * @param message a descriptive status message
*/ */
void bulk(const QByteArray & value); void status(const QString & message);
/** /**
* @brief Emitted when an error reply is received * @brief Emitted when an error reply is received
* @param message a descriptive error message * @param generic a generic error identifer
* @param specific a more specific error message
*/ */
void error(const QString & message); void error(const QString & generic, const QString & specific);
/** /**
* @brief Emitted when an integer reply is received * @brief Emitted when an integer reply is received
@ -58,6 +59,12 @@ namespace QRedis
*/ */
void integer(qlonglong value); void integer(qlonglong value);
/**
* @brief Emitted when a bulk reply is received
* @param value the value as a byte array
*/
void bulk(const QByteArray & value);
/** /**
* @brief Emitted when a multi-bulk reply is received * @brief Emitted when a multi-bulk reply is received
* @param a list of bulk values * @param a list of bulk values
@ -69,12 +76,6 @@ namespace QRedis
*/ */
void reply(); void reply();
/**
* @brief Emitted when a status reply is received
* @param message a descriptive status message
*/
void status(const QString & message);
private: private:
const QScopedPointer<RequestPrivate> d; const QScopedPointer<RequestPrivate> d;

View File

@ -4,124 +4,41 @@
using namespace QRedis; using namespace QRedis;
ClientPrivate::ClientPrivate(Client * client) ClientPrivate::ClientPrivate(Client * client)
: q(client) : lexer(&socket), parser(&lexer)
{ {
connect(&socket, &QTcpSocket::connected, q, &Client::connected); connect(&socket, SIGNAL(connected()), client, SIGNAL(connected()));
connect(&socket, &QTcpSocket::disconnected, q, &Client::disconnected); connect(&socket, SIGNAL(disconnected()), client, SIGNAL(disconnected()));
connect(&socket, &QTcpSocket::disconnected, this, &ClientPrivate::reset);
connect(&socket, &QTcpSocket::readyRead, this, &ClientPrivate::readReply); connect(&parser, SIGNAL(status(QString)), SLOT(sendStatus(QString)));
connect(&parser, SIGNAL(error(QString,QString)), SLOT(sendError(QString,QString)));
connect(&parser, SIGNAL(integer(qlonglong)), SLOT(sendInteger(qlonglong)));
connect(&parser, SIGNAL(bulk(QByteArray)), SLOT(sendBulk(QByteArray)));
connect(&parser, SIGNAL(multiBulk(QVariantList)), SLOT(sendMultiBulk(QVariantList)));
} }
int ClientPrivate::readInteger(qlonglong & value) void ClientPrivate::sendStatus(const QString & message)
{ {
int pos = buffer.indexOf("\r\n"); emit queue.dequeue()->status(message);
if(pos != -1)
{
value = buffer.mid(0, pos).toLongLong();
buffer.remove(0, pos + 2);
}
return pos;
} }
/* void ClientPrivate::sendError(const QString & generic, const QString & specific)
* Note: error replies actually contain a type and then the error description
* but we just combine them here for simplicity.
*/
bool ClientPrivate::readStatusOrErrorReply()
{ {
/* Check if the reply contains \r\n. */ emit queue.dequeue()->error(generic, specific);
int pos = buffer.indexOf("\r\n");
if(pos != -1)
{
Request * request = queue.dequeue();
if(buffer[0] == '+')
emit request->status(buffer.mid(1, pos - 1));
else
emit request->error(buffer.mid(1, pos - 1));
buffer.remove(0, pos + 2);
return true;
} }
return false; void ClientPrivate::sendInteger(qlonglong value)
{
emit queue.dequeue()->integer(value);
} }
bool ClientPrivate::readIntegerReply() void ClientPrivate::sendBulk(const QByteArray & value)
{ {
/* Check if the reply contains \r\n. */ emit queue.dequeue()->bulk(value);
int pos = buffer.indexOf("\r\n");
if(pos != -1)
{
emit queue.dequeue()->integer(buffer.mid(1, pos -1).toLongLong());
buffer.remove(0, pos + 2);
return true;
} }
return false; void ClientPrivate::sendMultiBulk(const QVariantList & values)
}
bool ClientPrivate::readBulkReply()
{ {
/* Check if the reply contains \r\n. */ emit queue.dequeue()->multiBulk(values);
int pos = buffer.indexOf("\r\n");
if(pos != -1)
{
int length = buffer.mid(1, pos -1).toInt();
if(buffer.size() >= pos + length + 4)
{
emit queue.dequeue()->bulk(buffer.mid(pos + 2, length));
buffer.remove(0, pos + length + 4);
return true;
}
}
return false;
}
bool ClientPrivate::readMultiBulkReply()
{
return false;
}
void ClientPrivate::reset()
{
foreach(Request * request, queue)
request->deleteLater();
queue.clear();
}
// TODO: unrecognized replies in the switch should be handled.
void ClientPrivate::readReply()
{
buffer.append(socket.readAll());
while(!buffer.isEmpty())
{
bool finished;
switch(buffer[0])
{
case '+':
case '-':
finished = readStatusOrErrorReply();
break;
case ':':
finished = readIntegerReply();
break;
case '$':
finished = readBulkReply();
break;
case '*':
finished = readMultiBulkReply();
break;
}
if(!finished)
break;
}
} }
Client::Client(QObject * parent) Client::Client(QObject * parent)

View File

@ -7,6 +7,8 @@
#include <qredis/client.h> #include <qredis/client.h>
#include <qredis/request.h> #include <qredis/request.h>
#include "lexer.h"
#include "parser.h"
namespace QRedis namespace QRedis
{ {
@ -18,27 +20,19 @@ namespace QRedis
ClientPrivate(Client *); ClientPrivate(Client *);
/* Utility methods for reading items from the buffer. */
int readInteger(qlonglong &);
bool readStatusOrErrorReply();
bool readIntegerReply();
bool readBulkReply();
bool readMultiBulkReply();
QTcpSocket socket; QTcpSocket socket;
QQueue<Request *> queue; QQueue<Request *> queue;
QByteArray buffer;
public Q_SLOTS: Lexer lexer;
Parser parser;
void reset(); private Q_SLOTS:
void readReply();
private: void sendStatus(const QString &);
void sendError(const QString &, const QString &);
Client * const q; void sendInteger(qlonglong);
void sendBulk(const QByteArray &);
void sendMultiBulk(const QVariantList &);
}; };
} }

View File

@ -17,7 +17,7 @@ Request::Request(QObject * parent)
* Each of these signals also causes the generic reply() signal to be emitted. * Each of these signals also causes the generic reply() signal to be emitted.
*/ */
connect(this, SIGNAL(bulk(QByteArray)), SIGNAL(reply())); connect(this, SIGNAL(bulk(QByteArray)), SIGNAL(reply()));
connect(this, SIGNAL(error(QString)), SIGNAL(reply())); connect(this, SIGNAL(error(QString,QString)), SIGNAL(reply()));
connect(this, SIGNAL(integer(qlonglong)), SIGNAL(reply())); connect(this, SIGNAL(integer(qlonglong)), SIGNAL(reply()));
connect(this, SIGNAL(multiBulk(QVariantList)), SIGNAL(reply())); connect(this, SIGNAL(multiBulk(QVariantList)), SIGNAL(reply()));
connect(this, SIGNAL(status(QString)), SIGNAL(reply())); connect(this, SIGNAL(status(QString)), SIGNAL(reply()));