diff --git a/tauth.cpp b/tauth.cpp index 62a6b87..d1cb01f 100644 --- a/tauth.cpp +++ b/tauth.cpp @@ -87,7 +87,13 @@ void TAuth::handleNewConnection() connect(m_clientSocket, &QTcpSocket::readyRead, this, &TAuth::readClientData); connect(m_clientSocket, &QTcpSocket::disconnected, - m_clientSocket, &QTcpSocket::deleteLater); + this, [this]() { + // Удаляем сокет после отключения + if (m_clientSocket) { + m_clientSocket->deleteLater(); + m_clientSocket = nullptr; + } + }); } } @@ -98,7 +104,6 @@ void TAuth::readClientData() QByteArray requestData = m_clientSocket->readAll(); QString request = QString::fromUtf8(requestData); - QStringList lines = request.split("\r\n"); if (lines.isEmpty()) return; @@ -118,7 +123,6 @@ void TAuth::readClientData() } } - // Обрабатываем обычный redirect if (document.startsWith("/redirect")) { handleRedirectRequest(document, m_clientSocket); @@ -237,6 +241,13 @@ void TAuth::handleRedirectRequest(const QString &request, QTcpSocket *socket) "

Authorization Successful!

\n" "

Token received. You can close this window.

\n" "\n"; + + // Отправляем ответ клиенту + sendResponse(socket, html); + + // Останавливаем сервер СРАЗУ + QTimer::singleShot(100, this, &TAuth::stopServer); + return; } // Проверяем наличие error_description else if (params.contains("error_description=")) { @@ -260,6 +271,13 @@ void TAuth::handleRedirectRequest(const QString &request, QTcpSocket *socket) "

Authorization Successful!

\n" "

Code received. You can close this window.

\n" "\n"; + + // Отправляем ответ клиенту + sendResponse(socket, html); + + // Останавливаем сервер СРАЗУ + QTimer::singleShot(100, this, &TAuth::stopServer); + return; } else { html = @@ -269,13 +287,16 @@ void TAuth::handleRedirectRequest(const QString &request, QTcpSocket *socket) "

Try again or check your authorization URL.

\n" "\n"; sendResponse(socket, html); + + // Останавливаем сервер через 5 секунд если нет данных + QTimer::singleShot(5000, this, &TAuth::stopServer); return; } sendResponse(socket, html); - // Останавливаем сервер после обработки - QTimer::singleShot(1000, this, &TAuth::stopServer); + // Останавливаем сервер через 5 секунд для других случаев + QTimer::singleShot(5000, this, &TAuth::stopServer); } QString TAuth::extractParam(const QString ¶ms, const QString ¶mName) diff --git a/ttw_api.cpp b/ttw_api.cpp index 71aff93..2a0d2c2 100644 --- a/ttw_api.cpp +++ b/ttw_api.cpp @@ -591,3 +591,104 @@ void TTwAPI::parseBadgesFromApi(const QString &jsonString, QVector &b badges.append(badge); } } + +bool TTwAPI::validateTwitchToken(const QString &tokenName, + const QString &tokenValue, + int &daysValid) +{ + daysValid = 0; + + if (tokenValue.trimmed().isEmpty()) { + toLog(1, "TTwAPI::validateTwitchToken", "Пустой токен: " + tokenName); + return false; + } + + QUrl url("https://id.twitch.tv/oauth2/validate"); + QNetworkRequest request(url); + + // Устанавливаем заголовки + request.setHeader(QNetworkRequest::UserAgentHeader, "YourApp/1.0"); + request.setRawHeader("Accept", "application/json"); + + // Формируем заголовок Authorization + QString authHeader = "OAuth " + tokenValue; + request.setRawHeader("Authorization", authHeader.toUtf8()); + + // Отправляем GET запрос + QNetworkReply *reply = m_networkManager->get(request); + + if (!reply) { + toLog(2, "TTwAPI::validateTwitchToken", "Не удалось создать запрос для токена: " + tokenName); + return false; + } + + // Ожидание завершения запроса + QEventLoop loop; + QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + + // Проверяем статус ответа + int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + QByteArray responseData = reply->readAll(); + QString responseText = QString::fromUtf8(responseData); + + // Обрабатываем ошибки сети + if (reply->error() != QNetworkReply::NoError) { + QString errorMsg = QString("Ошибка сети: %1 - %2") + .arg(reply->error()) + .arg(reply->errorString()); + toLog(2, "TTwAPI::validateTwitchToken", errorMsg); + reply->deleteLater(); + return false; + } + + reply->deleteLater(); + + // Обработка HTTP статусов + if (statusCode == 200) { + // Успешная валидация + QJsonDocument doc = QJsonDocument::fromJson(responseData); + if (!doc.isObject()) { + toLog(2, "TTwAPI::validateTwitchToken", "Ошибка парсинга JSON для токена: " + tokenName); + return false; + } + + QJsonObject jsonObj = doc.object(); + + // Извлекаем expires_in (в секундах) + if (jsonObj.contains("expires_in") && jsonObj["expires_in"].isDouble()) { + int expiresInSeconds = jsonObj["expires_in"].toInt(); + daysValid = qRound(expiresInSeconds / 86400.0); // Конвертируем секунды в дни + + // Логируем информацию о токене + QString logMsg = QString("Токен '%1' действителен. Осталось: %2 дней. " + "Client ID: %3, Логин: %4") + .arg(tokenName) + .arg(daysValid) + .arg(jsonObj.value("client_id").toString("N/A")) + .arg(jsonObj.value("login").toString("N/A")); + toLog(0, "TTwAPI::validateTwitchToken", logMsg); + + return true; + } else { + toLog(2, "TTwAPI::validateTwitchToken", + QString("В ответе отсутствует expires_in для токена: %1").arg(tokenName)); + return false; + } + } + else if (statusCode == 401) { + // Невалидный токен + toLog(2, "TTwAPI::validateTwitchToken", + QString("Токен '%1' невалиден (HTTP 401)").arg(tokenName)); + return false; + } + else { + // Другие HTTP ошибки + QString errorMsg = QString("HTTP %1 для токена '%2': %3") + .arg(statusCode) + .arg(tokenName) + .arg(responseText); + toLog(2, "TTwAPI::validateTwitchToken", errorMsg); + return false; + } +} diff --git a/websocketclient.cpp b/websocketclient.cpp index 11ecc31..a40a147 100644 --- a/websocketclient.cpp +++ b/websocketclient.cpp @@ -54,7 +54,7 @@ bool WebSocketClient::connectToServer(const QString &url) return true; } -void WebSocketClient::connectToTwitchChat(const QString &oauthToken, +bool WebSocketClient::connectToTwitchChat(const QString &oauthToken, const QString &nickname, const QString &channel) { @@ -65,7 +65,7 @@ void WebSocketClient::connectToTwitchChat(const QString &oauthToken, // URL для подключения к Twitch IRC через WebSocket QString url = "wss://irc-ws.chat.twitch.tv:443"; - connectToServer(url); + return connectToServer(url); } void WebSocketClient::onConnectedInternal() diff --git a/websocketclient.h b/websocketclient.h index 9c7ea2b..656f6a4 100644 --- a/websocketclient.h +++ b/websocketclient.h @@ -23,7 +23,7 @@ public: Q_INVOKABLE bool isConnected() const; // Методы для Twitch чата - Q_INVOKABLE void connectToTwitchChat(const QString &oauthToken, const QString &nickname, const QString &channel); + Q_INVOKABLE bool connectToTwitchChat(const QString &oauthToken, const QString &nickname, const QString &channel); Q_INVOKABLE void joinChannel(const QString &channel); Q_INVOKABLE void sendChatMessage(const QString &channel, const QString &message);