diff --git a/include/qredis/client.h b/include/qredis/client.h index 63f8803..3bd4235 100644 --- a/include/qredis/client.h +++ b/include/qredis/client.h @@ -63,7 +63,15 @@ namespace QRedis * @param command the command to execute * @return an object representing the request */ - Request * sendCommand(const QString & command); + Request * sendCommand(const QByteArray & command); + + /** + * @brief Attempts to set the specified key to the specified value + * @param name the name of the key + * @param value the value of the key + * @return the request issued + */ + Request * set(const QByteArray & name, const QByteArray & value); /** * @brief Waits for the socket to finish connecting diff --git a/include/qredis/request.h b/include/qredis/request.h index 2864024..2f0e803 100644 --- a/include/qredis/request.h +++ b/include/qredis/request.h @@ -64,6 +64,11 @@ namespace QRedis */ void multiBulk(const QVariantList & values); + /** + * @brief Emitted when any reply is received + */ + void reply(); + /** * @brief Emitted when a status reply is received * @param message a descriptive status message diff --git a/src/client.cpp b/src/client.cpp index 5b46bc7..d31b433 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -12,12 +12,23 @@ ClientPrivate::ClientPrivate(Client * client) connect(&socket, &QTcpSocket::readyRead, this, &ClientPrivate::readReply); } +int ClientPrivate::readInteger(qlonglong & value) +{ + int pos = buffer.indexOf("\r\n"); + if(pos != -1) + { + value = buffer.mid(0, pos).toLongLong(); + buffer.remove(0, pos + 2); + } + return pos; +} + /* * Note: error replies actually contain a type and then the error description * but we just combine them here for simplicity. */ -bool ClientPrivate::readStatusOrError() +bool ClientPrivate::readStatusOrErrorReply() { /* Check if the reply contains \r\n. */ int pos = buffer.indexOf("\r\n"); @@ -37,7 +48,7 @@ bool ClientPrivate::readStatusOrError() return false; } -bool ClientPrivate::readInteger() +bool ClientPrivate::readIntegerReply() { /* Check if the reply contains \r\n. */ int pos = buffer.indexOf("\r\n"); @@ -52,7 +63,7 @@ bool ClientPrivate::readInteger() return false; } -bool ClientPrivate::readBulk() +bool ClientPrivate::readBulkReply() { /* Check if the reply contains \r\n. */ int pos = buffer.indexOf("\r\n"); @@ -71,7 +82,7 @@ bool ClientPrivate::readBulk() return false; } -bool ClientPrivate::readMultiBulk() +bool ClientPrivate::readMultiBulkReply() { return false; } @@ -95,16 +106,16 @@ void ClientPrivate::readReply() { case '+': case '-': - finished = readStatusOrError(); + finished = readStatusOrErrorReply(); break; case ':': - finished = readInteger(); + finished = readIntegerReply(); break; case '$': - finished = readBulk(); + finished = readBulkReply(); break; case '*': - finished = readMultiBulk(); + finished = readMultiBulkReply(); break; } @@ -137,9 +148,9 @@ bool Client::isConnected() const return d->socket.state() == QAbstractSocket::ConnectedState; } -Request * Client::sendCommand(const QString & command) +Request * Client::sendCommand(const QByteArray & command) { - d->socket.write(QString("%1\r\n").arg(command).toUtf8()); + d->socket.write(command + "\r\n"); Request * request = new Request(this); d->queue.enqueue(request); diff --git a/src/client_p.h b/src/client_p.h index 6d08deb..5d72511 100644 --- a/src/client_p.h +++ b/src/client_p.h @@ -18,10 +18,13 @@ namespace QRedis ClientPrivate(Client *); - bool readStatusOrError(); - bool readInteger(); - bool readBulk(); - bool readMultiBulk(); + /* Utility methods for reading items from the buffer. */ + int readInteger(qlonglong &); + + bool readStatusOrErrorReply(); + bool readIntegerReply(); + bool readBulkReply(); + bool readMultiBulkReply(); QTcpSocket socket; diff --git a/src/request.cpp b/src/request.cpp index 5a9a285..fa8177a 100644 --- a/src/request.cpp +++ b/src/request.cpp @@ -13,6 +13,19 @@ void RequestPrivate::quitEventLoop() Request::Request(QObject * parent) : QObject(parent), d(new RequestPrivate) { + /* + * Each of these signals also causes the generic reply() signal to be emitted. + */ + connect(this, SIGNAL(bulk(QByteArray)), SIGNAL(reply())); + connect(this, SIGNAL(error(QString)), SIGNAL(reply())); + connect(this, SIGNAL(integer(qlonglong)), SIGNAL(reply())); + connect(this, SIGNAL(multiBulk(QVariantList)), SIGNAL(reply())); + connect(this, SIGNAL(status(QString)), SIGNAL(reply())); + + /* + * We also need to ensure that this object is deleted when the reply is received. + */ + connect(this, SIGNAL(reply()), SLOT(deleteLater())); } Request::~Request() @@ -25,12 +38,8 @@ bool Request::waitForReply(int msecs) timer.setInterval(msecs); timer.setSingleShot(true); - connect(&timer, SIGNAL(timeout()), &d->loop, SLOT(quit())); - connect(this, SIGNAL(bulk(QByteArray)), d.data(), SLOT(quitEventLoop())); - connect(this, SIGNAL(error(QString)), d.data(), SLOT(quitEventLoop())); - connect(this, SIGNAL(integer(qlonglong)), d.data(), SLOT(quitEventLoop())); - connect(this, SIGNAL(multiBulk(QVariantList)), d.data(), SLOT(quitEventLoop())); - connect(this, SIGNAL(status(QString)), d.data(), SLOT(quitEventLoop())); + connect(&timer, SIGNAL(timeout()), &d->loop, SLOT(quit())); + connect(this, SIGNAL(reply()), d.data(), SLOT(quitEventLoop())); /* * If the timer fires, the return value will be 0.