1
0
forked from BRT/arc
arc/services/net/NetworkErrorUtils.h

81 lines
5.7 KiB
C++

#pragma once
#include <QNetworkReply>
#include <QString>
// Хелперы для информативного логирования сетевых ошибок. Используются
// и в NetworkService, и в DeviceScreener — категория сразу показывает
// характер сбоя: timeout / refused / DNS / SSL / HTTP-уровень.
namespace NetworkErrorUtils {
// Удаляет схему+хост из URL, оставляет только путь (для логов/UI без секретов).
inline QString sanitizePath(const QString &fullUrl) {
const int schemeEnd = fullUrl.indexOf(QStringLiteral("://"));
if (schemeEnd < 0) return fullUrl;
const int pathStart = fullUrl.indexOf(QLatin1Char('/'), schemeEnd + 3);
return pathStart >= 0 ? fullUrl.mid(pathStart) : QStringLiteral("/");
}
// Категория ошибки в виде короткого ярлыка. См. QNetworkReply::NetworkError.
inline QString networkErrorCategory(QNetworkReply::NetworkError err) {
switch (err) {
case QNetworkReply::NoError: return QStringLiteral("NO_ERROR");
case QNetworkReply::ConnectionRefusedError: return QStringLiteral("CONNECTION_REFUSED");
case QNetworkReply::RemoteHostClosedError: return QStringLiteral("REMOTE_CLOSED");
case QNetworkReply::HostNotFoundError: return QStringLiteral("DNS_FAIL");
case QNetworkReply::TimeoutError: return QStringLiteral("QT_TIMEOUT");
case QNetworkReply::OperationCanceledError: return QStringLiteral("CANCELLED");
case QNetworkReply::SslHandshakeFailedError: return QStringLiteral("SSL_HANDSHAKE");
case QNetworkReply::TemporaryNetworkFailureError: return QStringLiteral("TEMP_NET_FAIL");
case QNetworkReply::NetworkSessionFailedError: return QStringLiteral("NO_NETWORK_SESSION");
case QNetworkReply::BackgroundRequestNotAllowedError: return QStringLiteral("BG_NOT_ALLOWED");
case QNetworkReply::TooManyRedirectsError: return QStringLiteral("TOO_MANY_REDIRECTS");
case QNetworkReply::InsecureRedirectError: return QStringLiteral("INSECURE_REDIRECT");
case QNetworkReply::UnknownNetworkError: return QStringLiteral("UNKNOWN_NETWORK");
case QNetworkReply::ProxyConnectionRefusedError: return QStringLiteral("PROXY_REFUSED");
case QNetworkReply::ProxyConnectionClosedError: return QStringLiteral("PROXY_CLOSED");
case QNetworkReply::ProxyNotFoundError: return QStringLiteral("PROXY_NOT_FOUND");
case QNetworkReply::ProxyTimeoutError: return QStringLiteral("PROXY_TIMEOUT");
case QNetworkReply::ProxyAuthenticationRequiredError: return QStringLiteral("PROXY_AUTH_REQ");
case QNetworkReply::ContentAccessDenied: return QStringLiteral("HTTP_403");
case QNetworkReply::ContentOperationNotPermittedError:return QStringLiteral("OP_NOT_PERMITTED");
case QNetworkReply::ContentNotFoundError: return QStringLiteral("HTTP_404");
case QNetworkReply::AuthenticationRequiredError: return QStringLiteral("HTTP_401");
case QNetworkReply::ContentReSendError: return QStringLiteral("RESEND_REQUIRED");
case QNetworkReply::ContentConflictError: return QStringLiteral("HTTP_409");
case QNetworkReply::ContentGoneError: return QStringLiteral("HTTP_410");
case QNetworkReply::InternalServerError: return QStringLiteral("HTTP_500");
case QNetworkReply::OperationNotImplementedError: return QStringLiteral("HTTP_501");
case QNetworkReply::ServiceUnavailableError: return QStringLiteral("HTTP_503");
case QNetworkReply::UnknownServerError: return QStringLiteral("UNKNOWN_SERVER");
case QNetworkReply::ProtocolUnknownError: return QStringLiteral("PROTO_UNKNOWN");
case QNetworkReply::ProtocolInvalidOperationError: return QStringLiteral("PROTO_INVALID_OP");
case QNetworkReply::UnknownContentError: return QStringLiteral("UNKNOWN_CONTENT");
case QNetworkReply::ProtocolFailure: return QStringLiteral("PROTO_FAILURE");
default: return QStringLiteral("err_%1").arg(static_cast<int>(err));
}
}
// Развёрнутое описание сетевой ошибки: HTTP-код + категория или просто
// категория + Qt errorString. Эндпоинт — без хоста.
inline QString describeNetError(QNetworkReply *reply, const QString &path) {
const int httpCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
const QString endpoint = sanitizePath(path);
const QString category = networkErrorCategory(reply->error());
if (httpCode > 0) {
return QStringLiteral("HTTP %1 [%2] %3").arg(httpCode).arg(category, endpoint);
}
return QStringLiteral("[%1] %2 (qt: %3)").arg(category, endpoint, reply->errorString());
}
// Случай нашего QTimer-таймаута (reply ещё не завершился). reply->error()
// обычно ещё NoError — помечаем категорию явно как CLIENT_TIMEOUT_30s.
inline QString describeClientTimeout(QNetworkReply *reply, const QString &path) {
const QString endpoint = sanitizePath(path);
const QString qtCategory = networkErrorCategory(reply->error());
return QStringLiteral("[CLIENT_TIMEOUT_30s] %1 (qt-state=%2 errorString=\"%3\")")
.arg(endpoint, qtCategory, reply->errorString());
}
} // namespace NetworkErrorUtils