[rkward-cvs] SF.net SVN: rkward-code:[4699] trunk/rkward/rkward/rbackend
tfry at users.sf.net
tfry at users.sf.net
Mon Apr 15 09:32:30 UTC 2013
Revision: 4699
http://sourceforge.net/p/rkward/code/4699
Author: tfry
Date: 2013-04-15 09:32:28 +0000 (Mon, 15 Apr 2013)
Log Message:
-----------
Split out RKAsyncDataStreamHelper, and also use it for the 'main' protocol.
Modified Paths:
--------------
trunk/rkward/rkward/rbackend/rktransmitter.cpp
trunk/rkward/rkward/rbackend/rktransmitter.h
trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.cpp
trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.h
trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.h
trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
Added Paths:
-----------
trunk/rkward/rkward/rbackend/rkasyncdatastreamhelper.h
Added: trunk/rkward/rkward/rbackend/rkasyncdatastreamhelper.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkasyncdatastreamhelper.h (rev 0)
+++ trunk/rkward/rkward/rbackend/rkasyncdatastreamhelper.h 2013-04-15 09:32:28 UTC (rev 4699)
@@ -0,0 +1,110 @@
+/***************************************************************************
+ rkasyncdatastreamhelper - description
+ -------------------
+ begin : Mon Mar 18 20:06:08 CET 2013
+ copyright : (C) 2013 by Thomas Friedrichsmeier
+ email : tfry at users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef RKASYNCDATASTREAMHELPER_H
+#define RKASYNCDATASTREAMHELPER_H
+
+#include <QIODevice>
+#include <QDataStream>
+#include <QByteArray>
+
+/** Using a QDataStream on an asynchronous connection is somewhat cumbersome due to the need to ensure that chunks of
+ * data are complete, when we process them. This small class helps with that. Essentially:
+ *
+ * - write to outstream
+ * - when a chunk is done, push it to the device using writeOutBuffer().
+ *
+ * To read a chunk call
+ * - readInBuffer() repeatedly, until it returns true
+ * - read from instream
+ *
+ * Class is implemented as a template, so you can squeeze some bytes out of the protocol, if you know transmission chunks to be short
+ * (e.g. never to exceed quint32). For maximum flexibility, use RKAsyncDataStreamHelper<quint64>.
+ */
+template <typename LENGTH_TYPE>
+class RKAsyncDataStreamHelper {
+public:
+ RKAsyncDataStreamHelper () :
+ auxbuffer(),
+ inbuffer(),
+ outbuffer(),
+ auxstream (&auxbuffer, QIODevice::ReadWrite),
+ instream (&inbuffer, QIODevice::ReadOnly),
+ outstream (&outbuffer, QIODevice::WriteOnly) {
+ device = 0;
+ expected_read_size = 0;
+ }
+ ~RKAsyncDataStreamHelper () {};
+
+ void setIODevice (QIODevice *_device) {
+ device = _device;
+ }
+
+ void writeOutBuffer () {
+ auxstream.device ()->seek (0);
+ auxbuffer.resize (0);
+ auxstream << (LENGTH_TYPE) outbuffer.size ();
+ device->write (auxbuffer);
+ device->write (outbuffer);
+ outstream.device ()->seek (0);
+ outbuffer.resize (0);
+ }
+
+/** @returns false if no complete chunk of data is available, yet. true, if the next chunk of data is available for
+ * processing from instream. */
+ bool readInBuffer () {
+ if (!expected_read_size) {
+ if (device->bytesAvailable () < (unsigned int) sizeof (LENGTH_TYPE)) {
+ return false;
+ } else {
+ auxbuffer = device->read (sizeof (LENGTH_TYPE));
+ auxstream.device ()->seek (0);
+ auxstream >> expected_read_size;
+ }
+ }
+
+ if ((LENGTH_TYPE) device->bytesAvailable () < expected_read_size) {
+ return false;
+ }
+
+ inbuffer = device->read (expected_read_size);
+ instream.device ()->seek (0);
+ expected_read_size = 0;
+ return true;
+ }
+
+ int inSize () const {
+ return inbuffer.size ();
+ }
+
+ int outSize () const {
+ return outbuffer.size ();
+ }
+private:
+ QIODevice *device;
+ LENGTH_TYPE expected_read_size;
+ // NOTE: Order of declaration of the buffers and streams is important, as these are initialized during construction, and depend on each other
+ QByteArray auxbuffer;
+ QByteArray inbuffer;
+ QByteArray outbuffer;
+ QDataStream auxstream;
+public:
+ QDataStream instream;
+ QDataStream outstream;
+};
+
+#endif
Modified: trunk/rkward/rkward/rbackend/rktransmitter.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rktransmitter.cpp 2013-04-14 19:13:29 UTC (rev 4698)
+++ trunk/rkward/rkward/rbackend/rktransmitter.cpp 2013-04-15 09:32:28 UTC (rev 4699)
@@ -2,7 +2,7 @@
rktransmitter - description
-------------------
begin : Thu Nov 18 2010
- copyright : (C) 2010 by Thomas Friedrichsmeier
+ copyright : (C) 2010, 2013 by Thomas Friedrichsmeier
email : tfry at users.sourceforge.net
***************************************************************************/
@@ -19,12 +19,9 @@
#include "../debug.h"
-QByteArray RKRBackendSerializer::serialize (const RBackendRequest &request) {
+void RKRBackendSerializer::serialize (const RBackendRequest &request, QDataStream &stream) {
RK_TRACE (RBACKEND);
- QByteArray ret;
- QDataStream stream (&ret, QIODevice::WriteOnly);
-
stream << (qint8) request.type;
stream << request.synchronous;
stream << request.done; // well, not really needed, but...
@@ -42,14 +39,11 @@
stream << false;
}
stream << request.params;
-
- return ret;
}
-RBackendRequest *RKRBackendSerializer::unserialize (const QByteArray &buffer) {
+RBackendRequest *RKRBackendSerializer::unserialize (QDataStream &stream) {
RK_TRACE (RBACKEND);
- QDataStream stream (buffer);
RBackendRequest *request = new RBackendRequest (false, RBackendRequest::OtherRequest); // will be overwritten
bool dummyb;
@@ -203,7 +197,6 @@
RK_ASSERT (_instance == 0); // NOTE: Although there are two instances of an abstract transmitter in an RKWard session, these live in different processes.
_instance = this;
connection = 0;
- fetching_transmission = false;
moveToThread (this);
}
@@ -221,10 +214,9 @@
return;
}
- QByteArray buffer = RKRBackendSerializer::serialize (*request);
- RK_DEBUG (RBACKEND, DL_DEBUG, "Transmitting request of length %s", QString::number (buffer.length ()).toLocal8Bit ().data ());
- connection->write (QString::number (buffer.length ()).toLocal8Bit () + "\n");
- connection->write (buffer);
+ RKRBackendSerializer::serialize (*request, streamer.outstream);
+ RK_DEBUG (RBACKEND, DL_DEBUG, "Transmitting request of length %d", streamer.outSize ());
+ streamer.writeOutBuffer ();
}
void RKAbstractTransmitter::customEvent (QEvent *e) {
@@ -242,38 +234,17 @@
void RKAbstractTransmitter::fetchTransmission () {
RK_TRACE (RBACKEND);
+ while (connection->bytesAvailable ()) {
+ if (!streamer.readInBuffer ()) break;
+
+ requestReceived (RKRBackendSerializer::unserialize (streamer.instream));
+ RK_ASSERT (streamer.instream.atEnd ()); // full transmission should have been read
+ }
+
if (!connection->isOpen ()) {
- handleTransmissionError ("Connection not open while trying to read request. Last error was: " + connection->errorString ());
+ handleTransmissionError ("Connection closed unexepctedly. Last error was: " + connection->errorString ());
return;
}
-
- if (fetching_transmission) return; // apparently, on Windows, readyRead() *does* get emitted from waitForReadyRead. Avoid recursion.
-
- if (!connection->canReadLine ()) return;
- fetching_transmission = true;
-
- QString line = QString::fromLocal8Bit (connection->readLine ());
- bool ok;
- int expected_length = line.toInt (&ok);
- if (!ok) handleTransmissionError ("Protocol header error. Last connection error was: " + connection->errorString ()+ "; header was: " + line);
-
- QByteArray receive_buffer;
- while (receive_buffer.length () < expected_length) {
- if (connection->bytesAvailable ()) {
- receive_buffer.append (connection->read (expected_length - receive_buffer.length ()));
- } else {
- connection->waitForReadyRead (1000);
- if (!connection->isOpen ()) {
- handleTransmissionError ("Connection closed unexepctedly. Last error: " + connection->errorString ());
- return;
- }
- }
- }
- fetching_transmission = false;
-
- requestReceived (RKRBackendSerializer::unserialize (receive_buffer));
-
- if (connection->bytesAvailable ()) QTimer::singleShot (0, this, SLOT (fetchTransmission ()));
}
void RKAbstractTransmitter::setConnection (QLocalSocket *_connection) {
@@ -281,6 +252,7 @@
RK_ASSERT (!connection);
connection = _connection;
+ streamer.setIODevice (connection);
RK_ASSERT (connection->isOpen ());
connect (connection, SIGNAL (readyRead()), this, SLOT (fetchTransmission()));
Modified: trunk/rkward/rkward/rbackend/rktransmitter.h
===================================================================
--- trunk/rkward/rkward/rbackend/rktransmitter.h 2013-04-14 19:13:29 UTC (rev 4698)
+++ trunk/rkward/rkward/rbackend/rktransmitter.h 2013-04-15 09:32:28 UTC (rev 4699)
@@ -19,6 +19,7 @@
#define RKTRANSMITTER_H
#include "rkrbackendprotocol_shared.h"
+#include "rkasyncdatastreamhelper.h"
#include <QThread>
#include <QByteArray>
@@ -27,8 +28,8 @@
NOTE: This could really be a namespace, instead of a class, but "friending" a class is simply easier... */
class RKRBackendSerializer {
public:
- static QByteArray serialize (const RBackendRequest &request);
- static RBackendRequest *unserialize (const QByteArray &buffer);
+ static void serialize (const RBackendRequest &request, QDataStream &buffer);
+ static RBackendRequest *unserialize (QDataStream &buffer);
private:
static void serializeOutput (const ROutputList &list, QDataStream &stream);
@@ -67,7 +68,7 @@
void disconnected ();
private:
static RKAbstractTransmitter* _instance;
- bool fetching_transmission;
+ RKAsyncDataStreamHelper<quint64> streamer;
};
#endif
Modified: trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.cpp 2013-04-14 19:13:29 UTC (rev 4698)
+++ trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.cpp 2013-04-15 09:32:28 UTC (rev 4699)
@@ -23,7 +23,7 @@
#include "../../debug.h"
-RKAsyncDataStreamHelper RKGraphicsDeviceBackendTransmitter::streamer;
+RKAsyncDataStreamHelper<RKGraphicsDeviceTransmittionLengthType> RKGraphicsDeviceBackendTransmitter::streamer;
QIODevice* RKGraphicsDeviceBackendTransmitter::connection = 0;
QMutex RKGraphicsDeviceBackendTransmitter::mutex;
RKGraphicsDeviceBackendTransmitter* RKGraphicsDeviceBackendTransmitter::_instance = 0;
Modified: trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.h 2013-04-14 19:13:29 UTC (rev 4698)
+++ trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.h 2013-04-15 09:32:28 UTC (rev 4699)
@@ -23,6 +23,7 @@
#include <QMutex>
#include "rkgraphicsdevice_protocol_shared.h"
+#include "../rkasyncdatastreamhelper.h"
/** This simple class is responsible for handling the backend side of transmitting data / requests for the RKGraphicsDevice
Also it provides the namespace for some statics.
@@ -34,7 +35,7 @@
static void kill ();
static bool connectionAlive ();
static RKGraphicsDeviceBackendTransmitter* instance ();
- static RKAsyncDataStreamHelper streamer;
+ static RKAsyncDataStreamHelper<RKGraphicsDeviceTransmittionLengthType> streamer;
static QIODevice* connection;
static QMutex mutex;
private:
Modified: trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.h 2013-04-14 19:13:29 UTC (rev 4698)
+++ trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.h 2013-04-15 09:32:28 UTC (rev 4699)
@@ -19,6 +19,7 @@
#define RKGRAPHICSDEVICE_FRONTENDTRANSMITTER_H
#include "rkgraphicsdevice_protocol_shared.h"
+#include "../rkasyncdatastreamhelper.h"
class QIODevice;
class QLocalServer;
@@ -44,7 +45,7 @@
QString server_name;
QIODevice *connection;
QLocalServer *local_server;
- RKAsyncDataStreamHelper streamer;
+ RKAsyncDataStreamHelper<RKGraphicsDeviceTransmittionLengthType> streamer;
};
#endif
Modified: trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h 2013-04-14 19:13:29 UTC (rev 4698)
+++ trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h 2013-04-15 09:32:28 UTC (rev 4699)
@@ -89,85 +89,7 @@
RKDCancel // 20
};
-#include <QIODevice>
-#include <QDataStream>
-#include <QByteArray>
+#include <QtGlobal>
+typedef quint32 RKGraphicsDeviceTransmittionLengthType;
-/** Using a QDataStream on an asynchronous connection is somewhat cumbersome due to the need to ensure that chunks of
- * data are complete, when we process them. This small class helps with that. Essentially:
- *
- * - write to outstream
- * - when a chunk is done, push it to the device using writeOutBuffer().
- *
- * To read a chunk call
- * - readInBuffer() repeatedly, until it returns true
- * - read from instream
- */
-class RKAsyncDataStreamHelper {
-public:
- RKAsyncDataStreamHelper () :
- auxbuffer(),
- inbuffer(),
- outbuffer(),
- auxstream (&auxbuffer, QIODevice::ReadWrite),
- instream (&inbuffer, QIODevice::ReadOnly),
- outstream (&outbuffer, QIODevice::WriteOnly) {
- device = 0;
- expected_read_size = 0;
- }
- ~RKAsyncDataStreamHelper () {};
-
- void setIODevice (QIODevice *_device) {
- device = _device;
- }
-
- void writeOutBuffer () {
- auxstream.device ()->seek (0);
- auxbuffer.resize (0);
- auxstream << (quint32) outbuffer.size ();
- device->write (auxbuffer);
- device->write (outbuffer);
- outstream.device ()->seek (0);
- outbuffer.resize (0);
- }
-
-/** @returns false if no complete chunk of data is available, yet. true, if the next chunk of data is available for
- * processing from instream. */
- bool readInBuffer () {
- if (!expected_read_size) {
- if (device->bytesAvailable () < (unsigned int) sizeof (quint32)) {
- return false;
- } else {
- auxbuffer = device->read (sizeof (quint32));
- auxstream.device ()->seek (0);
- auxstream >> expected_read_size;
- }
- }
-
- if (device->bytesAvailable () < expected_read_size) {
- return false;
- }
-
- inbuffer = device->read (expected_read_size);
- instream.device ()->seek (0);
- expected_read_size = 0;
- return true;
- }
-
- int inSize () const {
- return inbuffer.size ();
- }
-private:
- QIODevice *device;
- quint32 expected_read_size;
- // NOTE: Order of declaration of the buffers and streams is important, as these are initialized during construction, and depend on each other
- QByteArray auxbuffer;
- QByteArray inbuffer;
- QByteArray outbuffer;
- QDataStream auxstream;
-public:
- QDataStream instream;
- QDataStream outstream;
-};
-
#endif
More information about the rkward-tracker
mailing list