restructure curlrequester

This commit is contained in:
Anton Thomasson 2022-01-14 19:17:22 +01:00
parent 47cde78edc
commit 6c4e48d69c
5 changed files with 105 additions and 125 deletions

View file

@ -36,7 +36,6 @@ DEFINES += SEAPRINT_VERSION='\\"$$VERSION\\"'
SOURCES += src/harbour-seaprint.cpp \
src/convertchecker.cpp \
src/curlrequester.cpp \
src/curlworker.cpp \
src/ippdiscovery.cpp \
src/ippmsg.cpp \
src/ippprinter.cpp \
@ -83,7 +82,6 @@ TRANSLATIONS += translations/harbour-seaprint-de.ts \
HEADERS += \
src/convertchecker.h \
src/curlrequester.h \
src/curlworker.h \
src/ippdiscovery.h \
src/ippmsg.h \
src/ippprinter.h \

View file

@ -1,28 +1,86 @@
#include "curlrequester.h"
#include <algorithm>
#include "settings.h"
CurlRequester::CurlRequester(QUrl addr) : _addr(addr), _canWrite(1), _canRead(), _reading(false), _done(false), _dest(nullptr), _size(0), _offset(0), _performer(addr, this)
static size_t trampoline(char* dest, size_t size, size_t nmemb, void* userp)
{
_performer.start();
CurlRequester* cid = (CurlRequester*)userp;
return cid->requestWrite(dest, size*nmemb);
}
CurlRequester::CurlRequester(QUrl addr, Role role)
: _addr(addr), _canWrite(1), _canRead(), _reading(false), _done(false), _dest(nullptr), _size(0), _offset(0), _curl(curl_easy_init())
{
curl_easy_setopt(_curl, CURLOPT_URL, addr.toString().toStdString().c_str());
curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L);
if(Settings::instance()->ignoreSslErrors())
{
curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYSTATUS, 0L);
}
_opts = NULL;
_opts = curl_slist_append(_opts, "User-Agent: SeaPrint " SEAPRINT_VERSION);
switch (role) {
case IppRequest:
{
curl_easy_setopt(_curl, CURLOPT_POST, 1L);
curl_easy_setopt(_curl, CURLOPT_READFUNCTION, trampoline);
curl_easy_setopt(_curl, CURLOPT_READDATA, this);
_opts = curl_slist_append(_opts, "Expect:");
_opts = curl_slist_append(_opts, "Transfer-Encoding: chunked");
_opts = curl_slist_append(_opts, "Content-Type: application/ipp");
_opts = curl_slist_append(_opts, "Accept-Encoding: identity");
break;
}
case HttpGetRequest:
{
curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1L);
break;
}
}
curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _opts);
_worker = QtConcurrent::run([this](){
Bytestream buf;
curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &buf);
curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, write_callback);
CURLcode res = curl_easy_perform(_curl);
if(res != CURLE_OK)
qDebug() << "curl_easy_perform() failed: " << curl_easy_strerror(res);
emit done(res, buf);
});
}
CurlRequester::~CurlRequester()
{
while(!_canWrite.tryAcquire(1, 500))
{
if(!_performer.isRunning())
if(!_worker.isRunning())
{
break;
}
}
_done = true;
_canRead.release();
_performer.wait();
_worker.waitForFinished();
if(_dest != nullptr)
{
delete _dest;
}
curl_slist_free_all(_opts);
curl_easy_cleanup(_curl);
}
bool CurlRequester::write(const char *data, size_t size)
@ -30,7 +88,7 @@ bool CurlRequester::write(const char *data, size_t size)
qDebug() << "write " << size;
while(!_canWrite.tryAcquire(1, 500))
{
if(!_performer.isRunning())
if(!_worker.isRunning())
{
return false;
}

View file

@ -5,29 +5,56 @@
#include <QThread>
#include <QSemaphore>
#include <QMetaMethod>
#include <QtConcurrent/QtConcurrent>
#include <curl/curl.h>
#include <bytestream.h>
#include <QDebug>
#include "curlworker.h"
#include <functional>
class CurlRequester : public QObject
{
Q_OBJECT
public:
CurlRequester(QUrl addr);
~CurlRequester();
enum Role {
IppRequest,
HttpGetRequest
};
template<typename Class, typename Callback>
bool setFinishedCallback(const Class* receiverObject, Callback cb)
{
connect(&_performer, &CurlWorker::done, receiverObject, cb);
return true;
}
CurlRequester(QUrl addr, Role role = IppRequest);
~CurlRequester();
bool write(const char *data, size_t size);
size_t requestWrite(char* dest, size_t size);
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void* userdata)
{
size_t bytes_to_write = size*nmemb;
((Bytestream*)userdata)->putBytes(ptr, bytes_to_write);
return bytes_to_write;
}
signals:
void done(CURLcode, Bytestream);
private:
CurlRequester();
// Container for the cURL global init and cleanup
class GlobalEnv
{
public:
GlobalEnv()
{
curl_global_init(CURL_GLOBAL_DEFAULT);
}
~GlobalEnv()
{
curl_global_cleanup();
}
};
// Must be run exactly once, thus static
static GlobalEnv _gEnv;
QUrl _addr;
QSemaphore _canWrite;
@ -39,7 +66,12 @@ private:
size_t _size;
size_t _offset;
CurlWorker _performer;
friend class CurlWorker;
CURL* _curl;
struct curl_slist* _opts = NULL;
QFuture<void> _worker;
};
#endif // CURLREQUESTER_H

View file

@ -1,57 +0,0 @@
#include "curlworker.h"
#include "curlrequester.h"
#include "settings.h"
static size_t trampoline(char* dest, size_t size, size_t nmemb, void* userp)
{
CurlRequester* cid = (CurlRequester*)userp;
return cid->requestWrite(dest, size*nmemb);
}
CurlWorker::CurlWorker(QUrl addr, void* parent)
{
_curl = curl_easy_init();
// if(!curl)
// return false;
curl_easy_setopt(_curl, CURLOPT_URL, addr.toString().toStdString().c_str());
curl_easy_setopt(_curl, CURLOPT_POST, 1L);
curl_easy_setopt(_curl, CURLOPT_READFUNCTION, trampoline);
curl_easy_setopt(_curl, CURLOPT_READDATA, parent);
// curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L);
if(Settings::instance()->ignoreSslErrors())
{
curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYSTATUS, 0L);
}
_opts = NULL;
_opts = curl_slist_append(_opts, "Expect:");
_opts = curl_slist_append(_opts, "Transfer-Encoding: chunked");
_opts = curl_slist_append(_opts, "Content-Type: application/ipp");
_opts = curl_slist_append(_opts, "User-Agent: SeaPrint " SEAPRINT_VERSION);
_opts = curl_slist_append(_opts, "Accept-Encoding: identity");
curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _opts);
}
CurlWorker::~CurlWorker()
{
curl_slist_free_all(_opts);
curl_easy_cleanup(_curl);
}
void CurlWorker::run(){
Bytestream buf;
curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &buf);
curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, write_callback);
CURLcode res = curl_easy_perform(_curl);
if(res != CURLE_OK)
qDebug() << "curl_easy_perform() failed: " << curl_easy_strerror(res);
emit done(res, buf);
}

View file

@ -1,51 +0,0 @@
#ifndef CURLWORKER_H
#define CURLWORKER_H
#include <QThread>
#include <QUrl>
#include <curl/curl.h>
#include <QtDebug>
#include <bytestream.h>
class CurlWorker : public QThread
{
Q_OBJECT
public:
CurlWorker(QUrl addr, void* parent);
~CurlWorker();
void run() override;
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void* userdata)
{
size_t bytes_to_write = size*nmemb;
((Bytestream*)userdata)->putBytes(ptr, bytes_to_write);
return bytes_to_write;
}
signals:
void done(CURLcode, Bytestream);
private:
// Container for the cURL global init and cleanup
class GlobalEnv
{
public:
GlobalEnv()
{
curl_global_init(CURL_GLOBAL_DEFAULT);
}
~GlobalEnv()
{
curl_global_cleanup();
}
};
// Must be run exactly once, thus static
static GlobalEnv _gEnv;
CurlWorker();
CURL* _curl = nullptr;
struct curl_slist* _opts;
};
#endif // CURLWORKER_H