using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; using System.Timers; using System.Windows.Forms; using HeuristicLab.Clients.Hive.CloudManager.Model; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Core.Views; using HeuristicLab.MainForm; using HeuristicLab.MainForm.WindowsForms; using HeuristicLab.PluginInfrastructure; namespace HeuristicLab.Clients.Hive.CloudManager.Views { [View("Cloud Resources View")] [Content(typeof(IItemList), IsDefaultView = true)] public partial class CloudResourcesView : ItemView, IDisposable { ProgressView progressView; private System.Timers.Timer timer = new System.Timers.Timer(); private int updateInterval = 15000; private DateTime dueTime; private const int subscriptionImageIndex = 0; private const int serviceImageIndex = 1; private const int deploymentImageIndex = 2; public new IItemList Content { get { return (IItemList)base.Content; } set { base.Content = value; } } private IItemList hostedServices; public IItemList HostedServices { get { return hostedServices; } set { hostedServices = value; } } public CloudResourcesView() { InitializeComponent(); treeCloudResources.ImageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.NewFolder); treeCloudResources.ImageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.NetworkCenterLarge); treeCloudResources.ImageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.MonitorLarge); HostedServices = CloudManagerClient.Instance.HostedServices; Content = CloudManagerClient.Instance.Subscriptions; CloudManagerClient.Instance.Refreshing += new EventHandler(Instance_Refreshing); CloudManagerClient.Instance.Refreshed += new EventHandler(Instance_Refreshed); timer.AutoReset = true; timer.Interval = 1000; timer.Elapsed += PerformUpdate; timer.Start(); dueTime = DateTime.Now.AddMilliseconds(updateInterval); //IProgress progress = new Progress(); //progress.Status = "Restore Subscriptions"; //progressView = new ProgressView(this, progress); //CloudManagerClient.Instance.RestoreSubscriptionsFromUserConfig(); //progressView.Finish(); } #region Register Content Events protected override void DeregisterContentEvents() { Content.ItemsAdded -= new Collections.CollectionItemsChangedEventHandler>(Content_ItemsAdded); Content.ItemsRemoved -= new Collections.CollectionItemsChangedEventHandler>(Content_ItemsRemoved); base.DeregisterContentEvents(); } protected override void RegisterContentEvents() { base.RegisterContentEvents(); Content.ItemsAdded += new Collections.CollectionItemsChangedEventHandler>(Content_ItemsAdded); Content.ItemsRemoved += new Collections.CollectionItemsChangedEventHandler>(Content_ItemsRemoved); } #endregion /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); CloudManagerClient.Instance.Refreshing -= new EventHandler(Instance_Refreshing); CloudManagerClient.Instance.Refreshed -= new EventHandler(Instance_Refreshed); timer.Stop(); timer.Dispose(); timer = null; } CloudManagerClient.Instance.PersistSubscriptionsToUserConfig(); base.Dispose(disposing); } private void SetProgressView(IProgress progress) { if (InvokeRequired) { Invoke(new Action(SetProgressView), progress); } else { if (progressView == null) { progressView = new ProgressView(this, progress); } else { progressView.Progress = progress; } } } private void FinishProgressView() { if (InvokeRequired) { Invoke(new Action(FinishProgressView)); } else { if (progressView != null) { progressView.Finish(); progressView = null; SetEnabledStateOfControls(); } } } public void Restore() { var task = System.Threading.Tasks.Task.Factory.StartNew(RestoreAsync); task.ContinueWith((t) => { FinishProgressView(); ErrorHandling.ShowErrorDialog(this, "An error occured while restoring Azure Subscriptions.", t.Exception); }, TaskContinuationOptions.OnlyOnFaulted); FinishProgressView(); } private void RestoreAsync() { IProgress progress = new Progress(); progress.Status = "Restoring Azure Subscriptions"; SetProgressView(progress); List result = CloudManagerClient.Instance.RestoreSubscriptionsFromUserConfig(); FinishProgressView(); foreach (Subscription s in result) this.BeginInvoke((MethodInvoker)delegate() { CloudManagerClient.Instance.Add(s); }); } protected override void SetEnabledStateOfControls() { base.SetEnabledStateOfControls(); if (Content == null || Content.Count == 0) { if (this.InvokeRequired) { this.BeginInvoke((MethodInvoker)delegate() { SetBtnControlsEnabled(false); }); } else { SetBtnControlsEnabled(false); } } else { if (this.InvokeRequired) { this.BeginInvoke((MethodInvoker)delegate() { SetBtnControlsEnabled(true); }); } else { SetBtnControlsEnabled(true); } } } private void SetBtnControlsEnabled(bool enabled) { btnAddSlaveService.Enabled = enabled; btnDelete.Enabled = enabled; btnSave.Enabled = enabled; } protected override void OnContentChanged() { base.OnContentChanged(); SetEnabledStateOfControls(); if (Content == null) { viewHost.Content = null; treeCloudResources.Nodes.Clear(); } else if (treeCloudResources.Nodes.Count == 0) { treeCloudResources.BeginUpdate(); //treeCloudResources.Nodes.Clear(); foreach (Subscription sub in Content) { TreeNode nodeSub = GetTreeNode(sub, sub.SubscriptionName, subscriptionImageIndex); foreach (HostedService s in HostedServices) { if (s.Subscription.SubscriptionID == sub.SubscriptionID) { TreeNode nodeServ = GetTreeNode(s, s.HostedServiceProperties.Label, serviceImageIndex); foreach (Deployment d in s.Deployments) { TreeNode nodeDepl = GetTreeNode(d, d.Label + " (" + d.DeploymentSlot + ")", deploymentImageIndex); nodeServ.Nodes.Add(nodeDepl); } nodeSub.Nodes.Add(nodeServ); } } treeCloudResources.Nodes.Add(nodeSub); } treeCloudResources.EndUpdate(); } else { treeCloudResources.BeginUpdate(); TreeNodeCollection tncSubs = treeCloudResources.Nodes; // Delete treenodes that have no corresponding data in Content and HosteServices foreach (TreeNode tnSub in tncSubs) { Subscription s = (Subscription)tnSub.Tag; int idx = Content.IndexOf(s); if (idx == -1) { tncSubs.Remove(tnSub); } else { TreeNodeCollection tncHS = tnSub.Nodes; foreach (TreeNode tnHS in tncHS) { HostedService hs = (HostedService)tnHS.Tag; int idxHS = HostedServices.IndexOf(hs); if (idxHS == -1) { tncHS.Remove(tnHS); } else { TreeNodeCollection tncDep = tnHS.Nodes; foreach (TreeNode tnDep in tncDep) { Deployment dep = (Deployment)tnDep.Tag; HostedService hsDep = HostedServices[idxHS]; int idxDep = hsDep.Deployments.IndexOf(dep); if (idxDep == -1) { tncDep.Remove(tnDep); } } } } } } // Add missing treenodes foreach (Subscription sub in Content) { bool foundSub = false; TreeNode foundSubNode = null; foreach (TreeNode tnSub in treeCloudResources.Nodes) { if (((Subscription)tnSub.Tag).Equals(sub)) { foundSub = true; foundSubNode = tnSub; } } TreeNode nodeSub; if (!foundSub) { nodeSub = GetTreeNode(sub, sub.SubscriptionName, subscriptionImageIndex); treeCloudResources.Nodes.Add(nodeSub); } else { nodeSub = foundSubNode; } foreach (HostedService s in HostedServices) { if (s.Subscription.SubscriptionID == sub.SubscriptionID) { bool foundHS = false; TreeNode foundHSNode = null; foreach (TreeNode tnHS in nodeSub.Nodes) { if (((HostedService)tnHS.Tag).Equals(s)) { foundHS = true; foundHSNode = tnHS; } } TreeNode nodeServ; if (!foundHS) { nodeServ = GetTreeNode(s, s.HostedServiceProperties.Label, serviceImageIndex); nodeSub.Nodes.Add(nodeServ); } else { nodeServ = foundHSNode; } foreach (Deployment d in s.Deployments) { bool foundDep = false; TreeNode foundDepNode; foreach (TreeNode tnDep in nodeServ.Nodes) { if (((Deployment)tnDep.Tag).Equals(d)) { foundDep = true; foundDepNode = tnDep; } } TreeNode nodeDepl; if (!foundDep) { nodeDepl = GetTreeNode(d, d.Label + " (" + d.DeploymentSlot + ")", deploymentImageIndex); nodeServ.Nodes.Add(nodeDepl); } else { // nothing to do } } } } } // ---------------------------- treeCloudResources.EndUpdate(); } } private TreeNode GetTreeNode(Object tag, string text, int imageIndex) { TreeNode node = new TreeNode(); node.Tag = tag; node.Text = text; node.ImageIndex = imageIndex; node.SelectedImageIndex = node.ImageIndex; return node; } private void Instance_Refreshing(object sender, EventArgs e) { Debug.WriteLine("Instance_Refreshing"); //if (treeCloudResources.InvokeRequired) { // treeCloudResources.Invoke((MethodInvoker)delegate { OnContentChanged(); }); //} else { // OnContentChanged(); //} } private void Instance_Refreshed(object sender, EventArgs e) { Debug.WriteLine("Instance_Refreshed"); if (treeCloudResources.InvokeRequired) { treeCloudResources.Invoke((MethodInvoker)delegate { OnContentChanged(); }); } else { OnContentChanged(); } } private void Content_ItemsRemoved(object sender, Collections.CollectionItemsChangedEventArgs> e) { OnContentChanged(); } private void Content_ItemsAdded(object sender, Collections.CollectionItemsChangedEventArgs> e) { OnContentChanged(); } private void PerformUpdate(object sender, ElapsedEventArgs e) { TimeSpan timeToRefresh = dueTime - DateTime.Now; if (timeToRefresh.Seconds >= 0) { this.Invoke((MethodInvoker)delegate { lblRefresh.Text = "Done. " + timeToRefresh.Seconds + "s to next refresh."; }); } else { timer.Stop(); this.Invoke((MethodInvoker)delegate { lblRefresh.Text = "Refreshing data ..."; }); CloudManagerClient.Instance.Refresh(); dueTime = DateTime.Now.AddMilliseconds(updateInterval); if (timer != null) { timer.Start(); } } } private void btnAddSubscription_Click(object sender, EventArgs e) { using (var form = new AddSubscriptionDialog()) { form.ShowDialog(); if (!form.ErrorOccured) { if (form.Subscription != null) { Subscription sub = form.Subscription; CloudManagerClient.Instance.Add(sub); } } } } private void btnAddSlaveService_Click(object sender, EventArgs e) { // When refreshing subscriptions in the dialog, // discoverservices and safetoconfig properties are always set to false // -> work on deep copy Cloner cloner = new Cloner(); IItemList subscriptions = cloner.Clone(Content); using (var form = new AddAzureServiceDialog(subscriptions)) { form.ShowDialog(); } } private void treeCloudResources_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) { viewHost.Content = (IContent)e.Node.Tag; } private void btnSave_Click(object sender, EventArgs e) { if (treeCloudResources.SelectedNode != null) { TreeNode tn = treeCloudResources.SelectedNode; TreeNode tnParent = tn.Parent; Object obj = tn.Tag; Object objParent = tnParent.Tag; if (obj is Subscription) { // CloudManagerClient.Instance.Save((Subscription)obj); } else if (obj is HostedService) { // nothing to do so far } else if (obj is Deployment && objParent is HostedService) { HostedService hs = (HostedService)objParent; Deployment dep = (Deployment)obj; //call async CloudManagerClient.Instance.ChangeIntances(dep, hs); } } } private void btnDelete_Click(object sender, EventArgs e) { if (treeCloudResources.SelectedNode != null) { TreeNode tn = treeCloudResources.SelectedNode; TreeNode tnParent = tn.Parent; Object obj = tn.Tag; Object objParent = null; if (tnParent != null) { objParent = tnParent.Tag; } viewHost.Content = null; if (obj is Subscription) { CloudManagerClient.Instance.Delete((Subscription)obj); } else if (obj is HostedService) { HostedService hs = (HostedService)obj; using (var form = new DeleteHostedServiceView(hs)) { form.ShowDialog(); } } else if (obj is Deployment && objParent is HostedService) { HostedService hs = (HostedService)objParent; Deployment dep = (Deployment)obj; using (var form = new DeleteDeploymentView(dep, hs)) { form.ShowDialog(); } } } } } }