Is it possible to control download speed using QNetworkAccessManager - qt

Can we restrict QNetworkAccessManager from consuming whole bandwidth, by restricting the download speed, as we do see such options available with almost every download manager?

This is not possible out of the box. But have a look at the Qt Torrent Example, especially the class RateController (ratecontroller.h | ratecontroller.cpp). This class does almost what you want by controlling not only one but a set of connections.
However, this rate controller is operating on QTcpSockets (to be exact on PeerWireClients), so you need to change the type of the "peers" to be QIODevice, which I hope isn't that hard, since PeerWireClient inherits from QTcpSocket, which itself inherits from QIODevice:
// old
void addSocket(PeerWireClient *socket);
// new
void addDevice(QIODevice *device);
(Note that the RateController from the Torrent example controlls both upload and download, but you only need to control the download rate. So you can remove unnecessary code.)
Then you need to make requests made by your QNetworkAccessManager use this rate controller. This can be done by reimplementing QNetworkAccessManager and overwriting (extending) the method QNetworkAccessManager::createRequest, which will be called whenever a new request gets created. This method returns the QNetworkReply* (which inherits from QIODevice*) where the download will be read from, so telling the rate controller to control this device will limit the download rate:
QNetworkReply *MyNetworkAccessManager::createRequest(
QNetworkAccessManager::Operation op,
const QNetworkRequest &req,
QIODevice *outgoingData)
{
// original call to QNetworkAccessManager in order to get the reply
QNetworkReply *reply = QNetworkAccessManager::createRequest(op, req, outgoingData);
// add this reply (which is a QIODevice*) to the rate controller
rateController.addDevice(reply);
return reply;
}
You will not have to subclass QNetworkAccessManager if you already know the pieces of code where you actually perform requests. The methods get() and post() return a QNetworkReply* which you can also just add to the rate controller. (But this way, you manually do this outside of the manager, which is doesn't fulfill the concept of information/implementation hiding, in this case the fact that downloads are rate-controlled.)

Related

How should a Qt-based preferences panel broadcast that a pref has changed?

I am trying to design a preferences panel for my multidocument app. When a given pref changes – font size, say – all of the document windows should immediately update to reflect the new pref value. I don't want to construct the preferences panel up front, for all the document windows to connect to, because it contains a QFontComboBox that takes more than a second to set itself up (ouch); that's not a price I want to pay at startup. So then, my question is: what is an elegant design for the prefs panel to let all the document windows know about the change? In Cocoa, which I'm more used to, I'd use NSNotification to broadcast a notification from the prefs panel that all the document windows could observe; that provides the loose coupling required (since objects can add themselves as observers before the broadcaster exists).
Two approaches occur to me so far:
Loop through topLevelWidgets, do a dynamic cast to my document window class, and for all the document windows I thereby find, just call a hard-coded method on them directly.
Make a second class, PreferencesNotifier, that is separate from the UI object that takes so long to load, and construct a singleton object of this class at startup that all of the document windows can connect themselves to. When the preferences panel eventually gets created, it can send signals to slots in PreferencesNotifier, which will then call its own signals to notify the connected document windows.
Neither seems quite as elegant as NSNotification, and I'm wondering if I'm missing something. Thanks for any tips.
First thing, do not try to copy patterns, like Cocoa's NSNotification/NotificationCenter, to other frameworks (or languages, or...). There are various ways to send messages and generally each framework has picked one. Trying to use the one method that was picked by the framework you are using will lead to the most elegant solutions.
If you really want to, you could implement your own set of classes that will do exactly what NSNotification does. It will feel more elegant to you, but only because you are used to using Cocoa. It will feel odd to every other Qt developer. Also, this solution will require you to write a lot of code as you will not be able to leverage all the features of Qt.
The first solution you are suggesting is a bit ugly and looks more like a hack than anything.
What I do, when I have to handle preferences in a program, is something similar to your solution 2. I create a class that is responsible for handling all settings: read/write setting file, change setting, set default values, etc. Generally this class is a singleton. This class has very limited access to other parts of the program, and generally no access at all to the UI. Each components that needs to access the preferences will use this class. If you do it properly (e.g. use Q_PROPERTY), this class can even be accessed by QML, if you ever need to use Qt Quick.
class Settings: public QObject {
Q_OBJECT
Q_PROERTY(bool showX READ showX WRITE setShowX NOTIFY showXChanged)
public:
bool showX() const { return m_showX; }
void setShowX(bool show) {
if (show == m_showX)
return;
m_showX = show;
emit showXChanged(m_showX);
}
signals:
void showXChanged(bool);
public slots:
void save() const; // Save to disk
void load(); // Load from disk
private:
QSettings m_settings; // Handle load/save from/to disk
bool m_showX;
};
class Window {
Window() {
...
m_widgetX->setVisible(settings->showX());
connect(settings, &Settings::showXChanged,
this, [this](bool show) { m_widgetX->setVisible(show); }
);
...
}
};
class PrefWindow {
PrefWindow () {
...
ui->checkBoxShowX->setChecked(settings->showX());
...
}
private slots:
void on_saveButton_clicked() {
settings->setShowX(ui->checkBoxShowX->checked()):
settings->save();
}
};

Singleton QNetworkAccessManager not directing the response to desired form

In a small Qt application, I have a NetworkAccessManager(NAM) wrapped in a singleton class. NAM object of this class is used by four independent form classes. Each form class fires a request to a separate php (and php takes at least 3 seconds with sleep(3)).
Now there are two cases:
Case I: When NAM, for each form, is connected to form's slot IN CONSTRUCTOR.
In this case, when i send requests from all four forms simultaneously; all the responses are directed to just one form (the one that was first in firing the request) and not to the form that requested it.
Case II: When NAM is connected (for firing request) and disconnected (when response is received) to form's slot IN FUNCTIONS (and not constructor).
In this case, when i send requests from all four forms simultaneously (i.e. in less than 3 seconds); then only the first response is returned and the rest never returned. This is in accordance with the code as singleton NAM was disconnected as soon as it received the reply for the first request. Therefore other requests could not be processed.
All form classes are identical and use the same code. Here is the code (Case II specific):
void Request2::slotStartRequest(){
m_Req2 = NetworkAccessManager::getInstance();
connect(m_Req2, SIGNAL(finished(QNetworkReply*)), this, SLOT(slotReplyFinished(QNetworkReply*)));
QString postData = "value=222";
m_Req2->post(QNetworkRequest(QUrl(path)), postData.toUtf8());
}
void Request2::slotReplyFinished(QNetworkReply *reply){
disconnect(m_Req2, SIGNAL(finished(QNetworkReply*)), this, SLOT(slotReplyFinished(QNetworkReply*)));
ui->TEdit_Req2->setText(reply->readAll());
reply->deleteLater();
}
Though the code for both cases are very similar. This code is Case II specific. For Case I, only change is that 'connect' and 'getInstance' codes are put in constructor (and there is no 'disconnect').
The code will work fine with one NetworkAccessManager object per form class.
But how do I achieve the desired behaviour (with one NAM for whole application) that response is directed only to the form that requested it and also the requests for other forms should not be affected ?
The NAM function post() creates a new QNetworkReply instance to manage that request. It is possible to connect directly to QNetworkReply signals instead of signals of QNetworkAccessManager:
void Request2::slotStartRequest(){
QString postData = "value=222";
QNetworkAccessManager *nam = NetworkAccessManager::getInstance();
m_Reply = nam->post(QNetworkRequest(QUrl(path)), postData.toUtf8());
connect(m_Reply, SIGNAL(finished()), this, SLOT(slotReplyFinished()));
}
Now only this instance of QNetworkReply *m_Reply can call the signal of this. Note that there is no QNetworkReply *reply argument in the finished() signal:
void Request2::slotReplyFinished(){
ui->TEdit_Req2->setText(m_Reply->readAll());
m_Reply->deleteLater();
}
My suggestion (what I do) is to keep track of which object made the request on the manager, perhaps update your manager to take in the object pointer
m_Req2->post(QNetworkRequest(QUrl(path)), postData.toUtf8(), this);
Then on the Manager, use that pointer and use the QMetaObject to invoke the method, instead of emitting a signal: http://doc.qt.io/qt-5/qmetaobject.html#invokeMethod.
So you get something like this, on the Manager
QMetaObject::invokeMethod(obj, "slotReplyFinished", Qt::DirectConnection,
Q_ARG(QNetworkReply*, reply));
(not tested, but you should get the idea)
[edit: fixed code]

Qt5 QSerialPort write data

How I can write data in serial port, with delay between send's messages?
This is my code:
void MainWindow::on_pushButton_Done_clicked()
{
if(sport->isOpen()){
sport->clear();
QString cmd = Phase+Mode;
//Write Stop
sport->write("stop!", 5);
//Write Mode
sport->write(cmd.toStdString().c_str(), cmd.toStdString().length());
//Write Speed
sport->write(Speed.toStdString().c_str(), Speed.toStdString().length());
//Write Direction
sport->write(Direction.toStdString().c_str(), Direction.toStdString().length());
//Run
sport->write("start!", 6);
}
}
My device receives an error message when I call this function.
Thank you.
2 options:
use waitForBytesWritten to ensure the bytes are written and then a short sleep
however this will block the thread and will block the gui
the other is using a QTimer to trigger another slot a few times and a field that will indicate what needs to be sent
Looks like you are trying to program some step motor controller or something similar.
Usually in such controllers you should wait for controller response to verify that command was processed properly.
It looks like that your design of code is very bad. Move everything related with this controller to separate class, which has set of slots, something like: starRotateLeftWithSpeed(double). Code will be cleaner and it will be easy to use thread if you decide to use methods like waitForBytesWritten proposed in another answer.
Definitely you should read controller manual more carefully.

Using QTWebKit to display a website stored in memory

Currently I have my HTML, JS, CSS, graphics, etc stored locally on hard disk and access them using QWebFrame::SetUrl( QUrl::fromLocalFile( "appFolder\html\index.html" )). At some point I am going to need to encrypt the locally stored files so I'm looking for a way to either decrypt them as they're requested or to decrypt them all into memory and access them that way.
I know I can use QWebFrame::setContent( htmlData ) to load the HTML from memory so I can load the encrypted HTML file, decrypt it in memory and then display it that way, but how would I go about the other data (JS, CSS, graphics, etc) which is currently stored in subfolders?
Alternatively, is there a way I can intercept requests for access to all the HTML, JS, CSS, etc files and decrypt them as they're loaded?
By using my own NetworkAccessManager I can intercept calls to createRequest so I can see when each file is being loaded, but I can't see how to use this to decrypt the data on the fly. I can also connect a slot function to the finished(QNetworkReply*) signal, but at that point the data has already been read - the QIODevice's current position is pointing to the end of the file.
I'd be very grateful for any advice or pointers in the right direction.
I think in your case the best solution is to inherit QNetworkReply class and use this new class in reimplemented QNetworkAccessManager::createRequest() function.
In general, you should reimplement next virtual functions of QNetworkReply:
bytesAvailable(), readData(char *data, qint64 maxSize), close(), abort().
For example, readData should be the folowing:
qint64 NetworkReplyEx::readData(char *data, qint64 maxSize)
{
return m_buffer.read(data, maxSize);
}
where m_buffer is already decrypted data.
Also you need to add all necessary logic in this class to get encrypted data, decrypt this data...
In the end you should manually emit finished() signal inside new class, so QWebView or other related class will get decrypted html.

How to read data from QNetworkReply being used by QWebPage?

I use QWebPage to download a webpage as well as all its resources. At the same time I'd like to get hold on raw data being downloaded by Qt during this process. Doing this by reading data from QNetworkReply in void QNetworkAccessManager::finished(QNetworkReply * reply)
signal is not a good solution as data could have been already read by QWebPage itself. This is because
QNetworkReply is a sequential-access
QIODevice, which means that once data
is read from the object, it no longer
kept by the device.
according to detailed description of QNetworkReply.
However QWebPage can be configured to use custom QNetworkAccessManager with overriden createRequest method
QNetworkReply * QNetworkAccessManager::createRequest ( Operation op, const QNetworkRequest & req, QIODevice * outgoingData = 0 )
I think the right solution would be to create a proxy for QNetworkReply and return it in the createRequest method. This proxy should allow for reading data from reply as is the case with the original QNetworkReply (so that QWebPage could read data from it) but at the same time this proxy should allow for reading data by other objects after it have been read by QWebPage. In other words we need tee for QNetworkReply's IODevice base class.
How to write this proxy?
It looks like someone has already wanted the same and wrote a proxy for the QNetworkReply.

Resources