Work on Computer Manager

This commit is contained in:
Cameron Gutman 2018-06-24 15:13:37 -07:00
parent cded01187d
commit 5ee52f15c8
4 changed files with 242 additions and 71 deletions

View file

@ -0,0 +1,186 @@
#include "computermanager.h"
#include "nvhttp.h"
#include <QThread>
ComputerManager::ComputerManager()
: m_Polling(false)
{
}
void ComputerManager::startPolling()
{
m_Polling = true;
}
class PcMonitorThread : public QThread
{
Q_OBJECT
#define TRIES_BEFORE_OFFLINING 2
#define POLLS_PER_APPLIST_FETCH 10
PcMonitorThread(NvComputer* computer, IdentityManager im)
: m_Im(im),
m_Computer(computer)
{
}
#define DECLARE_UPDATE_COMPUTER_FIELD(Type) \
bool UpdateComputerField(Type& oldValue, Type newValue) \
{ \
if (oldValue == newValue) { \
return false; \
} \
\
oldValue = newValue; \
return true; \
}
DECLARE_UPDATE_COMPUTER_FIELD(QString)
DECLARE_UPDATE_COMPUTER_FIELD(int)
DECLARE_UPDATE_COMPUTER_FIELD(QByteArray)
DECLARE_UPDATE_COMPUTER_FIELD(NvComputer::ComputerState)
DECLARE_UPDATE_COMPUTER_FIELD(NvComputer::PairState)
bool TryPollComputer(QString& address, bool& changed)
{
NvHTTP http(address, m_Im);
QString serverInfo;
try {
serverInfo = http.getServerInfo();
} catch (...) {
return false;
}
changed = false;
QString newName = http.getXmlString(serverInfo, "hostname");
if (newName.isNull()) {
newName = "UNKNOWN";
}
changed |= UpdateComputerField(m_Computer->name, newName);
changed |= UpdateComputerField(m_Computer->uuid, http.getXmlString(serverInfo, "uniqueid"));
QString newMacString = http.getXmlString(serverInfo, "mac");
QByteArray newMac;
if (newMacString != "00:00:00:00:00:00") {
QStringList macOctets = newMacString.split(':');
for (QString macOctet : macOctets) {
newMac.append((char) macOctet.toInt(nullptr, 16));
}
changed |= UpdateComputerField(m_Computer->macAddress, newMac);
}
changed |= UpdateComputerField(m_Computer->localAddress, http.getXmlString(serverInfo, "LocalIP"));
changed |= UpdateComputerField(m_Computer->remoteAddress, http.getXmlString(serverInfo, "ExternalIP"));
changed |= UpdateComputerField(m_Computer->pairState, http.getXmlString(serverInfo, "PairStatus") == "1" ?
NvComputer::PS_PAIRED : NvComputer::PS_NOT_PAIRED);
changed |= UpdateComputerField(m_Computer->currentGameId, http.getCurrentGame(serverInfo));
changed |= UpdateComputerField(m_Computer->activeAddress, address);
changed |= UpdateComputerField(m_Computer->state, NvComputer::CS_ONLINE);
return true;
}
bool UpdateAppList(bool& changed)
{
changed = false;
return false;
}
void run() override
{
// Always fetch the applist the first time
int pollsSinceLastAppListFetch = POLLS_PER_APPLIST_FETCH;
while (!isInterruptionRequested()) {
QVector<QString> uniqueAddressList;
// Start with addresses correctly ordered
uniqueAddressList.append(m_Computer->activeAddress);
uniqueAddressList.append(m_Computer->localAddress);
uniqueAddressList.append(m_Computer->remoteAddress);
uniqueAddressList.append(m_Computer->manualAddress);
// Prune duplicates (always giving precedence to the first)
for (int i = 0; i < uniqueAddressList.count(); i++) {
if (uniqueAddressList[i].isEmpty() || uniqueAddressList[i].isNull()) {
uniqueAddressList.remove(i);
i--;
continue;
}
for (int j = i + 1; j < uniqueAddressList.count(); j++) {
if (uniqueAddressList[i] == uniqueAddressList[j]) {
// Always remove the later occurrence
uniqueAddressList.remove(j);
j--;
}
}
}
// We must have at least 1 address for this host
Q_ASSERT(uniqueAddressList.count() != 0);
bool stateChanged = false;
for (int i = 0; i < TRIES_BEFORE_OFFLINING; i++) {
for (auto& address : uniqueAddressList) {
if (isInterruptionRequested()) {
return;
}
if (TryPollComputer(address, stateChanged)) {
break;
}
}
// No need to continue retrying if we're online
if (m_Computer->state == NvComputer::CS_ONLINE) {
break;
}
}
// Check if we failed after all retry attempts
if (m_Computer->state != NvComputer::CS_ONLINE) {
if (m_Computer->state != NvComputer::CS_OFFLINE) {
m_Computer->state = NvComputer::CS_OFFLINE;
stateChanged = true;
}
}
if (stateChanged) {
// Tell anyone listening that we've changed state
emit computerStateChanged(m_Computer);
}
// Grab the applist if it's empty or it's been long enough that we need to refresh
pollsSinceLastAppListFetch++;
if (m_Computer->state == NvComputer::CS_ONLINE &&
(m_Computer->appList.isEmpty() || pollsSinceLastAppListFetch >= POLLS_PER_APPLIST_FETCH)) {
stateChanged = false;
if (UpdateAppList(stateChanged)) {
pollsSinceLastAppListFetch = 0;
}
if (stateChanged) {
emit computerStateChanged(m_Computer);
}
}
// Wait a bit to poll again
QThread::sleep(3);
}
}
signals:
void computerStateChanged(NvComputer* computer);
private:
IdentityManager m_Im;
NvComputer* m_Computer;
};

View file

@ -0,0 +1,56 @@
#pragma once
#include "nvhttp.h"
class ComputerManager
{
public:
ComputerManager();
void startPolling();
private:
bool m_Polling;
};
class NvApp
{
public:
int id;
QString name;
bool hdrSupported;
};
class NvComputer
{
public:
enum PairState
{
PS_UNKNOWN,
PS_PAIRED,
PS_NOT_PAIRED
};
enum ComputerState
{
CS_UNKNOWN,
CS_ONLINE,
CS_OFFLINE
};
// Ephemeral traits
ComputerState state;
PairState pairState;
QString activeAddress;
int currentGameId;
// Persisted traits
QString localAddress;
QString remoteAddress;
QString manualAddress;
QByteArray macAddress;
QString name;
QString uuid;
int serverCodecModeSupport;
QVector<NvApp> appList;
};

View file

@ -23,45 +23,6 @@ NvHTTP::NvHTTP(QString address, IdentityManager im) :
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;
}
QVector<int>
NvHTTP::getServerVersionQuad(QString serverInfo)
{

View file

@ -37,43 +37,11 @@ private:
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:
NvHTTP(QString address, IdentityManager im);
NvComputer
getComputerInfo();
int
getCurrentGame(QString serverInfo);