When I worked on the network client for my messenger I found that there are a lot of duplicate code in methods created for different requests to API (getting chats of the user, for example) so I decided to create a container that will contain methods for different signals like the request has failed or smth and just call those depending on the given method name but now i don't know how to create such a structure. For example, that's how it looks now:
void HttpClient::getUserChats(int failCounter) { // getting your chats
QNetworkAccessManager *networkManager = new QNetworkAccessManager();
QNetworkRequest request = formHttpRequest("api/chats");
try {
setAuthorizationHeader(request);
}
catch (const std::runtime_error& e) {
QString what = e.what();
if (what == "Wrong or exp") {
emit unauthorized();
}
else if (what == "Has no internet connection") {
++failCounter;
if (failCounter == 3) {
emit getUserChatsFailed();
}
else {
getUserChats(failCounter);
}
}
delete networkManager;
return ;
}
QNetworkReply *reply = networkManager->get(request);
QObject::connect(reply, &QNetworkReply::finished, this, [reply, networkManager, &failCounter, this]() {
if (reply->error() == QNetworkReply::HostNotFoundError || reply->error() == QNetworkReply::ConnectionRefusedError) {
++failCounter;
if (failCounter == 3) {
emit getUserChatsFailed();
}
else {
getUserChats(failCounter);
}
}
else {
QByteArray dataAsArray = reply->readAll();
QJsonDocument dataAsDocument = QJsonDocument::fromJson(dataAsArray);
QJsonArray data = dataAsDocument.array();
emit getUserChatsProcessed(data);
}
reply->deleteLater();
networkManager->deleteLater();
});
}
void HttpClient::findChats(QMap<QString, QString> body, int failCounter) { // Searching for users or groups
QNetworkAccessManager *networkManager = new QNetworkAccessManager();
QNetworkRequest request = formHttpRequest("api/find", body);
try {
setAuthorizationHeader(request);
}
catch (const std::runtime_error& e) {
QString what = e.what();
if (what == "Wrong or exp") {
emit unauthorized();
}
else if (what == "Has no internet connection") {
++failCounter;
if (failCounter == 3) {
emit findChatsFailed();
}
else {
findChats(body, failCounter);
}
}
delete networkManager;
return ;
}
QNetworkReply *reply = networkManager->get(request);
QObject::connect(reply, &QNetworkReply::finished, this, [body, reply, networkManager, &failCounter, this]() {
if (reply->error() == QNetworkReply::HostNotFoundError || reply->error() == QNetworkReply::ConnectionRefusedError) {
++failCounter;
if (failCounter == 3) {
emit findChatsFailed();
}
else {
findChats(body, failCounter);
}
}
else {
QByteArray dataAsArray = reply->readAll();
QJsonDocument dataAsDocument = QJsonDocument::fromJson(dataAsArray);
QJsonArray data = dataAsDocument.array();
emit findChatsProcessed(data);
}
reply->deleteLater();
networkManager->deleteLater();
});
}
How it logically should be:
void HttpClient::doGet(QMap<QString, QString> body, QString method, int failCounter) {
QNetworkAccessManager *networkManager = new QNetworkAccessManager();
QNetworkRequest request = formHttpRequest(method, body);
try {
setAuthorizationHeader(request);
}
catch (const std::runtime_error& e) {
QString what = e.what();
if (what == "Wrong or exp") {
emit unauthorized();
}
else if (what == "Has no internet connection") {
++failCounter;
if (failCounter == 3) {
emit requestInfo[method].at(0); // zero element of requestInfo is the request failed signal
}
else {
doGet(body, method, failCounter);
}
}
delete networkManager;
return ;
}
QNetworkReply *reply = networkManager->get(request);
QObject::connect(reply, &QNetworkReply::finished, this, [body, reply, networkManager, &failCounter, this]() {
if (reply->error() == QNetworkReply::HostNotFoundError || reply->error() == QNetworkReply::ConnectionRefusedError) {
++failCounter;
if (failCounter == 3) {
emit requestInfo[method].at(0);
}
else {
findChats(body, failCounter);
}
}
else {
QByteArray dataAsArray = reply->readAll();
QJsonDocument dataAsDocument = QJsonDocument::fromJson(dataAsArray);
QJsonArray data = dataAsDocument.array();
// pseudocode here!
const char* processedMethod = requestInfo[method].at(1); // first element of requestInfo is the request processed signal
processedMethod.withArg(data); // give the data as the arg
emit processedMethod;
}
reply->deleteLater();
networkManager->deleteLater();
});
}
I've tried to create a QVector<const char*> but it doesn't work
QVector<const char*> vec(&HttpClient::getUserChats, &HttpClient::getUserChatsProcessed, &HttpClient::getUserChatsFailed);
Method signatures:
signals:
void getUserChatsFailed();
void getUserChatsProcessed(QJsonArray data);
private:
void getUserChats(int failCounter);
These methods will possibly have different signature so I can't use concrete signature as the vector type
When I worked on the network client for my messenger I found that there are a lot of duplicate code in methods created for different requests to API (getting chats of the user, for example) so I decided to create a container that will contain methods for different signals like the request has failed or smth and just call those depending on the given method name but now i don't know how to create such a structure. For example, that's how it looks now:
void HttpClient::getUserChats(int failCounter) { // getting your chats
QNetworkAccessManager *networkManager = new QNetworkAccessManager();
QNetworkRequest request = formHttpRequest("api/chats");
try {
setAuthorizationHeader(request);
}
catch (const std::runtime_error& e) {
QString what = e.what();
if (what == "Wrong or exp") {
emit unauthorized();
}
else if (what == "Has no internet connection") {
++failCounter;
if (failCounter == 3) {
emit getUserChatsFailed();
}
else {
getUserChats(failCounter);
}
}
delete networkManager;
return ;
}
QNetworkReply *reply = networkManager->get(request);
QObject::connect(reply, &QNetworkReply::finished, this, [reply, networkManager, &failCounter, this]() {
if (reply->error() == QNetworkReply::HostNotFoundError || reply->error() == QNetworkReply::ConnectionRefusedError) {
++failCounter;
if (failCounter == 3) {
emit getUserChatsFailed();
}
else {
getUserChats(failCounter);
}
}
else {
QByteArray dataAsArray = reply->readAll();
QJsonDocument dataAsDocument = QJsonDocument::fromJson(dataAsArray);
QJsonArray data = dataAsDocument.array();
emit getUserChatsProcessed(data);
}
reply->deleteLater();
networkManager->deleteLater();
});
}
void HttpClient::findChats(QMap<QString, QString> body, int failCounter) { // Searching for users or groups
QNetworkAccessManager *networkManager = new QNetworkAccessManager();
QNetworkRequest request = formHttpRequest("api/find", body);
try {
setAuthorizationHeader(request);
}
catch (const std::runtime_error& e) {
QString what = e.what();
if (what == "Wrong or exp") {
emit unauthorized();
}
else if (what == "Has no internet connection") {
++failCounter;
if (failCounter == 3) {
emit findChatsFailed();
}
else {
findChats(body, failCounter);
}
}
delete networkManager;
return ;
}
QNetworkReply *reply = networkManager->get(request);
QObject::connect(reply, &QNetworkReply::finished, this, [body, reply, networkManager, &failCounter, this]() {
if (reply->error() == QNetworkReply::HostNotFoundError || reply->error() == QNetworkReply::ConnectionRefusedError) {
++failCounter;
if (failCounter == 3) {
emit findChatsFailed();
}
else {
findChats(body, failCounter);
}
}
else {
QByteArray dataAsArray = reply->readAll();
QJsonDocument dataAsDocument = QJsonDocument::fromJson(dataAsArray);
QJsonArray data = dataAsDocument.array();
emit findChatsProcessed(data);
}
reply->deleteLater();
networkManager->deleteLater();
});
}
How it logically should be:
void HttpClient::doGet(QMap<QString, QString> body, QString method, int failCounter) {
QNetworkAccessManager *networkManager = new QNetworkAccessManager();
QNetworkRequest request = formHttpRequest(method, body);
try {
setAuthorizationHeader(request);
}
catch (const std::runtime_error& e) {
QString what = e.what();
if (what == "Wrong or exp") {
emit unauthorized();
}
else if (what == "Has no internet connection") {
++failCounter;
if (failCounter == 3) {
emit requestInfo[method].at(0); // zero element of requestInfo is the request failed signal
}
else {
doGet(body, method, failCounter);
}
}
delete networkManager;
return ;
}
QNetworkReply *reply = networkManager->get(request);
QObject::connect(reply, &QNetworkReply::finished, this, [body, reply, networkManager, &failCounter, this]() {
if (reply->error() == QNetworkReply::HostNotFoundError || reply->error() == QNetworkReply::ConnectionRefusedError) {
++failCounter;
if (failCounter == 3) {
emit requestInfo[method].at(0);
}
else {
findChats(body, failCounter);
}
}
else {
QByteArray dataAsArray = reply->readAll();
QJsonDocument dataAsDocument = QJsonDocument::fromJson(dataAsArray);
QJsonArray data = dataAsDocument.array();
// pseudocode here!
const char* processedMethod = requestInfo[method].at(1); // first element of requestInfo is the request processed signal
processedMethod.withArg(data); // give the data as the arg
emit processedMethod;
}
reply->deleteLater();
networkManager->deleteLater();
});
}
I've tried to create a QVector<const char*> but it doesn't work
QVector<const char*> vec(&HttpClient::getUserChats, &HttpClient::getUserChatsProcessed, &HttpClient::getUserChatsFailed);
Method signatures:
signals:
void getUserChatsFailed();
void getUserChatsProcessed(QJsonArray data);
private:
void getUserChats(int failCounter);
These methods will possibly have different signature so I can't use concrete signature as the vector type
Share Improve this question edited Mar 20 at 15:37 ikakslozhno asked Mar 20 at 8:59 ikakslozhnoikakslozhno 134 bronze badges 3 |1 Answer
Reset to default 4If you want to store as char-pointer, you need to be using the SIGNAL()
and SLOT()
macros to obtain names for the signal/slot members.
If you want to store as a function, you'll need some type-erasure to reach a common type that can be used as a template type for a collection. Consider QVector<QMetaMethod>
instead.
getUserChats
?const char*
should be replaced by something likevoid (HttpClient::*)(/*..*/)/*const*/
... – Jarod42 Commented Mar 20 at 9:06