#region License Information
/* HeuristicLab
* Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.ServiceModel;
using System.Windows.Forms;
using HeuristicLab.PluginInfrastructure.Manager;
namespace HeuristicLab.PluginInfrastructure.Advanced {
internal partial class UploadPluginsView : InstallationManagerControl {
private const string UploadMessage = "Uploading plugins...";
private const string RefreshMessage = "Downloading plugin information from deployment service...";
private Dictionary localAndServerPlugins;
private BackgroundWorker pluginUploadWorker;
private BackgroundWorker refreshPluginsWorker;
private PluginManager pluginManager;
public PluginManager PluginManager {
get { return pluginManager; }
set { pluginManager = value; }
}
public UploadPluginsView() {
InitializeComponent();
pluginImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.Plugin);
localAndServerPlugins = new Dictionary();
#region initialize backgroundworkers
pluginUploadWorker = new BackgroundWorker();
pluginUploadWorker.DoWork += new DoWorkEventHandler(pluginUploadWorker_DoWork);
pluginUploadWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(pluginUploadWorker_RunWorkerCompleted);
refreshPluginsWorker = new BackgroundWorker();
refreshPluginsWorker.DoWork += new DoWorkEventHandler(refreshPluginsWorker_DoWork);
refreshPluginsWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(refreshPluginsWorker_RunWorkerCompleted);
#endregion
}
#region refresh plugins from server backgroundworker
void refreshPluginsWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Error != null) {
StatusView.ShowError("Connection Error",
"There was an error while connecting to the server." + Environment.NewLine +
"Please check your connection settings and user credentials.");
} else {
UpdatePluginListView((IEnumerable)e.Result);
}
StatusView.HideProgressIndicator();
StatusView.RemoveMessage(RefreshMessage);
StatusView.UnlockUI();
}
void refreshPluginsWorker_DoWork(object sender, DoWorkEventArgs e) {
// refresh available plugins
var client = DeploymentService.UpdateServiceClientFactory.CreateClient();
try {
e.Result = client.GetPlugins();
client.Close();
}
catch (TimeoutException) {
client.Abort();
throw;
}
catch (FaultException) {
client.Abort();
throw;
}
catch (CommunicationException) {
client.Abort();
throw;
}
}
#endregion
#region upload plugins to server backgroundworker
void pluginUploadWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Error != null) {
StatusView.ShowError("Connection Error",
"There was an error while connecting to the server." + Environment.NewLine +
"Please check your connection settings and user credentials.");
} else {
UpdatePluginListView((IEnumerable)e.Result);
}
StatusView.RemoveMessage(UploadMessage);
StatusView.HideProgressIndicator();
StatusView.UnlockUI();
}
void pluginUploadWorker_DoWork(object sender, DoWorkEventArgs e) {
// upload plugins
var selectedPlugins = (IEnumerable)e.Argument;
DeploymentService.AdminServiceClient adminClient = DeploymentService.AdminServiceClientFactory.CreateClient();
Dictionary cachedPluginDescriptions =
new Dictionary();
try {
foreach (var plugin in IteratePlugins(selectedPlugins)) {
adminClient.DeployPlugin(MakePluginDescription(plugin, cachedPluginDescriptions), CreateZipPackage(plugin));
}
adminClient.Close();
}
catch (TimeoutException) {
adminClient.Abort();
throw;
}
catch (FaultException) {
adminClient.Abort();
throw;
}
catch (CommunicationException) {
adminClient.Abort();
throw;
}
// refresh available plugins
var client = DeploymentService.UpdateServiceClientFactory.CreateClient();
try {
e.Result = client.GetPlugins();
client.Close();
}
catch (TimeoutException) {
client.Abort();
throw;
}
catch (FaultException) {
client.Abort();
throw;
}
catch (CommunicationException) {
client.Abort();
throw;
}
}
#endregion
#region button events
private void uploadButton_Click(object sender, EventArgs e) {
var selectedPlugins = from item in listView.Items.Cast()
where item.Checked
where item.Tag is IPluginDescription
select item.Tag as IPluginDescription;
if (selectedPlugins.Count() > 0) {
StatusView.LockUI();
StatusView.ShowProgressIndicator();
StatusView.ShowMessage(UploadMessage);
pluginUploadWorker.RunWorkerAsync(selectedPlugins.ToList());
}
}
private void refreshButton_Click(object sender, EventArgs e) {
StatusView.LockUI();
StatusView.ShowProgressIndicator();
StatusView.ShowMessage(RefreshMessage);
refreshPluginsWorker.RunWorkerAsync();
}
#endregion
#region item list events
private bool ignoreItemCheckedEvents = false;
private void listView_ItemChecked(object sender, ItemCheckedEventArgs e) {
if (ignoreItemCheckedEvents) return;
List modifiedPlugins = new List();
if (e.Item.Checked) {
foreach (ListViewItem item in listView.SelectedItems) {
var plugin = (IPluginDescription)item.Tag;
// also check all dependencies
if (!modifiedPlugins.Contains(plugin))
modifiedPlugins.Add(plugin);
foreach (var dep in Util.GetAllDependencies(plugin)) {
if (!modifiedPlugins.Contains(dep))
modifiedPlugins.Add(dep);
}
}
listView.CheckItems(modifiedPlugins.Select(x => FindItemForPlugin(x)));
} else {
foreach (ListViewItem item in listView.SelectedItems) {
var plugin = (IPluginDescription)item.Tag;
// also uncheck all dependent plugins
if (!modifiedPlugins.Contains(plugin))
modifiedPlugins.Add(plugin);
foreach (var dep in Util.GetAllDependents(plugin, localAndServerPlugins.Keys)) {
if (!modifiedPlugins.Contains(dep))
modifiedPlugins.Add(dep);
}
}
listView.UncheckItems(modifiedPlugins.Select(x => FindItemForPlugin(x)));
}
uploadButton.Enabled = (from i in listView.Items.OfType()
where i.Checked
select i).Any();
}
#endregion
#region helper methods
private void UpdatePluginListView(IEnumerable remotePlugins) {
// refresh local plugins
localAndServerPlugins.Clear();
foreach (var plugin in pluginManager.Plugins) {
localAndServerPlugins.Add(plugin, null);
}
foreach (var plugin in remotePlugins) {
var matchingLocalPlugin = (from localPlugin in localAndServerPlugins.Keys
where localPlugin.Name == plugin.Name
where localPlugin.Version == plugin.Version
select localPlugin).SingleOrDefault();
if (matchingLocalPlugin != null) {
localAndServerPlugins[matchingLocalPlugin] = plugin;
}
}
// refresh the list view with plugins
listView.Items.Clear();
ignoreItemCheckedEvents = true;
foreach (var pair in localAndServerPlugins) {
var item = MakeListViewItem(pair.Key);
listView.Items.Add(item);
}
Util.ResizeColumns(listView.Columns.OfType());
ignoreItemCheckedEvents = false;
}
private IEnumerable IteratePlugins(IEnumerable plugins) {
HashSet yieldedItems = new HashSet();
foreach (var plugin in plugins) {
foreach (var dependency in IteratePlugins(plugin.Dependencies)) {
if (!yieldedItems.Contains(dependency)) {
yieldedItems.Add(dependency);
yield return dependency;
}
}
if (!yieldedItems.Contains(plugin)) {
yieldedItems.Add(plugin);
yield return plugin;
}
}
}
private static byte[] CreateZipPackage(IPluginDescription plugin) {
using (MemoryStream stream = new MemoryStream()) {
ZipArchive zipFile = new ZipArchive(stream, ZipArchiveMode.Create);
foreach (var file in plugin.Files) {
zipFile.CreateEntry(file.Name);
}
stream.Seek(0, SeekOrigin.Begin);
return stream.GetBuffer();
}
}
private ListViewItem MakeListViewItem(IPluginDescription plugin) {
ListViewItem item;
if (localAndServerPlugins[plugin] != null) {
item = new ListViewItem(new string[] { plugin.Name, plugin.Version.ToString(),
localAndServerPlugins[plugin].Version.ToString(), localAndServerPlugins[plugin].Description });
if (plugin.Version <= localAndServerPlugins[plugin].Version)
item.ForeColor = Color.Gray;
} else {
item = new ListViewItem(new string[] { plugin.Name, plugin.Version.ToString(),
string.Empty, plugin.Description });
}
item.Tag = plugin;
item.ImageIndex = 0;
item.Checked = false;
return item;
}
private ListViewItem FindItemForPlugin(IPluginDescription dep) {
return (from i in listView.Items.Cast()
where i.Tag == dep
select i).Single();
}
private DeploymentService.PluginDescription MakePluginDescription(IPluginDescription plugin, Dictionary cachedPluginDescriptions) {
if (!cachedPluginDescriptions.ContainsKey(plugin)) {
var dependencies = (from dep in plugin.Dependencies
select MakePluginDescription(dep, cachedPluginDescriptions))
.ToList();
cachedPluginDescriptions.Add(plugin,
new DeploymentService.PluginDescription(plugin.Name, plugin.Version, dependencies, plugin.ContactName, plugin.ContactEmail, plugin.LicenseText));
}
return cachedPluginDescriptions[plugin];
}
#endregion
}
}