Files
crtr/Assets/Cryville/Crtr/Network/UpdateChecker.cs

137 lines
4.9 KiB
C#

using Cryville.Common.Network.Http11;
using Cryville.Common.Unity;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using UnityEngine;
using Logger = Cryville.Common.Logging.Logger;
using ThreadPriority = System.Threading.ThreadPriority;
namespace Cryville.Crtr.Network {
public class UpdateChecker : MonoBehaviour {
string _currentVersion;
Thread _thread;
#pragma warning disable IDE0044
bool _shutdown;
#pragma warning restore IDE0044
void Start() {
_currentVersion = Application.version;
_thread = new Thread(ThreadLogic) { IsBackground = true, Priority = ThreadPriority.BelowNormal };
_thread.Start();
}
void Update() {
if (!_thread.IsAlive) {
Destroy(gameObject);
if (_shutdown) Application.Quit();
}
}
static readonly Uri BaseUri = new Uri("https://www.cryville.world/api/crtr/index");
List<VersionInfo> _versions;
void ThreadLogic() {
try {
CheckVersion();
Logger.Log("main", 0, "Network", "Update checker exited normally");
}
catch (Exception ex) {
Logger.Log("main", 4, "Network", "An error occurred while checking for update: {0}", ex);
Dialog.Show(null, "Failed to check for update.");
}
}
void CheckVersion() {
using (var client = new Https11Client(BaseUri)) {
client.Connect();
using (var response = client.Request("GET", new Uri(BaseUri, "versions"))) {
var data = Encoding.UTF8.GetString(response.MessageBody.ReadToEnd());
_versions = JsonConvert.DeserializeObject<List<VersionInfo>>(data, Game.GlobalJsonSerializerSettings);
}
}
var availableVersions = _versions.Where(v => v.platforms.ContainsKey(PlatformConfig.Name)).ToArray();
var versionIndex = new Dictionary<string, int>(availableVersions.Length);
for (int i = 0; i < availableVersions.Length; i++) versionIndex.Add(availableVersions[i].name, i);
var currentVersion = availableVersions.Where(v => v.name == _currentVersion).SingleOrDefault();
var latestVersion = availableVersions.Last();
if (currentVersion == null) {
Dialog.Show(null, string.Format("You are playing an unknown version of Cosmo Resona: {0}\nThe latest version is: {1}", _currentVersion, latestVersion.name));
return;
}
if (latestVersion.name != _currentVersion) {
var latestResources = latestVersion.platforms[PlatformConfig.Name].resources;
VersionResourceInfo fullPackage = null;
if (latestResources != null) {
fullPackage = (from r in latestResources where r.upstream == null select r).SingleOrDefault();
}
if (fullPackage == null) {
Dialog.Show(null, string.Format("A new version is present: {0}\nUpdate is not available.", latestVersion.name));
return;
}
long totalDiffSize = 0;
int searchIndex = versionIndex[latestVersion.name], targetIndex = versionIndex[currentVersion.name];
while (searchIndex != targetIndex) {
var searchVersion = availableVersions[searchIndex];
VersionResourceInfo matchedUpstream = null;
var resources = searchVersion.platforms[PlatformConfig.Name].resources;
if (resources == null) {
totalDiffSize = 0;
break;
}
foreach (var r in resources) {
if (r.upstream == null) continue;
var upstreamIndex = versionIndex[r.upstream];
if (upstreamIndex >= targetIndex && upstreamIndex < searchIndex) {
matchedUpstream = r;
searchIndex = upstreamIndex;
}
}
if (matchedUpstream != null) {
if (matchedUpstream.external) {
totalDiffSize = 0;
Dialog.ShowAndWait("An error occurred while checking for update.\nPlease report this to the developers.");
Logger.Log("main", 4, "Network", "Diff package is external, which is not expected");
break;
}
totalDiffSize += matchedUpstream.size;
if (totalDiffSize >= fullPackage.size) {
totalDiffSize = 0;
break;
}
}
else {
totalDiffSize = 0;
break;
}
}
if (totalDiffSize == 0 || totalDiffSize >= fullPackage.size) {
// TODO Check if external
if (Dialog.ShowAndWait(string.Format("A new version is available: {0}\nYou have to download the full package.\nOpen the download link now?", latestVersion.name), "Yes", "No") == 0) {
UrlOpener.OpenThreaded(fullPackage.url);
}
}
else {
Dialog.ShowAndWait(string.Format("A new version is available: {0}\nDo you want to update?", latestVersion.name), "Yes", "No");
}
}
Logger.Log("main", 0, "Network", "Update checker exited");
}
class VersionInfo {
[JsonRequired]
public string name;
public string type;
public Dictionary<string, PlatformVersionInfo> platforms;
}
class PlatformVersionInfo {
public List<VersionResourceInfo> resources;
}
class VersionResourceInfo {
public bool external;
public string upstream;
[JsonRequired]
public string url;
[JsonRequired]
public long size;
}
}
}