From 3685f819cc18e4393997825b5dee98ca13f5a915 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Sun, 8 Feb 2009 22:11:14 +0000 Subject: [PATCH] Provide an async SodepClient class to send/receive a message. svn path=/branches/work/~ervin/sodep/; revision=923534 --- private/qtjolie-branch/sodep/CMakeLists.txt | 23 +++ private/qtjolie-branch/sodep/sodepclient.cpp | 177 ++++++++++++++++++ private/qtjolie-branch/sodep/sodepclient.h | 66 +++++++ .../sodep/sodepclientthread.cpp | 60 ++++++ .../sodep/sodepclientthread_p.h | 54 ++++++ .../tests/sodepmetaservicetest.cpp | 34 +++- 6 files changed, 411 insertions(+), 3 deletions(-) create mode 100644 private/qtjolie-branch/sodep/CMakeLists.txt create mode 100644 private/qtjolie-branch/sodep/sodepclient.cpp create mode 100644 private/qtjolie-branch/sodep/sodepclient.h create mode 100644 private/qtjolie-branch/sodep/sodepclientthread.cpp create mode 100644 private/qtjolie-branch/sodep/sodepclientthread_p.h diff --git a/private/qtjolie-branch/sodep/CMakeLists.txt b/private/qtjolie-branch/sodep/CMakeLists.txt new file mode 100644 index 000000000..dd4049464 --- /dev/null +++ b/private/qtjolie-branch/sodep/CMakeLists.txt @@ -0,0 +1,23 @@ +project(sodep) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${QT_INCLUDE_DIR}) + +set(sodep_LIB_SRCS sodepclient.cpp sodepclientthread.cpp sodepvalue.cpp sodepfault.cpp sodepmessage.cpp) + +kde4_add_library(sodep SHARED ${sodep_LIB_SRCS}) + +target_link_libraries(sodep ${QT_QTCORE_LIBRARY}) + +install(TARGETS sodep + DESTINATION ${LIB_INSTALL_DIR}) + +set_target_properties(sodep PROPERTIES VERSION 1.0.0 SOVERSION 1) + +install(FILES + sodepclient.h + sodepvalue.h + sodepfault.h + sodepmessage.h + DESTINATION ${INCLUDE_INSTALL_DIR}) diff --git a/private/qtjolie-branch/sodep/sodepclient.cpp b/private/qtjolie-branch/sodep/sodepclient.cpp new file mode 100644 index 000000000..b1bf023c5 --- /dev/null +++ b/private/qtjolie-branch/sodep/sodepclient.cpp @@ -0,0 +1,177 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2009 Kevin Ottens + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "sodepclient.h" + +#include +#include +#include + +#include "sodepmessage.h" +#include "sodephelpers_p.h" +#include "sodepclientthread_p.h" + +struct SodepRequest +{ + enum { Send, Receive } type; + SodepMessage message; +}; + +class SodepClientPrivate +{ +public: + SodepClientPrivate(SodepClient *client) + : q(client), device(0), + error(SodepClient::NoError), + lastAllocatedRequestId(0), + currentRequestId(-1) {} + + void startRequest(int id); + void emitCurrentRequestFinished(); + + void _k_messageLoaded(const SodepMessage &message); + void _k_bytesWritten(); + + SodepClient * const q; + + QIODevice *device; + SodepClientThread *readerThread; + + SodepClient::Error error; + QString errorString; + + int lastAllocatedRequestId; + int currentRequestId; + QHash queuedRequests; +}; + +SodepClient::SodepClient(QIODevice *device) + : d(new SodepClientPrivate(this)) +{ + d->device = device; + d->readerThread = new SodepClientThread(device, this); +} + +SodepClient::~SodepClient() +{ + delete d; +} + +int SodepClient::requestMessage() +{ + int id = ++d->lastAllocatedRequestId; + + SodepRequest request; + request.type = SodepRequest::Receive; + d->queuedRequests[id] = request; + + if (d->currentRequestId==-1) { + d->startRequest(id); + } + + return id; +} + +int SodepClient::postMessage(const SodepMessage &message) +{ + int id = ++d->lastAllocatedRequestId; + + SodepRequest request; + request.type = SodepRequest::Send; + request.message = message; + d->queuedRequests[id] = request; + + if (d->currentRequestId==-1) { + d->startRequest(id); + } + + return id; +} + +SodepClient::Error SodepClient::error() const +{ + return d->error; +} + +QString SodepClient::errorString() const +{ + return d->errorString; +} + +void SodepClientPrivate::startRequest(int id) +{ + currentRequestId = id; + + SodepRequest &request = queuedRequests[id]; + + error = SodepClient::NoError; + errorString = QString(); + + emit q->requestStarted(id); + + if (request.type == SodepRequest::Receive) { + QObject::connect(readerThread, SIGNAL(messageLoaded(const SodepMessage&)), + q, SLOT(_k_messageLoaded(const SodepMessage&))); + readerThread->requestMessage(); + } else { + QObject::connect(device, SIGNAL(bytesWritten(qint64)), + q, SLOT(_k_bytesWritten())); + SodepMessage &message = request.message; + sodepWrite(*device, message); + } +} + +void SodepClientPrivate::emitCurrentRequestFinished() +{ + SodepRequest request = queuedRequests.take(currentRequestId); + + if (request.type == SodepRequest::Receive) { + QObject::disconnect(readerThread, SIGNAL(messageLoaded(const SodepMessage&)), + q, SLOT(_k_messageLoaded(const SodepMessage&))); + } else { + QObject::disconnect(device, SIGNAL(bytesWritten(qint64)), + q, SLOT(_k_bytesWritten())); + } + + emit q->requestFinished(currentRequestId, request.message, false); + + if (currentRequestIdbytesToWrite()>0) { + return; + } + + emitCurrentRequestFinished(); +} + +#include "sodepclient.moc" diff --git a/private/qtjolie-branch/sodep/sodepclient.h b/private/qtjolie-branch/sodep/sodepclient.h new file mode 100644 index 000000000..fced7708e --- /dev/null +++ b/private/qtjolie-branch/sodep/sodepclient.h @@ -0,0 +1,66 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2009 Kevin Ottens + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef SODEPCLIENT_H +#define SODEPCLIENT_H + +#include + +class QIODevice; + +class SodepClientPrivate; +class SodepMessage; + +class Q_DECL_EXPORT SodepClient : public QObject +{ + Q_OBJECT + Q_ENUMS(Error) + +public: + enum Error + { + NoError, + UnexpectedClose, + UnkownError + }; + + explicit SodepClient(QIODevice *device); + + ~SodepClient(); + + int requestMessage(); + int postMessage(const SodepMessage &message); + + Error error() const; + QString errorString() const; + +signals: + void requestStarted(int id); + void requestFinished(int id, const SodepMessage &message, bool hasError); + +private: + Q_PRIVATE_SLOT(d, void _k_messageLoaded(const SodepMessage&)) + Q_PRIVATE_SLOT(d, void _k_bytesWritten()) + + friend class SodepClientPrivate; + SodepClientPrivate * const d; +}; + +#endif diff --git a/private/qtjolie-branch/sodep/sodepclientthread.cpp b/private/qtjolie-branch/sodep/sodepclientthread.cpp new file mode 100644 index 000000000..ead18b53f --- /dev/null +++ b/private/qtjolie-branch/sodep/sodepclientthread.cpp @@ -0,0 +1,60 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2009 Kevin Ottens + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "sodepclientthread_p.h" + +#include "sodepmessage.h" +#include "sodephelpers_p.h" + +SodepClientThread::SodepClientThread(QIODevice *device, QObject *parent) + : QThread(parent), m_device(device), m_quit(false) +{ + +} + +SodepClientThread::~SodepClientThread() +{ + m_quit = true; + m_cond.wakeOne(); + wait(); +} + +void SodepClientThread::requestMessage() +{ + if (!isRunning()) { + start(); + } else { + m_cond.wakeOne(); + } +} + +void SodepClientThread::run() +{ + while (!m_quit) { + QMutexLocker locker(&m_mutex); + + SodepMessage message = sodepReadMessage(*m_device); + emit messageLoaded(message); + + m_cond.wait(&m_mutex); + } +} + +#include "sodepclientthread_p.moc" diff --git a/private/qtjolie-branch/sodep/sodepclientthread_p.h b/private/qtjolie-branch/sodep/sodepclientthread_p.h new file mode 100644 index 000000000..895b85635 --- /dev/null +++ b/private/qtjolie-branch/sodep/sodepclientthread_p.h @@ -0,0 +1,54 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2009 Kevin Ottens + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef SODEPCLIENTTHREAD_P_H +#define SODEPCLIENTTHREAD_P_H + +#include +#include +#include + +class QIODevice; + +class SodepMessage; + +class SodepClientThread : public QThread +{ + Q_OBJECT + +public: + explicit SodepClientThread(QIODevice *device, QObject *parent = 0); + ~SodepClientThread(); + + void requestMessage(); + void run(); + +signals: + void messageLoaded(const SodepMessage &message); + +private: + QIODevice *m_device; + + QMutex m_mutex; + QWaitCondition m_cond; + bool m_quit; +}; + +#endif diff --git a/private/qtjolie-branch/tests/sodepmetaservicetest.cpp b/private/qtjolie-branch/tests/sodepmetaservicetest.cpp index f77398581..899111683 100644 --- a/private/qtjolie-branch/tests/sodepmetaservicetest.cpp +++ b/private/qtjolie-branch/tests/sodepmetaservicetest.cpp @@ -18,11 +18,13 @@ * Boston, MA 02110-1301, USA. */ +#include #include #include #include #include +#include #include #include "sodeptesthelpers.h" @@ -66,6 +68,14 @@ class SodepMetaServiceTest : public QObject QProcess m_metaserviceProcess; QTcpSocket m_socket; + SodepClient m_client; + +public: + SodepMetaServiceTest() + : QObject(), m_client(&m_socket) + { + qRegisterMetaType(); + } private slots: void initTestCase() @@ -121,9 +131,23 @@ private slots: void shouldListServices() { SodepMessage message("/", "getServices"); - sodepWrite(m_socket, message); - SodepMessage reply = sodepReadMessage(m_socket); + QSignalSpy spy(&m_client, SIGNAL(requestFinished(int, const SodepMessage&, bool))); + + int id = m_client.postMessage(message); + QEventLoop eventLoop; + connect(&m_client, SIGNAL(requestFinished(int, const SodepMessage&, bool)), + &eventLoop, SLOT(quit())); + eventLoop.exec(); + + QCOMPARE(spy.count(), 1); + QVariantList signal = spy.takeFirst(); + QCOMPARE(signal.at(0).toInt(), id); + sodepCompare(signal.at(1).value(), message); + QCOMPARE(signal.at(2).toBool(), false); + + id = m_client.requestMessage(); + eventLoop.exec(); SodepMessage expected("/", "getServices"); SodepValue value; @@ -138,7 +162,11 @@ private slots: value.children("service") << s1 << s2; expected.setData(value); - sodepCompare(reply, expected); + QCOMPARE(spy.count(), 1); + signal = spy.takeFirst(); + QCOMPARE(signal.at(0).toInt(), id); + sodepCompare(signal.at(1).value(), expected); + QCOMPARE(signal.at(2).toBool(), false); } void shouldPlaceServiceCalls_data()