Add "Open Folder" functionality to plugins tab, crash-safe plugin updating
This commit is contained in:
@@ -10,7 +10,7 @@ namespace Torch.API.Plugins
|
||||
/// <summary>
|
||||
/// Indicates that the given type should be loaded by the plugin manager as a plugin.
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
[Obsolete("All plugin meta-information is now defined in the manifest.xml.")]
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class PluginAttribute : Attribute
|
||||
{
|
||||
|
@@ -12,7 +12,7 @@
|
||||
</UserControl.DataContext>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="200"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Grid.Column="0">
|
||||
@@ -27,7 +27,7 @@
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
<Button Grid.Row="1" Content="Open Folder" Margin="3" DockPanel.Dock="Bottom" IsEnabled="false"/>
|
||||
<Button Grid.Row="1" Content="Open Folder" Margin="3" DockPanel.Dock="Bottom" Click="OpenFolder_OnClick"/>
|
||||
</Grid>
|
||||
<Frame Grid.Column="1" NavigationUIVisibility="Hidden" Content="{Binding SelectedPlugin.Control}"/>
|
||||
</Grid>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -15,6 +16,8 @@ using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using NLog;
|
||||
using Torch.API;
|
||||
using Torch.API.Managers;
|
||||
using Torch.Managers;
|
||||
using Torch.Server.ViewModels;
|
||||
|
||||
namespace Torch.Server.Views
|
||||
@@ -24,6 +27,9 @@ namespace Torch.Server.Views
|
||||
/// </summary>
|
||||
public partial class PluginsControl : UserControl
|
||||
{
|
||||
private ITorchServer _server;
|
||||
private PluginManager _plugins;
|
||||
|
||||
public PluginsControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -31,8 +37,15 @@ namespace Torch.Server.Views
|
||||
|
||||
public void BindServer(ITorchServer server)
|
||||
{
|
||||
var pluginManager = new PluginManagerViewModel(server.Plugins);
|
||||
_server = server;
|
||||
_plugins = _server.Managers.GetManager<PluginManager>();
|
||||
var pluginManager = new PluginManagerViewModel(_plugins);
|
||||
DataContext = pluginManager;
|
||||
}
|
||||
|
||||
private void OpenFolder_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start("explorer.exe", _plugins.PluginDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -98,10 +98,13 @@ namespace Torch.Managers
|
||||
var count = 0;
|
||||
var pluginItems = Directory.EnumerateFiles(PluginDir, "*.zip").Union(Directory.EnumerateDirectories(PluginDir));
|
||||
Parallel.ForEach(pluginItems, async item =>
|
||||
{
|
||||
PluginManifest manifest = null;
|
||||
try
|
||||
{
|
||||
var path = Path.Combine(PluginDir, item);
|
||||
var isZip = item.EndsWith(".zip", StringComparison.CurrentCultureIgnoreCase);
|
||||
var manifest = isZip ? GetManifestFromZip(path) : GetManifestFromDirectory(path);
|
||||
manifest = isZip ? GetManifestFromZip(path) : GetManifestFromDirectory(path);
|
||||
if (manifest == null)
|
||||
{
|
||||
_log.Warn($"Item '{item}' is missing a manifest, skipping update check.");
|
||||
@@ -118,11 +121,20 @@ namespace Torch.Managers
|
||||
}
|
||||
|
||||
if (latest.Item1 <= currentVersion)
|
||||
{
|
||||
_log.Debug($"{manifest.Name} {manifest.Version} is up to date.");
|
||||
return;
|
||||
}
|
||||
|
||||
_log.Info($"Updating plugin '{manifest.Name}' from {currentVersion} to {latest.Item1}.");
|
||||
await UpdatePlugin(path, latest.Item2).ConfigureAwait(false);
|
||||
await UpdatePluginAsync(path, latest.Item2).ConfigureAwait(false);
|
||||
count++;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.Error($"An error occurred updating the plugin {manifest.Name}.");
|
||||
_log.Error(e);
|
||||
}
|
||||
});
|
||||
|
||||
_log.Info($"Updated {count} plugins.");
|
||||
@@ -155,7 +167,7 @@ namespace Torch.Managers
|
||||
}
|
||||
}
|
||||
|
||||
private Task UpdatePlugin(string localPath, string downloadUrl)
|
||||
private Task UpdatePluginAsync(string localPath, string downloadUrl)
|
||||
{
|
||||
if (File.Exists(localPath))
|
||||
File.Delete(localPath);
|
||||
@@ -238,9 +250,7 @@ namespace Torch.Managers
|
||||
|
||||
using (var stream = new StreamReader(entry.Open()))
|
||||
{
|
||||
var ser = new XmlSerializer(typeof(PluginManifest));
|
||||
var manifest = (PluginManifest)ser.Deserialize(stream);
|
||||
return manifest;
|
||||
return PluginManifest.Load(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -266,7 +276,7 @@ namespace Torch.Managers
|
||||
|
||||
if (pluginType != null)
|
||||
{
|
||||
_log.Error($"The plugin '{manifest.Name}' has multiple implementations of {nameof(ITorchPlugin)}.");
|
||||
_log.Error($"The plugin '{manifest.Name}' has multiple implementations of {nameof(ITorchPlugin)}, not loading.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -276,7 +286,7 @@ namespace Torch.Managers
|
||||
|
||||
if (pluginType == null)
|
||||
{
|
||||
_log.Error($"The plugin '{manifest.Name}' does not have an implementation of {nameof(ITorchPlugin)}.");
|
||||
_log.Error($"The plugin '{manifest.Name}' does not have an implementation of {nameof(ITorchPlugin)}, not loading.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -301,6 +311,7 @@ namespace Torch.Managers
|
||||
_commandManager.RegisterPluginCommands(plugin);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IEnumerable.GetEnumerator"/>
|
||||
public IEnumerator<ITorchPlugin> GetEnumerator()
|
||||
{
|
||||
return Plugins.Values.GetEnumerator();
|
@@ -10,11 +10,30 @@ namespace Torch
|
||||
{
|
||||
public class PluginManifest
|
||||
{
|
||||
/// <summary>
|
||||
/// The display name of the plugin.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A unique identifier for the plugin.
|
||||
/// </summary>
|
||||
public Guid Guid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A GitHub repository in the format of Author/Repository to retrieve plugin updates.
|
||||
/// </summary>
|
||||
public string Repository { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The plugin version. This must include a string in the format of #[.#[.#]] for update checking purposes.
|
||||
/// </summary>
|
||||
public string Version { get; set; }
|
||||
public List<Guid> Dependencies { get; } = new List<Guid>();
|
||||
|
||||
/// <summary>
|
||||
/// A list of dependent plugin repositories. This may be updated to include GUIDs in the future.
|
||||
/// </summary>
|
||||
public List<string> Dependencies { get; } = new List<string>();
|
||||
|
||||
public void Save(string path)
|
||||
{
|
@@ -181,7 +181,7 @@
|
||||
<Compile Include="Managers\MultiplayerManager.cs" />
|
||||
<Compile Include="Managers\UpdateManager.cs" />
|
||||
<Compile Include="Persistent.cs" />
|
||||
<Compile Include="PluginManifest.cs" />
|
||||
<Compile Include="Plugins\PluginManifest.cs" />
|
||||
<Compile Include="Utils\Reflection.cs" />
|
||||
<Compile Include="Managers\ScriptingManager.cs" />
|
||||
<Compile Include="Utils\TorchAssemblyResolver.cs" />
|
||||
@@ -198,7 +198,7 @@
|
||||
<Compile Include="Extensions\StringExtensions.cs" />
|
||||
<Compile Include="ViewModels\PlayerViewModel.cs" />
|
||||
<Compile Include="ViewModels\ViewModel.cs" />
|
||||
<Compile Include="Managers\PluginManager.cs" />
|
||||
<Compile Include="Plugins\PluginManager.cs" />
|
||||
<Compile Include="ViewModels\PluginViewModel.cs" />
|
||||
<Compile Include="Views\CollectionEditor.xaml.cs">
|
||||
<DependentUpon>CollectionEditor.xaml</DependentUpon>
|
||||
|
Reference in New Issue
Block a user