2017-01-30 11 views
0

Я пишу простой клиент для веб-службы для личного обучения. И я решил сделать это с Qt. Я использую версию 5.7. Мне удалось преодолеть проблемы с отправкой и получением запросов с сервера. Но проблема все еще остается.
У меня есть слот on_scanButton_click(), который, в зависимости от того, какая радиокнопка проверена, вызывает некоторый запрос на сервер. Моя проблема заключается в том, как отправить другой запрос на сервер после первого с периодом, чтобы я мог проверить, действительно ли response_code, и я могу вызвать для него отдельное окно.
Это мой mainwindow.cppКак вызвать запрос на сервер с периодом и отправить его снова, если ответ был недействительным?

#include "mainwindow.h" 
#include "networkmanager.h" 
#include "commentdialog.h" 
#include "rescanfiledialog.h" 
#include "filebrowser.h" 
#include "program_exceptions.h" 
#include "overlaywidget.h" 

#include <QMessageBox> 
#include <regex> 


MainWindow::MainWindow(QWidget* parent) : 
    QMainWindow{parent} { 
    ui.setupUi(this); 

    ui.fileRadioButton->setFixedWidth(100); 
    ui.urlRadioButton->setFixedWidth(100); 
    ui.searchRadioButton->setFixedWidth(100); 

    ui.stringFormater->setFixedSize(500, 30); 
    ui.stringFormater->setPlaceholderText("No file selected"); 
    ui.uploadButton->setFixedHeight(30); 

    ui.scanButton->setFixedSize(120, 50); 
    ui.rescanButton->setFixedSize(120, 50); 
    ui.commentButton->setFixedSize(120, 50); 
} 


void MainWindow::changeEvent(QEvent* e) { 
    QMainWindow::changeEvent(e); 

    switch (e->type()) { 

     case QEvent::LanguageChange: 
      ui.retranslateUi(this); 
      break; 

     default: 
      break; 
    } 
} 


void MainWindow::on_scanButton_clicked() { 
    NetworkManager* network_manager{new NetworkManager}; 
    QString input_string = ui.stringFormater->text(); 

    try { 

     if (ui.fileRadioButton->isChecked()) { 

      if (std::regex_match(input_string.toStdString(), std::regex("^(.*/)([^/]*)$"))) { 

       network_manager->scanFileRequest(input_string); 

      } else { 
       throw InvalidFilePathException(); 
      } 

     } else if (ui.urlRadioButton->isChecked()) { 

      if (std::regex_match(input_string.toStdString(), 
          std::regex("^(ht{2}ps?:\\/{2})?(w{3}\\.)?([^:\\/\\.\\s]+)\\.([^:\\/\\.\\s]+)$"))) { 
       network_manager->scanUrlRequest(input_string); 

      } else { 
       throw InvalidUrlNameException(); 
      } 

     } else if (ui.searchRadioButton->isChecked()) { 

      if (!std::regex_match(input_string.toStdString(), std::regex("([^:\\/\\.\\s]+)\\.([^:\\/\\.\\s]+)$"))) { 

       if (!std::regex_match(input_string.toStdString(), std::regex("^(([0-9]{1,3})\\.){3}([0-9]{1,3})$"))) { 
        throw InvalidIpAddressException(); 

       } else { 
        network_manager->retrieveIpReportRequest(input_string); 
       } 

       throw InvalidDomainNameException(); 

      } else { 
       network_manager->retrieveDomainReportRequest(input_string); 
      } 
     } 

    } catch (std::exception& ex) { 
     QString exception_message{ex.what()}; 
     QMessageBox::warning(this, "Warning", exception_message); 
    } 

    ui.stringFormater->clear(); 
} 


void MainWindow::on_fileRadioButton_clicked() { 
    ui.stringFormater->setPlaceholderText("No file selected"); 
    ui.uploadButton->setText("Choose File"); 
    ui.scanButton->setText("Scan it!"); 
    ui.stringFormater->clear(); 
} 

void MainWindow::on_urlRadioButton_clicked() { 
    ui.stringFormater->setPlaceholderText("http://example.com"); 
    ui.uploadButton->setText("Enter URL"); 
    ui.scanButton->setText("Scan it!"); 
    ui.stringFormater->clear(); 
} 

void MainWindow::on_searchRadioButton_clicked() { 
    ui.stringFormater->setPlaceholderText("hash, URL, domain, IP address..."); 
    ui.uploadButton->setText("Enter Term"); 
    ui.scanButton->setText("Search it!"); 
    ui.stringFormater->clear(); 
} 


void MainWindow::on_uploadButton_clicked() { 
    if (ui.fileRadioButton->isChecked()) { 
     FileBrowser* file_browser{new FileBrowser(this)}; 
     file_browser->exec(); 

     ui.stringFormater->setText(file_browser->getFilePath()); 
     file_browser->setFilePath(""); 
    } 
} 


void MainWindow::on_rescanButton_clicked() { 
    RescanFileDialog* rescan_file_doalog{new RescanFileDialog(this)}; 
    rescan_file_doalog->exec(); 
} 


void MainWindow::on_commentButton_clicked() { 
    CommentDialog* comment_dialog{new CommentDialog(this)}; 
    comment_dialog->exec(); 
} 

Здесь идет networkmanager.h.

#ifndef NETWORKMANAGER_H 
#define NETWORKMANAGER_H 

#include <QtNetwork> 


class NetworkManager : public QObject { 

    Q_OBJECT 

private: 

    QString api_address{"https://www.virustotal.com/vtapi/v2"}; 
    QByteArray api_key{"API KEY HERE"}; 
    QNetworkAccessManager* network_manager{new QNetworkAccessManager(this)}; 

    static QJsonObject json_response; 

public: 

    explicit NetworkManager() { 
     connect(network_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*))); 
    } 

    virtual ~NetworkManager() = default; 

    void scanFileRequest(const QString&); 
    void rescanFileRequest(const QString&); 
    void retrieveFileReportRequest(const QString&); 

    void scanUrlRequest(const QString&); 
    void retrieveUrlReportRequest(const QString&); 

    void retrieveIpReportRequest(const QString&); 
    void retrieveDomainReportRequest(const QString&); 
    void makeCommentRequest(const QString&, const QString&); 

    const static QJsonObject getJsonResponse() { 
     return json_response; 
    } 

private slots: 

    void requestFinished(QNetworkReply*); 
}; 


#endif // NETWORKMANAGER_H 

И networkmanager.cpp.

#include "networkmanager.h" 
#include "responses.h" 
#include "status_codes.h" 
#include "program_exceptions.h" 

#include <QMessageBox> 
#include <QTimer> 


QJsonObject NetworkManager::json_response{}; 


void NetworkManager::scanFileRequest(const QString& absolute_file_path) { 
    const QFileInfo file_info{absolute_file_path}; 
    QHttpMultiPart* multi_part{new QHttpMultiPart(QHttpMultiPart::FormDataType)}; 

    QHttpPart api_key_part{}; 
    api_key_part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"apikey\"")); 
    api_key_part.setBody(api_key); 

    QHttpPart file_part{}; 
    QMimeDatabase db{}; 
    QMimeType mime_message{db.mimeTypeForFile(file_info)}; 
    file_part.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(mime_message.name())); 
    file_part.setHeader(QNetworkRequest::ContentDispositionHeader, 
        QVariant("form-data; name=\"file\"; filename=\"" + file_info.fileName() + "\"")); 

    QFile* file{new QFile(absolute_file_path)}; 

    try { 

     if (!file->open(QIODevice::ReadOnly)) { 
      throw FileDoesNotExistException(); 
     } 

    } catch (std::exception& ex) { 
     QMessageBox message_box{QMessageBox::Warning, "Warning", QObject::tr(ex.what()), 
          QMessageBox::NoButton, 0, Qt::FramelessWindowHint}; 

     message_box.exec(); 
    } 

    file_part.setBodyDevice(file); 
    file->setParent(multi_part); 

    multi_part->append(api_key_part); 
    multi_part->append(file_part); 

    QNetworkRequest request{QUrl{api_address + "/file/scan"}}; 
    network_manager->post(request, multi_part); 
} 


void NetworkManager::rescanFileRequest(const QString& resource) { 
    QUrlQuery query_set{}; 
    query_set.addQueryItem("apikey", api_key); 
    query_set.addQueryItem("resource", resource); 

    QUrl post_params{}; 
    post_params.setQuery(query_set); 

    QByteArray post_data{post_params.toEncoded(QUrl::RemoveFragment)}; 
    post_data.remove(0, 1); 

    QNetworkRequest request{QUrl{api_address + "/file/rescan"}}; 
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); 

    network_manager->post(request, post_data); 
} 


void NetworkManager::retrieveFileReportRequest(const QString& resource) { 
    QUrl url{api_address + "/file/report"}; 

    QUrlQuery query_set{}; 
    query_set.addQueryItem("apikey", api_key); 
    query_set.addQueryItem("resource", resource); 

    url.setQuery(query_set.query()); 
    QNetworkRequest request{url}; 

    network_manager->get(request); 
} 


void NetworkManager::scanUrlRequest(const QString& url) { 
    QUrlQuery query_set{}; 
    query_set.addQueryItem("apikey", api_key); 
    query_set.addQueryItem("url", url); 

    QUrl post_params{}; 
    post_params.setQuery(query_set); 

    QByteArray post_data{post_params.toEncoded(QUrl::RemoveFragment)}; 
    post_data.remove(0, 1); 

    QNetworkRequest request{QUrl{api_address + "/url/scan"}}; 
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); 

    network_manager->post(request, post_data); 
} 


void NetworkManager::retrieveUrlReportRequest(const QString& resource) { 
    QUrlQuery query_set{}; 
    query_set.addQueryItem("apikey", api_key); 
    query_set.addQueryItem("resource", resource); 

    QUrl post_params{}; 
    post_params.setQuery(query_set); 

    QByteArray post_data{post_params.toEncoded(QUrl::RemoveFragment)}; 
    post_data.remove(0, 1); 

    QNetworkRequest request{QUrl{api_address + "/url/report"}}; 
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); 

    network_manager->post(request, post_data); 
} 


void NetworkManager::retrieveIpReportRequest(const QString& ip) { 
    QUrl url{api_address + "/ip-address/report"}; 

    QUrlQuery query_set{}; 
    query_set.addQueryItem("apikey", api_key); 
    query_set.addQueryItem("ip", ip); 

    url.setQuery(query_set.query()); 
    QNetworkRequest request{url}; 

    network_manager->get(request); 
} 


void NetworkManager::retrieveDomainReportRequest(const QString& domain) { 
    QUrl url{api_address + "/domain/report"}; 

    QUrlQuery query_set{}; 
    query_set.addQueryItem("apikey", api_key); 
    query_set.addQueryItem("domain", domain); 

    url.setQuery(query_set.query()); 
    QNetworkRequest request{url}; 

    network_manager->get(request); 
} 


void NetworkManager::makeCommentRequest(const QString& resource, const QString& comment) { 
    QUrlQuery query_set{}; 
    query_set.addQueryItem("apikey", api_key); 
    query_set.addQueryItem("resource", resource); 
    query_set.addQueryItem("comment", comment); 

    QUrl post_params{}; 
    post_params.setQuery(query_set); 

    QByteArray post_data{post_params.toEncoded(QUrl::RemoveFragment)}; 
    post_data.remove(0, 1); 

    QNetworkRequest request{QUrl{api_address + "/comments/put"}}; 
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); 

    network_manager->post(request, post_data); 
} 


void NetworkManager::requestFinished(QNetworkReply* reply) { 
    try { 
     http_status_code_t server_reply{static_cast<http_status_code_t>(
             reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt())}; 

     if (server_reply == OK) { 
      QJsonObject json_object = QJsonDocument::fromJson(reply->readAll()).object(); 
      response_code_t response_code{static_cast<response_code_t>(json_object["response_code"].toInt())}; 
      std::string verbose_msg{json_object["verbose_msg"].toString().toStdString()}; 

      if (response_code == ITEM_IS_PRESENT) { 
       json_response = json_object; 
       qDebug() << json_response; 

      } else if (response_code == ITEM_IS_STILL_IN_QUEUE) { 
       throw RequestStillInQueueException(verbose_msg); 

      } else if (response_code == ITEM_DOES_NOT_EXIST) { 
       throw ItemDoesNotExistException(verbose_msg); 

      } else { 
       throw UnknownResponseCodeException(); 
      } 

     } else if (server_reply == API_REQUEST_LIMIT_EXCEEDED) { 
      throw PublicAPIRequestRateExceededException(); 

     } else if (server_reply == FORBIDDEN) { 
      throw ForbiddenException(); 

     } else { 
      throw UnknownHttpStatusCodeException(); 
     } 

    } catch (std::exception& ex) { 
     QMessageBox message_box{QMessageBox::Warning, "Warning", QObject::tr(ex.what()), 
          QMessageBox::NoButton, 0, Qt::FramelessWindowHint}; 

     message_box.exec(); 
    } 
} 

Таким образом, вопрос, где я должен поставить свою QTimer, который будет посылать функцию retireveXXXXRequest() каждые 15 секунд, пока она не получает код ответа, что мне нужно.

Это ссылка на github для более глубокого понимания.
https://github.com/lieroz/VirusTotalClient/tree/develop

ответ

0

Так что ответ был очень прост. Я отправлю решение здесь.
только что изменил некоторые строки в networkmanager.cpp в requestFinished.

void NetworkManager::requestFinished(QNetworkReply* reply) { 
try { 
    http_status_code_t server_reply{static_cast<http_status_code_t>(
             reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt())}; 

    if (server_reply == OK) { 
     QJsonObject json_object = QJsonDocument::fromJson(reply->readAll()).object(); 
     response_code_t response_code{static_cast<response_code_t>(json_object["response_code"].toInt())}; 
     std::string verbose_msg{json_object["verbose_msg"].toString().toStdString()}; 

     if (response_code == ITEM_IS_PRESENT) { 
      qDebug() << json_object; 

      if (verbose_msg == "Scan finished, information embedded") { 

       auto antiviruses = json_object["scans"].toObject().keys(); 
       auto values = json_object["scans"].toObject(); 

       for (auto antivirus : antiviruses) { 
        qDebug() << antivirus; 

        auto keys = values.value(antivirus).toObject().keys(); 

        for (auto key : keys) { 
         qDebug() << key << " : " << values.value(antivirus).toObject().value(key); 
        } 
       } 

       return; 
      } 

      QTimer::singleShot(15000, this, [=]{ 
       retrieveFileReportRequest(json_object["resource"].toString()); 
      }); 

     } else { 
      qDebug() << json_object; 
      QTimer::singleShot(15000, this, [=]{ 
       retrieveFileReportRequest(json_object["resource"].toString()); 
      }); 
     } 

    } else if (server_reply == API_REQUEST_LIMIT_EXCEEDED) { 
     throw PublicAPIRequestRateExceededException(); 

    } else if (server_reply == FORBIDDEN) { 
     throw ForbiddenException(); 

    } else { 
     throw UnknownHttpStatusCodeException(); 
    } 

} catch (std::exception& ex) { 
    QMessageBox message_box{QMessageBox::Warning, "Warning", QObject::tr(ex.what()), 
          QMessageBox::NoButton, 0, Qt::FramelessWindowHint}; 

    message_box.exec(); 
} 

}