|  |  |  | @@ -47,14 +47,16 @@ bool UpdateChecker::hasChannels() const | 
		
	
		
			
				|  |  |  |  | 	return !m_channels.isEmpty(); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | void UpdateChecker::checkForUpdate() | 
		
	
		
			
				|  |  |  |  | void UpdateChecker::checkForUpdate(bool notifyNoUpdate) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	QLOG_DEBUG() << "Checking for updates."; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	// If the channel list hasn't loaded yet, load it and defer checking for updates until later. | 
		
	
		
			
				|  |  |  |  | 	// If the channel list hasn't loaded yet, load it and defer checking for updates until | 
		
	
		
			
				|  |  |  |  | 	// later. | 
		
	
		
			
				|  |  |  |  | 	if (!m_chanListLoaded) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		QLOG_DEBUG() << "Channel list isn't loaded yet. Loading channel list and deferring update check."; | 
		
	
		
			
				|  |  |  |  | 		QLOG_DEBUG() << "Channel list isn't loaded yet. Loading channel list and deferring " | 
		
	
		
			
				|  |  |  |  | 						"update check."; | 
		
	
		
			
				|  |  |  |  | 		m_checkUpdateWaiting = true; | 
		
	
		
			
				|  |  |  |  | 		updateChanList(); | 
		
	
		
			
				|  |  |  |  | 		return; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -72,7 +74,8 @@ void UpdateChecker::checkForUpdate() | 
		
	
		
			
				|  |  |  |  | 	// TODO: Allow user to select channels. For now, we'll just use the current channel. | 
		
	
		
			
				|  |  |  |  | 	QString updateChannel = m_currentChannel; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	// Find the desired channel within the channel list and get its repo URL. If if cannot be found, error. | 
		
	
		
			
				|  |  |  |  | 	// Find the desired channel within the channel list and get its repo URL. If if cannot be | 
		
	
		
			
				|  |  |  |  | 	// found, error. | 
		
	
		
			
				|  |  |  |  | 	m_repoUrl = ""; | 
		
	
		
			
				|  |  |  |  | 	for (ChannelListEntry entry : m_channels) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
	
		
			
				
					
					|  |  |  | @@ -91,20 +94,22 @@ void UpdateChecker::checkForUpdate() | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	auto job = new NetJob("GoUpdate Repository Index"); | 
		
	
		
			
				|  |  |  |  | 	job->addNetAction(ByteArrayDownload::make(indexUrl)); | 
		
	
		
			
				|  |  |  |  | 	connect(job, SIGNAL(succeeded()), SLOT(updateCheckFinished())); | 
		
	
		
			
				|  |  |  |  | 	connect(job, &NetJob::succeeded, [this, notifyNoUpdate]() | 
		
	
		
			
				|  |  |  |  | 	{ updateCheckFinished(notifyNoUpdate); }); | 
		
	
		
			
				|  |  |  |  | 	connect(job, SIGNAL(failed()), SLOT(updateCheckFailed())); | 
		
	
		
			
				|  |  |  |  | 	indexJob.reset(job); | 
		
	
		
			
				|  |  |  |  | 	job->start(); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | void UpdateChecker::updateCheckFinished() | 
		
	
		
			
				|  |  |  |  | void UpdateChecker::updateCheckFinished(bool notifyNoUpdate) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	QLOG_DEBUG() << "Finished downloading repo index. Checking for new versions."; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	QJsonParseError jsonError; | 
		
	
		
			
				|  |  |  |  | 	QByteArray data; | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		ByteArrayDownloadPtr dl = std::dynamic_pointer_cast<ByteArrayDownload>(indexJob->first()); | 
		
	
		
			
				|  |  |  |  | 		ByteArrayDownloadPtr dl = | 
		
	
		
			
				|  |  |  |  | 			std::dynamic_pointer_cast<ByteArrayDownload>(indexJob->first()); | 
		
	
		
			
				|  |  |  |  | 		data = dl->m_data; | 
		
	
		
			
				|  |  |  |  | 		indexJob.reset(); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
	
		
			
				
					
					|  |  |  | @@ -112,7 +117,8 @@ void UpdateChecker::updateCheckFinished() | 
		
	
		
			
				|  |  |  |  | 	QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); | 
		
	
		
			
				|  |  |  |  | 	if (jsonError.error != QJsonParseError::NoError || !jsonDoc.isObject()) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		QLOG_ERROR() << "Failed to parse GoUpdate repository index. JSON error" << jsonError.errorString() << "at offset" << jsonError.offset; | 
		
	
		
			
				|  |  |  |  | 		QLOG_ERROR() << "Failed to parse GoUpdate repository index. JSON error" | 
		
	
		
			
				|  |  |  |  | 					 << jsonError.errorString() << "at offset" << jsonError.offset; | 
		
	
		
			
				|  |  |  |  | 		return; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -122,7 +128,8 @@ void UpdateChecker::updateCheckFinished() | 
		
	
		
			
				|  |  |  |  | 	int apiVersion = object.value("ApiVersion").toVariant().toInt(&success); | 
		
	
		
			
				|  |  |  |  | 	if (apiVersion != API_VERSION || !success) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		QLOG_ERROR() << "Failed to check for updates. API version mismatch. We're using" << API_VERSION << "server has" << apiVersion; | 
		
	
		
			
				|  |  |  |  | 		QLOG_ERROR() << "Failed to check for updates. API version mismatch. We're using" | 
		
	
		
			
				|  |  |  |  | 					 << API_VERSION << "server has" << apiVersion; | 
		
	
		
			
				|  |  |  |  | 		return; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -132,19 +139,27 @@ void UpdateChecker::updateCheckFinished() | 
		
	
		
			
				|  |  |  |  | 	for (QJsonValue versionVal : versions) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		QJsonObject version = versionVal.toObject(); | 
		
	
		
			
				|  |  |  |  | 		if (newestVersion.value("Id").toVariant().toInt() < version.value("Id").toVariant().toInt()) | 
		
	
		
			
				|  |  |  |  | 		if (newestVersion.value("Id").toVariant().toInt() < | 
		
	
		
			
				|  |  |  |  | 			version.value("Id").toVariant().toInt()) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			QLOG_DEBUG() << "Found newer version with ID" << version.value("Id").toVariant().toInt(); | 
		
	
		
			
				|  |  |  |  | 			QLOG_DEBUG() << "Found newer version with ID" | 
		
	
		
			
				|  |  |  |  | 						 << version.value("Id").toVariant().toInt(); | 
		
	
		
			
				|  |  |  |  | 			newestVersion = version; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	// We've got the version with the greatest ID number. Now compare it to our current build number and update if they're different. | 
		
	
		
			
				|  |  |  |  | 	// We've got the version with the greatest ID number. Now compare it to our current build | 
		
	
		
			
				|  |  |  |  | 	// number and update if they're different. | 
		
	
		
			
				|  |  |  |  | 	int newBuildNumber = newestVersion.value("Id").toVariant().toInt(); | 
		
	
		
			
				|  |  |  |  | 	if (newBuildNumber != MMC->version().build) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		// Update! | 
		
	
		
			
				|  |  |  |  | 		emit updateAvailable(m_repoUrl, newestVersion.value("Name").toVariant().toString(), newBuildNumber); | 
		
	
		
			
				|  |  |  |  | 		emit updateAvailable(m_repoUrl, newestVersion.value("Name").toVariant().toString(), | 
		
	
		
			
				|  |  |  |  | 							 newBuildNumber); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else if (notifyNoUpdate) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		emit noUpdateFound(); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	m_updateChecking = false; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -163,12 +178,13 @@ void UpdateChecker::updateChanList() | 
		
	
		
			
				|  |  |  |  | 	if (m_channelListUrl.isEmpty()) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		QLOG_ERROR() << "Failed to update channel list. No channel list URL set." | 
		
	
		
			
				|  |  |  |  | 					 << "If you'd like to use MultiMC's update system, please pass the channel list URL to CMake at compile time."; | 
		
	
		
			
				|  |  |  |  | 					 << "If you'd like to use MultiMC's update system, please pass the channel " | 
		
	
		
			
				|  |  |  |  | 						"list URL to CMake at compile time."; | 
		
	
		
			
				|  |  |  |  | 		return; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	m_chanListLoading = true; | 
		
	
		
			
				|  |  |  |  | 	NetJob* job = new NetJob("Update System Channel List"); | 
		
	
		
			
				|  |  |  |  | 	NetJob *job = new NetJob("Update System Channel List"); | 
		
	
		
			
				|  |  |  |  | 	job->addNetAction(ByteArrayDownload::make(QUrl(m_channelListUrl))); | 
		
	
		
			
				|  |  |  |  | 	QObject::connect(job, &NetJob::succeeded, this, &UpdateChecker::chanListDownloadFinished); | 
		
	
		
			
				|  |  |  |  | 	QObject::connect(job, &NetJob::failed, this, &UpdateChecker::chanListDownloadFailed); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -180,7 +196,8 @@ void UpdateChecker::chanListDownloadFinished() | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	QByteArray data; | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		ByteArrayDownloadPtr dl = std::dynamic_pointer_cast<ByteArrayDownload>(chanListJob->first()); | 
		
	
		
			
				|  |  |  |  | 		ByteArrayDownloadPtr dl = | 
		
	
		
			
				|  |  |  |  | 			std::dynamic_pointer_cast<ByteArrayDownload>(chanListJob->first()); | 
		
	
		
			
				|  |  |  |  | 		data = dl->m_data; | 
		
	
		
			
				|  |  |  |  | 		chanListJob.reset(); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
	
		
			
				
					
					|  |  |  | @@ -190,17 +207,20 @@ void UpdateChecker::chanListDownloadFinished() | 
		
	
		
			
				|  |  |  |  | 	if (jsonError.error != QJsonParseError::NoError) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		// TODO: Report errors to the user. | 
		
	
		
			
				|  |  |  |  | 		QLOG_ERROR() << "Failed to parse channel list JSON:" << jsonError.errorString() << "at" << jsonError.offset; | 
		
	
		
			
				|  |  |  |  | 		QLOG_ERROR() << "Failed to parse channel list JSON:" << jsonError.errorString() << "at" | 
		
	
		
			
				|  |  |  |  | 					 << jsonError.offset; | 
		
	
		
			
				|  |  |  |  | 		return; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	QJsonObject object = jsonDoc.object(); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	bool success = false; | 
		
	
		
			
				|  |  |  |  | 	int formatVersion = object.value("format_version").toVariant().toInt(&success); | 
		
	
		
			
				|  |  |  |  | 	if (formatVersion != CHANLIST_FORMAT || !success) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		QLOG_ERROR() << "Failed to check for updates. Channel list format version mismatch. We're using" << CHANLIST_FORMAT << "server has" << formatVersion; | 
		
	
		
			
				|  |  |  |  | 		QLOG_ERROR() | 
		
	
		
			
				|  |  |  |  | 			<< "Failed to check for updates. Channel list format version mismatch. We're using" | 
		
	
		
			
				|  |  |  |  | 			<< CHANLIST_FORMAT << "server has" << formatVersion; | 
		
	
		
			
				|  |  |  |  | 		return; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -210,12 +230,10 @@ void UpdateChecker::chanListDownloadFinished() | 
		
	
		
			
				|  |  |  |  | 	for (QJsonValue chanVal : channelArray) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		QJsonObject channelObj = chanVal.toObject(); | 
		
	
		
			
				|  |  |  |  | 		ChannelListEntry entry{ | 
		
	
		
			
				|  |  |  |  | 				channelObj.value("id").toVariant().toString(), | 
		
	
		
			
				|  |  |  |  | 				channelObj.value("name").toVariant().toString(), | 
		
	
		
			
				|  |  |  |  | 				channelObj.value("description").toVariant().toString(), | 
		
	
		
			
				|  |  |  |  | 				channelObj.value("url").toVariant().toString() | 
		
	
		
			
				|  |  |  |  | 			}; | 
		
	
		
			
				|  |  |  |  | 		ChannelListEntry entry{channelObj.value("id").toVariant().toString(), | 
		
	
		
			
				|  |  |  |  | 							   channelObj.value("name").toVariant().toString(), | 
		
	
		
			
				|  |  |  |  | 							   channelObj.value("description").toVariant().toString(), | 
		
	
		
			
				|  |  |  |  | 							   channelObj.value("url").toVariant().toString()}; | 
		
	
		
			
				|  |  |  |  | 		if (entry.id.isEmpty() || entry.name.isEmpty() || entry.url.isEmpty()) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			QLOG_ERROR() << "Channel list entry with empty ID, name, or URL. Skipping."; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -233,7 +251,7 @@ void UpdateChecker::chanListDownloadFinished() | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	// If we're waiting to check for updates, do that now. | 
		
	
		
			
				|  |  |  |  | 	if (m_checkUpdateWaiting) | 
		
	
		
			
				|  |  |  |  | 		checkForUpdate(); | 
		
	
		
			
				|  |  |  |  | 		checkForUpdate(false); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	emit channelListLoaded(); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -244,4 +262,3 @@ void UpdateChecker::chanListDownloadFailed() | 
		
	
		
			
				|  |  |  |  | 	QLOG_ERROR() << "Failed to download channel list."; | 
		
	
		
			
				|  |  |  |  | 	emit channelListLoaded(); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					| 
							
							
							
						 |  |  |   |