Add network test option to PC context menu

This commit is contained in:
Cameron Gutman 2020-08-08 20:25:26 -07:00
parent 8c2c4d3282
commit fb6995db94
6 changed files with 102 additions and 0 deletions

View File

@ -6,6 +6,8 @@ NavigableDialog {
id: dialog id: dialog
property alias text: dialogLabel.dialogText property alias text: dialogLabel.dialogText
property alias showSpinner: dialogSpinner.visible
property alias imageSrc: dialogImage.source
property string helpText property string helpText
property string helpUrl : "https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting" property string helpUrl : "https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting"
@ -19,7 +21,13 @@ NavigableDialog {
RowLayout { RowLayout {
spacing: 10 spacing: 10
BusyIndicator {
id: dialogSpinner
visible: false
}
Image { Image {
id: dialogImage
source: (standardButtons & Dialog.Yes) ? source: (standardButtons & Dialog.Yes) ?
"qrc:/res/baseline-help_outline-24px.svg" : "qrc:/res/baseline-help_outline-24px.svg" :
"qrc:/res/baseline-error_outline-24px.svg" "qrc:/res/baseline-error_outline-24px.svg"
@ -28,6 +36,7 @@ NavigableDialog {
width: 50 width: 50
height: 50 height: 50
} }
visible: !showSpinner
} }
Label { Label {

View File

@ -79,6 +79,7 @@ CenteredGridView {
var model = Qt.createQmlObject('import ComputerModel 1.0; ComputerModel {}', parent, '') var model = Qt.createQmlObject('import ComputerModel 1.0; ComputerModel {}', parent, '')
model.initialize(ComputerManager) model.initialize(ComputerManager)
model.pairingCompleted.connect(pairingComplete) model.pairingCompleted.connect(pairingComplete)
model.connectionTestCompleted.connect(testConnectionDialog.connectionTestComplete)
return model return model
} }
@ -184,6 +185,15 @@ CenteredGridView {
onTriggered: computerModel.wakeComputer(index) onTriggered: computerModel.wakeComputer(index)
visible: !model.online && model.wakeable visible: !model.online && model.wakeable
} }
NavigableMenuItem {
parentMenu: pcContextMenu
text: "Test Network"
onTriggered: {
computerModel.testConnectionForComputer(index)
testConnectionDialog.open()
}
}
NavigableMenuItem { NavigableMenuItem {
parentMenu: pcContextMenu parentMenu: pcContextMenu
text: "Rename PC" text: "Rename PC"
@ -302,6 +312,37 @@ CenteredGridView {
onAccepted: deletePc() onAccepted: deletePc()
} }
NavigableMessageDialog {
id: testConnectionDialog
closePolicy: Popup.CloseOnEscape
standardButtons: Dialog.Ok
onAboutToShow: {
testConnectionDialog.text = "Moonlight is testing your network connection to determine if NVIDIA GameStream is blocked.\n\nThis may take a few seconds…"
showSpinner = true
}
function connectionTestComplete(result, blockedPorts)
{
if (result === -1) {
text = "The network test could not be performed because none of Moonlight's connection testing servers were reachable from this PC. Check your Internet connection or try again later."
imageSrc = "qrc:/res/baseline-warning-24px.svg"
}
else if (result === 0) {
text = "This network does not appear to be blocking Moonlight. If you still have trouble connecting, check your PC's firewall settings.\n\nIf you are trying to stream over the Internet, install the Moonlight Internet Hosting Tool on your gaming PC and run the included Internet Streaming Tester to check your gaming PC's Internet connection."
imageSrc = "qrc:/res/baseline-check_circle_outline-24px.svg"
}
else {
text = "Your PC's current network connection seems to be blocking Moonlight. Streaming over the Internet may not work while connected to this network.\n\nThe following network ports were blocked:\n"
text += blockedPorts
imageSrc = "qrc:/res/baseline-error_outline-24px.svg"
}
// Stop showing the spinner and show the image instead
showSpinner = false
}
}
NavigableDialog { NavigableDialog {
id: renamePcDialog id: renamePcDialog
property string label: "Enter the new name for this PC:" property string label: "Enter the new name for this PC:"

View File

@ -147,6 +147,52 @@ QString ComputerModel::generatePinString()
return QString::asprintf("%04u", dist(engine)); return QString::asprintf("%04u", dist(engine));
} }
class DeferredTestConnectionTask : public QObject, public QRunnable
{
Q_OBJECT
public:
void run()
{
unsigned int portTestResult = LiTestClientConnectivity("qt.conntest.moonlight-stream.org", 443, ML_PORT_FLAG_ALL);
if (portTestResult == ML_TEST_RESULT_INCONCLUSIVE) {
emit connectionTestCompleted(-1, QString());
}
else {
QString blockedPorts;
for (int i = 0; i < 32; i++) {
if (portTestResult & (1 << i)) {
if (!blockedPorts.isEmpty()) {
blockedPorts += "\n";
}
if (LiGetProtocolFromPortFlagIndex(i) == 17 /* IPPROTO_UDP */) {
blockedPorts += "UDP ";
}
else {
blockedPorts += "TCP ";
}
blockedPorts += QString::number(LiGetPortFromPortFlagIndex(i));
}
}
emit connectionTestCompleted(portTestResult, blockedPorts);
}
}
signals:
void connectionTestCompleted(int result, QString blockedPorts);
};
void ComputerModel::testConnectionForComputer(int)
{
DeferredTestConnectionTask* testConnectionTask = new DeferredTestConnectionTask();
QObject::connect(testConnectionTask, &DeferredTestConnectionTask::connectionTestCompleted,
this, &ComputerModel::connectionTestCompleted);
QThreadPool::globalInstance()->start(testConnectionTask);
}
void ComputerModel::pairComputer(int computerIndex, QString pin) void ComputerModel::pairComputer(int computerIndex, QString pin)
{ {
Q_ASSERT(computerIndex < m_Computers.count()); Q_ASSERT(computerIndex < m_Computers.count());
@ -177,3 +223,4 @@ void ComputerModel::handleComputerStateChanged(NvComputer* computer)
} }
} }
#include "computermodel.moc"

View File

@ -35,6 +35,8 @@ public:
Q_INVOKABLE void pairComputer(int computerIndex, QString pin); Q_INVOKABLE void pairComputer(int computerIndex, QString pin);
Q_INVOKABLE void testConnectionForComputer(int computerIndex);
Q_INVOKABLE void wakeComputer(int computerIndex); Q_INVOKABLE void wakeComputer(int computerIndex);
Q_INVOKABLE void renameComputer(int computerIndex, QString name); Q_INVOKABLE void renameComputer(int computerIndex, QString name);
@ -43,6 +45,7 @@ public:
signals: signals:
void pairingCompleted(QVariant error); void pairingCompleted(QVariant error);
void connectionTestCompleted(int result, QString blockedPorts);
private slots: private slots:
void handleComputerStateChanged(NvComputer* computer); void handleComputerStateChanged(NvComputer* computer);

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" fill="#FFFFFF"><path d="M0 0h24v24H0V0zm0 0h24v24H0V0z" fill="none"/><path d="M16.59 7.58L10 14.17l-3.59-3.58L5 12l5 5 8-8zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/></svg>

After

Width:  |  Height:  |  Size: 339 B

View File

@ -15,6 +15,7 @@
<file>res/update.svg</file> <file>res/update.svg</file>
<file>res/baseline-help_outline-24px.svg</file> <file>res/baseline-help_outline-24px.svg</file>
<file>res/baseline-error_outline-24px.svg</file> <file>res/baseline-error_outline-24px.svg</file>
<file>res/baseline-check_circle_outline-24px.svg</file>
</qresource> </qresource>
<qresource prefix="/data"> <qresource prefix="/data">
<file alias="gamecontrollerdb.txt">SDL_GameControllerDB/gamecontrollerdb.txt</file> <file alias="gamecontrollerdb.txt">SDL_GameControllerDB/gamecontrollerdb.txt</file>