Files
TeslaSuite/Console/TeslaConsole/SiteManagement.cs
T
CydandClaude Opus 4.8 a91d31913e Remove redundant "Push to selected pods now" checkbox from Add Product
Deployment intent is now implied by the install package field: if a package is
supplied the product is installed to the selected pods after being added; if not,
it is only added to the catalog. Removes the checkbox (dlgAddProduct) and the
push-decision branch (AddProduct_Click). The register-only-without-package path is
retired with it, so the now-dead RegisterProductOnSelectedPods is removed too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 20:36:30 -05:00

1387 lines
47 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;
using System.Windows.Forms;
using Microsoft.VisualBasic;
using Tesla.Net;
using TeslaConsole.Properties;
namespace TeslaConsole;
public class SiteManagement : Form
{
private class PodData
{
public Pod Pod;
public PodInfo Conn;
public string Squad;
public PingReply PingReply;
public int pings;
public Size? Install_CustomResolution;
public List<PodInstallType> Install_HostTypes = new List<PodInstallType>();
public bool OperationInProgress;
public int PercentProgress = -1;
public string Status = "";
public Exception Error;
private SiteManagement Parent;
private Thread PingThread;
private bool Running = true;
public PodData(Pod pod, string squad, SiteManagement parent)
{
Pod = pod;
Squad = squad;
if (pod.IsLocal)
{
Conn = new PodInfo(pod);
Conn.ConnectCompleted += parent.PodInfo_ConnectCompleted;
Conn.InstallProductCompleted += parent.PodInfo_InstallProductCompleted;
Conn.UninstallProductCompleted += parent.PodInfo_UninstallProductCompleted;
}
Parent = parent;
PingThread = new Thread(Ping);
PingThread.Name = pod.Name + " - Ping Thread";
PingThread.IsBackground = true;
}
public void StartPing()
{
PingThread.Start();
}
public void StopPing()
{
Running = false;
}
private void Ping()
{
Ping ping = new Ping();
while (Running)
{
if (!OperationInProgress)
{
PingReply = ping.Send(Pod.IPAddress, 5000);
pings++;
Parent.Pod_PingCompleted(this);
}
Thread.Sleep(1000);
}
}
}
private enum PodInstallType
{
GameClient,
LiveCamera,
MissionReview
}
private IContainer components;
private DataGridView dgvPods;
private ContextMenuStrip cmnuDataGrid;
private ToolStripMenuItem installProductToolStripMenuItem;
private ToolStripMenuItem importSiteConfigurationToolStripMenuItem;
private ToolStripMenuItem exportSiteConfigurationToolStripMenuItem;
private OpenFileDialog dlgOpenFile;
private SaveFileDialog dlgSaveFile;
private OpenFileDialog dlgSelectPackage;
private FlowLayoutPanel flpPodsToConfigure;
private ToolStripMenuItem deletePodToolStripMenuItem;
private ToolStripMenuItem resendPodConfigurationToolStripMenuItem;
private DataGridViewCheckBoxColumn colIsLocal;
private DataGridViewTextBoxColumn colPodName;
private DataGridViewComboBoxColumn colSquad;
private DataGridViewComboBoxColumn colType;
private DataGridViewTextBoxColumn colMacAddress;
private DataGridViewTextBoxColumn colIPAddress;
private DataGridViewTextBoxColumn colSubnet;
private DataGridViewTextBoxColumn colGateway;
private DataGridViewTextBoxColumn colDNSServer;
private DataGridViewTextBoxColumn colHostName;
private DataGridViewTextBoxColumn colOperationProgress;
private ToolStripMenuItem uninstallProductToolStripMenuItem;
public static readonly Guid RPAppGuid = new Guid("7D241B1F-AB6D-4e08-9C20-12294E743D94");
public static readonly Guid RPMRAppGuid = new Guid("8F71D5C2-38E4-413c-8E22-88CAD08774D2");
public static readonly Guid RPLCAppGuid = new Guid("57A0B3C2-D5CF-46d6-ABED-A8F4A26AB086");
public static readonly Guid MW4AppGuid = new Guid("CC8500ED-A653-45a7-BEF8-C332D30371A6");
public static readonly Guid MW4LCAppGuid = new Guid("8EE93A6C-F16A-49be-B867-37FAE9087FFF");
private Site mSite;
private List<PodData> mPods = new List<PodData>();
private PodData mPodInEdit;
private int mRowInEdit = -1;
private Dictionary<Guid, Pod> mReconfiguringPods = new Dictionary<Guid, Pod>();
private Dictionary<string, Button> mConfigureButtons = new Dictionary<string, Button>();
private Dictionary<Guid, Label> mConfigureLabels = new Dictionary<Guid, Label>();
private static bool mIsOpen = false;
public static bool IsOpen => mIsOpen;
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle = new System.Windows.Forms.DataGridViewCellStyle();
this.dgvPods = new System.Windows.Forms.DataGridView();
this.colIsLocal = new System.Windows.Forms.DataGridViewCheckBoxColumn();
this.colPodName = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colSquad = new System.Windows.Forms.DataGridViewComboBoxColumn();
this.colType = new System.Windows.Forms.DataGridViewComboBoxColumn();
this.colMacAddress = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colIPAddress = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colSubnet = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colGateway = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colDNSServer = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colHostName = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colOperationProgress = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.cmnuDataGrid = new System.Windows.Forms.ContextMenuStrip(this.components);
this.deletePodToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.installProductToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.uninstallProductToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.resendPodConfigurationToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.importSiteConfigurationToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exportSiteConfigurationToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.dlgOpenFile = new System.Windows.Forms.OpenFileDialog();
this.dlgSaveFile = new System.Windows.Forms.SaveFileDialog();
this.dlgSelectPackage = new System.Windows.Forms.OpenFileDialog();
this.flpPodsToConfigure = new System.Windows.Forms.FlowLayoutPanel();
((System.ComponentModel.ISupportInitialize)this.dgvPods).BeginInit();
this.cmnuDataGrid.SuspendLayout();
base.SuspendLayout();
this.dgvPods.AllowUserToResizeRows = false;
dataGridViewCellStyle.BackColor = System.Drawing.Color.FromArgb(225, 225, 255);
this.dgvPods.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle;
this.dgvPods.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
this.dgvPods.BackgroundColor = System.Drawing.Color.White;
this.dgvPods.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.dgvPods.ClipboardCopyMode = System.Windows.Forms.DataGridViewClipboardCopyMode.Disable;
this.dgvPods.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dgvPods.Columns.AddRange(this.colIsLocal, this.colPodName, this.colSquad, this.colType, this.colMacAddress, this.colIPAddress, this.colSubnet, this.colGateway, this.colDNSServer, this.colHostName, this.colOperationProgress);
this.dgvPods.ContextMenuStrip = this.cmnuDataGrid;
this.dgvPods.Location = new System.Drawing.Point(12, 12);
this.dgvPods.Name = "dgvPods";
this.dgvPods.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
this.dgvPods.Size = new System.Drawing.Size(1106, 395);
this.dgvPods.TabIndex = 0;
this.dgvPods.VirtualMode = true;
this.dgvPods.UserDeletingRow += new System.Windows.Forms.DataGridViewRowCancelEventHandler(dgvPods_UserDeletingRow);
this.dgvPods.CellMouseClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(dgvPods_CellMouseClick);
this.dgvPods.CancelRowEdit += new System.Windows.Forms.QuestionEventHandler(dgvPods_CancelRowEdit);
this.dgvPods.CellValueNeeded += new System.Windows.Forms.DataGridViewCellValueEventHandler(dgvPods_CellValueNeeded);
this.dgvPods.CellFormatting += new System.Windows.Forms.DataGridViewCellFormattingEventHandler(dgvPods_CellFormatting);
this.dgvPods.CellValidating += new System.Windows.Forms.DataGridViewCellValidatingEventHandler(dgvPods_CellValidating);
this.dgvPods.RowValidated += new System.Windows.Forms.DataGridViewCellEventHandler(dgvPods_RowValidated);
this.dgvPods.CellPainting += new System.Windows.Forms.DataGridViewCellPaintingEventHandler(dgvPods_CellPainting);
this.dgvPods.CellValuePushed += new System.Windows.Forms.DataGridViewCellValueEventHandler(dgvPods_CellValuePushed);
this.dgvPods.NewRowNeeded += new System.Windows.Forms.DataGridViewRowEventHandler(dgvPods_NewRowNeeded);
this.colIsLocal.HeaderText = "Local";
this.colIsLocal.MinimumWidth = 40;
this.colIsLocal.Name = "colIsLocal";
this.colIsLocal.ReadOnly = true;
this.colIsLocal.Resizable = System.Windows.Forms.DataGridViewTriState.False;
this.colIsLocal.Width = 40;
this.colPodName.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.colPodName.HeaderText = "Pod";
this.colPodName.MinimumWidth = 100;
this.colPodName.Name = "colPodName";
this.colSquad.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.colSquad.HeaderText = "Squad";
this.colSquad.MinimumWidth = 75;
this.colSquad.Name = "colSquad";
this.colSquad.Width = 75;
this.colType.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.colType.HeaderText = "Type";
this.colType.MinimumWidth = 100;
this.colType.Name = "colType";
this.colMacAddress.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.colMacAddress.HeaderText = "MAC Address";
this.colMacAddress.MinimumWidth = 75;
this.colMacAddress.Name = "colMacAddress";
this.colMacAddress.ReadOnly = true;
this.colMacAddress.Width = 88;
this.colIPAddress.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.colIPAddress.HeaderText = "IP Address";
this.colIPAddress.MinimumWidth = 75;
this.colIPAddress.Name = "colIPAddress";
this.colIPAddress.ReadOnly = true;
this.colIPAddress.Width = 77;
this.colSubnet.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.colSubnet.HeaderText = "Subnet Mask";
this.colSubnet.MinimumWidth = 75;
this.colSubnet.Name = "colSubnet";
this.colSubnet.ReadOnly = true;
this.colSubnet.Width = 88;
this.colGateway.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.colGateway.HeaderText = "Default Gateway";
this.colGateway.MinimumWidth = 75;
this.colGateway.Name = "colGateway";
this.colGateway.ReadOnly = true;
this.colGateway.Width = 102;
this.colDNSServer.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.colDNSServer.HeaderText = "DNS Server";
this.colDNSServer.MinimumWidth = 75;
this.colDNSServer.Name = "colDNSServer";
this.colDNSServer.ReadOnly = true;
this.colDNSServer.Width = 82;
this.colHostName.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.colHostName.HeaderText = "Host Name";
this.colHostName.MinimumWidth = 75;
this.colHostName.Name = "colHostName";
this.colHostName.ReadOnly = true;
this.colHostName.Width = 79;
this.colOperationProgress.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
this.colOperationProgress.HeaderText = "Operation Progress";
this.colOperationProgress.MinimumWidth = 150;
this.colOperationProgress.Name = "colOperationProgress";
this.colOperationProgress.ReadOnly = true;
this.colOperationProgress.Resizable = System.Windows.Forms.DataGridViewTriState.True;
this.colOperationProgress.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
this.cmnuDataGrid.Items.AddRange(new System.Windows.Forms.ToolStripItem[6] { this.deletePodToolStripMenuItem, this.installProductToolStripMenuItem, this.uninstallProductToolStripMenuItem, this.resendPodConfigurationToolStripMenuItem, this.importSiteConfigurationToolStripMenuItem, this.exportSiteConfigurationToolStripMenuItem });
this.cmnuDataGrid.Name = "cmnuDataGrid";
this.cmnuDataGrid.Size = new System.Drawing.Size(219, 136);
this.cmnuDataGrid.Opening += new System.ComponentModel.CancelEventHandler(cmnuDataGrid_Opening);
this.deletePodToolStripMenuItem.Image = TeslaConsole.Properties.Resources.DeleteHS;
this.deletePodToolStripMenuItem.Name = "deletePodToolStripMenuItem";
this.deletePodToolStripMenuItem.Size = new System.Drawing.Size(218, 22);
this.deletePodToolStripMenuItem.Text = "Delete";
this.deletePodToolStripMenuItem.Click += new System.EventHandler(deletePodToolStripMenuItem_Click);
this.installProductToolStripMenuItem.Image = TeslaConsole.Properties.Resources.install;
this.installProductToolStripMenuItem.Name = "installProductToolStripMenuItem";
this.installProductToolStripMenuItem.Size = new System.Drawing.Size(218, 22);
this.installProductToolStripMenuItem.Text = "Install Product";
// Install Product children are built dynamically from AppRegistry (see BuildInstallProductMenu).
this.uninstallProductToolStripMenuItem.Name = "uninstallProductToolStripMenuItem";
this.uninstallProductToolStripMenuItem.Size = new System.Drawing.Size(218, 22);
this.uninstallProductToolStripMenuItem.Text = "Uninstall Product";
this.resendPodConfigurationToolStripMenuItem.Name = "resendPodConfigurationToolStripMenuItem";
this.resendPodConfigurationToolStripMenuItem.Size = new System.Drawing.Size(218, 22);
this.resendPodConfigurationToolStripMenuItem.Text = "Reconfigure...";
this.resendPodConfigurationToolStripMenuItem.Visible = false;
this.resendPodConfigurationToolStripMenuItem.Click += new System.EventHandler(resendPodConfigurationToolStripMenuItem_Click);
this.importSiteConfigurationToolStripMenuItem.Image = TeslaConsole.Properties.Resources.openHS;
this.importSiteConfigurationToolStripMenuItem.Name = "importSiteConfigurationToolStripMenuItem";
this.importSiteConfigurationToolStripMenuItem.Size = new System.Drawing.Size(218, 22);
this.importSiteConfigurationToolStripMenuItem.Text = "Import Site Configuration...";
this.importSiteConfigurationToolStripMenuItem.Click += new System.EventHandler(importSiteConfigurationToolStripMenuItem_Click);
this.exportSiteConfigurationToolStripMenuItem.Image = TeslaConsole.Properties.Resources.saveHS;
this.exportSiteConfigurationToolStripMenuItem.Name = "exportSiteConfigurationToolStripMenuItem";
this.exportSiteConfigurationToolStripMenuItem.Size = new System.Drawing.Size(218, 22);
this.exportSiteConfigurationToolStripMenuItem.Text = "Export Site Configuration...";
this.exportSiteConfigurationToolStripMenuItem.Click += new System.EventHandler(exportSiteConfigurationToolStripMenuItem_Click);
this.dlgOpenFile.DefaultExt = "siteconfig";
this.dlgOpenFile.Filter = "Site Configuration Files (*.siteconfig)|*.siteconfig|All Files (*.*)|*.*";
this.dlgOpenFile.Title = "Import Configuration";
this.dlgSaveFile.DefaultExt = "siteconfig";
this.dlgSaveFile.Filter = "Site Configuration Files (*.siteconfig)|*.siteconfig|All Files (*.*)|*.*";
this.dlgSaveFile.Title = "Export Configuration";
this.dlgSelectPackage.Filter = "VWE Install Archive (*.zip)|*.zip|All Files (*.*)|*.*";
this.dlgSelectPackage.Title = "Select Package to Install";
this.flpPodsToConfigure.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
this.flpPodsToConfigure.Location = new System.Drawing.Point(12, 413);
this.flpPodsToConfigure.Name = "flpPodsToConfigure";
this.flpPodsToConfigure.Size = new System.Drawing.Size(1106, 27);
this.flpPodsToConfigure.TabIndex = 1;
base.AutoScaleDimensions = new System.Drawing.SizeF(6f, 13f);
base.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
base.ClientSize = new System.Drawing.Size(1130, 452);
base.Controls.Add(this.flpPodsToConfigure);
base.Controls.Add(this.dgvPods);
base.Name = "SiteManagement";
base.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Site Management";
base.Load += new System.EventHandler(SiteManagement_Load);
base.FormClosing += new System.Windows.Forms.FormClosingEventHandler(SiteManagement_FormClosing);
((System.ComponentModel.ISupportInitialize)this.dgvPods).EndInit();
this.cmnuDataGrid.ResumeLayout(false);
base.ResumeLayout(false);
}
public SiteManagement()
{
InitializeComponent();
LoadConfiguration(TeslaConsole.Site.Active);
BuildInstallProductMenu();
foreach (string activeConfigRequest in PodManager.ActiveConfigRequests)
{
PodManager_PodReadyForConfig(activeConfigRequest, PodManager.GetMacAddressForRequest(activeConfigRequest));
}
PodManager.PodReadyForConfig += PodManager_PodReadyForConfig;
PodManager.PodConfigured += PodManager_PodConfigured;
}
protected override void OnClosing(CancelEventArgs e)
{
if (dgvPods.IsCurrentCellInEditMode)
{
MessageBox.Show("You can not close this window while a cell is being edited.", "Currently Editing", MessageBoxButtons.OK);
e.Cancel = true;
}
base.OnClosing(e);
}
private void PodManager_PodReadyForConfig(string requestId, byte[] macAddress)
{
if (base.InvokeRequired)
{
Invoke(new PodManager.PodReadyConfigHandler(PodManager_PodReadyForConfig), requestId, macAddress);
return;
}
PodData podData = null;
foreach (PodData mPod in mPods)
{
if (mPod.Pod.MacAddressEquals(macAddress))
{
podData = mPod;
break;
}
}
Button button = new Button();
button.Image = Resources.PodOffline16;
if (podData == null)
{
button.Text = "Configure " + requestId;
button.Tag = new Tuple<string, byte[]>(requestId, macAddress);
}
else
{
button.Text = "Configure " + podData.Pod.Name;
button.Tag = new Tuple<string, PodData>(requestId, podData);
}
button.ImageAlign = ContentAlignment.MiddleLeft;
button.TextAlign = ContentAlignment.MiddleLeft;
button.TextImageRelation = TextImageRelation.ImageBeforeText;
button.AutoSize = true;
button.AutoSizeMode = AutoSizeMode.GrowAndShrink;
button.Click += ConfigureButton_Click;
flpPodsToConfigure.Controls.Add(button);
}
private void PodManager_PodConfigured(string requestId, byte[] macAddress)
{
if (mConfigureButtons.ContainsKey(requestId))
{
Button value = mConfigureButtons[requestId];
mConfigureButtons.Remove(requestId);
flpPodsToConfigure.Controls.Remove(value);
}
}
private void ConfigureButton_Click(object sender, EventArgs e)
{
Button button = sender as Button;
if (button.Tag is Tuple<string, PodData>)
{
Tuple<string, PodData> tuple = button.Tag as Tuple<string, PodData>;
string text = Interaction.InputBox("Enter passphrase for " + tuple.B.Pod.Name, "Configure " + tuple.B.Pod.Name);
if (!string.IsNullOrEmpty(text))
{
Label label = new Label();
label.Text = "Configuring " + tuple.B.Pod.Name + "...";
label.AutoSize = false;
label.Size = new Size((int)((double)button.Width * 1.5), button.Height);
label.BorderStyle = BorderStyle.FixedSingle;
label.BackColor = Color.SkyBlue;
label.TextAlign = ContentAlignment.MiddleLeft;
flpPodsToConfigure.Controls.Remove(button);
mConfigureButtons.Remove(tuple.A);
flpPodsToConfigure.Controls.Add(label);
mConfigureLabels.Add(tuple.B.Pod.ID, label);
// Reconfiguring an already-known pod (e.g. after a launcher reinstall):
// pause its ping/connect loop and drop any stale connection to its old IP,
// so the console isn't racing SecureConfig for that address. Resumed when
// configuration completes (see ConfigureWorker_RunWorkerCompleted).
tuple.B.OperationInProgress = true;
tuple.B.Conn?.Disconnect();
ConfigurePod(tuple.A, text.ToUpper(), tuple.B.Pod, tuple.B.Squad);
}
}
else
{
if (!(button.Tag is Tuple<string, byte[]>))
{
return;
}
Tuple<string, byte[]> tuple2 = button.Tag as Tuple<string, byte[]>;
Pod pod = new Pod();
pod.MacAddress = tuple2.B;
SetupPod setupPod;
string text2;
while (true)
{
setupPod = new SetupPod(tuple2.A, pod, TeslaConsole.Site.Active.Squads);
if (setupPod.ShowDialog(this) == DialogResult.OK)
{
Label label2 = new Label();
label2.Text = "Configuring " + pod.Name + "...";
label2.AutoSize = false;
label2.Size = new Size((int)((double)button.Width * 1.5), button.Height);
label2.BorderStyle = BorderStyle.FixedSingle;
label2.BackColor = Color.SlateBlue;
flpPodsToConfigure.Controls.Remove(button);
mConfigureButtons.Remove(tuple2.A);
flpPodsToConfigure.Controls.Add(label2);
mConfigureLabels.Add(pod.ID, label2);
text2 = setupPod.Squad.Name;
if (!(setupPod.Squad.Guid == Guid.Empty))
{
break;
}
text2 = Interaction.InputBox("Enter the name of the new squad:", "New Squad");
if (!string.IsNullOrEmpty(text2))
{
Squad squad = new Squad(setupPod.Squad.Name);
TeslaConsole.Site.Active.Squads.Add(squad);
colSquad.Items.Add(squad.Name);
break;
}
}
}
ConfigurePod(tuple2.A, setupPod.Passphrase, setupPod.Pod, text2);
}
}
private void ConfigurePod(string requestId, string passphrase, Pod pod, string squadName)
{
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += ConfigureWorker_DoWork;
backgroundWorker.RunWorkerCompleted += ConfigureWorker_RunWorkerCompleted;
backgroundWorker.RunWorkerAsync(new Tuple<string, string, Pod, string>(requestId, passphrase, pod, squadName));
}
private void ConfigureWorker_DoWork(object sender, DoWorkEventArgs e)
{
Tuple<string, string, Pod, string> tuple = (Tuple<string, string, Pod, string>)e.Argument;
tuple.C.Key = PodManager.ConfigurePod(tuple.A, tuple.B, tuple.C);
if (tuple.C.Key == null)
{
e.Result = new PodConfigurationException("Passphrase was incorrect.", tuple.C);
}
else
{
e.Result = new Tuple<Pod, string>(tuple.C, tuple.D);
}
}
private void ConfigureWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Result is PodConfigurationException)
{
PodConfigurationException ex = e.Result as PodConfigurationException;
MessageBox.Show(this, "There was an error configuring " + ex.Pod.Name + ":" + Environment.NewLine + ex.Message, "Configure " + ex.Pod.Name, MessageBoxButtons.OK, MessageBoxIcon.Hand);
Label value = mConfigureLabels[ex.Pod.ID];
flpPodsToConfigure.Controls.Remove(value);
mConfigureLabels.Remove(ex.Pod.ID);
// If this was a known pod, resume its ping/connect loop (paused before SecureConfig).
foreach (PodData mPod in mPods)
{
if (mPod.Pod.ID == ex.Pod.ID) { mPod.OperationInProgress = false; break; }
}
}
else
{
if (!(e.Result is Tuple<Pod, string>))
{
return;
}
Tuple<Pod, string> tuple = e.Result as Tuple<Pod, string>;
MessageBox.Show(this, tuple.A.Name + " successfully configured!", "Configure " + tuple.A.Name, MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
Label value2 = mConfigureLabels[tuple.A.ID];
flpPodsToConfigure.Controls.Remove(value2);
mConfigureLabels.Remove(tuple.A.ID);
foreach (PodData mPod in mPods)
{
if (mPod.Pod.ID == tuple.A.ID)
{
// Existing pod reconfigured: resume its ping/connect loop so the console
// reconnects with the new session key (paused before SecureConfig).
mPod.OperationInProgress = false;
return;
}
}
PodData podData = new PodData(tuple.A, tuple.B, this);
podData.StartPing();
mPods.Add(podData);
List<PodData> list = new List<PodData>(mPods);
dgvPods.Rows.Clear();
mPods.Clear();
mPods = list;
dgvPods.RowCount = mPods.Count + 1;
}
}
private void SiteManagement_Load(object sender, EventArgs e)
{
mIsOpen = true;
}
private void SiteManagement_FormClosing(object sender, FormClosingEventArgs e)
{
foreach (PodData mPod in mPods)
{
if (e.CloseReason == CloseReason.UserClosing && mPod.OperationInProgress && mPod.Status.StartsWith("Installing"))
{
MessageBox.Show(this, "Site Management cannot be closed while installations are in progress.", "Site Management", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
e.Cancel = true;
return;
}
}
PodManager.PodReadyForConfig -= PodManager_PodReadyForConfig;
foreach (Squad squad in mSite.Squads)
{
squad.Pods.Clear();
}
foreach (PodData mPod2 in mPods)
{
mPod2.StopPing();
foreach (Squad squad2 in mSite.Squads)
{
if (squad2.Name == mPod2.Squad)
{
squad2.Pods.Add(mPod2.Pod);
}
}
}
mSite.Save();
mIsOpen = false;
}
private void dgvPods_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (colOperationProgress.Index != e.ColumnIndex || e.RowIndex < 0 || e.RowIndex >= mPods.Count || (string)e.FormattedValue != "draw_progress")
{
return;
}
e.Handled = true;
e.PaintBackground(e.ClipBounds, cellsPaintSelectionBackground: false);
PodData podData = mPods[e.RowIndex];
Rectangle rectangle = Rectangle.Inflate(e.CellBounds, -3, -3);
Rectangle rectangle2 = new Rectangle(rectangle.Location, rectangle.Size);
rectangle2.Inflate(-1, -1);
if (podData.PercentProgress >= 0)
{
rectangle2.Width = (int)Math.Round((double)podData.PercentProgress / 100.0 * (double)rectangle2.Width);
if (ProgressBarRenderer.IsSupported)
{
ProgressBarRenderer.DrawHorizontalBar(e.Graphics, rectangle);
ProgressBarRenderer.DrawHorizontalChunks(e.Graphics, rectangle2);
}
else
{
e.Graphics.FillRectangle(Brushes.LightGray, rectangle);
e.Graphics.FillRectangle(Brushes.Green, rectangle2);
e.Graphics.DrawRectangle(Pens.Black, rectangle);
}
}
StringFormat stringFormat = new StringFormat(StringFormatFlags.NoWrap);
stringFormat.Alignment = StringAlignment.Near;
stringFormat.LineAlignment = StringAlignment.Center;
e.Graphics.DrawString(podData.Status, Font, Brushes.Black, rectangle, stringFormat);
}
private void dgvPods_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.RowIndex < 0)
{
return;
}
if (colMacAddress.Index == e.ColumnIndex)
{
if (e.Value is byte[] array)
{
string[] array2 = new string[array.Length];
for (int i = 0; i < array2.Length; i++)
{
array2[i] = array[i].ToString("x2");
}
e.Value = string.Join("-", array2);
e.FormattingApplied = true;
}
}
else
{
if (colOperationProgress.Index != e.ColumnIndex)
{
return;
}
if (e.RowIndex < mPods.Count && mPods[e.RowIndex].Pod.IsLocal)
{
PodData podData = mPods[e.RowIndex];
if (podData.Error != null)
{
e.Value = "Install Failed";
e.CellStyle.BackColor = Color.Red;
e.CellStyle.ForeColor = Color.White;
}
else if (!podData.OperationInProgress)
{
if (podData.PingReply == null)
{
e.Value = "Idle. [pinging...]";
}
else if (podData.PingReply.Status == IPStatus.Success)
{
if (!podData.Conn.IsConnected)
{
e.Value = "Could not connect to pod service.";
}
else
{
e.Value = $"Idle [{podData.PingReply.RoundtripTime} ms]";
}
}
else
{
e.Value = $"Pod unreachable. Ping result: {podData.PingReply.Status}";
}
}
else
{
e.Value = "draw_progress";
}
}
else
{
e.Value = "";
}
e.FormattingApplied = true;
}
}
private void dgvPods_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if (e.ColumnIndex < 0 || e.RowIndex < 0 || e.RowIndex >= dgvPods.Rows.Count)
{
return;
}
DataGridViewRow dataGridViewRow = dgvPods.Rows[e.RowIndex];
if (e.ColumnIndex >= dataGridViewRow.Cells.Count)
{
return;
}
DataGridViewCell dataGridViewCell = dataGridViewRow.Cells[e.ColumnIndex];
if (e.ColumnIndex == colPodName.Index)
{
if (!dgvPods.Rows[e.RowIndex].IsNewRow && (e.FormattedValue == null || (string)e.FormattedValue == ""))
{
dataGridViewCell.ErrorText = "Pod name cannot be blank";
}
else
{
dataGridViewCell.ErrorText = "";
}
}
}
private void dgvPods_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right && e.RowIndex >= 0 && e.RowIndex < dgvPods.Rows.Count && e.RowIndex != dgvPods.NewRowIndex)
{
if (dgvPods.SelectedRows.Count > 0)
{
dgvPods.SelectedRows[0].Selected = false;
}
dgvPods.Rows[e.RowIndex].Selected = true;
int num = ((e.ColumnIndex >= 0) ? dgvPods.GetColumnDisplayRectangle(e.ColumnIndex, cutOverflow: true).X : (num = e.Location.X));
int num2 = dgvPods.GetRowDisplayRectangle(e.RowIndex, cutOverflow: true).Y;
cmnuDataGrid.Show(dgvPods, num + e.X, num2 + e.Y);
}
}
private void dgvPods_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
if (e.RowIndex != dgvPods.Rows.Count - 1)
{
PodData podData = ((e.RowIndex != mRowInEdit) ? mPods[e.RowIndex] : mPodInEdit);
if (e.ColumnIndex == colIsLocal.Index)
{
e.Value = podData.Pod.IsLocal;
}
else if (e.ColumnIndex == colPodName.Index)
{
e.Value = podData.Pod.Name;
}
else if (e.ColumnIndex == colSquad.Index)
{
e.Value = podData.Squad;
}
else if (e.ColumnIndex == colType.Index)
{
e.Value = (HostTypeHelper)podData.Pod.HostType;
}
else if (e.ColumnIndex == colMacAddress.Index)
{
e.Value = podData.Pod.MacAddress;
}
else if (e.ColumnIndex == colIPAddress.Index)
{
e.Value = podData.Pod.IPAddress;
dgvPods.Rows[e.RowIndex].Cells[e.ColumnIndex].ReadOnly = podData.Pod.IsLocal;
}
else if (e.ColumnIndex == colSubnet.Index)
{
e.Value = podData.Pod.Subnet;
}
else if (e.ColumnIndex == colGateway.Index)
{
e.Value = podData.Pod.Gateway;
}
else if (e.ColumnIndex == colDNSServer.Index)
{
e.Value = podData.Pod.DNS;
}
else if (e.ColumnIndex == colHostName.Index)
{
e.Value = podData.Pod.HostName;
}
}
}
private void dgvPods_CellValuePushed(object sender, DataGridViewCellValueEventArgs e)
{
PodData podData = null;
if (e.RowIndex < mPods.Count)
{
if (mPodInEdit == null)
{
mPodInEdit = new PodData(mPods[e.RowIndex].Pod.Clone(), mPods[e.RowIndex].Squad, this);
}
podData = mPodInEdit;
mRowInEdit = e.RowIndex;
}
else
{
podData = mPodInEdit;
}
if (e.ColumnIndex == colPodName.Index)
{
podData.Pod.Name = (string)e.Value;
}
else if (e.ColumnIndex == colSquad.Index)
{
podData.Squad = (string)e.Value;
}
else if (e.ColumnIndex == colType.Index)
{
podData.Pod.HostType = ((e.Value is string) ? HostTypeHelper.Parse((string)e.Value).HostType : ((HostTypeHelper)e.Value).HostType);
}
else if (e.ColumnIndex == colIPAddress.Index)
{
if (IPAddress.TryParse((string)e.Value, out var address))
{
podData.Pod.IPAddress = address;
}
else
{
MessageBox.Show("Address could not be parsed.", "Parsing Error", MessageBoxButtons.OK);
}
}
}
private void dgvPods_NewRowNeeded(object sender, DataGridViewRowEventArgs e)
{
mPodInEdit = new PodData(new Pod(), (mSite.Squads.Count > 0) ? mSite.Squads[0].Name : "", this);
mRowInEdit = dgvPods.Rows.Count - 1;
e.Row.Cells[colIPAddress.Index].ReadOnly = false;
}
private void dgvPods_RowValidated(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= mPods.Count && e.RowIndex != dgvPods.Rows.Count - 1)
{
if (mPodInEdit.Pod.IsLocal)
{
mPodInEdit.StartPing();
}
mPods.Add(mPodInEdit);
mPodInEdit = null;
mRowInEdit = -1;
}
else if (mPodInEdit != null && e.RowIndex < mPods.Count)
{
if (mPodInEdit.Pod.IsLocal)
{
mPodInEdit.StartPing();
}
if (mPods[e.RowIndex] != null)
{
mPods[e.RowIndex].StopPing();
}
mPods[e.RowIndex] = mPodInEdit;
mPodInEdit = null;
mRowInEdit = -1;
}
else if (dgvPods.ContainsFocus)
{
mPodInEdit = null;
mRowInEdit = -1;
}
}
private void dgvPods_CancelRowEdit(object sender, QuestionEventArgs e)
{
if (mRowInEdit == dgvPods.Rows.Count - 2 && mRowInEdit == mPods.Count)
{
mPodInEdit = new PodData(new Pod(), mSite.Squads[0].Name, this);
return;
}
mPodInEdit = null;
mRowInEdit = -1;
}
private void dgvPods_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
{
if (e.Row.Index < mPods.Count)
{
if (mPods[e.Row.Index].OperationInProgress)
{
e.Cancel = true;
return;
}
Pod pod = mPods[e.Row.Index].Pod;
if (MessageBox.Show(this, "Are you sure you want to delete " + pod.Name + "?", "Site Management", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
e.Cancel = true;
return;
}
mPods[e.Row.Index].StopPing();
mPods.RemoveAt(e.Row.Index);
}
if (e.Row.Index == mRowInEdit)
{
mRowInEdit = -1;
mPodInEdit = null;
}
}
private void cmnuDataGrid_Opening(object sender, CancelEventArgs e)
{
int num = 0;
int num2 = 0;
List<LaunchData> list = null;
foreach (DataGridViewRow selectedRow in dgvPods.SelectedRows)
{
if (selectedRow.Index >= mPods.Count)
{
continue;
}
if (mPods[selectedRow.Index].Pod.IsLocal && !mPods[selectedRow.Index].OperationInProgress && mPods[selectedRow.Index].PingReply != null && mPods[selectedRow.Index].PingReply.Status == IPStatus.Success && mPods[selectedRow.Index].Conn.IsConnected)
{
num++;
}
if (!mPods[selectedRow.Index].OperationInProgress)
{
num2++;
}
if (list == null)
{
list = new List<LaunchData>();
if (mPods[selectedRow.Index].Pod.IsLocal)
{
LaunchData[] allApplications = mPods[selectedRow.Index].Conn.AllApplications;
if (allApplications != null)
{
list.AddRange(allApplications);
}
}
}
else if (mPods[selectedRow.Index].Pod.IsLocal)
{
for (int num3 = list.Count - 1; num3 >= 0; num3--)
{
bool flag = false;
LaunchData[] allApplications2 = mPods[selectedRow.Index].Conn.AllApplications;
for (int i = 0; i < allApplications2.Length; i++)
{
LaunchData launchData = allApplications2[i];
if (list[num3].LaunchPair.LaunchKey == launchData.LaunchPair.LaunchKey)
{
flag = true;
break;
}
}
if (!flag)
{
list.RemoveAt(num3);
}
}
}
else
{
list.Clear();
}
}
deletePodToolStripMenuItem.Enabled = num2 > 0;
installProductToolStripMenuItem.Enabled = num > 0;
resendPodConfigurationToolStripMenuItem.Enabled = num > 0;
uninstallProductToolStripMenuItem.Enabled = list != null && list.Count > 0;
uninstallProductToolStripMenuItem.DropDownItems.Clear();
if (list == null)
{
return;
}
foreach (LaunchData item in list)
{
ToolStripMenuItem toolStripMenuItem = new ToolStripMenuItem();
toolStripMenuItem.Text = item.LaunchPair.DisplayName;
toolStripMenuItem.Tag = item;
toolStripMenuItem.Click += UninstallProduct_Click;
uninstallProductToolStripMenuItem.DropDownItems.Add(toolStripMenuItem);
}
}
/// <summary>
/// Rebuilds the "Install Product" context menu from the data-driven catalog
/// (<see cref="AppRegistry"/>) — one entry per product plus the "Add New Product..."
/// management action.
/// </summary>
private void BuildInstallProductMenu()
{
installProductToolStripMenuItem.DropDownItems.Clear();
foreach (ProductDefinition product in AppRegistry.Products)
{
ToolStripMenuItem installItem = new ToolStripMenuItem(product.MenuText) { Tag = product };
installItem.Click += InstallProduct_Click;
installProductToolStripMenuItem.DropDownItems.Add(installItem);
}
installProductToolStripMenuItem.DropDownItems.Add(new ToolStripSeparator());
ToolStripMenuItem addItem = new ToolStripMenuItem("Add New Product...");
addItem.Click += AddProduct_Click;
installProductToolStripMenuItem.DropDownItems.Add(addItem);
}
/// <summary>Defines a new catalog product, persists it, and optionally pushes it to the selected pods.</summary>
private void AddProduct_Click(object sender, EventArgs e)
{
using dlgAddProduct dialog = new dlgAddProduct();
if (dialog.ShowDialog(this) != DialogResult.OK)
{
return;
}
AppRegistry.AddProduct(dialog.Product);
BuildInstallProductMenu();
// A package means "deploy now" — install it (file transfer + entry registration on
// completion) to the selected pods. No package → the product is only added to the catalog.
if (dialog.PackagePath == null)
{
return;
}
foreach (int podIndex in SelectedInstallablePodIndices())
{
mPods[podIndex].Install_CustomResolution = null;
mPods[podIndex].Install_HostTypes = new List<PodInstallType>();
InstallProduct(podIndex, dialog.Product.Id, dialog.PackagePath);
}
}
/// <summary>Indices of selected rows that are local, idle pods eligible for install.</summary>
private IEnumerable<int> SelectedInstallablePodIndices()
{
foreach (DataGridViewRow selectedRow in dgvPods.SelectedRows)
{
if (selectedRow.Index < mPods.Count && mPods[selectedRow.Index].Pod.IsLocal && !mPods[selectedRow.Index].OperationInProgress)
{
yield return selectedRow.Index;
}
}
}
/// <summary>Generic install handler: selects a package, optionally prompts for roles/resolution, installs to selected local pods.</summary>
private void InstallProduct_Click(object sender, EventArgs e)
{
ProductDefinition product = (ProductDefinition)((ToolStripMenuItem)sender).Tag;
dlgSelectPackage.Title = "Select " + product.Name + " Install Package";
if (dlgSelectPackage.ShowDialog(this) != DialogResult.OK)
{
return;
}
Size? resolution = null;
List<PodInstallType> hostTypes = new List<PodInstallType>();
if (product.HostTypeDialog)
{
using dlgOptionalStartParams startParams = new dlgOptionalStartParams();
if (startParams.ShowDialog(this) != DialogResult.OK)
{
return;
}
resolution = startParams.Resolution;
if (startParams.IsGameClient)
{
hostTypes.Add(PodInstallType.GameClient);
}
if (startParams.IsLiveCam)
{
hostTypes.Add(PodInstallType.LiveCamera);
}
if (startParams.IsMissionReview)
{
hostTypes.Add(PodInstallType.MissionReview);
}
}
foreach (int podIndex in SelectedInstallablePodIndices())
{
mPods[podIndex].Install_CustomResolution = resolution;
mPods[podIndex].Install_HostTypes = new List<PodInstallType>(hostTypes);
InstallProduct(podIndex, product.Id, dlgSelectPackage.FileName);
}
}
private void Pod_PingCompleted(object sender, PingCompletedEventArgs e)
{
PodData podData = e.UserState as PodData;
podData.OperationInProgress = false;
podData.Error = e.Error;
podData.PingReply = e.Reply;
if (e.Reply.Status == IPStatus.Success)
{
podData.Conn.ConnectAsync(podData);
}
podData.StartPing();
int num = mPods.IndexOf(podData);
if (num >= 0 && num < dgvPods.Rows.Count)
{
dgvPods.InvalidateRow(num);
}
}
private void Pod_PingCompleted(PodData pod)
{
if (base.InvokeRequired)
{
BeginInvoke(new Action<PodData>(Pod_PingCompleted), pod);
return;
}
if (!pod.Conn.IsConnecting && !pod.Conn.IsConnected && pod.PingReply != null && pod.PingReply.Status == IPStatus.Success)
{
pod.Conn.ConnectAsync(pod);
}
int num = mPods.IndexOf(pod);
if (num >= 0 && num < dgvPods.Rows.Count)
{
dgvPods.InvalidateRow(num);
}
}
private void PodInfo_InstallProductProgress(InstallProductProgressEventArgs e)
{
Tuple<PodData, Guid> tuple = e.UserState as Tuple<PodData, Guid>;
tuple.A.PercentProgress = e.ProgressPercentage;
ProductDefinition product = AppRegistry.GetProduct(tuple.B);
tuple.A.Status = "Installing " + (product?.Name ?? "product") + ": " + e.Status;
dgvPods.InvalidateCell(colOperationProgress.Index, mPods.IndexOf(tuple.A));
}
private void PodInfo_InstallProductCompleted(object sender, InstallProductCompletedEventArgs e)
{
Tuple<PodData, Guid> tuple = e.UserState as Tuple<PodData, Guid>;
PodData a = tuple.A;
foreach (LaunchData appData in BuildLaunchData(tuple.B, a))
{
a.Conn.AddApp(appData);
}
a.OperationInProgress = false;
a.Error = e.Error;
dgvPods.InvalidateCell(colOperationProgress.Index, mPods.IndexOf(a));
}
/// <summary>
/// Builds the launch entries a product registers on a pod, honoring (for host-type products)
/// the roles selected during install. Returns empty if the product is unknown.
/// </summary>
private static List<LaunchData> BuildLaunchData(Guid productId, PodData pod)
{
List<LaunchData> list = new List<LaunchData>();
ProductDefinition product = AppRegistry.GetProduct(productId);
if (product == null)
{
return list;
}
foreach (LaunchEntryDefinition entry in product.Entries)
{
if (product.HostTypeDialog && entry.HostType != AppHostType.None
&& !pod.Install_HostTypes.Contains(ToInstallType(entry.HostType)))
{
continue;
}
list.Add(entry.ToLaunchData(pod.Install_CustomResolution));
}
return list;
}
private static PodInstallType ToInstallType(AppHostType hostType)
{
return hostType switch
{
AppHostType.LiveCamera => PodInstallType.LiveCamera,
AppHostType.MissionReview => PodInstallType.MissionReview,
_ => PodInstallType.GameClient,
};
}
private void PodInfo_UninstallProductCompleted(object sender, AsyncCompletedEventArgs e)
{
PodData podData = (PodData)e.UserState;
podData.OperationInProgress = false;
podData.Error = e.Error;
podData.Status = "Uninstall completed!";
dgvPods.InvalidateCell(colOperationProgress.Index, mPods.IndexOf(podData));
}
private void PodInfo_ConnectCompleted(object sender, AsyncCompletedEventArgs e)
{
PodData podData = e.UserState as PodData;
if (e.Error != null)
{
podData.Error = e.Error;
if (podData.PingReply != null && podData.PingReply.Status == IPStatus.Success)
{
new System.Threading.Timer(delegate(object state)
{
PodData podData2 = (PodData)state;
if (!podData2.Conn.IsConnected && !podData2.Conn.IsConnecting)
{
((PodData)state).Conn.ConnectAsync((PodData)state);
}
}, podData, 5000, -1);
}
}
else
{
podData.OperationInProgress = false;
}
int num = mPods.IndexOf(podData);
if (num >= 0 && num < dgvPods.Rows.Count)
{
dgvPods.InvalidateRow(num);
}
}
private void UninstallProduct_Click(object sender, EventArgs e)
{
ToolStripMenuItem toolStripMenuItem = (ToolStripMenuItem)sender;
LaunchData launchData = (LaunchData)toolStripMenuItem.Tag;
foreach (DataGridViewRow selectedRow in dgvPods.SelectedRows)
{
if (selectedRow.Index < mPods.Count && mPods[selectedRow.Index].Pod.IsLocal && !mPods[selectedRow.Index].OperationInProgress)
{
UninstallProduct(selectedRow.Index, launchData.LaunchPair.LaunchKey);
}
}
}
private void InstallProduct(int podIndex, Guid appId, string packageFilename)
{
PodInfo conn = mPods[podIndex].Conn;
mPods[podIndex].OperationInProgress = true;
mPods[podIndex].Error = null;
mPods[podIndex].PercentProgress = 0;
mPods[podIndex].Status = "";
conn.InstallProductAsync(packageFilename, new Tuple<PodData, Guid>(mPods[podIndex], appId), PodInfo_InstallProductProgress);
}
private void UninstallProduct(int podIndex, Guid appId)
{
PodInfo conn = mPods[podIndex].Conn;
mPods[podIndex].OperationInProgress = true;
mPods[podIndex].Error = null;
mPods[podIndex].PercentProgress = 0;
mPods[podIndex].Status = "Uninstalling product(s)...";
dgvPods.InvalidateCell(colOperationProgress.Index, podIndex);
conn.UninstallProductAsync(appId, mPods[podIndex]);
}
private void LoadConfiguration(Site site)
{
mSite = site;
dgvPods.Rows.Clear();
mPods.Clear();
foreach (Squad squad in site.Squads)
{
colSquad.Items.Add(squad.Name);
foreach (Pod pod in squad.Pods)
{
PodData podData = new PodData(pod, squad.Name, this);
mPods.Add(podData);
if (pod.IsLocal)
{
podData.PercentProgress = -1;
podData.OperationInProgress = true;
podData.Status = "Pinging pod...";
Ping ping = new Ping();
ping.PingCompleted += Pod_PingCompleted;
ping.SendAsync(pod.IPAddress, 10000, podData);
}
}
}
colType.Items.Add((HostTypeHelper)HostType.GameMachineHostType);
colType.Items.Add((HostTypeHelper)HostType.MissionReviewHostType);
dgvPods.RowCount = mPods.Count + 1;
dgvPods.AutoResizeColumns();
}
private void importSiteConfigurationToolStripMenuItem_Click(object sender, EventArgs e)
{
if (MessageBox.Show(this, "Importing a site configuration will replace the current configuration. Are you sure you want to continue?", "Site Management", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes && dlgOpenFile.ShowDialog(this) == DialogResult.OK)
{
LoadConfiguration(TeslaConsole.Site.LoadFromFile(dlgOpenFile.FileName));
}
}
private void exportSiteConfigurationToolStripMenuItem_Click(object sender, EventArgs e)
{
if (dlgSaveFile.ShowDialog(this) == DialogResult.OK)
{
mSite.SaveAs(dlgSaveFile.FileName);
}
}
private void DeletePod(int rowIndex)
{
if (rowIndex < mPods.Count && !mPods[rowIndex].OperationInProgress)
{
dgvPods.Rows.RemoveAt(rowIndex);
mPods[rowIndex].StopPing();
// Close any lingering/half-open connection to the pod's IP. Without this the
// socket + connection state survive until the console process exits — which is
// why deleting a pod previously still required a console restart before it
// could be reconfigured.
mPods[rowIndex].Conn?.Disconnect();
mPods.RemoveAt(rowIndex);
}
}
private void deletePodToolStripMenuItem_Click(object sender, EventArgs e)
{
if (dgvPods.SelectedRows.Count > 1)
{
if (MessageBox.Show(this, "Are you sure you want to delete these pods?", "Site Management", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
return;
}
}
else if (dgvPods.CurrentRow.Index < mPods.Count && MessageBox.Show(this, "Are you sure you want to delete " + mPods[dgvPods.CurrentRow.Index].Pod.Name + "?", "Site Management", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
return;
}
for (int num = dgvPods.SelectedRows.Count - 1; num >= 0; num--)
{
DeletePod(dgvPods.SelectedRows[num].Index);
}
}
private void resendPodConfigurationToolStripMenuItem_Click(object sender, EventArgs e)
{
if (dgvPods.SelectedRows.Count == 1)
{
if (MessageBox.Show(this, "Reconfiguring this pod will remove it from your site, allowing you to reconfigure it. Are you sure you want to continue?", "Reconfigure", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
return;
}
}
else if (MessageBox.Show(this, "Reconfiguring these pods will remove them from your site, allowing you to reconfigure them. Are you sure you want to continue?", "Reconfigure", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
return;
}
List<PodData> list = new List<PodData>();
foreach (DataGridViewRow selectedRow in dgvPods.SelectedRows)
{
if (selectedRow.Index >= mPods.Count)
{
continue;
}
PodData podData = mPods[selectedRow.Index];
list.Add(podData);
DeletePod(selectedRow.Index);
foreach (Squad squad in mSite.Squads)
{
if (!(squad.Name == podData.Squad))
{
continue;
}
for (int num = squad.Pods.Count - 1; num >= 0; num--)
{
if (squad.Pods[num].ID == podData.Pod.ID)
{
squad.Pods.RemoveAt(num);
}
}
}
}
mSite.Save();
foreach (PodData item in list)
{
try
{
item.Conn.ClearStore();
}
catch (ConnectionLostException)
{
MessageBox.Show($"The data store on {item.Pod.Name} could not be cleared because the connection has been lost. Please try again.", "Connection Lost");
}
}
}
}