From c22ea8f4cf0023956e34c9fc3e6a7a29574a6fca Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 1 Apr 2021 10:54:05 +0800 Subject: [PATCH] fix: fix crash when more than one thread wants to access same avatar file --- src/App.xaml.cs | 3 ++ src/Helpers/Avatar.cs | 86 +++++++++++++++++++++---------------------- src/UI/Histories.xaml | 6 +-- 3 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/App.xaml.cs b/src/App.xaml.cs index 76c2c926..a92df019 100644 --- a/src/App.xaml.cs +++ b/src/App.xaml.cs @@ -103,6 +103,9 @@ namespace SourceGit { Setting = JsonSerializer.Deserialize(File.ReadAllText(settingFile)); } + // Make sure avatar cache folder exists + if (!Directory.Exists(Helpers.Avatar.CACHE_PATH)) Directory.CreateDirectory(Helpers.Avatar.CACHE_PATH); + // Try auto configure git via registry. if (Setting == null || !IsGitConfigured) { var root = RegistryKey.OpenBaseKey( diff --git a/src/Helpers/Avatar.cs b/src/Helpers/Avatar.cs index a6596436..68aaaa05 100644 --- a/src/Helpers/Avatar.cs +++ b/src/Helpers/Avatar.cs @@ -2,8 +2,10 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Net; using System.Security.Cryptography; using System.Text; +using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -36,6 +38,14 @@ namespace SourceGit.Helpers { Brushes.DarkViolet }; + /// + /// Path to cache downloaded avatars + /// + public static readonly string CACHE_PATH = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "SourceGit", + "avatars"); + /// /// User property definition. /// @@ -53,26 +63,15 @@ namespace SourceGit.Helpers { set { SetValue(UserProperty, value); } } - /// - /// Loading request - /// - private class Request { - public BitmapImage img = null; - public List targets = new List(); - } - - /// - /// Path to cache downloaded avatars - /// - private static readonly string CACHE_PATH = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), - "SourceGit", - "avatars"); - /// /// Current requests. /// - private static Dictionary requesting = new Dictionary(); + private static Dictionary> requesting = new Dictionary>(); + + /// + /// Loaded images. + /// + private static Dictionary loaded = new Dictionary(); /// /// Render implementation. @@ -112,10 +111,10 @@ namespace SourceGit.Helpers { /// private void ReloadImage(Git.User oldUser) { if (oldUser != null && requesting.ContainsKey(oldUser.Email)) { - if (requesting[oldUser.Email].targets.Count <= 1) { + if (requesting[oldUser.Email].Count <= 1) { requesting.Remove(oldUser.Email); } else { - requesting[oldUser.Email].targets.Remove(this); + requesting[oldUser.Email].Remove(this); } } @@ -125,8 +124,13 @@ namespace SourceGit.Helpers { if (User == null) return; var email = User.Email; + if (loaded.ContainsKey(email)) { + Source = loaded[email]; + return; + } + if (requesting.ContainsKey(email)) { - requesting[email].targets.Add(this); + requesting[email].Add(this); return; } @@ -137,36 +141,32 @@ namespace SourceGit.Helpers { string filePath = Path.Combine(CACHE_PATH, md5); if (File.Exists(filePath)) { - Source = new BitmapImage(new Uri(filePath)); + var img = new BitmapImage(new Uri(filePath)); + loaded.Add(email, img); + Source = img; return; } - requesting.Add(email, new Request()); - requesting[email].targets.Add(this); + requesting.Add(email, new List()); + requesting[email].Add(this); - BitmapImage downloading = new BitmapImage(new Uri("https://www.gravatar.com/avatar/" + md5 + "?d=404")); - requesting[email].img = downloading; - downloading.DownloadCompleted += (o, e) => { - var owner = o as BitmapImage; - if (owner != null) { - if (!Directory.Exists(CACHE_PATH)) Directory.CreateDirectory(CACHE_PATH); - - var encoder = new PngBitmapEncoder(); - encoder.Frames.Add(BitmapFrame.Create(owner)); - using (var fs = new FileStream(filePath, FileMode.Create)) { - encoder.Save(fs); - } + Task.Run(() => { + try { + var agent = new WebClient(); + var data = agent.DownloadData("https://www.gravatar.com/avatar/" + md5 + "?d=404"); + //var data = agent.DownloadData("https://cdn.s.loli.top/avatar/" + md5 + "?d=404"); + File.WriteAllBytes(filePath, data); if (requesting.ContainsKey(email)) { - BitmapImage exists = new BitmapImage(new Uri(filePath)); - foreach (var one in requesting[email].targets) one.Source = exists; - requesting.Remove(email); + Dispatcher.Invoke(() => { + var img = new BitmapImage(new Uri(filePath)); + loaded[email] = img; + foreach (var one in requesting[email]) one.Source = img; + requesting.Remove(email); + }); } - } - }; - downloading.DownloadFailed += (o, e) => { - requesting.Remove(email); - }; + } catch {} + }); } /// diff --git a/src/UI/Histories.xaml b/src/UI/Histories.xaml index 9ec1781e..16c18e65 100644 --- a/src/UI/Histories.xaml +++ b/src/UI/Histories.xaml @@ -73,7 +73,7 @@ - + @@ -144,7 +144,7 @@ - + @@ -162,7 +162,7 @@ - +