Control Panel instance manager

This commit is contained in:
Cyberboss
2017-11-01 13:26:13 -04:00
parent 481fca3afe
commit ef9f4adfaa
8 changed files with 2627 additions and 20 deletions
+9 -1
View File
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using TGServiceInterface;
@@ -8,8 +9,13 @@ namespace TGControlPanel
/// <summary>
/// The main <see cref="ControlPanel"/> form
/// </summary>
partial class ControlPanel : Form
partial class ControlPanel : CountedForm
{
/// <summary>
/// List of instances being used by open control panels
/// </summary>
public static IDictionary<string, ControlPanel> InstancesInUse { get; private set; } = new Dictionary<string, ControlPanel>();
/// <summary>
/// The <see cref="TGServiceInterface.Interface"/> instance for this <see cref="ControlPanel"/>
/// </summary>
@@ -35,6 +41,7 @@ namespace TGControlPanel
InitServerPage();
LoadChatPage();
InitStaticPage();
InstancesInUse.Add(I.InstanceName, this);
}
/// <summary>
@@ -42,6 +49,7 @@ namespace TGControlPanel
/// </summary>
void Cleanup()
{
InstancesInUse.Remove(Interface.InstanceName);
Interface.Dispose();
}
+35
View File
@@ -0,0 +1,35 @@
using System.Windows.Forms;
namespace TGControlPanel
{
/// <summary>
/// Calls <see cref="Application.Exit"/> when all <see cref="CountedForm"/>s are <see cref="Form.Close"/>d
/// </summary>
class CountedForm : Form
{
/// <summary>
/// The current number of active <see cref="CountedForm"/>s
/// </summary>
static uint FormCount;
/// <summary>
/// Construct a <see cref="CountedForm"/>. Increments <see cref="FormCount"/>
/// </summary>
public CountedForm()
{
FormClosed += CountedForm_FormClosed;
++FormCount;
}
/// <summary>
/// Decrements <see cref="FormCount"/>. Calls <see cref="Application.Exit"/> if it reaches 0
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="FormClosedEventArgs"/></param>
private void CountedForm_FormClosed(object sender, FormClosedEventArgs e)
{
if (--FormCount == 0)
Application.Exit();
}
}
}
+134
View File
@@ -0,0 +1,134 @@
namespace TGControlPanel
{
partial class InstanceSelector
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
Cleanup();
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InstanceSelector));
this.InstanceListBox = new System.Windows.Forms.ListBox();
this.CreateInstanceButton = new System.Windows.Forms.Button();
this.ImportInstanceButton = new System.Windows.Forms.Button();
this.RenameInstanceButton = new System.Windows.Forms.Button();
this.DetachInstanceButton = new System.Windows.Forms.Button();
this.RefreshButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// InstanceListBox
//
this.InstanceListBox.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.InstanceListBox.FormattingEnabled = true;
this.InstanceListBox.Location = new System.Drawing.Point(13, 13);
this.InstanceListBox.Name = "InstanceListBox";
this.InstanceListBox.Size = new System.Drawing.Size(339, 238);
this.InstanceListBox.TabIndex = 0;
//
// CreateInstanceButton
//
this.CreateInstanceButton.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.CreateInstanceButton.Location = new System.Drawing.Point(358, 15);
this.CreateInstanceButton.Name = "CreateInstanceButton";
this.CreateInstanceButton.Size = new System.Drawing.Size(148, 25);
this.CreateInstanceButton.TabIndex = 14;
this.CreateInstanceButton.Text = "Create Instance";
this.CreateInstanceButton.UseVisualStyleBackColor = true;
this.CreateInstanceButton.Click += new System.EventHandler(this.CreateInstanceButton_Click);
//
// ImportInstanceButton
//
this.ImportInstanceButton.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.ImportInstanceButton.Location = new System.Drawing.Point(358, 45);
this.ImportInstanceButton.Name = "ImportInstanceButton";
this.ImportInstanceButton.Size = new System.Drawing.Size(148, 25);
this.ImportInstanceButton.TabIndex = 15;
this.ImportInstanceButton.Text = "Import Instance";
this.ImportInstanceButton.UseVisualStyleBackColor = true;
this.ImportInstanceButton.Click += new System.EventHandler(this.ImportInstanceButton_Click);
//
// RenameInstanceButton
//
this.RenameInstanceButton.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.RenameInstanceButton.Location = new System.Drawing.Point(358, 76);
this.RenameInstanceButton.Name = "RenameInstanceButton";
this.RenameInstanceButton.Size = new System.Drawing.Size(148, 25);
this.RenameInstanceButton.TabIndex = 16;
this.RenameInstanceButton.Text = "Rename Instance";
this.RenameInstanceButton.UseVisualStyleBackColor = true;
this.RenameInstanceButton.Click += new System.EventHandler(this.RenameInstanceButton_Click);
//
// DetachInstanceButton
//
this.DetachInstanceButton.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.DetachInstanceButton.Location = new System.Drawing.Point(358, 107);
this.DetachInstanceButton.Name = "DetachInstanceButton";
this.DetachInstanceButton.Size = new System.Drawing.Size(148, 25);
this.DetachInstanceButton.TabIndex = 17;
this.DetachInstanceButton.Text = "Detach Instance";
this.DetachInstanceButton.UseVisualStyleBackColor = true;
this.DetachInstanceButton.Click += new System.EventHandler(this.DetachInstanceButton_Click);
//
// RefreshButton
//
this.RefreshButton.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.RefreshButton.Location = new System.Drawing.Point(358, 226);
this.RefreshButton.Name = "RefreshButton";
this.RefreshButton.Size = new System.Drawing.Size(148, 25);
this.RefreshButton.TabIndex = 19;
this.RefreshButton.Text = "Refresh";
this.RefreshButton.UseVisualStyleBackColor = true;
this.RefreshButton.Click += new System.EventHandler(this.RefreshButton_Click);
//
// InstanceSelector
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(39)))), ((int)(((byte)(40)))), ((int)(((byte)(34)))));
this.ClientSize = new System.Drawing.Size(518, 261);
this.Controls.Add(this.RefreshButton);
this.Controls.Add(this.DetachInstanceButton);
this.Controls.Add(this.RenameInstanceButton);
this.Controls.Add(this.ImportInstanceButton);
this.Controls.Add(this.CreateInstanceButton);
this.Controls.Add(this.InstanceListBox);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "InstanceSelector";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Server Instances";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ListBox InstanceListBox;
private System.Windows.Forms.Button CreateInstanceButton;
private System.Windows.Forms.Button ImportInstanceButton;
private System.Windows.Forms.Button RenameInstanceButton;
private System.Windows.Forms.Button DetachInstanceButton;
private System.Windows.Forms.Button RefreshButton;
}
}
+214
View File
@@ -0,0 +1,214 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms;
using TGServiceInterface;
namespace TGControlPanel
{
/// <summary>
/// Form used for managing <see cref="TGServiceInterface.Components.ITGSService"/> <see cref="TGServiceInterface.Components.ITGInstance"/> manipulation functions
/// </summary>
partial class InstanceSelector : CountedForm
{
/// <summary>
/// The <see cref="Interface"/> we build instance connections from
/// </summary>
readonly Interface masterInterface;
/// <summary>
/// List of <see cref="InstanceMetadata"/> from <see cref="masterInterface"/>
/// </summary>
IList<InstanceMetadata> InstanceData;
public InstanceSelector(Interface I)
{
InitializeComponent();
InstanceListBox.MouseDoubleClick += InstanceListBox_MouseDoubleClick;
masterInterface = I;
RefreshInstances();
}
/// <summary>
/// Used to wrap <see cref="Interface"/> calls in a non-blocking fashion
/// </summary>
/// <param name="action">The <see cref="Interface"/> operation to wrap</param>
Task WrapServerOp(Action action)
{
Enabled = false;
UseWaitCursor = true;
try
{
return Task.Factory.StartNew(action);
}
finally
{
Enabled = true;
UseWaitCursor = false;
}
}
/// <summary>
/// Connects to a <see cref="TGServiceInterface.Components.ITGInstance"/> if it is double clicked in <see cref="InstanceListBox"/>
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="MouseEventArgs"/></param>
void InstanceListBox_MouseDoubleClick(object sender, MouseEventArgs e)
{
var index = InstanceListBox.IndexFromPoint(e.Location);
if (index != ListBox.NoMatches)
TryConnectToInstance(InstanceData[index].Name);
}
/// <summary>
/// Returns the <see cref="InstanceMetadata"/> associated with <see cref="InstanceListBox"/>'s current selected index
/// </summary>
/// <returns>The <see cref="InstanceMetadata"/> associated with <see cref="InstanceListBox"/>'s current selected index if it exists, <see langword="null"/> otherwise</returns>
InstanceMetadata GetSelectedInstanceMetadata()
{
var index = InstanceListBox.SelectedIndex;
return index != ListBox.NoMatches ? InstanceData[index] : null;
}
/// <summary>
/// Called by <see cref="Dispose(bool)"/>
/// </summary>
void Cleanup()
{
masterInterface.Dispose();
}
/// <summary>
/// Loads the <see cref="InstanceListBox"/> using <see cref="TGServiceInterface.Components.ITGSService.ListInstances"/>
/// </summary>
async void RefreshInstances()
{
InstanceListBox.Items.Clear();
await WrapServerOp(() => {
InstanceData = masterInterface.GetService().ListInstances();
});
foreach(var I in InstanceData)
InstanceListBox.Items.Add(String.Format("{0}: {1} - {2} - {3}", I.LoggingID, I.Name, I.Path, I.Enabled ? "ONLINE" : "OFFLINE"));
}
/// <summary>
/// Tries to start a <see cref="ControlPanel"/> for a given <paramref name="instanceName"/>
/// </summary>
/// <param name="instanceName">The name of the <see cref="TGServiceInterface.Components.ITGInstance"/> to connect to</param>
async void TryConnectToInstance(string instanceName)
{
var activeCP = ControlPanel.InstancesInUse[instanceName];
if(activeCP != null)
{
activeCP.BringToFront();
return;
}
var InstanceAccessor = new Interface(masterInterface);
try
{
ConnectivityLevel res = ConnectivityLevel.None;
await WrapServerOp(() => { res = InstanceAccessor.ConnectToInstance(instanceName); });
if (!res.HasFlag(ConnectivityLevel.Connected))
{
MessageBox.Show("Unable to connect to instance! Does it exist?");
RefreshInstances();
}
else if (!res.HasFlag(ConnectivityLevel.Authenticated))
MessageBox.Show("The current user is not authorized to access this instance!");
else
new ControlPanel(InstanceAccessor).Show();
}
catch
{
InstanceAccessor.Dispose();
throw;
}
}
/// <summary>
/// Prompts the user for parameters to <see cref="TGServiceInterface.Components.ITGSService.DetachInstance(string)"/>
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="EventArgs"/></param>
async void DetachInstanceButton_Click(object sender, EventArgs e)
{
var imd = GetSelectedInstanceMetadata();
if (imd == null)
return;
if (MessageBox.Show(String.Format("This will dissociate the server instance at \"{0}\"! Are you sure?", imd.Path), "Instance Detach", MessageBoxButtons.YesNo) != DialogResult.Yes)
return;
string res = null;
await WrapServerOp(() => { res = masterInterface.GetService().DetachInstance(imd.Name); });
if (res != null)
MessageBox.Show(res);
RefreshInstances();
}
/// <summary>
/// Calls <see cref="RefreshInstances"/>
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="EventArgs"/></param>
void RefreshButton_Click(object sender, EventArgs e)
{
RefreshInstances();
}
/// <summary>
/// Prompts the user for parameters to <see cref="TGServiceInterface.Components.ITGSService.RenameInstance(string, string)"/>
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="EventArgs"/></param>
async void RenameInstanceButton_Click(object sender, EventArgs e)
{
var imd = GetSelectedInstanceMetadata();
if (imd == null)
return;
var new_name = Program.TextPrompt("Instance Rename", "Enter a new name for the instance:");
if (new_name == null)
return;
if (imd.Enabled && MessageBox.Show(String.Format("This will temporarily offline the server instance! Are you sure?", imd.Path), "Instance Restart", MessageBoxButtons.YesNo) != DialogResult.Yes)
return;
string res = null;
await WrapServerOp(() => { res = masterInterface.GetService().RenameInstance(imd.Name, new_name); });
if (res != null)
MessageBox.Show(res);
RefreshInstances();
}
/// <summary>
/// Prompts the user for parameters to <see cref="TGServiceInterface.Components.ITGSService.ImportInstance(string)/>
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="EventArgs"/></param>
async void ImportInstanceButton_Click(object sender, EventArgs e)
{
var instance_path = Program.TextPrompt("Instance Import", "Enter the full path to the instance:");
if (instance_path == null)
return;
string res = null;
await WrapServerOp(() => { res = masterInterface.GetService().ImportInstance(instance_path); });
if (res != null)
MessageBox.Show(res);
RefreshInstances();
}
/// <summary>
/// Prompts the user for parameters to <see cref="TGServiceInterface.Components.ITGSService.CreateInstance(string, string)/>
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="EventArgs"/></param>
async void CreateInstanceButton_Click(object sender, EventArgs e)
{
var instance_name = Program.TextPrompt("Instance Creation", "Enter the name of the instance:");
if (instance_name == null)
return;
var instance_path = Program.TextPrompt("Instance Creation", "Enter the full path to the instance:");
if (instance_path == null)
return;
string res = null;
await WrapServerOp(() => { res = masterInterface.GetService().CreateInstance(instance_name, instance_path); });
if (res != null)
MessageBox.Show(res);
RefreshInstances();
}
}
}
File diff suppressed because it is too large Load Diff
+41 -17
View File
@@ -4,7 +4,7 @@ using TGServiceInterface;
namespace TGControlPanel
{
partial class Login : Form
partial class Login : CountedForm
{
/// <summary>
/// Create a <see cref="Login"/> form
@@ -53,30 +53,54 @@ namespace TGControlPanel
private void LocalLoginButton_Click(object sender, EventArgs e)
{
using (var I = new Interface())
{
Properties.Settings.Default.RemoteDefault = false;
VerifyAndConnect(I);
}
Properties.Settings.Default.RemoteDefault = false;
VerifyAndConnect(new Interface());
}
void VerifyAndConnect(Interface I)
{
var res = I.ConnectionStatus(out string error);
if (!res.HasFlag(ConnectivityLevel.Connected))
try
{
MessageBox.Show("Unable to connect to service! Error: " + error);
return;
var res = I.ConnectionStatus(out string error);
if (!res.HasFlag(ConnectivityLevel.Connected))
{
MessageBox.Show("Unable to connect to service! Error: " + error);
return;
}
if (!res.HasFlag(ConnectivityLevel.Authenticated))
{
MessageBox.Show("Authentication error: Username/password/windows identity is not authorized! Ensure you are a system administrator or in the correct Windows group on the service machine.");
return;
}
if (!res.HasFlag(ConnectivityLevel.Administrator))
{
while (true)
{
var InstanceToConnectTo = Program.TextPrompt("Select instance", "You do not have permission to list server instances. Please enter the name of the instance to connect to:");
if (InstanceToConnectTo == null)
return;
res = I.ConnectToInstance(InstanceToConnectTo);
if (!res.HasFlag(ConnectivityLevel.Connected))
MessageBox.Show("Unable to connect to instance! Does it exist?");
else if (!res.HasFlag(ConnectivityLevel.Authenticated))
MessageBox.Show("The current user is not authorized to access this instance!");
else
break;
}
new ControlPanel(I).Show();
}
else
new InstanceSelector(I).Show();
Close();
}
if (!res.HasFlag(ConnectivityLevel.Authenticated))
catch
{
MessageBox.Show("Authentication error: Username/password/windows identity is not authorized! Ensure you are a system administrator or in the correct Windows group on the service machine.");
return;
I.Dispose();
throw;
}
Hide();
using (var M = new ControlPanel(I))
M.ShowDialog();
Close();
}
private void SavePasswordCheckBox_CheckedChanged(object sender, EventArgs e)
+3 -2
View File
@@ -19,8 +19,9 @@ namespace TGControlPanel
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
using(var L = new Login())
Application.Run(L);
var login = new Login();
login.Show();
Application.Run();
}
catch (Exception e)
{
+12
View File
@@ -55,6 +55,15 @@
<Compile Include="ControlPanel\ChatPage.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="CountedForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="InstanceSelector.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="InstanceSelector.Designer.cs">
<DependentUpon>InstanceSelector.cs</DependentUpon>
</Compile>
<Compile Include="Login.cs">
<SubType>Form</SubType>
</Compile>
@@ -84,6 +93,9 @@
<Compile Include="ControlPanel\StaticPage.cs">
<SubType>Form</SubType>
</Compile>
<EmbeddedResource Include="InstanceSelector.resx">
<DependentUpon>InstanceSelector.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Login.resx">
<DependentUpon>Login.cs</DependentUpon>
</EmbeddedResource>