diff --git a/AssetStudio/AIVersionManager.cs b/AssetStudio/AIVersionManager.cs index 66bb947..982cf45 100644 --- a/AssetStudio/AIVersionManager.cs +++ b/AssetStudio/AIVersionManager.cs @@ -6,135 +6,174 @@ using System.Threading.Tasks; using System.Net.Http; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using System.Threading; namespace AssetStudio { - public class VersionIndex - { - public string MappedPath; - public string RawPath; - public string Version; - public double Coverage; - } - public static class AIVersionManager { private const string BaseUrl = "https://raw.githubusercontent.com/radioegor146/gi-asset-indexes/master/"; private const string CommitsUrl = "https://api.github.com/repos/radioegor146/gi-asset-indexes/commits?path="; - + private const string VersionIndexName = "version-index.json"; + private const string VersionIndexKey = "index"; + private static readonly string BaseAIFolder = Path.Combine(Environment.CurrentDirectory, "AI"); private static readonly string VersionsPath = Path.Combine(BaseAIFolder, "versions.json"); - private static readonly string VersionIndexUrl = Path.Combine(BaseUrl, "version-index.json"); + private static readonly HttpClient Client; - private static List Versions; - - public static bool Loaded; + private static Dictionary Versions; static AIVersionManager() { Client = new HttpClient(); Client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (compatible; MSIE 6.0; Windows 98; Trident/5.1)"); - Client.Timeout = TimeSpan.FromMinutes(1); - Versions = new List(); - Loaded = false; + Versions = new Dictionary(); } - public static Uri CreateUri(string source, out Uri result) => Uri.TryCreate(source, UriKind.Absolute, out result) && result.Scheme == Uri.UriSchemeHttps ? result : null; - - public static void FetchVersions() + public static List<(string, bool)> GetVersions() { - var versions = Task.Run(() => DownloadString(VersionIndexUrl)).Result; - if (string.IsNullOrEmpty(versions)) + var versions = new List<(string, bool)>(); + var cachedVersions = LoadVersions(); + foreach (var version in Versions) { - Logger.Warning("Could not load AI versions !!"); - return; + versions.Add((version.Key, cachedVersions.ContainsKey(version.Key))); } - Versions = JsonConvert.DeserializeObject>(versions); - Loaded = Versions.Count > 0; + return versions; + } + public static async Task FetchVersions() + { + var versions = ""; + var url = Path.Combine(BaseUrl, VersionIndexName); + var path = GetPath(VersionIndexKey); + if (await NeedDownload(VersionIndexKey, VersionIndexName)) + { + versions = await DownloadString(url, TimeSpan.FromSeconds(2)); + if (string.IsNullOrEmpty(versions)) + { + Logger.Warning("Could not load AI versions !!"); + return false; + } + if (!await StoreCommit(VersionIndexKey, VersionIndexName)) + { + throw new Exception("Failed to store version list !!"); + } + File.WriteAllText(path, versions); + } + else + { + versions = File.ReadAllText(path); + } + Versions = JsonConvert.DeserializeObject>(versions).ToDictionary(x => x.Version, x => x); + return Versions.Count > 0; } - public static async Task DownloadString(string url) + public static async Task FetchAI(string version) { - string json = ""; - if (CreateUri(url, out var uri) != null) + var path = ""; + if (Versions.TryGetValue(version, out var versionIndex)) + { + var url = Path.Combine(BaseUrl, versionIndex.MappedPath); + path = GetPath(version); + if (await NeedDownload(version, versionIndex.MappedPath)) + { + Logger.Info("Downloading..."); + var json = await DownloadString(url, TimeSpan.FromMinutes(1)); + if (string.IsNullOrEmpty(json)) + { + Logger.Warning("Could not load AI !!"); + return ""; + } + if (!await StoreCommit(version, versionIndex.MappedPath)) + { + throw new Exception("Failed to store AI !!"); + } + File.WriteAllText(path, json); + } + } + return path; + } + private static bool CreateUri(string source, out Uri result) => Uri.TryCreate(source, UriKind.Absolute, out result) && result.Scheme == Uri.UriSchemeHttps; + + private static async Task DownloadString(string url, TimeSpan timeout) + { + var content = ""; + if (CreateUri(url, out var uri)) { try { - json = await Client.GetStringAsync(uri); + using (var cts = new CancellationTokenSource()) + { + cts.CancelAfter(timeout); + var response = await Client.GetAsync(uri, cts.Token); + content = await response.Content.ReadAsStringAsync(); + } + } + catch (TaskCanceledException ex) + { + Logger.Warning($"Timeout occured while trying to download {Path.GetFileName(url)}, {ex.Message}"); } catch (Exception ex) { - Logger.Warning($"Failed to fetch {Path.GetFileName(url)}, {ex.Message}"); + Logger.Warning($"Failed to download {Path.GetFileName(url)}, {ex.Message}"); } } - return json; + return content; } - public static async Task DownloadAI(string version) + private static async Task NeedDownload(string key, string path) { - var versionIndex = Versions.FirstOrDefault(x => x.Version == version); - - Logger.Info("Downloading...."); - string json = await DownloadString(BaseUrl + versionIndex.MappedPath); - if (!await StoreCommit(version)) + if (!File.Exists(GetPath(key))) { - throw new Exception("Failed to store AIVersion"); + return true; } - return json; - } - - public static async Task NeedDownload(string version) - { - var path = GetAIPath(version); - if (!File.Exists(path)) return true; - var latestCommit = await GetLatestCommit(version); - if (string.IsNullOrEmpty(latestCommit)) return true; - var dict = LoadVersions(); - if (dict.TryGetValue(version, out var commit)) + var latestCommit = await GetLatestCommit(path); + if (string.IsNullOrEmpty(latestCommit)) { - if (commit == latestCommit) return false; + return !File.Exists(GetPath(key)); + } + var dict = LoadVersions(); + if (dict.TryGetValue(key, out var commit)) + { + if (commit == latestCommit) + { + return false; + } } return true; } - public static async Task StoreCommit(string version) + private static async Task StoreCommit(string key, string path) { - var latestCommit = await GetLatestCommit(version); - if (string.IsNullOrEmpty(latestCommit)) return false; + var latestCommit = await GetLatestCommit(path); + if (string.IsNullOrEmpty(latestCommit)) + { + return false; + } var dict = LoadVersions(); - if (dict.TryGetValue(version, out var commit)) + if (dict.TryGetValue(key, out var commit)) { if (commit != latestCommit) - dict[version] = latestCommit; + { + dict[key] = latestCommit; + } } - else dict.Add(version, latestCommit); + else dict.Add(key, latestCommit); StoreVersions(dict); return true; } - public static Dictionary CreateVersions() + private static Dictionary CreateVersions() { var dict = new Dictionary(); var dir = Path.GetDirectoryName(VersionsPath); - if (!Directory.Exists(dir)) - Directory.CreateDirectory(dir); - using (var stream = File.Create(VersionsPath)) - { - var serializer = new JsonSerializer(); - - using (StreamWriter writer = new StreamWriter(stream)) - using (JsonTextWriter jsonWriter = new JsonTextWriter(writer)) - { - JsonSerializer ser = new JsonSerializer(); - ser.Serialize(jsonWriter, dict); - jsonWriter.Flush(); - } - } + Directory.CreateDirectory(dir); + var json = JsonConvert.SerializeObject(dict); + File.WriteAllText(VersionsPath, json); return dict; } - public static Dictionary LoadVersions() + private static Dictionary LoadVersions() { if (!File.Exists(VersionsPath)) { @@ -145,35 +184,48 @@ namespace AssetStudio return JsonConvert.DeserializeObject>(file); } - public static void StoreVersions(Dictionary dict) + private static void StoreVersions(Dictionary dict) { var json = JsonConvert.SerializeObject(dict, Formatting.Indented); File.WriteAllText(VersionsPath, json); } - public static string GetAIPath(string version) + private static string GetPath(string version) { - var versionIndex = Versions.FirstOrDefault(x => x.Version == version); - return Path.Combine(BaseAIFolder, Path.GetFileName(versionIndex.MappedPath)); + string path = ""; + if (Versions.TryGetValue(version, out var versionIndex)) + { + path = Path.Combine(BaseAIFolder, Path.GetFileName(versionIndex.MappedPath)); + } + else if (version == VersionIndexKey) + { + path = Path.Combine(BaseAIFolder, VersionIndexName); + } + return path; } - public static async Task GetLatestCommit(string version) + private static async Task GetLatestCommit(string path) { - var versionIndex = Versions.FirstOrDefault(x => x.Version == version); string commit = ""; + var json = await DownloadString($"{CommitsUrl}{path}", TimeSpan.FromSeconds(2)); try { - string json = await DownloadString(CommitsUrl + versionIndex.MappedPath); JArray data = JArray.Parse(json); commit = data[0]["sha"].ToString(); } - catch (Exception ex) + catch (Exception) { - Logger.Error($"Failed to fetch latest commit", ex); + Logger.Warning($"Failed to parse latest commit {Path.GetFileName(path)}"); } return commit; } - public static string[] GetVersions() => Versions.Select(x => x.Version).ToArray(); + internal class VersionIndex + { + public string MappedPath = ""; + public string RawPath = ""; + public string Version = ""; + public double Coverage = 0; + } } }