mirror of
https://github.com/moonlight-stream/moonlight-qt
synced 2024-11-10 05:34:17 +00:00
Merge branch 'master' into aidan/dev
This commit is contained in:
commit
4d0341fd9a
2 changed files with 260 additions and 2 deletions
180
nvhttp.cpp
180
nvhttp.cpp
|
@ -2,8 +2,14 @@
|
|||
|
||||
#include <QUuid>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QEventLoop>
|
||||
#include <QTimer>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
NvHTTP::NvHTTP(QString address)
|
||||
#define REQUEST_TIMEOUT_MS 5000
|
||||
|
||||
NvHTTP::NvHTTP(QString address) :
|
||||
m_Address(address)
|
||||
{
|
||||
m_BaseUrlHttp.setScheme("http");
|
||||
m_BaseUrlHttps.setScheme("https");
|
||||
|
@ -13,21 +19,191 @@ NvHTTP::NvHTTP(QString address)
|
|||
m_BaseUrlHttps.setPort(47984);
|
||||
}
|
||||
|
||||
NvComputer
|
||||
NvHTTP::getComputerInfo()
|
||||
{
|
||||
NvComputer computer;
|
||||
QString serverInfo = getServerInfo();
|
||||
|
||||
computer.m_Name = getXmlString(serverInfo, "hostname");
|
||||
if (computer.m_Name == nullptr)
|
||||
{
|
||||
computer.m_Name = "UNKNOWN";
|
||||
}
|
||||
|
||||
computer.m_Uuid = getXmlString(serverInfo, "uniqueid");
|
||||
computer.m_MacAddress = getXmlString(serverInfo, "mac");
|
||||
|
||||
// If there's no LocalIP field, use the address we hit the server on
|
||||
computer.m_LocalAddress = getXmlString(serverInfo, "LocalIP");
|
||||
if (computer.m_LocalAddress == nullptr)
|
||||
{
|
||||
computer.m_LocalAddress = m_Address;
|
||||
}
|
||||
|
||||
// If there's no ExternalIP field, use the address we hit the server on
|
||||
computer.m_RemoteAddress = getXmlString(serverInfo, "ExternalIP");
|
||||
if (computer.m_RemoteAddress == nullptr)
|
||||
{
|
||||
computer.m_RemoteAddress = m_Address;
|
||||
}
|
||||
|
||||
computer.m_PairState = getXmlString(serverInfo, "PairStatus") == "1" ?
|
||||
NvComputer::PS_PAIRED : NvComputer::PS_NOT_PAIRED;
|
||||
|
||||
computer.m_RunningGameId = getCurrentGame(serverInfo);
|
||||
|
||||
computer.m_State = NvComputer::CS_ONLINE;
|
||||
|
||||
return computer;
|
||||
}
|
||||
|
||||
int
|
||||
NvHTTP::getCurrentGame(QString serverInfo)
|
||||
{
|
||||
// GFE 2.8 started keeping currentgame set to the last game played. As a result, it no longer
|
||||
// has the semantics that its name would indicate. To contain the effects of this change as much
|
||||
// as possible, we'll force the current game to zero if the server isn't in a streaming session.
|
||||
QString serverState = getXmlString(serverInfo, "state");
|
||||
if (serverState != nullptr && serverState.endsWith("_SERVER_BUSY")) {
|
||||
return getXmlString(serverInfo, "currentgame").toInt();
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QString
|
||||
NvHTTP::getServerInfo()
|
||||
{
|
||||
QString serverInfo;
|
||||
|
||||
try
|
||||
{
|
||||
// Always try HTTPS first, since it properly reports
|
||||
// pairing status (and a few other attributes).
|
||||
serverInfo = openConnectionToString(m_BaseUrlHttps,
|
||||
"serverinfo",
|
||||
nullptr,
|
||||
true);
|
||||
// Throws if the request failed
|
||||
verifyResponseStatus(serverInfo);
|
||||
}
|
||||
catch (GfeHttpResponseException& e)
|
||||
{
|
||||
if (e.getStatusCode() == 401)
|
||||
{
|
||||
// Certificate validation error, fallback to HTTP
|
||||
serverInfo = openConnectionToString(m_BaseUrlHttps,
|
||||
"serverinfo",
|
||||
nullptr,
|
||||
true);
|
||||
verifyResponseStatus(serverInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return serverInfo;
|
||||
}
|
||||
|
||||
void
|
||||
NvHTTP::verifyResponseStatus(QString xml)
|
||||
{
|
||||
QXmlStreamReader xmlReader(xml);
|
||||
|
||||
while (xmlReader.readNextStartElement())
|
||||
{
|
||||
if (xmlReader.name() == "root")
|
||||
{
|
||||
int statusCode = xmlReader.attributes().value("status_code").toInt();
|
||||
if (statusCode == 200)
|
||||
{
|
||||
// Successful
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
QString statusMessage = xmlReader.attributes().value("status_message").toString();
|
||||
qDebug() << "Request failed: " << statusCode << " " << statusMessage;
|
||||
throw GfeHttpResponseException(statusCode, statusMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString
|
||||
NvHTTP::getXmlString(QString xml,
|
||||
QString tagName)
|
||||
{
|
||||
QXmlStreamReader xmlReader(xml);
|
||||
|
||||
while (xmlReader.readNextStartElement())
|
||||
{
|
||||
if (xmlReader.name() == tagName)
|
||||
{
|
||||
return xmlReader.text().toString();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString
|
||||
NvHTTP::openConnectionToString(QUrl baseUrl,
|
||||
QString command,
|
||||
QString arguments,
|
||||
bool enableTimeout)
|
||||
{
|
||||
QNetworkReply* reply = openConnection(baseUrl, command, arguments, enableTimeout);
|
||||
QString ret;
|
||||
|
||||
ret = QTextStream(reply).readAll();
|
||||
delete reply;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QNetworkReply*
|
||||
NvHTTP::openConnection(QUrl baseUrl,
|
||||
QString command,
|
||||
QString arguments,
|
||||
bool enableTimeout)
|
||||
{
|
||||
// Build a URL for the request
|
||||
QUrl url(baseUrl);
|
||||
|
||||
url.setPath(command +
|
||||
"?uniqueid=" + "0" +
|
||||
"&uuid=" + QUuid::createUuid().toString() +
|
||||
((arguments != nullptr) ? (arguments + "&") : ""));
|
||||
|
||||
QNetworkReply* reply = m_Nam.get(QNetworkRequest(url));
|
||||
|
||||
// Ignore self-signed certificate errors (since GFE uses them)
|
||||
reply->ignoreSslErrors(QList<QSslError>{ QSslError::SelfSignedCertificate });
|
||||
|
||||
// Run the request with a timeout if requested
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
if (enableTimeout)
|
||||
{
|
||||
QTimer::singleShot(REQUEST_TIMEOUT_MS, &loop, SLOT(quit()));
|
||||
}
|
||||
qDebug() << "Executing request: " << url.toString();
|
||||
loop.exec(QEventLoop::ExcludeUserInputEvents);
|
||||
|
||||
// Abort the request if it timed out
|
||||
if (!reply->isFinished())
|
||||
{
|
||||
qDebug() << "Aborting timed out request for " << url.toString();
|
||||
reply->abort();
|
||||
}
|
||||
|
||||
// Handle error
|
||||
if (reply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
qDebug() << command << " request for failed with error " << reply->error();
|
||||
delete reply;
|
||||
throw new GfeHttpResponseException(reply->error(), reply->errorString());
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
|
82
nvhttp.h
82
nvhttp.h
|
@ -3,6 +3,65 @@
|
|||
#include <QUrl>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
|
||||
class GfeHttpResponseException : public std::exception
|
||||
{
|
||||
public:
|
||||
GfeHttpResponseException(int statusCode, QString message) :
|
||||
m_StatusCode(statusCode),
|
||||
m_StatusMessage(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const char* what() const throw()
|
||||
{
|
||||
return m_StatusMessage.toStdString().c_str();
|
||||
}
|
||||
|
||||
const char* getStatusMessage()
|
||||
{
|
||||
return m_StatusMessage.toStdString().c_str();
|
||||
}
|
||||
|
||||
int getStatusCode()
|
||||
{
|
||||
return m_StatusCode;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_StatusCode;
|
||||
QString m_StatusMessage;
|
||||
};
|
||||
|
||||
class NvComputer
|
||||
{
|
||||
public:
|
||||
NvComputer() {}
|
||||
|
||||
enum PairState
|
||||
{
|
||||
PS_UNKNOWN,
|
||||
PS_PAIRED,
|
||||
PS_NOT_PAIRED
|
||||
};
|
||||
|
||||
enum ComputerState
|
||||
{
|
||||
CS_UNKNOWN,
|
||||
CS_ONLINE,
|
||||
CS_OFFLINE
|
||||
};
|
||||
|
||||
QString m_Name;
|
||||
QString m_Uuid;
|
||||
QString m_MacAddress;
|
||||
QString m_LocalAddress;
|
||||
QString m_RemoteAddress;
|
||||
int m_RunningGameId;
|
||||
PairState m_PairState;
|
||||
ComputerState m_State;
|
||||
};
|
||||
|
||||
class NvHTTP
|
||||
{
|
||||
public:
|
||||
|
@ -15,6 +74,29 @@ private:
|
|||
QString arguments,
|
||||
bool enableTimeout);
|
||||
|
||||
NvComputer
|
||||
getComputerInfo();
|
||||
|
||||
int
|
||||
getCurrentGame(QString serverInfo);
|
||||
|
||||
QString
|
||||
getServerInfo();
|
||||
|
||||
void
|
||||
verifyResponseStatus(QString xml);
|
||||
|
||||
QString
|
||||
getXmlString(QString xml,
|
||||
QString tagName);
|
||||
|
||||
QString
|
||||
openConnectionToString(QUrl baseUrl,
|
||||
QString command,
|
||||
QString arguments,
|
||||
bool enableTimeout);
|
||||
|
||||
QString m_Address;
|
||||
QUrl m_BaseUrlHttp;
|
||||
QUrl m_BaseUrlHttps;
|
||||
QNetworkAccessManager m_Nam;
|
||||
|
|
Loading…
Reference in a new issue