Files
qt-migration-legatus/qt5-before/dlbo/Lts/Common/httq/DataStream.cpp
T
torstenandCopilot 7173785915 Qt6 Migration: Complete migration with DDS/RTI support and build validation
Major Changes:
- Merged latest Qt5 devel content from dlbo (292 files changed, 7 new dirs)
- Consolidated forward-declarations and include folders
- Removed unneeded modules per Niklas' repo check list

Build System Fixes:
- Fixed CMake VERSION_GREATER syntax in ParticipantManagement/CMakeLists.txt
- Added VLC packages (libvlc-dev, vlc-plugin-base) to docker_build.sh
- Added PostgreSQL dev packages (libpq-dev, postgresql-server-dev-all) to Dockerfile
- Fixed locale warnings (ANSI_X3.4-1968 → C.UTF-8)
- Fixed ArcGIS SDK path warnings when BUILD_ARCGIS=OFF

Code Generation Fixes:
- Fixed IDL enum collisions (PortType→CorePortType/DdsutPortType, PdmEventType)
- Fixed Grantlee template svc_translation.cpp.grantlee:
  - Changed {{ idl_enum.name }}_def:: to {{ idl_enum.name }}::
  - Fixed .underlying() calls for C++11 scoped enums (enum class)
- Removed generated files from repo (moc_*, *_dtc.h, *_ftc.h)

Validation:
- BUILD_RTI=ON: SUCCESS
- BUILD_RTI=OFF: SUCCESS
- C++17 standard maintained for RTI 7.7 compatibility
- Ubuntu 26.04 Docker environment verified

Remaining Warnings (expected):
- BgViewer, KDChart, KDReports, Poppler-Qt6 not found (optional features)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-15 18:20:26 +00:00

263 lines
7.1 KiB
C++
Executable File

#include <httq/DataStream.h>
#include <httq/HttpRequest.h>
#include <QIODevice>
#include <QTcpSocket>
#include <QTimer>
#include <QDataStream>
#include <QTemporaryFile>
#include <QFile>
#ifdef Q_OS_UNIX
#include <unistd.h>
#endif
namespace httq
{
DataStream::DataStream(QIODevice *from, QIODevice *to, const QByteArray &bodyPartial,
qint64 fileLength, size_t bufferSize, LoggerFactory *loggerFactory,
QObject *parent)
: QObject(parent)
, mBodyPartial(bodyPartial)
, mFrom(from)
, mTo(to)
, mBufferSize(bufferSize)
, mFileLength(fileLength)
, mLogger(loggerFactory->createLogger(this))
{
//#define SAVE_PARTIAL_BODY
#ifdef SAVE_PARTIAL_BODY
{
QTemporaryFile f;
f.open();
f.write(mBodyPartial);
f.setAutoRemove(false);
qWarning() << "partial:" << f.fileName();
}
#endif
if (mFileLength == 0) // basically, we are done here
{
mLogger->warning(QStringLiteral("file size = 0 - done"));
QTimer::singleShot(1, this, [this]() { emit signalDone(); deleteLater(); } ); // needs to be queued, so the developer has enough time to connect this signal to a slot first
return;
}
mLogger->debug(QStringLiteral("DataStream c_tor"));
// TODO: timeout!
mBuffer.reserve(bufferSize);
// from QFile manpage: "Unlike other QIODevice implementations, such as QTcpSocket, QFile does not emit the aboutToClose(), bytesWritten(), or readyRead() signals."
mFromSupportsSignals = (qobject_cast<QFileDevice *>(mFrom) == nullptr);
mToSupportsSignals = (qobject_cast<QFileDevice *>(mTo) == nullptr);
mLogger->debug(QStringLiteral("signal support - from: %1 - to: %2").arg(mFromSupportsSignals).arg(mToSupportsSignals));
//if (mFromSupportsSignals)
//connect(mFrom, &QIODevice::readyRead,
auto sock = qobject_cast<QTcpSocket *>(mFrom);
qWarning() << "######################### SOCK" << sock;
connect(sock, &QTcpSocket::readyRead,
this, [this]()
{
mLogger->debug(QStringLiteral(">> DataStream readyRead"));
//mReadyRead = true;
QTimer::singleShot(1, this, [this]() { readNext(); } );
});
if (mToSupportsSignals)
connect(mTo, &QIODevice::bytesWritten,
this, [this]()
{
mLogger->debug(QStringLiteral(">> DataStream write"));
mReadyWrite = true;
QTimer::singleShot(1, this, [this]() { readNext(); } );
});
QTimer::singleShot(1, this, [this]() { readNext(); } );
}
DataStream::~DataStream()
{
mLogger->debug(QStringLiteral("~DataStream"));
}
void DataStream::readNext()
{
#if defined(DEBUG_SLOW) && defined(Q_OS_UNIX)
mLogger->debug(QStringLiteral("read: slowing down....."));
usleep(2 * 1000 * 1000);
#endif
mLogger->debug(QStringLiteral("read: readNext: %1").arg(mBuffer.size()));
if (mBuffer.size() > 0)
{
mLogger->debug(QStringLiteral("read: ignoring read until buffer was written"));
return;
}
if (mToSupportsSignals && !mReadyWrite)
{
mLogger->debug(QStringLiteral("read: won't read until write is ready!"));
return;
}
if (!mBodyPartial.isEmpty()) // don't read from device, but read from data that was already read when the connection was established
{
mBuffer = mBodyPartial;
// qWarning() << "mBuffer content (partial):"));
// for (int i = 0; (i < mBuffer.size() && i < 100); i++)
// qWarning() << Qt::hex << mBuffer[i];
alreadyRead += mBuffer.size();
mLogger->debug(QStringLiteral("read: prebody size: %1").arg(mBuffer.size()));
mBodyPartial.clear();
//mReadyWrite = true;
mLogger->debug(QStringLiteral("read: queueing writeNext after prebody read"));
QTimer::singleShot(1, this, [this]() { /*qWarning() << "triggering writeNext and hoping that writeReady is true!!"));*/ writeNext(); } );
return;
}
if (/*!mFrom->isOpen() || !mFrom->isReadable() || */ (mFrom->bytesAvailable() < 1 /* && !mReadyRead*/))
{
// qWarning() << "nothing to read: bytes available" << mFrom->bytesAvailable() << "ready read" << mReadyRead;
// qWarning() << "try reading anyways..." << mFrom->read(3000);
mLogger->debug(QStringLiteral("read: no bytes available and not ready read"));
// XXX: TODO: FIXME: readyRead never arrives.... we need to have this extremely ugly workaround .... :'(
QTimer::singleShot(1000, this, [this]() { readNext(); } ); // try again........ TEST
return;
}
// if (mFromSupportsSignals)
// mReadyRead = false;
mBuffer = mFrom->read(mBufferSize);
mLogger->debug(QStringLiteral("read: mPos is now %1").arg(mBuffer.size()));
// qWarning() << "read" << mPos << "bytes"));
alreadyRead += mBuffer.size();
mLogger->debug(QStringLiteral("read: alreadyRead = %1").arg(alreadyRead));
if (mBuffer.size() < 1)
{
mLogger->debug(QStringLiteral("read: cannot read anything"));
deleteLater();
return;
}
mLogger->debug(QStringLiteral("read: queueing writeNext"));
QTimer::singleShot(1, this, [this]() { writeNext(); } );
}
void DataStream::writeNext()
{
mLogger->debug(QStringLiteral("write: writeNext: %1").arg(mBuffer.size()));
if (mBuffer.size() < 1)
{
mLogger->debug(QStringLiteral("write: nothing to write"));
QTimer::singleShot(1, this, [this]() { readNext(); } );
return;
}
// TODO: check isOpen & isWritable maybe in c_tor?
if (!mTo->isOpen() || !mTo->isWritable())
{
mLogger->debug(QStringLiteral("write: file error: open? %1 - writable? %2").arg(mTo->isOpen()).arg(mTo->isWritable()));
deleteLater();
return;
}
if (mToSupportsSignals && !mReadyWrite /* wait until bytesWritten signal calls writeNext, but only if bytesWritten is supported, that is, when device is buffered */)
{
mLogger->debug(QStringLiteral("write: !mReadyWrite"));
//readNext();
return;
}
if (mToSupportsSignals)
mReadyWrite = false;
const qint64 size = mTo->write(mBuffer);
mLogger->debug(QStringLiteral("write: wrote to buffer %1 bytes").arg(size)); //QString::fromUtf8(mBuffer.constData(), mPos);
mLogger->debug(QStringLiteral("write: %1 / %2 bytes done (%3 bytes left until DataStream done)").arg(alreadyRead).arg(mFileLength).arg(mFileLength - alreadyRead));
if (size < mBuffer.size())
{
mLogger->warning(QStringLiteral("write: cannot write all bytes: %1 / %2 bytes").arg(mBuffer.size()).arg(size));
deleteLater();
return;
}
mLogger->debug(QStringLiteral("write: mPos is now %1 and was set to zero now!!").arg(mBuffer.size()));
mBuffer.clear();
if (alreadyRead == mFileLength) // done
{
mLogger->debug(QStringLiteral("write: DONE!"));
emit signalDone();
deleteLater();
return;
}
if (alreadyRead > mFileLength)
{
mLogger->debug(QStringLiteral("write: oops... we read too much!! data may be corrupt!! already read %1 bytes, but content length is only %2 (%1 / %2)").arg(alreadyRead).arg(mFileLength));
emit signalDone(); // TODO: emit error??
deleteLater();
return;
}
// give the buffer a chance to emit a bytesWritten signal before trying to read again
if (mToSupportsSignals)
mLogger->debug(QStringLiteral("write: waiting for bytes written to be triggered..."));
mLogger->debug(QStringLiteral("write: queueing writeNext again"));
QTimer::singleShot(1, this, [this]() { writeNext(); } );
}
}