[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