Co-locate the two cockpit-pod projects into a single repository:
- Console/ : TeslaConsole, the net48 WinForms operator console (decompiled
reconstruction) plus its differential + catalog test suite.
- Launcher/ : TeslaLauncher, the net6 pod-side Service + Agent rewrite.
Adds a combined TeslaSuite.sln, root README documenting the shared wire
contract (and its current duplication, the main follow-up), and a root
.gitignore. Histories were not preserved per request; this is a fresh start
from the current working state of both projects.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1429 lines
48 KiB
C#
1429 lines
48 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 registerProductToolStripMenuItem;
|
|
|
|
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);
|
|
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);
|
|
}
|
|
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)
|
|
{
|
|
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;
|
|
if (registerProductToolStripMenuItem != null)
|
|
{
|
|
registerProductToolStripMenuItem.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 product-related context menus from the data-driven catalog (<see cref="AppRegistry"/>):
|
|
/// • "Install Product" → transfer a package and register its launch entries
|
|
/// • "Register Product" → push launch entries to pods over the network, no file install
|
|
/// plus the "Add New Product..." management action.
|
|
/// </summary>
|
|
private void BuildInstallProductMenu()
|
|
{
|
|
// Lazily create the "Register Product" parent and place it after "Install Product".
|
|
if (registerProductToolStripMenuItem == null)
|
|
{
|
|
registerProductToolStripMenuItem = new ToolStripMenuItem("Register Product on Pods");
|
|
int insertAt = cmnuDataGrid.Items.IndexOf(installProductToolStripMenuItem) + 1;
|
|
cmnuDataGrid.Items.Insert(insertAt, registerProductToolStripMenuItem);
|
|
}
|
|
|
|
installProductToolStripMenuItem.DropDownItems.Clear();
|
|
registerProductToolStripMenuItem.DropDownItems.Clear();
|
|
foreach (ProductDefinition product in AppRegistry.Products)
|
|
{
|
|
ToolStripMenuItem installItem = new ToolStripMenuItem(product.MenuText) { Tag = product };
|
|
installItem.Click += InstallProduct_Click;
|
|
installProductToolStripMenuItem.DropDownItems.Add(installItem);
|
|
|
|
ToolStripMenuItem registerItem = new ToolStripMenuItem(product.Name) { Tag = product };
|
|
registerItem.Click += RegisterProduct_Click;
|
|
registerProductToolStripMenuItem.DropDownItems.Add(registerItem);
|
|
}
|
|
|
|
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();
|
|
|
|
if (!dialog.PushNow)
|
|
{
|
|
return;
|
|
}
|
|
if (dialog.PackagePath != null)
|
|
{
|
|
// Package supplied → full install (file transfer + entry registration on completion).
|
|
foreach (int podIndex in SelectedInstallablePodIndices())
|
|
{
|
|
mPods[podIndex].Install_CustomResolution = null;
|
|
mPods[podIndex].Install_HostTypes = new List<PodInstallType>();
|
|
InstallProduct(podIndex, dialog.Product.Id, dialog.PackagePath);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RegisterProductOnSelectedPods(dialog.Product);
|
|
}
|
|
}
|
|
|
|
/// <summary>Pushes a catalog product's launch entries to selected connected pods without installing files.</summary>
|
|
private void RegisterProduct_Click(object sender, EventArgs e)
|
|
{
|
|
ProductDefinition product = (ProductDefinition)((ToolStripMenuItem)sender).Tag;
|
|
RegisterProductOnSelectedPods(product);
|
|
}
|
|
|
|
private void RegisterProductOnSelectedPods(ProductDefinition product)
|
|
{
|
|
int pushed = 0;
|
|
int skipped = 0;
|
|
foreach (int podIndex in SelectedInstallablePodIndices())
|
|
{
|
|
PodData pod = mPods[podIndex];
|
|
if (!pod.Conn.IsConnected)
|
|
{
|
|
skipped++;
|
|
continue;
|
|
}
|
|
foreach (LaunchEntryDefinition entry in product.Entries)
|
|
{
|
|
pod.Conn.AddApp(entry.ToLaunchData(null));
|
|
}
|
|
pod.Status = "Registered " + product.Name;
|
|
dgvPods.InvalidateCell(colOperationProgress.Index, podIndex);
|
|
pushed++;
|
|
}
|
|
if (skipped > 0)
|
|
{
|
|
MessageBox.Show(this,
|
|
$"Registered \"{product.Name}\" on {pushed} pod(s). {skipped} selected pod(s) were skipped because they are not connected.",
|
|
"Register Product", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
|
|
/// <summary>Indices of selected rows that are local, idle pods eligible for install/registration.</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();
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
}
|