File download - check for error before file write - c++

I'm using Qt to download a file from HTTP, for that, I'm using two signals:
connect(currentDownload, SIGNAL(finished()),
SLOT(downloadFinished()));
connect(currentDownload, SIGNAL(readyRead()),
SLOT(downloadReadyRead()));
Callbacks:
void DownloadManager::downloadFinished()
{
output.close();
if (currentDownload->error()) {
// download failed
std::cout << "Failed: [" << currentDownload->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()
<< "] " << qPrintable(currentDownload->errorString()) << std::endl;
} else {
std::cout << "Download succeeded" << std::endl;
}
currentDownload->deleteLater();
startNextDownload();
}
void DownloadManager::downloadReadyRead()
{
output.write(currentDownload->readAll());
}
The problem I'm having is that I cant figure out how to skip writing the output file, if any error has occured during download for whatever reason. This is not logical - since I can only check for error during the finished() signal emitting. Checking for errors during the readyRead() signal won't show any, even though they exist. In the results, 404 output file will be written to the disk. How can I solve that?

You should use QNetworkRequest to get all the infromation.
Refer to this example.
QNetworkAccessManager provide more signals to tackle errors.
QNetworkReply *reply = manager->get(request);
connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(slotError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(slotSslErrors(QList<QSslError>)));

Related

Qt Concurrent with signals & slots

I'm a novice in threads and someone advises me to use Qt Concurrent (Qt C++).
I'm trying to run a function in a thread by using Qt Concurrent, my functions runs well but my signal/slot is never emitted.
However for your information if I launch my function without using thread everything works fine.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QFutureWatcher<void> *watcher1 = new QFutureWatcher<void>();
connect(watcher1, SIGNAL(finished()), this, SLOT(getSizeFinished()));
QString string = "http://ipv4.download.thinkbroadband.com/50MB.zip";
QFuture<void> future1 = QtConcurrent::run(this, &MainWindow::getRemoteFileSize, string);
watcher1->setFuture(future1);
}
void MainWindow::getSizeFinished()
{
qDebug() << "--- FINISHED ---";
}
void MainWindow::getRemoteFileSize(const QString &url)
{
qDebug() << "Function - getRemoteFileSize";
QNetworkRequest req;
m_netmanager = new QNetworkAccessManager();
req.setUrl(QUrl(url));
m_reply = m_netmanager->get(req);
connect(m_reply, SIGNAL(metaDataChanged()), this, SLOT(remoteHTTPHeader()));
}
void MainWindow::remoteHTTPHeader()
{
qDebug() << "Function - remoteHTTPHeader";
remoteSize = m_reply->header(QNetworkRequest::ContentLengthHeader).toInt();
qDebug() << "Remote File Size: " << remoteSize;
m_reply->deleteLater();
m_netmanager->deleteLater();
qDebug() << "SIZE " << remoteSize;
}
You probably don't need to create a connection in this case, you could call MainWindow::remoteHTTPHeader() right after m_reply = m_netmanager->get(req);.
You might want to check if the reply is effectively finished like so:
if (m_reply->isFinished()) {
remoteHTTPHeader();
} else {
connect(m_reply, &QNetworkReply::finished, this, &MainWindow::remoteHTTPHeader);
}
This way you handle both fast and slow connections. Also notice how I created the connection using function pointers instead of SIGNAL and SLOT macro, this syntax is better since it checks at compile time if the functions exist so you avoid making typos and the like.

QTcpServer::incomingConnection(qintptr socketDescriptor) is it possible to connect with specified socket?

void server::incomingConnection(qintptr socketDescriptor) {
qDebug() << "incoming connection";
connection* new_connection = new connection(this);
new_connection->set_socket_descriptor(socketDescriptor);
connect(new_connection, SIGNAL(ready_read()), this, SLOT(ready_read()));
connect(new_connection, SIGNAL(disconnected()), this, SLOT(disconnected()));
emit signal_new_connection(new_connection);
}
server class is inherited from QTcpServer, and connection class
has a QTcpSocket as member and some info about user who want to
connect( name, ip, id...)
my problem is that i don't know nothing about new_connection. i need to know who is connecting with server. for this reason i want to connect-back but how? is there any way? or must wait till i receive data(greeting message) from connected socket(user) ?
I've just accidentaly bumped into this old thread having the same problem. And I just found the solution, so I decided to post here in case someone has similar problem.
To get actual QTcpSocket (the one which emitted readyRead() signal), you can use QObject::sender() method, e.g.:
void NetServer::onNewConnection() {
QObject::connect(clientSocket, SIGNAL(readyRead()), this, SLOT(onData()));
}
// ...
void NetServer::onData() {
QTcpSocket *client = this->server->nextPendingConnection();
qDebug() << "Received data from" << sender();
// or
qDebug() << "Received data from" << this->sender();
// or even
qDebug() << "Received data from" << QObject::sender();
}

Retrieving data from web with QNetworkAccessManager: the file is downloaded but QNetworkReply::readAll returns null

There has been the same question already, but the single answer is not helpful: Qt Download File - QNetworkAccessManager, not getting data
So, I'm trying to download a file:
QNetworkRequest request;
request.setUrl(QUrl(fileUrl));
QNetworkReply * reply = m_nam.get(request);
connect(reply, SIGNAL(finished()), this, SLOT(onDownloadRequestFinished()), Qt::UniqueConnection);
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onDownloadRequestProgress(qint64, qint64)), Qt::UniqueConnection);
And in the onDownloadRequestFinished slot:
QNetworkReply * reply = qobject_cast<QNetworkReply *>(sender());
if (reply && reply->error() == QNetworkReply::NoError) {
Q_ASSERT(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200);
qDebug() << "reply " << reply->bytesAvailable() << reply->pos() << reply->size() << reply->isReadable() << reply->openMode() << reply->isOpen();
}
The slot prints the following: reply 0 0 0 true OpenMode( "ReadOnly" ) true
So, no data. However, I can clearly see that it does download something somewhere. It's a big file and it does download it, judging from onDownloadRequestProgress.
Important clarification: pretty much the same code works in another project on the same computer. I'm trying to find differences, but see none so far.
Where's the data?
Did you connected readyRead() signal to write bytes received into a specific file?
I always did this to save a file:
const QNetworkRequest& request = QNetworkRequest(url);
reply = qnetworkaccessmanager->get(request);
QObject::connect(reply, SIGNAL(readyRead()), this,
SLOT( readingReadyBytes() ));
then i create my slot:
void yourClass::readingReadyBytes() {
file->write(reply->read(reply->bytesAvailable()));
}

Qt Download File - QNetworkAccessManager, not getting data

I'm trying to have my application download a file from a URL, typically an EXE or a Jar, not that this should change much though. I have this all running in a thread, but I don't think that will make a difference (if it does let me know).
So Do_Download is my function that creates the manager, sets the URL and request, and performs get. I then try to connect the finished signal to the slot the will write the file.
void DownloadManager::Do_Download() {
QNetworkAccessManager *netManager = new QNetworkAccessManager(this);
QUrl url(install_mirror); //istall_mirror is the URL provided by user
QNetworkRequest req(url);
QNetworkReply *reply = netManager->get(req);
connect(reply, SIGNAL(finished()), this, SLOT(writeData()));
}
My writeData function checks for errors, and if there are no errors it writes the data to file.
void DownloadManager::writeData() {
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (reply) {
if (reply->error() == QNetworkReply::NoError) {
QFile file(location);
if(file.open(QIODevice::WriteOnly)) {
file.write(reply->readAll());
} else {
errorMessage = "Error writing downloaded file for mirror installation";
}
} else {
//get http status code
int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
errorMessage = "HTTP Error code while downloading from mirror: " + httpStatus;
}
reply->deleteLater();
} else {
errorMessage = "Error downloading file from installation mirror";
}
}
The problem being there is no data being written. It just creates a 0Kb file.
I tried adding a download progress slot so I could see what was going on recieving the data. So I added this to my Do_Download method.
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(DL_Progress(qint64,qint64)));
void DownloadManager::DL_Progress(qint64 recieved, qint64 total) {
std::cout << recieved << " / " << total << endl;
}
The output displays one time as 0 / 01
What am I doing wrong?
The only problem I see in your code is you are not waiting for the download to be finished. The NetworkRequest object would be destructed at the end of function call.
So, I would rewrite Do_Download like this (QEventLoop syncronizes the network request):
void DownloadManager::Do_Download() {
QEventLoop eventLoop;
QNetworkAccessManager *netManager = new QNetworkAccessManager(this);
QUrl url(install_mirror); //istall_mirror is the URL provided by user
QNetworkRequest req(url);
QNetworkReply *reply = netManager->get(req);
connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec();
writeData(reply);
}

QProcess does not complete creating file

I am just trying to create a file with QProcess by the following source code:
void Processmethod()
{
QDialog *ProcessMessage = new QDialog;
Ui::DialogProcessMessage Dialog;
Dialog.setupUi(ProcessMessage);
ProcessMessage->setModal(true);
ProcessMessage->setAttribute(Qt::WA_DeleteOnClose);
ProcessMessage->show();
processmethodONE();
}
void processmethodONE()
{
QString ProcessCommand = "w8 " + blablubli";
Prozess.setWorkingDirectory(Path); //QProcess "Prozess" is globaly defined
Prozess.setStandardOutputFile(Path); //in my class
Prozess.start(ProcessCommand);
QProcess::ExitStatus Status = Prozess.exitStatus();
if (Status == 0)
{
std::cout << "File created!" << std::endl;
}
}
This process creates out of another file which is located in the QString "Path" a new file, let me call it "PROFILE" (PRO for Problem :). The Profile also is created, but is never completed, I guess not even 50% of the file are completed.
Just when using
while(!Prozess.waitForFinished())
{
qApp->processEvents();
std::cerr << "Process Create PROFile running " << std::endl;
}
the file is written completely.
Furthermore I tried to use the QProcess finished(int) Signal to start another method and deleted the while loop (which freezes the whole GUI). I declared it in the constructor with:
connect(&Prozess, SIGNAL(finished(int)), this, (SLOT(processmethodTWO())));
But I guess this could not work because the first process isn't finished completely. Where is the problem?
There is no warranty that right after Prozess.start(ProcessCommand); process will be finished, so calling "Prozess.exitStatus();" right after it will give you "false positive". You certainly will have to wait until process is finished. You may either do it with with while loop, that you suggested or with QEventLoop
// ...
Prozess.setStandardOutputFile(Path); //in my class
QEventLoop loop;
connect(&Prozess, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
connect(&Prozess, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit()));
Prozess.start();
loop.exec();
// Now your process status should be valid:
QProcess::ExitStatus Status = Prozess.exitStatus();