My Objective
I want to upload a sqlite file to google drive.
Although I have been able to achieve uploading the file to google drive, the file uploaded name is being "Untitled". I tried Performing Multipart Upload with the help of Qt's QHttpMultiPart.
Here is my code
bool File_Control::Upload_File_Multipart(const QString &FileName, const QByteArray &rawData)
{
if(FileName.isEmpty()){
emit setMessage("Error: File Name can not be empty");
return false;
}
if(rawData.size()==0){
emit setMessage("Error: File size can not be zero");
return false;
}
// Prepare MetaDataPart
QHttpPart MetadataPart;
MetadataPart.setRawHeader("Content-Type", "application/json; charset=UTF-8");
QString Body;
Body = "{\n"
+ tr("\"name\": \"%1\"\n").arg(FileName)
+ tr("}");
MetadataPart.setBody(Body.toUtf8());
// Prepare MediaPart
QHttpPart MediaPart;
MediaPart.setRawHeader("Content-Type", "application/octet-stream");
MediaPart.setBody(rawData);
// Now add MetaDataPart and MediaPart together to form multiPart
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::RelatedType);
multiPart->setBoundary("bound1");
multiPart->append(MetadataPart);
multiPart->append(MediaPart);
// Now Prepare the request
QUrl url("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
QNetworkRequest request(url);
QString AccessTokenBearer = "Bearer " + mAccess_Token; // mAccess_Token holds the access_token for the session
request.setRawHeader("Content-Type","Content-Type: multipart/related; boundary=bound1");
request.setRawHeader("Authorization", AccessTokenBearer.toUtf8());
// Get Reply and connect it to set Value
QNetworkReply *reply = mQNAM.post(request, multiPart); // mQNAM is QNetworkAccessManager
QObject::connect(reply, SIGNAL(uploadProgress(qint64,qint64)),
this, SIGNAL(setValue(qint64,qint64))); // Update in gui
// Set timeout mechanism while waiting for reply finished
bool stop = false;
QTimer timer;
timer.setSingleShot(true);
QObject::connect(reply, &QNetworkReply::uploadProgress, [&](){
timer.stop();
timer.start(TIMEOUT); // Restart timer every time upload progress
});
QObject::connect(&timer, &QTimer::timeout, [&](){
stop = true;
});
timer.start(TIMEOUT);
// Wait till the response is completed
while(!reply->isFinished()){
QCoreApplication::processEvents();
if(stop){
reply->abort();
}
}
// Check reply
if(reply->error() != QNetworkReply::NoError){
if(reply->error() == QNetworkReply::OperationCanceledError){
emit setMessage("Error: Timeout");
}
else{
emit setMessage("Error: "+reply->errorString());
}
delete reply;
return false;
}
else{
QByteArray rawData = reply->readAll();
qDebug()<<"Size of reply "<<rawData.size();
qDebug()<<"Data "<<rawData;
delete reply;
return true;
}
}
Edit 1
Body.utf8 log -> "{\n\"name\": \"db_06_08_2018_16_18_11_979.sqlite\"\n}"
I finally found the mistake. It was nothing but a typo in preparing the request
Before:
request.setRawHeader("Content-Type","Content-Type: multipart/related; boundary=bound1");
After:
request.setRawHeader("Content-Type","multipart/related; boundary=bound1");
This solved the issue.
Related
I am using google speech-to-text api to convert my audio file to text. Following is my code(in Qt):
`QString fileName = QDir::currentPath() + "/audio.wav"; //this is my audio file
QFile audioFile(fileName);
if(!audioFile.open(QIODevice::ReadOnly | QIODevice::Text)){
QMessageBox::critical(0,"Error",fileName+" Not found!");
ui->pushButton_4->setText("Speech to text");
return;
}
int idx = ui->comboBox->currentIndex();
QString enc;
if (idx == -1)
enc = "en-US";
else
enc = ui->comboBox->itemData(idx).toString(); //Language selected by user
QByteArray audioData=audioFile.readAll();
QUrl url("https://speech.googleapis.com/v1/speech:recognize");
QUrlQuery query;
query.addQueryItem("key","myKeyHere...");
url.setQuery(query);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader,"audio/x-flac");
QJsonObject json;
QJsonObject config;
config["encoding"]="FLAC";
config["sampleRateHertz"]=44100;
config["languageCode"]=enc;
json["config"]=config;
QJsonObject audio;
audio["content"]=QString::fromLatin1(audioData.toBase64());
json["audio"]=audio;
QByteArray jsonData=QJsonDocument(json).toJson();
QNetworkAccessManager *manager=new QNetworkAccessManager();
QNetworkReply *reply=manager->post(request,jsonData);
QObject::connect(reply,&QNetworkReply::finished,[this,reply](){
if(reply->error()!=QNetworkReply::NoError){
QMessageBox::critical(0,"Error Occured",reply->errorString());
qDebug() << reply->readAll();
ui->pushButton_4->setText("Speech to text");
return;
}
else if(reply->error()==QNetworkReply::UnknownNetworkError){
QMessageBox::warning(0,"Network Error","Please check your internet connection and try again!");
ui->pushButton_4->setText("Speech to text");
}
else if(reply->isFinished() && reply->error()==QNetworkReply::NoError){
QJsonDocument responseJson=QJsonDocument::fromJson(reply->readAll());
QJsonObject object=responseJson.object();
QString ResponseText=object["results"].toArray()[0].toObject()
["alternatives"].toArray()[0].toObject()["transcript"].toString();
QTextCursor cur = curr_browser->textCursor();
qDebug() << "Response Data :" << ResponseText;
cur.insertText(ResponseText);
ui->pushButton_4->setText("Speech to text");
}
reply->deleteLater();
});`
This code is working perfectly on Ubuntu but not on windows. When i run this on Ubunutu, i am receiving the response, but on windows i receive the following error:
Error transferring https://speech.googleapis.com/v1/speech:recognize?key=,myKey> - server replied: Bad Request
Following is the code to record an audio file:
`if (m_audioRecorder->state() == QMediaRecorder::StoppedState) {
QString fileName = QDir::currentPath() + "/audio.wav";
m_audioRecorder->setOutputLocation(QUrl::fromLocalFile(fileName));
qDebug()<<"Recording your audio!!";
ui->pushButton_4->setText("Stop ?");
QAudioEncoderSettings settings;
settings.setCodec("audio/x-flac");
settings.setSampleRate(0);
settings.setBitRate(0);
settings.setChannelCount(1);
settings.setQuality(QMultimedia::EncodingQuality(2));
settings.setEncodingMode(QMultimedia::ConstantQualityEncoding);
m_audioRecorder->setEncodingSettings(settings, QVideoEncoderSettings(), "");
m_audioRecorder->record();
}
else {
qDebug()<<"stopped your recording!";
ui->pushButton_4->setText("Processing ...");
m_audioRecorder->stop();
speechToTextCall(); //calling the code to send request to google api
}`
Can anyone help please?
I tried changing the encodig and container type, but nothing worked on Windows.
I have found the solution of above problem. Windows does not recognize the auido/x-flac encoding so i modified my encoding code as follows:
'
#ifdef Q_OS_WIN
settings.setCodec("audio/pcm");
#else
settings.setCodec("audio/x-flac");
#endif
'
I made the same changes at other two places where encoding was set and it worked on windows as well.
I was learning the Github API and wanted to create an Issue on github by Qt.
But, when I submit my Issue, the "Debug Console" said
QNetworkReply::RemoteHostClosedError
(I catched error).
I don't know why, please help me!
Code on Github:
void MainWindow::on_pushButton_2_clicked()
{
QString id = ui->ID_Send->text();
QJsonObject JJ;
QJsonDocument jd;
JJ["title"] = ui->Title->text();
JJ["body"] = ui->Comment->toPlainText();
QHttpMultiPart *part = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart info;
info.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/json"));
jd.setObject(JJ);
info.setBody(jd.toJson());
part->append(info);
QNetworkRequest request;
qDebug()<<"https://api.github.com/repos/MoyuSteve/Comment/issues?client_id="+
client_id+"&client_secret="+client_secret;
request.setUrl(QUrl("https://api.github.com/repos/MoyuSteve/Comment/issues?client_id="+
client_id+"&client_secret="+client_secret));
QNetworkReply* reply = manager->post(request,part);
QObject::connect(reply, &QNetworkReply::finished, [reply, this] () {
if (reply->error() == QNetworkReply::NoError) {
ui->status->setText("ok");
} else {
ui->status->setText("failed");
qDebug()<<reply->error();
}
reply->deleteLater();
});
}
You can take example in this answer or here.
Compared to your code, it sets the header to "application/json".
And it uses a QNetworkAccessManager to send network requests and receive replies.
QUrl url("https://api.github.com/repos/" + owner +"/" + project + "/tags");
qInfo() << url.toString();
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QNetworkAccessManager nam;
QNetworkReply * reply = nam.get(request);
I'm using the code below to make a http request:
QNetworkReply* ApiRequest::req(QString url, QString method, QByteArray data) {
QByteArray request_method = method.toUtf8();
QNetworkAccessManager* manager = new QNetworkAccessManager();
QNetworkRequest request("http://127.0.0.1:9090" + url);
request.setRawHeader("Content-Type", "application/json");
QNetworkReply* reply = manager->sendCustomRequest(request, request_method, data);
return reply;
}
void ApiRequest::requestConfig()
{
NetworkReply* reply = req("/configs",
"GET",
"");
}
The Remote server did execute the request and reply a 204 code.
I have used wireshark to capture and make sure it had reply a 204 No Content.
However, the output there is QVariant(Invalid), the toInt output is 0.
I tried to change PUT to GET but it still not working.
You are analyzing the state even when the request has not been made so it is valid that the result is null, what you should do is analyze it when the finished signal is emitted:
QNetworkReply* reply = mg->sendCustomRequest(request, "PUT", "....some json....");
connec(reply, &QNetworkReply::finished, [reply](){
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
});
Update:
connec(mg, &QNetworkAccessManager::finished, [](QNetworkReply *reply){
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
});
Update 2:
Is there a way to return that reply when it is finished?
Yes, use a QEventLoop, but in general it is a bad design since you should use signals and slots to notify you of the changes.
QNetworkReply* ApiRequest::req(const QString & url, const QString & method, const QByteArray & data) {
QByteArray request_method = method.toUtf8();
QNetworkAccessManager manager;
QNetworkRequest request("http://127.0.0.1:9090" + url);
request.setRawHeader("Content-Type", "application/json");
QNetworkReply* reply = manager.sendCustomRequest(request, request_method, data);
QEventLoop loop;
connec(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
return reply;
}
// ...
void ApiRequest::requestConfig()
{
QNetworkReply* reply = req("/configs", "GET", "");
// ...
reply->deleteLater();
}
You can include QtNetworkReply and QEventLoop classes and use signal/slot mechanism.
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QUrl resource(url);
QNetworkRequest request(resource);
QNetworkReply *reply = manager->get(request);
QEventLoop loop;
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
QJsonObject jsonObject = QJsonDocument::fromJson(reply->readAll()).object();
I am downloading an ".apk" file from a Url with Get method.
The file successfully donwload on my disk from the server.
I actually want to add a progressbar to my program. THE problem is : I can show the bytesReceived but I can't show the totalBytes of the file I am downloading (ContentLenth). How can I get it please from the server.
Here is what i get on my qDebug while downloading:
3498 of -1
799062 of -1
1923737 of -1
3037550 of -1
3200231 of 3200231
Here is my code:
void DownloadApk::LaunchDownload()
{
QNetworkProxy proxy;
proxy.setType(QNetworkProxy::HttpProxy);
proxy.setHostName("proxy");
proxy.setPort(8080);
QNetworkProxy::setApplicationProxy(proxy);
QUrl url("I put my Url here");
QNetworkRequest request(url);
_file = new QFile("C:/Users/Desktop/testdownload/downloadedFile.apk");
_file->open(QIODevice::WriteOnly);
QNetworkAccessManager *_manager= new QNetworkAccessManager;
_reply = _manager->get(request);// Manager is my QNetworkAccessManager
_file->write(_reply->readAll());
connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(error(QNetworkReply::NetworkError)));
connect(_reply, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(updateProgress(qint64, qint64)));
connect(_reply, SIGNAL(finished()),
this, SLOT(finished()));
}
void DownloadApk::error(QNetworkReply::NetworkError err)
{qDebug() << err;
// Manage error here.
_reply->deleteLater();
}
void DownloadApk::updateProgress(qint64 read, qint64 total)
{
qDebug() << read <<"of"<<total ;
QByteArray b = _reply->readAll();
QDataStream out(_file);
out << b;
}
void DownloadApk::finished()
{
QMessageBox::information(this, tr("Complete"), tr("Successfully Downloaded"));
// Done
_reply->deleteLater();
_file->close();
// probably delete the file object too
}
I fixed the problem. Actually it was not a QT problem. This Qt code works correctly.
The probleme was from the server that wasn't sending ContentLenth on the header of the reply.
I have used this code to sent the user name and a password to the server using POST Method.
This returns me a reply,So how can I access the reply variable in the way that i can read the data sent from the server back to me ??
Used Code:
void MainWindow::post(QString name, QString password)
{
QUrl serviceUrl = QUrl("http://lascivio.co/mobile/post.php");
QByteArray postData;
QString s = "param1="+name+"&";
postData.append(s);
s = "param2=" +password;
postData.append(s);
QNetworkAccessManager *networkManager = new QNetworkAccessManager(this);
connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(serviceRequestFinished(QNetworkReply*)));
QNetworkRequest request;
request.setUrl(serviceUrl);
QNetworkReply* reply = networkManager->post(request, postData);
}
void MainWindow::serviceRequestFinished(QNetworkReply* reply)
{
//????????????
}
QNetworkReply is a QIODevice, so you can read it the same way you would read a file. But you have to destroy the QNetworkReply and check for error too in that slot.
For example, in the simplest case (without HTTP redirection):
void MainWindow::serviceRequestFinished(QNetworkReply* reply)
{
// At the end of that slot, we won't need it anymore
reply->deleteLater();
if(reply->error() == QNetworkReply::NoError) {
QByteArray data = reply->readAll();
// do something with data
...
} else {
// Handle the error
...
}
}
You should probably declare the QNetworkAccessManager variable as a member of your class instead of creating a new one for each request.