Skip to content

Commit

Permalink
Merge branch 'cjmanca-master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Icehunter committed Dec 11, 2014
2 parents 892cb4d + afd605c commit 166b4e3
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 35 deletions.
1 change: 1 addition & 0 deletions FFXIVAPP.Client/FFXIVAPP.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
<Compile Include="Utilities\MicroStopwatch.cs" />
<Compile Include="Utilities\MicroTimer.cs" />
<Compile Include="Utilities\MicroTimerEventArgs.cs" />
<Compile Include="Utilities\UpdateUtilities.cs" />
<Compile Include="ViewModels\AboutViewModel.cs" />
<Compile Include="ViewModels\UpdateViewModel.cs" />
<Compile Include="ViewModels\SettingsViewModel.cs" />
Expand Down
5 changes: 4 additions & 1 deletion FFXIVAPP.Client/Initializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,12 @@ where enabled
Files = new List<PluginFile>(pluginFiles.Select(pluginFile => new PluginFile
{
Location = pluginFile["Location"].ToString(),
Name = pluginFile["Name"].ToString()
Name = pluginFile["Name"].ToString(),
Checksum = pluginFile["Checksum"] == null ? "" : pluginFile["Checksum"].ToString()
})),
Name = pluginInfo["Name"].ToString(),
FriendlyName = pluginInfo["FriendlyName"] == null ? pluginInfo["Name"].ToString() : pluginInfo["FriendlyName"].ToString(),
Description = pluginInfo["Description"] == null ? "" : pluginInfo["Description"].ToString(),
SourceURI = pluginInfo["SourceURI"].ToString(),
LatestVersion = pluginInfo["Version"].ToString()
};
Expand Down
22 changes: 22 additions & 0 deletions FFXIVAPP.Client/Models/PluginDownloadItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public class PluginDownloadItem : INotifyPropertyChanged
private List<PluginFile> _files;
private string _latestVersion;
private string _name;
private string _friendlyName;
private string _description;
private string _sourceUri;
private PluginStatus _status;

Expand All @@ -52,6 +54,26 @@ public string Name
}
}

public string FriendlyName
{
get { return _friendlyName; }
set
{
_friendlyName = value;
RaisePropertyChanged();
}
}

public string Description
{
get { return _description; }
set
{
_description = value;
RaisePropertyChanged();
}
}

public string CurrentVersion
{
get { return _currentVersion; }
Expand Down
11 changes: 11 additions & 0 deletions FFXIVAPP.Client/Models/PluginFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class PluginFile : INotifyPropertyChanged
{
private string _location;
private string _name;
private string _checksum;

public string Name
{
Expand All @@ -57,6 +58,16 @@ public string Location
}
}

public string Checksum
{
get { return _checksum; }
set
{
_checksum = value;
RaisePropertyChanged();
}
}

#region Implementation of INotifyPropertyChanged

public event PropertyChangedEventHandler PropertyChanged = delegate { };
Expand Down
60 changes: 60 additions & 0 deletions FFXIVAPP.Client/Utilities/UpdateUtilities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace FFXIVAPP.Client.Utilities
{
public static class UpdateUtilities
{
/// <summary>
/// Compares a file against an expected checksum.
/// </summary>
/// <param name="FilePath">Path to file</param>
/// <param name="Checksum">Expected MD5 checksum</param>
/// <returns>True if the file matches. False if the file doesn't match OR doesn't exist.</returns>
public static bool VerifyFile(string FilePath, string Checksum)
{
if (!File.Exists(FilePath))
{
return false;
}

return GetFileHash(FilePath).Equals(Checksum, StringComparison.OrdinalIgnoreCase);
}

/// <summary>
/// Computes a file's checksum
/// </summary>
/// <param name="FilePath">Path to file</param>
/// <returns>MD5 checksum for the file, or an empty string if the file doesn't exist.</returns>
public static string GetFileHash(string FilePath)
{
string FileHash = "";

if (!File.Exists(FilePath))
{
return FileHash;
}

using (FileStream file = new FileStream(FilePath, FileMode.Open, FileAccess.Read))
{
using (MD5 md5 = new MD5CryptoServiceProvider())
{
byte[] retVal = md5.ComputeHash(file);
file.Close();

StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
FileHash = sb.ToString();
}
}

return FileHash;
}

}
}
77 changes: 55 additions & 22 deletions FFXIVAPP.Client/ViewModels/UpdateViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
using System.Windows.Input;
using System.Windows.Threading;
using FFXIVAPP.Client.Models;
using FFXIVAPP.Client.Utilities;
using FFXIVAPP.Client.Views;
using FFXIVAPP.Common.Helpers;
using FFXIVAPP.Common.Utilities;
Expand Down Expand Up @@ -188,45 +189,77 @@ private static void InstallByKey(string key, Action asyncAction = null)
var saveLocation = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly()
.Location), "Plugins", plugin.Name, pluginFile.Location, pluginFile.Name);
Directory.CreateDirectory(Path.GetDirectoryName(saveLocation));
sb.Append(plugin.SourceURI.Trim('/'));
var location = pluginFile.Location.Trim('/');
if (!String.IsNullOrWhiteSpace(location))


if (UpdateUtilities.VerifyFile(saveLocation, pluginFile.Checksum))
{
sb.AppendFormat("/{0}", location);
// no need to download file, since it hasn't changed
// count this file as "updated" for the purpose of checking if the install finished
updateCount++;
}
sb.AppendFormat("/{0}", pluginFile.Name.Trim('/'));
var uri = new Uri(sb.ToString());
client.DownloadFileAsync(uri, saveLocation);
client.DownloadProgressChanged += delegate { DispatcherHelper.Invoke(delegate { UpdateView.View.AvailableLoadingProgressMessage.Text = String.Format("{0}/{1}", pluginFile.Location.Trim('/'), pluginFile.Name); }); };
client.DownloadFileCompleted += delegate
else
{
updateCount++;
DispatcherHelper.Invoke(delegate
sb.Append(plugin.SourceURI.Trim('/'));
var location = pluginFile.Location.Trim('/');
if (!String.IsNullOrWhiteSpace(location))
{
UpdateView.View.AvailableLoadingProgressMessage.Text = "";
sb.AppendFormat("/{0}", location);
}
sb.AppendFormat("/{0}", pluginFile.Name.Trim('/'));
var uri = new Uri(sb.ToString());
client.DownloadFileAsync(uri, saveLocation);
client.DownloadProgressChanged += delegate { DispatcherHelper.Invoke(delegate { UpdateView.View.AvailableLoadingProgressMessage.Text = String.Format("{0}/{1}", pluginFile.Location.Trim('/'), pluginFile.Name); }); };
client.DownloadFileCompleted += delegate
{
updateCount++;

if (updateCount >= updateLimit)
{
if (plugin.Status != PluginStatus.Installed)
DispatcherHelper.Invoke(delegate
{
plugin.Status = PluginStatus.Installed;
Instance.SetupGrouping();
if (asyncAction != null)
if (plugin.Status != PluginStatus.Installed)
{
DispatcherHelper.Invoke(asyncAction);
plugin.Status = PluginStatus.Installed;
Instance.SetupGrouping();
if (asyncAction != null)
{
DispatcherHelper.Invoke(asyncAction);
}
}
}
UpdateView.View.AvailableLoadingInformation.Visibility = Visibility.Collapsed;
UpdateView.View.AvailableLoadingProgressMessage.Visibility = Visibility.Collapsed;
UpdateView.View.AvailableLoadingProgressMessage.Text = "";
UpdateView.View.AvailableLoadingInformation.Visibility = Visibility.Collapsed;
UpdateView.View.AvailableLoadingProgressMessage.Visibility = Visibility.Collapsed;
}, DispatcherPriority.Send);
}
}, DispatcherPriority.Send);
};
};
}
}
}
catch (Exception ex)
{
updateCount++;
}
}

// need to check here aswell, since if all files mathced hash, none will be downloaded, so the DownloadFileCompleted delegate would never be triggered
if (updateCount >= updateLimit)
{
if (plugin.Status != PluginStatus.Installed)
{
plugin.Status = PluginStatus.Installed;
Instance.SetupGrouping();
if (asyncAction != null)
{
DispatcherHelper.Invoke(asyncAction);
}
}
DispatcherHelper.Invoke(delegate
{
UpdateView.View.AvailableLoadingInformation.Visibility = Visibility.Collapsed;
UpdateView.View.AvailableLoadingProgressMessage.Visibility = Visibility.Collapsed;
}, DispatcherPriority.Send);
}

return true;
};
checkAvailable.BeginInvoke(null, null);
Expand Down
20 changes: 8 additions & 12 deletions FFXIVAPP.Client/Views/UpdateView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,11 @@
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}"
<DataGridTextColumn Binding="{Binding FriendlyName}"
Header="{Binding Locale[app_NameHeader],
Source={StaticResource AppProperties}}"
Utilities:GridViewSort.PropertyName="Name" />
IsReadOnly="True"
Utilities:GridViewSort.PropertyName="FriendlyName" />
<DataGridTextColumn Binding="{Binding CurrentVersion}"
Header="{Binding Locale[app_CurrentVersionHeader],
Source={StaticResource AppProperties}}"
Expand All @@ -152,11 +153,10 @@
Source={StaticResource AppProperties}}"
IsReadOnly="True"
Utilities:GridViewSort.PropertyName="Status" />
<DataGridTextColumn Binding="{Binding SourceURI}"
Header="{Binding Locale[app_SourceURIHeader],
Source={StaticResource AppProperties}}"
<DataGridTextColumn Binding="{Binding Description}"
Header="Description"
IsReadOnly="True"
Utilities:GridViewSort.PropertyName="SourceURI" />
Utilities:GridViewSort.PropertyName="Description" />
</DataGrid.Columns>
</DataGrid>
<DockPanel Grid.Row="3"
Expand All @@ -172,12 +172,8 @@
RenderOptions.BitmapScalingMode="HighQuality"
Source="/FFXIVAPP.Client;component/Resources/Media/Images/Refresh.png" />
<TextBlock Padding="3,0,3,0"
Text="{Binding Locale[app_RefreshPluginsButtonText],
Source={StaticResource AppProperties},
Converter={StaticResource ToUpperConverter}}"
Visibility="{Binding EnableHelpLabels,
Converter={StaticResource VisibilityConverter},
Source={x:Static Properties:Settings.Default}}" />
Text="{Binding Locale[app_RefreshPluginsButtonText], Converter={StaticResource ToUpperConverter}, Source={StaticResource AppProperties}}"
Visibility="{Binding EnableHelpLabels, Converter={StaticResource VisibilityConverter}, Source={x:Static Properties:Settings.Default}}" />
</StackPanel>
</Button>
<Button Height="28"
Expand Down

0 comments on commit 166b4e3

Please sign in to comment.