143 lines
4.0 KiB
C#
143 lines
4.0 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Threading;
|
|
|
|
using BizHawk.Client.Common;
|
|
|
|
namespace BizHawk.Client.EmuHawk
|
|
{
|
|
public static class UpdateChecker
|
|
{
|
|
private static readonly string _latestVersionInfoURL = "http://tasvideos.org/SystemBizHawkReleaseManager.html";
|
|
private static readonly TimeSpan _minimumCheckDuration = TimeSpan.FromHours(8);
|
|
|
|
private static bool AutoCheckEnabled
|
|
{
|
|
get { return Global.Config.Update_AutoCheckEnabled; }
|
|
set { Global.Config.Update_AutoCheckEnabled = value; }
|
|
}
|
|
|
|
private static DateTime? LastCheckTimeUTC
|
|
{
|
|
get { return Global.Config.Update_LastCheckTimeUTC; }
|
|
set { Global.Config.Update_LastCheckTimeUTC = value; }
|
|
}
|
|
|
|
private static string LatestVersion
|
|
{
|
|
get { return Global.Config.Update_LatestVersion; }
|
|
set { Global.Config.Update_LatestVersion = value; }
|
|
}
|
|
|
|
private static string IgnoreVersion
|
|
{
|
|
get { return Global.Config.Update_IgnoreVersion; }
|
|
set { Global.Config.Update_IgnoreVersion = value; }
|
|
}
|
|
|
|
public static void BeginCheck(bool skipCheck = false)
|
|
{
|
|
if (skipCheck || String.IsNullOrEmpty(_latestVersionInfoURL) || !AutoCheckEnabled || LastCheckTimeUTC > DateTime.UtcNow - _minimumCheckDuration)
|
|
{
|
|
OnCheckComplete();
|
|
return;
|
|
}
|
|
|
|
ThreadPool.QueueUserWorkItem((s) => CheckInternal());
|
|
}
|
|
|
|
public static bool IsNewVersionAvailable
|
|
{
|
|
get
|
|
{
|
|
return AutoCheckEnabled &&
|
|
LatestVersion != IgnoreVersion &&
|
|
ParseVersion(VersionInfo.MAINVERSION) != 0 && // Avoid notifying if current version string is invalid
|
|
ParseVersion(LatestVersion) > ParseVersion(VersionInfo.MAINVERSION);
|
|
}
|
|
}
|
|
|
|
public static void IgnoreNewVersion()
|
|
{
|
|
IgnoreVersion = LatestVersion;
|
|
}
|
|
|
|
public static void ResetHistory()
|
|
{
|
|
LastCheckTimeUTC = null;
|
|
LatestVersion = "";
|
|
IgnoreVersion = "";
|
|
}
|
|
|
|
private static void CheckInternal()
|
|
{
|
|
try
|
|
{
|
|
string latestVersionInfo = WebUtility.HtmlDecode(DownloadURLAsString(_latestVersionInfoURL));
|
|
|
|
LatestVersion = GetVersionNumberFromVersionInfo(latestVersionInfo);
|
|
}
|
|
catch
|
|
{
|
|
// Ignore errors, and fall through to set the last check time to avoid requesting too frequently from the web server
|
|
}
|
|
|
|
LastCheckTimeUTC = DateTime.UtcNow;
|
|
|
|
OnCheckComplete();
|
|
}
|
|
|
|
private static string DownloadURLAsString(string url)
|
|
{
|
|
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
|
|
request.KeepAlive = false;
|
|
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
|
|
using (StreamReader responseStream = new StreamReader(response.GetResponseStream()))
|
|
{
|
|
return responseStream.ReadToEnd();
|
|
}
|
|
}
|
|
|
|
private static string GetVersionNumberFromVersionInfo(string info)
|
|
{
|
|
string versionNumber = GetTextFromTag(info, "VersionNumber");
|
|
return (versionNumber != null && ParseVersion(versionNumber) != 0) ? versionNumber : "";
|
|
}
|
|
|
|
private static string GetTextFromTag(string info, string tagName)
|
|
{
|
|
string openTag = "[" + tagName + "]";
|
|
string closeTag = "[/" + tagName + "]";
|
|
int start = info.IndexOf(openTag, StringComparison.OrdinalIgnoreCase);
|
|
if (start == -1) return null;
|
|
start += openTag.Length;
|
|
int end = info.IndexOf(closeTag, start, StringComparison.OrdinalIgnoreCase);
|
|
if (end == -1) return null;
|
|
return info.Substring(start, end - start).Trim();
|
|
}
|
|
|
|
// Major version goes in the first 16 bits, and so on, up to 4 parts
|
|
private static ulong ParseVersion(string str)
|
|
{
|
|
string[] split = str.Split('.');
|
|
if (split.Length > 4) return 0;
|
|
ulong version = 0;
|
|
for (int i = 0; i < split.Length; i++)
|
|
{
|
|
ushort versionPart;
|
|
if (!UInt16.TryParse(split[i], out versionPart)) return 0;
|
|
version |= (ulong)versionPart << (48 - (i * 16));
|
|
}
|
|
return version;
|
|
}
|
|
|
|
private static void OnCheckComplete()
|
|
{
|
|
CheckComplete(null, EventArgs.Empty);
|
|
}
|
|
|
|
public static event EventHandler CheckComplete = delegate { };
|
|
}
|
|
}
|