2018-08-10 05:51:27 +00:00
# include "autoupdatechecker.h"
# include <QNetworkReply>
# include <QJsonDocument>
# include <QJsonArray>
# include <QJsonObject>
AutoUpdateChecker : : AutoUpdateChecker ( QObject * parent ) :
QObject ( parent ) ,
m_Nam ( this )
{
// Never communicate over HTTP
m_Nam . setStrictTransportSecurityEnabled ( true ) ;
2018-12-04 07:29:49 +00:00
// Allow HTTP redirects
m_Nam . setRedirectPolicy ( QNetworkRequest : : NoLessSafeRedirectPolicy ) ;
2018-08-10 05:51:27 +00:00
connect ( & m_Nam , SIGNAL ( finished ( QNetworkReply * ) ) ,
this , SLOT ( handleUpdateCheckRequestFinished ( QNetworkReply * ) ) ) ;
QString currentVersion ( VERSION_STR ) ;
qDebug ( ) < < " Current Moonlight version: " < < currentVersion ;
parseStringToVersionQuad ( currentVersion , m_CurrentVersionQuad ) ;
// Should at least have a 1.0-style version number
Q_ASSERT ( m_CurrentVersionQuad . count ( ) > 1 ) ;
}
void AutoUpdateChecker : : start ( )
{
2020-04-04 00:03:12 +00:00
# if defined(Q_OS_WIN32) || defined(Q_OS_DARWIN) || defined(STEAM_LINK) || defined(APP_IMAGE) // Only run update checker on platforms without auto-update
2020-08-20 04:47:45 +00:00
# if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) && QT_VERSION < QT_VERSION_CHECK(5, 15, 1) && !defined(QT_NO_BEARERMANAGEMENT)
// HACK: Set network accessibility to work around QTBUG-80947 (introduced in Qt 5.14.0 and fixed in Qt 5.15.1)
2020-05-02 17:14:54 +00:00
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
2019-12-21 20:58:45 +00:00
m_Nam . setNetworkAccessible ( QNetworkAccessManager : : Accessible ) ;
2020-05-02 17:14:54 +00:00
QT_WARNING_POP
2019-12-21 21:54:09 +00:00
# endif
2019-12-21 20:58:45 +00:00
2018-08-10 05:51:27 +00:00
// We'll get a callback when this is finished
2018-12-04 05:48:49 +00:00
QUrl url ( " https://moonlight-stream.org/updates/qt.json " ) ;
2020-11-24 00:35:46 +00:00
QNetworkRequest request ( url ) ;
2020-11-24 02:39:50 +00:00
# if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
2020-11-24 00:35:46 +00:00
request . setAttribute ( QNetworkRequest : : Http2AllowedAttribute , true ) ;
2020-11-24 02:39:50 +00:00
# else
request . setAttribute ( QNetworkRequest : : HTTP2AllowedAttribute , true ) ;
# endif
2020-11-24 00:35:46 +00:00
m_Nam . get ( request ) ;
2018-08-10 05:51:27 +00:00
# endif
}
void AutoUpdateChecker : : parseStringToVersionQuad ( QString & string , QVector < int > & version )
{
QStringList list = string . split ( ' . ' ) ;
for ( const QString & component : list ) {
version . append ( component . toInt ( ) ) ;
}
}
2019-12-14 04:15:52 +00:00
QString AutoUpdateChecker : : getPlatform ( )
{
2020-04-04 00:03:12 +00:00
# if defined(STEAM_LINK)
2019-12-14 04:15:52 +00:00
return QStringLiteral ( " steamlink " ) ;
2020-04-04 00:03:12 +00:00
# elif defined(APP_IMAGE)
return QStringLiteral ( " appimage " ) ;
2019-12-14 04:15:52 +00:00
# else
return QSysInfo : : productType ( ) ;
# endif
}
2021-02-28 20:27:29 +00:00
int AutoUpdateChecker : : compareVersion ( QVector < int > & version1 , QVector < int > & version2 ) {
for ( int i = 0 ; ; i + + ) {
int v1Val = 0 ;
int v2Val = 0 ;
// Treat missing decimal places as 0
if ( i < version1 . count ( ) ) {
v1Val = version1 [ i ] ;
}
if ( i < version2 . count ( ) ) {
v2Val = version2 [ i ] ;
}
if ( i > = version1 . count ( ) & & i > = version2 . count ( ) ) {
// Equal versions
return 0 ;
}
if ( v1Val < v2Val ) {
return - 1 ;
}
else if ( v1Val > v2Val ) {
return 1 ;
}
}
}
2018-08-10 05:51:27 +00:00
void AutoUpdateChecker : : handleUpdateCheckRequestFinished ( QNetworkReply * reply )
{
Q_ASSERT ( reply - > isFinished ( ) ) ;
2020-03-24 01:30:56 +00:00
if ( reply - > error ( ) = = QNetworkReply : : NoError ) {
2018-08-10 05:51:27 +00:00
QTextStream stream ( reply ) ;
2020-10-15 23:57:04 +00:00
# if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
stream . setEncoding ( QStringConverter : : Utf8 ) ;
# else
2018-08-10 05:51:27 +00:00
stream . setCodec ( " UTF-8 " ) ;
2020-10-15 23:57:04 +00:00
# endif
2018-08-10 05:51:27 +00:00
// Read all data and queue the reply for deletion
QString jsonString = stream . readAll ( ) ;
reply - > deleteLater ( ) ;
QJsonParseError error ;
QJsonDocument jsonDoc = QJsonDocument : : fromJson ( jsonString . toUtf8 ( ) , & error ) ;
if ( jsonDoc . isNull ( ) ) {
qWarning ( ) < < " Update manifest malformed: " < < error . errorString ( ) ;
return ;
}
QJsonArray array = jsonDoc . array ( ) ;
if ( array . isEmpty ( ) ) {
qWarning ( ) < < " Update manifest doesn't contain an array " ;
return ;
}
for ( QJsonValueRef updateEntry : array ) {
if ( updateEntry . isObject ( ) ) {
QJsonObject updateObj = updateEntry . toObject ( ) ;
if ( ! updateObj . contains ( " platform " ) | |
! updateObj . contains ( " arch " ) | |
! updateObj . contains ( " version " ) | |
! updateObj . contains ( " browser_url " ) ) {
qWarning ( ) < < " Update manifest entry missing vital field " ;
continue ;
}
if ( ! updateObj [ " platform " ] . isString ( ) | |
! updateObj [ " arch " ] . isString ( ) | |
! updateObj [ " version " ] . isString ( ) | |
! updateObj [ " browser_url " ] . isString ( ) ) {
qWarning ( ) < < " Update manifest entry has unexpected vital field type " ;
continue ;
}
if ( updateObj [ " arch " ] = = QSysInfo : : buildCpuArchitecture ( ) & &
2019-12-14 04:15:52 +00:00
updateObj [ " platform " ] = = getPlatform ( ) ) {
2021-02-28 20:27:29 +00:00
// Check the kernel version minimum if one exists
if ( updateObj . contains ( " kernel_version_at_least " ) & & updateObj [ " kernel_version_at_least " ] . isString ( ) ) {
QVector < int > requiredVersionQuad ;
QVector < int > actualVersionQuad ;
QString requiredVersion = updateObj [ " kernel_version_at_least " ] . toString ( ) ;
QString actualVersion = QSysInfo : : kernelVersion ( ) ;
parseStringToVersionQuad ( requiredVersion , requiredVersionQuad ) ;
parseStringToVersionQuad ( actualVersion , actualVersionQuad ) ;
if ( compareVersion ( actualVersionQuad , requiredVersionQuad ) < 0 ) {
qDebug ( ) < < " Skipping manifest entry due to kernel version ( " < < actualVersion < < " < " < < requiredVersion < < " ) " ;
continue ;
}
}
2018-08-10 05:51:27 +00:00
qDebug ( ) < < " Found update manifest match for current platform " ;
QString latestVersion = updateObj [ " version " ] . toString ( ) ;
qDebug ( ) < < " Latest version of Moonlight for this platform is: " < < latestVersion ;
QVector < int > latestVersionQuad ;
parseStringToVersionQuad ( latestVersion , latestVersionQuad ) ;
2021-02-28 20:27:29 +00:00
int res = compareVersion ( m_CurrentVersionQuad , latestVersionQuad ) ;
if ( res < 0 ) {
// m_CurrentVersionQuad < latestVersionQuad
qDebug ( ) < < " Update available " ;
emit onUpdateAvailable ( updateObj [ " version " ] . toString ( ) ,
updateObj [ " browser_url " ] . toString ( ) ) ;
return ;
}
else if ( res > 0 ) {
qDebug ( ) < < " Update manifest version lower than current version " ;
return ;
}
else {
qDebug ( ) < < " Update manifest version equal to current version " ;
return ;
2018-08-10 05:51:27 +00:00
}
}
}
else {
qWarning ( ) < < " Update manifest contained unrecognized entry: " < < updateEntry . toString ( ) ;
}
}
2021-02-28 20:27:29 +00:00
qWarning ( ) < < " No entry in update manifest found for current platform: "
< < QSysInfo : : buildCpuArchitecture ( ) < < getPlatform ( ) < < QSysInfo : : kernelVersion ( ) ;
2018-08-10 05:51:27 +00:00
}
else {
2020-03-24 01:30:56 +00:00
qWarning ( ) < < " Update checking failed with error: " < < reply - > error ( ) ;
2018-08-10 05:51:27 +00:00
reply - > deleteLater ( ) ;
}
}